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.
This commit is contained in:
Neil
2026-10-20 02:36:11 -07:00
committed by GitHub
parent e3ad4acaa3
commit 41f15805b4
4 changed files with 111 additions and 8 deletions
@@ -11,8 +11,8 @@ import {
getLocalProjectGitExecOptions,
getLocalProjectGhExecOptions
} from '../project-runtime-git-options'
import { SshHostNotServedError } from '../providers/ssh-host-not-served-error'
import { isFolderRepo } from '../../shared/repo-kind'
import { requireRepoLocalGitRoute } from '../repo-execution-host'
import type { ProjectRuntimeResolutionStore } from '../local-project-runtime-resolution'
export type RuntimeGitHubWorktreeBaseArgs = {
@@ -42,9 +42,8 @@ export async function resolveRuntimeGitHubWorktreeBase(
if (isFolderRepo(repo)) {
return { error: 'Folder mode does not support creating worktrees.' }
}
if (repo.connectionId) {
throw new SshHostNotServedError(repo.connectionId)
}
// 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)