mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(github): accept SSH certificate org remotes (org-<id>@github.com) (#30659)
GitHub orgs using an SSH certificate authority get an SCP remote whose user is org-<id> rather than git. The three GitHub remote parsers only matched a literal git@ user, so those repos were classified not-github and lost PR, issue and check support. Co-authored-by: Yi-111-a <yi-111-a@users.noreply.github.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
parseGitHubOwnerRepo,
|
||||
parseGitHubOwnerRepoWithResolvedSshHostname,
|
||||
parseGitHubRemoteIdentity,
|
||||
rawSshTransportHost,
|
||||
remoteUrlUsesSshTransport
|
||||
} from './github-remote-identity-parsing'
|
||||
|
||||
@@ -188,3 +189,36 @@ describe('SSH Host alias identity (#10284)', () => {
|
||||
expect(effectiveGitHubRemoteHost('github.com', null)).toBe('github.com')
|
||||
})
|
||||
})
|
||||
|
||||
describe('SSH certificate org remotes (#30601)', () => {
|
||||
const certRemote = 'org-123456@github.com:Acme/app.git'
|
||||
|
||||
it('parses an org-id SCP remote as a GitHub identity', () => {
|
||||
expect(parseGitHubRemoteIdentity(certRemote)).toEqual({
|
||||
host: 'github.com',
|
||||
owner: 'Acme',
|
||||
repo: 'app'
|
||||
})
|
||||
expect(parseGitHubOwnerRepo(certRemote)).toEqual({ owner: 'Acme', repo: 'app' })
|
||||
})
|
||||
|
||||
it('treats an org-id SCP remote as SSH transport', () => {
|
||||
expect(remoteUrlUsesSshTransport(certRemote)).toBe(true)
|
||||
})
|
||||
|
||||
it('reads the transport host from an org-id SCP remote', () => {
|
||||
expect(rawSshTransportHost(certRemote)).toBe('github.com')
|
||||
})
|
||||
|
||||
it('does not need an SSH config expansion for an org-id github.com remote', () => {
|
||||
expect(gitHubSshConfigHostAlias(certRemote)).toBeNull()
|
||||
expect(
|
||||
parseGitHubOwnerRepoWithResolvedSshHostname(certRemote, null)
|
||||
).toEqual({ owner: 'Acme', repo: 'app' })
|
||||
})
|
||||
|
||||
it('still ignores non-GitHub hosts carrying an org-id user', () => {
|
||||
expect(parseGitHubOwnerRepo('org-123456@github-work:Acme/app.git')).toBeNull()
|
||||
expect(gitHubSshConfigHostAlias('org-123456@github-work:Acme/app.git')).toBe('github-work')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -27,14 +27,22 @@ function parseGitHubRemotePath(path: string): Pick<GitHubRemoteIdentity, 'owner'
|
||||
export function remoteUrlUsesSshTransport(remoteUrl: string): boolean {
|
||||
const trimmed = remoteUrl.trim().toLowerCase()
|
||||
return (
|
||||
trimmed.startsWith('git@') || trimmed.startsWith('ssh://') || trimmed.startsWith('git+ssh://')
|
||||
isScpStyleRemote(trimmed) || trimmed.startsWith('ssh://') || trimmed.startsWith('git+ssh://')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Why: GitHub SSH certificate organizations hand out `org-<id>@github.com:<owner>/<repo>`,
|
||||
* so the SCP user is not always `git`.
|
||||
*/
|
||||
function isScpStyleRemote(remoteUrl: string): boolean {
|
||||
return /^[^@\s/:]+@[^:\s/]+:[^\s]+$/.test(remoteUrl)
|
||||
}
|
||||
|
||||
/** SSH transport host as written, preserving SCP alias case. */
|
||||
export function rawSshTransportHost(remoteUrl: string): string | null {
|
||||
const trimmed = remoteUrl.trim()
|
||||
const scpMatch = trimmed.match(/^git@([^:]+):/i)
|
||||
const scpMatch = trimmed.match(/^[^@\s/:]+@([^:]+):/i)
|
||||
if (scpMatch) {
|
||||
return scpMatch[1]
|
||||
}
|
||||
@@ -63,7 +71,7 @@ export function gitHubSshConfigHostAlias(remoteUrl: string): string | null {
|
||||
|
||||
export function parseGitHubRemoteIdentity(remoteUrl: string): GitHubRemoteIdentity | null {
|
||||
const trimmed = remoteUrl.trim()
|
||||
const sshMatch = trimmed.match(/^git@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/i)
|
||||
const sshMatch = trimmed.match(/^[^@\s/:]+@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/i)
|
||||
if (sshMatch) {
|
||||
return { host: normalizeGitHubRemoteHost(sshMatch[1]), owner: sshMatch[2], repo: sshMatch[3] }
|
||||
}
|
||||
|
||||
@@ -197,7 +197,8 @@ function parseGitHubRemoteUrl(remoteUrl: string | undefined): ProjectProviderIde
|
||||
if (!trimmed) {
|
||||
return null
|
||||
}
|
||||
const sshMatch = trimmed.match(/^git@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/i)
|
||||
// Why: SSH certificate orgs use `org-<id>@github.com:<owner>/<repo>`, so the user is not always `git`.
|
||||
const sshMatch = trimmed.match(/^[^@\s/:]+@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/i)
|
||||
if (sshMatch?.[1] && sshMatch[2] && sshMatch[3]) {
|
||||
return projectProviderIdentity(sshMatch[1], sshMatch[2], sshMatch[3])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user