Files
orca/src/main/runtime/runtime-github-worktree-base.ts
T
Neil 41f15805b4 fix(runtime): PR/MR worktree base refuses SSH projects named only by executionHostId (#31054)
* fix(runtime): PR/MR worktree base refuses SSH projects named only by executionHostId

Codex review 6 #4: the guard read the legacy connectionId, so a row stamped
executionHostId 'ssh:<target>' without it ran git fetch on this machine.

* fix(runtime): one gate for local Git on a repo row; base resolution agrees with create

Review follow-up: a local row with a stale connectionId and runtime: rows now
refuse too (create already refused runtime: rows), through
requireRepoLocalGitRoute in repo-execution-host.ts.

* fix(runtime): keep base resolution for runtime-stamped rows this server owns

Codex follow-up: older servers keep a client-minted runtime:<id> stamp on
rows whose files are here, and base resolution worked for them before.
requireRepoLocalGitRoute reads the stored host (getStoredRepoExecutionHostId),
so they run locally again; SSH rows and any row with a connectionId still
refuse.
2026-10-20 02:36:11 -07:00

79 lines
2.8 KiB
TypeScript

import type { GitHubPrStartPoint } from '../../shared/worktree/types'
import type { Repo } from '../../shared/repo-types'
import {
fetchPrHeadTrackingRef,
fetchGitHubPullRequestHeadRef
} from '../github/pr-head-tracking-ref'
import { resolveGitHubPrStartPoint } from '../github/pr-start-point'
import { resolveGitHubReviewHeadRemote } from '../github/review-head-remote'
import { gitExecFileAsync } from '../git/runner'
import {
getLocalProjectGitExecOptions,
getLocalProjectGhExecOptions
} from '../project-runtime-git-options'
import { isFolderRepo } from '../../shared/repo-kind'
import { requireRepoLocalGitRoute } from '../repo-execution-host'
import type { ProjectRuntimeResolutionStore } from '../local-project-runtime-resolution'
export type RuntimeGitHubWorktreeBaseArgs = {
repoSelector: string
prNumber: number
headRefName?: string
baseRefName?: string
isCrossRepository?: boolean
}
export async function resolveRuntimeGitHubWorktreeBase(
args: RuntimeGitHubWorktreeBaseArgs,
deps: {
store: ProjectRuntimeResolutionStore | null
resolveRepo: (selector: string) => Promise<Repo>
}
): Promise<GitHubPrStartPoint | { error: string }> {
if (!deps.store) {
throw new Error('runtime_unavailable')
}
let repo: Repo
try {
repo = await deps.resolveRepo(args.repoSelector)
} catch {
return { error: 'Repo not found' }
}
if (isFolderRepo(repo)) {
return { error: 'Folder mode does not support creating worktrees.' }
}
// Why the shared gate: a row may name its SSH host only as `executionHostId`.
requireRepoLocalGitRoute(repo)
const localGitExecOptions = getLocalProjectGitExecOptions(deps.store, repo)
const localGhOptions = getLocalProjectGhExecOptions(deps.store, repo)
const gitExec = (gitArgs: string[]) => gitExecFileAsync(gitArgs, localGitExecOptions)
const resolveRemote = (): Promise<string> =>
resolveGitHubReviewHeadRemote({
repoPath: repo.path,
issueSourcePreference: repo.issueSourcePreference,
connectionId: null,
localGitOptions: localGhOptions,
gitExec
})
const fetchRemoteTrackingRef = (remote: string, branch: string): Promise<void> =>
fetchPrHeadTrackingRef(repo, remote, branch, { localGitExecOptions })
const fetchPullRequestHeadRef = (remote: string, prNumber: number): Promise<string> =>
fetchGitHubPullRequestHeadRef(repo, remote, prNumber, {
localGitExecOptions
})
return resolveGitHubPrStartPoint({
repoPath: repo.path,
prNumber: args.prNumber,
headRefName: args.headRefName,
baseRefName: args.baseRefName,
isCrossRepository: args.isCrossRepository,
issueSourcePreference: repo.issueSourcePreference,
connectionId: null,
localGitOptions: localGhOptions,
gitExec,
fetchRemoteTrackingRef,
fetchPullRequestHeadRef,
resolveRemote
})
}