mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 16:03:17 +00:00
fix(codex): keep automatic resume home authoritative
This commit is contained in:
@@ -37,7 +37,7 @@ describe('resolveTrustedCodexSessionResumeHome', () => {
|
||||
})
|
||||
|
||||
it('rejects paths outside trusted homes or outside the rollout layout', () => {
|
||||
const fileIsRegular = (): boolean => true
|
||||
const fileIsRegular = vi.fn((): boolean => true)
|
||||
expect(
|
||||
resolveTrustedCodexSessionResumeHome({
|
||||
transcriptPath: '/tmp/sessions/2026/07/20/rollout-a.jsonl',
|
||||
@@ -60,6 +60,7 @@ describe('resolveTrustedCodexSessionResumeHome', () => {
|
||||
fileIsRegular
|
||||
})
|
||||
).toBeNull()
|
||||
expect(fileIsRegular).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('rejects a trusted-looking path when the rollout no longer exists', () => {
|
||||
|
||||
@@ -48,15 +48,20 @@ function resolveTrustedCodexSessionResume(args: {
|
||||
fileIsRegular?: (filePath: string) => boolean
|
||||
}): { homePath: string; transcriptPath: string } | null {
|
||||
const persistedPath = args.transcriptPath?.trim()
|
||||
const transcriptPath = persistedPath
|
||||
? resolveExistingRolloutPath(persistedPath, args.fileIsRegular ?? isRegularFile)
|
||||
: null
|
||||
if (!transcriptPath) {
|
||||
if (!persistedPath) {
|
||||
return null
|
||||
}
|
||||
|
||||
for (const homePath of args.trustedCodexHomes) {
|
||||
if (isCodexRolloutInsideSessionsRoot(join(homePath, 'sessions'), transcriptPath)) {
|
||||
const sessionsRoot = join(homePath, 'sessions')
|
||||
if (!isCodexRolloutInsideSessionsRoot(sessionsRoot, persistedPath)) {
|
||||
continue
|
||||
}
|
||||
const transcriptPath = resolveExistingRolloutPath(
|
||||
persistedPath,
|
||||
args.fileIsRegular ?? isRegularFile
|
||||
)
|
||||
if (transcriptPath) {
|
||||
return { homePath, transcriptPath }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,7 +985,8 @@ describe('registerPtyHandlers', () => {
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
command: 'codex resume session-a',
|
||||
env: { CODEX_HOME: '/custom/codex' },
|
||||
env: { CODEX_HOME: '/custom/codex', REMOVE_ME: 'stale' },
|
||||
envToDelete: ['CODEX_HOME', 'ORCA_CODEX_HOME', 'REMOVE_ME'],
|
||||
launchAgent: 'codex',
|
||||
resumeProviderSession: {
|
||||
key: 'session_id',
|
||||
@@ -998,6 +999,7 @@ describe('registerPtyHandlers', () => {
|
||||
expect(selectedHome).not.toHaveBeenCalled()
|
||||
expect(env.CODEX_HOME).toBe(systemHome)
|
||||
expect(env.ORCA_CODEX_HOME).toBe(systemHome)
|
||||
expect(env.REMOVE_ME).toBeUndefined()
|
||||
})
|
||||
|
||||
it('does not fall back to the selected account when automatic resume provenance is rejected', async () => {
|
||||
@@ -1851,7 +1853,8 @@ describe('registerPtyHandlers', () => {
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
command: 'codex resume session-a',
|
||||
env: { CODEX_HOME: '/custom/codex' },
|
||||
env: { CODEX_HOME: '/custom/codex', REMOVE_ME: 'stale' },
|
||||
envToDelete: ['CODEX_HOME', 'ORCA_CODEX_HOME', 'REMOVE_ME'],
|
||||
launchAgent: 'codex',
|
||||
resumeProviderSession: {
|
||||
key: 'session_id',
|
||||
@@ -1864,6 +1867,68 @@ describe('registerPtyHandlers', () => {
|
||||
expect(selectedHome).not.toHaveBeenCalled()
|
||||
expect(env.CODEX_HOME).toBe(systemHome)
|
||||
expect(env.ORCA_CODEX_HOME).toBe(systemHome)
|
||||
expect(env.REMOVE_ME).toBeUndefined()
|
||||
})
|
||||
|
||||
it('keeps the authoritative home for runtime-created daemon resumes', async () => {
|
||||
type RuntimeSpawnController = {
|
||||
spawn(args: {
|
||||
cols: number
|
||||
rows: number
|
||||
command: string
|
||||
env: Record<string, string>
|
||||
envToDelete: string[]
|
||||
launchAgent: 'codex'
|
||||
resumeProviderSession: {
|
||||
key: 'session_id'
|
||||
id: string
|
||||
transcriptPath: string
|
||||
}
|
||||
}): Promise<{ id: string }>
|
||||
}
|
||||
const daemonSpawn = setupDaemonAdapter()
|
||||
const runtime = {
|
||||
setPtyController: vi.fn(),
|
||||
registerPty: vi.fn(),
|
||||
noteTerminalSpawnCommand: vi.fn(),
|
||||
onPtySpawned: vi.fn(),
|
||||
onPtyExit: vi.fn(),
|
||||
onPtyData: vi.fn()
|
||||
}
|
||||
const systemHome = '/Users/example/.codex'
|
||||
handlers.clear()
|
||||
registerPtyHandlers(
|
||||
mainWindow as never,
|
||||
runtime as never,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{ prepareCodexSessionResume: async () => ({ codexHomePath: systemHome }) }
|
||||
)
|
||||
const controller = runtime.setPtyController.mock.calls[0]?.[0] as RuntimeSpawnController
|
||||
|
||||
await controller.spawn({
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
command: 'codex resume session-a',
|
||||
env: { CODEX_HOME: '/custom/codex', REMOVE_ME: 'stale' },
|
||||
envToDelete: ['CODEX_HOME', 'ORCA_CODEX_HOME', 'REMOVE_ME'],
|
||||
launchAgent: 'codex',
|
||||
resumeProviderSession: {
|
||||
key: 'session_id',
|
||||
id: 'session-a',
|
||||
transcriptPath: `${systemHome}/sessions/2026/07/20/rollout-a.jsonl`
|
||||
}
|
||||
})
|
||||
|
||||
const spawnOptions = daemonSpawn.mock.calls.at(-1)?.[0] as DaemonSpawnCall
|
||||
expect(spawnOptions.env.CODEX_HOME).toBe(systemHome)
|
||||
expect(spawnOptions.env.ORCA_CODEX_HOME).toBe(systemHome)
|
||||
expect(spawnOptions.env.REMOVE_ME).toBeUndefined()
|
||||
expect(spawnOptions.envToDelete ?? []).not.toContain('CODEX_HOME')
|
||||
expect(spawnOptions.envToDelete ?? []).not.toContain('ORCA_CODEX_HOME')
|
||||
expect(spawnOptions.envToDelete).toContain('REMOVE_ME')
|
||||
})
|
||||
|
||||
it('prepares Codex project trust before a daemon-backed interactive launch', async () => {
|
||||
|
||||
+13
-1
@@ -757,6 +757,12 @@ function mergePtyEnvDeletions(
|
||||
return Array.from(new Set([...(existingKeys ?? []), ...additionalKeys]))
|
||||
}
|
||||
|
||||
function removeCodexHomeDeletionRequests(keys: string[] | undefined): string[] | undefined {
|
||||
// Why: resume provenance is launch-authoritative; late deletions must not fall back to the current account.
|
||||
const filtered = keys?.filter((key) => key !== 'CODEX_HOME' && key !== 'ORCA_CODEX_HOME')
|
||||
return filtered?.length ? filtered : undefined
|
||||
}
|
||||
|
||||
function getInheritedAgentHookEnvKeysToDelete(
|
||||
spawnEnv: Record<string, string> | undefined
|
||||
): string[] {
|
||||
@@ -2922,6 +2928,9 @@ export function registerPtyHandlers(
|
||||
'ORCA_CODEX_HOME'
|
||||
])
|
||||
}
|
||||
if (codexResumeHome?.codexHomePath) {
|
||||
spawnOptions.envToDelete = removeCodexHomeDeletionRequests(spawnOptions.envToDelete)
|
||||
}
|
||||
deleteRequestedEnvKeys(env, spawnOptions.envToDelete)
|
||||
promoteAgentTeamsShimPath(env, requestedAgentTeamsPath)
|
||||
if (args.command !== undefined) {
|
||||
@@ -3830,7 +3839,7 @@ export function registerPtyHandlers(
|
||||
const envToDelete = claudeAuth?.stripAuthEnv
|
||||
? [...CLAUDE_AUTH_ENV_VARS, 'ANTHROPIC_CUSTOM_HEADERS']
|
||||
: undefined
|
||||
const combinedEnvToDelete = mergePtyEnvDeletions(
|
||||
let combinedEnvToDelete = mergePtyEnvDeletions(
|
||||
mergePtyEnvDeletions(
|
||||
mergePtyEnvDeletions(
|
||||
mergePtyEnvDeletions(
|
||||
@@ -3845,6 +3854,9 @@ export function registerPtyHandlers(
|
||||
// main cannot safely decide ownership for a process it may not parent.
|
||||
stripInheritedOrcaCodexHome ? ['ORCA_CODEX_HOME'] : []
|
||||
)
|
||||
if (codexResumeHome?.codexHomePath) {
|
||||
combinedEnvToDelete = removeCodexHomeDeletionRequests(combinedEnvToDelete)
|
||||
}
|
||||
deleteRequestedEnvKeys(spawnEnv, combinedEnvToDelete)
|
||||
promoteAgentTeamsShimPath(spawnEnv, requestedAgentTeamsPath)
|
||||
const spawnOptions: PtySpawnOptions = {
|
||||
|
||||
Reference in New Issue
Block a user