Files
orca/src/main/codex/codex-session-resume-preparation.ts
T
Brennan Benson 4340781c9f fix(codex): drop the resume argv when session provenance is unverifiable (#10805)
Closes #10793.

When Orca could not verify the originating Codex session file it either threw — a
red per-pane toast and a failed spawn, reported as constant spam on #10757 — or
returned null. Returning null did NOT start a fresh session: the renderer had
already baked ['codex','resume',<id>] into the command and pty.ts never rewrote
it, so CODEX_HOME simply fell through to whichever account was selected.

The resume argv is now dropped so a plain `codex` launches, with a banner telling
the user. The invariant — never run `codex resume <id>` under an account that does
not own that rollout — is now satisfied by construction rather than by refusing to
spawn. A verified resume is unchanged and still pins CODEX_HOME to the
originating home.

Reviewed over two adversarial rounds; seven defects found and fixed, including a
HIGH where local-provider (non-daemon) spawns still carried
ORCA_SEQUENCED_STARTUP_COMMAND with `resume <id>` — the wrong account behind a
banner claiming it started fresh. `env` is now declared after the strip so no
point in the handler can reach the pre-strip value.

Live-validated in a real Orca dev build: all five cases proven on the SPAWNED
PROCESS, including a real rollout under an untrusted home (the only shape that
discriminates) and the local-provider path forced by stopping the daemon.

An earlier CI failure on multi-client-navigation-isolation.integration.test.ts was
investigated and is a PRE-EXISTING flake — a ~4ms race in the session-tabs notify
coalescer that fails 5-8/24 on clean main, more often than on this branch. Fixed
separately in #11022.

Not verified: no Windows execution — its POSIX-only tests skip there and the
#10757 reporter is on Windows. SSH is partial: no spurious banner or drop observed
against a real target, but headless spawn does not deliver startup commands so the
remote argv could not be read. The relay/mobile notice channel deliberately has no
banner; the argv drop does happen there, so the invariant holds.
2026-07-27 18:06:30 -07:00

49 lines
2.0 KiB
TypeScript

import {
resolveCodexSessionResumeProvenance,
type CodexSessionResumePreparation
} from './codex-session-resume-home'
export type VerifiedCodexResumeSource = { homePath: string; transcriptPath: string }
/**
* The launch decision for an automatic Codex resume: pin the verified origin home, or
* fall back to a fresh session whose resume argv the PTY layer drops (#10793). The
* caller supplies `resolveVerifiedResumeHome` because migration, project trust and hook
* repair only run once provenance is verified — a fresh outcome must skip all of them.
*
* The three rescan ranking inputs stay required through this hop (#10801): defaulting or
* nulling any of them would silently degrade the legacy rescan to pure path order.
*/
export async function prepareCodexSessionResume(args: {
sessionId: string
transcriptPath: string | undefined
trustedCodexHomes: readonly string[]
getSelectedAccountCodexHome: () => string | null
systemCodexHomePath: string | null
sharedRuntimeCodexHomePath: string | null
resolveVerifiedResumeHome: (source: VerifiedCodexResumeSource) => Promise<string>
fileIsRegular?: (filePath: string) => boolean
listSessionFiles?: (sessionsRoot: string) => AsyncIterable<string>
}): Promise<CodexSessionResumePreparation> {
const provenance = await resolveCodexSessionResumeProvenance({
sessionId: args.sessionId,
transcriptPath: args.transcriptPath,
trustedCodexHomes: args.trustedCodexHomes,
getSelectedAccountCodexHome: args.getSelectedAccountCodexHome,
systemCodexHomePath: args.systemCodexHomePath,
sharedRuntimeCodexHomePath: args.sharedRuntimeCodexHomePath,
...(args.fileIsRegular ? { fileIsRegular: args.fileIsRegular } : {}),
...(args.listSessionFiles ? { listSessionFiles: args.listSessionFiles } : {})
})
if (provenance.outcome === 'fresh') {
return provenance
}
return {
outcome: 'resume',
codexHomePath: await args.resolveVerifiedResumeHome({
homePath: provenance.homePath,
transcriptPath: provenance.transcriptPath
})
}
}