Skip to content

Commit c4eae8d

Browse files
committed
fix(terminal): restrict GitHub shorthand owner to real slug rules
Owner segment now matches GitHub's user/org rules (ASCII alphanumerics + single hyphens, no dots/underscores, no leading/trailing/consecutive hyphen, <=39 chars) instead of the lax repo charset. Prevents slash-separated terminal tokens that fail path resolution (text/html, foo.bar/baz, my_org/x) from producing bogus 'Open Link in Browser' items. Repo names stay laxer (dots/underscores) to match real repos like mrdoob/three.js. Addresses Greptile P2 on manaflow-ai#5491.
1 parent 73ac6c6 commit c4eae8d

1 file changed

Lines changed: 27 additions & 8 deletions

File tree

Sources/GhosttyTerminalView.swift

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11651,17 +11651,36 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
1165111651
guard parts.count == 2 else { return nil }
1165211652
let owner = String(parts[0])
1165311653
let repo = String(parts[1])
11654-
let allowed = CharacterSet(
11655-
charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"
11656-
)
11657-
guard !owner.isEmpty, !repo.isEmpty,
11658-
owner.count <= 39, repo.count <= 100,
11659-
!owner.hasPrefix("-"), !owner.hasPrefix("."),
11660-
owner.unicodeScalars.allSatisfy(allowed.contains),
11661-
repo.unicodeScalars.allSatisfy(allowed.contains) else { return nil }
11654+
// The owner segment must match GitHub's real user/org slug rules:
11655+
// ASCII alphanumerics and single hyphens only — no dots or
11656+
// underscores, no leading/trailing/consecutive hyphen, ≤39 chars.
11657+
// This stops slash-separated terminal tokens that failed path
11658+
// resolution (e.g. `src/index.ts`, `dist/bundle.js`, MIME types
11659+
// like `text/html`) from producing bogus "Open Link" menu items.
11660+
// Repo names are laxer (dots/underscores allowed), matching GitHub.
11661+
guard Self.isPlausibleGitHubOwner(owner),
11662+
Self.isPlausibleGitHubRepo(repo) else { return nil }
1166211663
return URL(string: "https://github.com/\(owner)/\(repo)\(suffixPath)")
1166311664
}
1166411665

11666+
private static let gitHubOwnerAllowed = CharacterSet(
11667+
charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-")
11668+
private static let gitHubRepoAllowed = CharacterSet(
11669+
charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._")
11670+
11671+
private static func isPlausibleGitHubOwner(_ owner: String) -> Bool {
11672+
(1...39).contains(owner.count)
11673+
&& !owner.hasPrefix("-") && !owner.hasSuffix("-")
11674+
&& !owner.contains("--")
11675+
&& owner.unicodeScalars.allSatisfy(gitHubOwnerAllowed.contains)
11676+
}
11677+
11678+
private static func isPlausibleGitHubRepo(_ repo: String) -> Bool {
11679+
(1...100).contains(repo.count)
11680+
&& repo != "." && repo != ".."
11681+
&& repo.unicodeScalars.allSatisfy(gitHubRepoAllowed.contains)
11682+
}
11683+
1166511684
private func writeStringToPasteboard(_ string: String) {
1166611685
let pasteboard = NSPasteboard.general
1166711686
pasteboard.clearContents()

0 commit comments

Comments
 (0)