Files
orca/src/main/codex/managed-home-shell-preflight.ts
T
Brennan Benson 537864a248 Fix Codex hook trust before manual shell launches (#14326)
* fix codex hook trust before shell launch

* fix packaged cli preflight dependency

* fix codex shell preflight safety

* fix Codex shell preflight settings and startup safety
2026-08-13 17:02:28 -07:00

99 lines
3.1 KiB
TypeScript

import { existsSync, readFileSync, realpathSync } from 'node:fs'
import { join, relative, resolve, sep } from 'node:path'
import type { AgentHookInstallStatus } from '../../shared/agent-hook-types'
import { normalizeRuntimePathForComparison } from '../../shared/cross-platform-path'
import { codexHookService } from './hook-service'
type ShellPreflightEnvironment = {
CODEX_HOME?: string
ORCA_CODEX_HOME?: string
}
function pathsEqual(left: string, right: string): boolean {
return (
normalizeRuntimePathForComparison(resolve(left)) ===
normalizeRuntimePathForComparison(resolve(right))
)
}
function realPathMatches(left: string, expectedRealPath: string): boolean {
try {
return pathsEqual(realpathSync.native(left), expectedRealPath)
} catch {
return false
}
}
function resolveAccountManagedHome(candidate: string, userDataPath: string): string | null {
const accountsRoot = join(userDataPath, 'codex-accounts')
const pathParts = relative(accountsRoot, candidate).split(sep)
if (pathParts.length !== 2 || !pathParts[0] || pathParts[1] !== 'home') {
return null
}
const accountId = pathParts[0]
if (accountId === '.' || accountId === '..') {
return null
}
const expectedHome = join(accountsRoot, accountId, 'home')
let expectedRealHome: string
try {
expectedRealHome = join(realpathSync.native(userDataPath), 'codex-accounts', accountId, 'home')
} catch {
return null
}
if (!pathsEqual(candidate, expectedHome) || !realPathMatches(candidate, expectedRealHome)) {
return null
}
try {
return readFileSync(join(candidate, '.orca-managed-home'), 'utf-8').trim() === accountId
? expectedHome
: null
} catch {
return null
}
}
export function resolveManagedCodexShellPreflightHome(
env: ShellPreflightEnvironment,
userDataPath: string
): string | null {
const codexHome = env.CODEX_HOME?.trim()
const orcaCodexHome = env.ORCA_CODEX_HOME?.trim()
if (!codexHome || !orcaCodexHome || !pathsEqual(codexHome, orcaCodexHome)) {
return null
}
const sharedHome = join(userDataPath, 'codex-runtime-home', 'home')
if (pathsEqual(codexHome, sharedHome)) {
let expectedRealHome: string
try {
expectedRealHome = join(realpathSync.native(userDataPath), 'codex-runtime-home', 'home')
} catch {
return null
}
return existsSync(sharedHome) && realPathMatches(codexHome, expectedRealHome)
? sharedHome
: null
}
return resolveAccountManagedHome(codexHome, userDataPath)
}
export function prepareManagedCodexHomeBeforeShellLaunch(args: {
env?: ShellPreflightEnvironment
userDataPath: string
hooksEnabled: boolean
install?: (runtimeHomePath: string) => AgentHookInstallStatus
}): AgentHookInstallStatus | null {
if (!args.hooksEnabled) {
return null
}
const env = args.env ?? {
CODEX_HOME: process.env.CODEX_HOME,
ORCA_CODEX_HOME: process.env.ORCA_CODEX_HOME
}
const runtimeHomePath = resolveManagedCodexShellPreflightHome(env, args.userDataPath)
if (!runtimeHomePath) {
return null
}
return (args.install ?? ((home) => codexHookService.install(home)))(runtimeHomePath)
}