mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 16:03:17 +00:00
Fix GitHub Enterprise host identity loss across PR/work-item paths
- Thread `host` through mobile PR RPC params, IPC work-item lookups, and RPC schemas so GHES identity survives the renderer/mobile/main boundary instead of silently falling back to a same-named github.com repo. - Qualify `--repo`/`-R` args for github.com too (not just GHES), since gh resolves bare shorthand against a process-level GH_HOST that can redirect pinned github.com commands. - Cache `getOriginGitHubApiRepository` to avoid a per-call uncached `git remote get-url` round trip on connection-backed repos. - Add a local-fork fallback in `getWorkItemDetails` so PRs living on a base repo (not visible via the origin slug) still resolve via cwd. - Centralize the github.com-vs-GHES host predicate in `isDefaultGitHubHost` so cache keys, quota scoping, and identity checks can't drift out of sync.
This commit is contained in:
@@ -1,9 +1,31 @@
|
||||
import type { GitHubOwnerRepo } from '../../shared/types'
|
||||
import { isDefaultGitHubHost } from '../../shared/github-repository-identity-key'
|
||||
import { getOwnerRepo, type LocalGitExecOptions } from './gh-utils'
|
||||
import { getEnterpriseGitHubRepoSlug } from './github-enterprise-repository'
|
||||
|
||||
export type GitHubApiRepository = GitHubOwnerRepo
|
||||
|
||||
// Why: the enterprise branch spawns an uncached `git remote get-url` (an SSH
|
||||
// round trip on connection-backed repos) — hot paths like per-file contents
|
||||
// and viewed-state toggles resolve per call, so cache like ownerRepoCache does.
|
||||
const ORIGIN_REPO_CACHE_TTL_MS = 30_000
|
||||
const originRepoCache = new Map<string, { value: GitHubApiRepository | null; expiresAt: number }>()
|
||||
const originRepoInFlight = new Map<string, Promise<GitHubApiRepository | null>>()
|
||||
|
||||
function originRepoCacheKey(
|
||||
repoPath: string,
|
||||
connectionId?: string | null,
|
||||
localGitOptions: LocalGitExecOptions = {}
|
||||
): string {
|
||||
return `${connectionId ?? 'local'}\0${localGitOptions.wslDistro ?? ''}\0${repoPath}`
|
||||
}
|
||||
|
||||
/** @internal - exposed for tests only */
|
||||
export function _resetOriginGitHubApiRepositoryCache(): void {
|
||||
originRepoCache.clear()
|
||||
originRepoInFlight.clear()
|
||||
}
|
||||
|
||||
export async function getOriginGitHubApiRepository(
|
||||
repoPath: string,
|
||||
connectionId?: string | null,
|
||||
@@ -13,9 +35,30 @@ export async function getOriginGitHubApiRepository(
|
||||
if (ownerRepo) {
|
||||
return { ...ownerRepo, host: 'github.com' }
|
||||
}
|
||||
const enterpriseOptions =
|
||||
Object.keys(localGitOptions).length > 0 ? { localGitExecOptions: localGitOptions } : {}
|
||||
return getEnterpriseGitHubRepoSlug(repoPath, connectionId, enterpriseOptions)
|
||||
const cacheKey = originRepoCacheKey(repoPath, connectionId, localGitOptions)
|
||||
const cached = originRepoCache.get(cacheKey)
|
||||
if (cached && cached.expiresAt > Date.now()) {
|
||||
return cached.value
|
||||
}
|
||||
const inFlight = originRepoInFlight.get(cacheKey)
|
||||
if (inFlight) {
|
||||
return inFlight
|
||||
}
|
||||
const probe = (async () => {
|
||||
const enterpriseOptions =
|
||||
Object.keys(localGitOptions).length > 0 ? { localGitExecOptions: localGitOptions } : {}
|
||||
const slug = await getEnterpriseGitHubRepoSlug(repoPath, connectionId, enterpriseOptions)
|
||||
originRepoCache.set(cacheKey, { value: slug, expiresAt: Date.now() + ORIGIN_REPO_CACHE_TTL_MS })
|
||||
return slug
|
||||
})()
|
||||
originRepoInFlight.set(cacheKey, probe)
|
||||
try {
|
||||
return await probe
|
||||
} finally {
|
||||
if (originRepoInFlight.get(cacheKey) === probe) {
|
||||
originRepoInFlight.delete(cacheKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function resolveGitHubApiRepository(
|
||||
@@ -46,7 +89,7 @@ export async function resolveGitHubApiRepository(
|
||||
}
|
||||
|
||||
export function isGitHubDotComRepository(repository: GitHubApiRepository): boolean {
|
||||
return !repository.host || repository.host.toLowerCase() === 'github.com'
|
||||
return isDefaultGitHubHost(repository.host)
|
||||
}
|
||||
|
||||
// Why: the gh runner host-qualifies argv from `options.host`, so every known
|
||||
|
||||
Reference in New Issue
Block a user