diff --git a/config/scripts/run-codex-real-account-validation.mjs b/config/scripts/run-codex-real-account-validation.mjs index 53d237f22..9318f412f 100644 --- a/config/scripts/run-codex-real-account-validation.mjs +++ b/config/scripts/run-codex-real-account-validation.mjs @@ -35,7 +35,6 @@ const RESTRICTED_ENV_KEYS = [ 'HOMEPATH', 'CODEX_HOME', 'ORCA_CODEX_HOME', - 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME', 'ORCA_E2E_HOME_DIR', 'ORCA_E2E_USER_DATA_DIR', 'ORCA_USER_DATA_PATH', @@ -69,7 +68,7 @@ async function resolveRealPath(candidate) { } } -export function createValidationEnv(inheritedEnv, layout, options = {}) { +export function createValidationEnv(inheritedEnv, layout) { const env = { ...inheritedEnv } for (const key of RESTRICTED_ENV_KEYS) { delete env[key] @@ -81,12 +80,7 @@ export function createValidationEnv(inheritedEnv, layout, options = {}) { NODE_ENV: 'development', ORCA_E2E_HOME_DIR: layout.homeDir, ORCA_E2E_USER_DATA_DIR: layout.userDataDir, - ORCA_USER_DATA_PATH: layout.userDataDir, - // Why: flag OFF pins every codex spawn to an explicit managed CODEX_HOME, - // so native codex never resolves the OS profile — the only Windows - // configuration where strict zero-event containment is reachable. It also - // exercises the emergency kill-switch lane users fall back to. - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: options.systemDefaultRealHome === 'off' ? '0' : '1' + ORCA_USER_DATA_PATH: layout.userDataDir } } @@ -268,8 +262,7 @@ function parseArgs(argv) { primaryHome: os.homedir(), configTemplate: null, tempParent: null, - laneAwareContainment: false, - systemDefaultRealHome: 'on' + laneAwareContainment: false } for (let index = 0; index < argv.length; index += 1) { const arg = argv[index] @@ -299,14 +292,8 @@ function parseArgs(argv) { options.skipBuild = true } else if (arg === '--keep') { options.keep = true - } else if (arg === '--system-default-real-home') { - const value = readValue() - if (value !== 'on' && value !== 'off') { - throw new Error('--system-default-real-home must be "on" or "off"') - } - options.systemDefaultRealHome = value } else if (arg === '--lane-aware-containment') { - // Why: on Windows the flag-ON system-default lane cannot be env-sandboxed + // Why: on Windows the system-default real-home lane cannot be env-sandboxed // (native codex ignores USERPROFILE), so strict zero-event containment is // structurally unreachable there. This mode records codex's designed // volatile churn without aborting while every other real-home write stays @@ -314,7 +301,7 @@ function parseArgs(argv) { options.laneAwareContainment = true } else if (arg === '--help') { console.log( - 'Usage: node config/scripts/run-codex-real-account-validation.mjs [--scenario mixed|managed-only|codex-lb] [--config-template ] [--temp-parent ] [--skip-build] [--dry-run] [--close-after-launch] [--keep] [--lane-aware-containment] [--system-default-real-home on|off] [--report ]' + 'Usage: node config/scripts/run-codex-real-account-validation.mjs [--scenario mixed|managed-only|codex-lb] [--config-template ] [--temp-parent ] [--skip-build] [--dry-run] [--close-after-launch] [--keep] [--lane-aware-containment] [--report ]' ) process.exit(0) } else { @@ -480,7 +467,7 @@ async function main() { const reportPath = options.reportPath ?? path.join(os.tmpdir(), `orca-codex-real-account-${options.scenario}-${Date.now()}.json`) - const launchEnv = createValidationEnv(process.env, layout, options) + const launchEnv = createValidationEnv(process.env, layout) let app = null let tripwire = null const abortController = new AbortController() diff --git a/config/scripts/run-codex-real-account-validation.test.ts b/config/scripts/run-codex-real-account-validation.test.ts index 0b10dee6e..43b949837 100644 --- a/config/scripts/run-codex-real-account-validation.test.ts +++ b/config/scripts/run-codex-real-account-validation.test.ts @@ -46,29 +46,9 @@ describe('Codex real-account validation harness', () => { expect(env.CODEX_HOME).toBeUndefined() expect(env.ORCA_CODEX_HOME).toBeUndefined() expect(env.ZDOTDIR).toBeUndefined() - expect(env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME).toBe('1') expect(env.SAFE_VALUE).toBe('preserved') }) - it('pins the real-home flag off when the system-default lane is disabled', async () => { - const primaryHome = path.join(os.tmpdir(), 'orca-primary-home-sentinel') - const { layout, env } = runValidationModule<{ - layout: { tempRoot: string } - env: Record - }>( - ` - const { createValidationEnv, createValidationLayout } = await import(process.argv[1]) - const layout = await createValidationLayout({ primaryHome: process.argv[2] }) - const env = createValidationEnv({}, layout, { systemDefaultRealHome: 'off' }) - console.log(JSON.stringify({ layout, env })) - `, - [primaryHome] - ) - cleanupPaths.push(layout.tempRoot) - - expect(env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME).toBe('0') - }) - it('records only fingerprints for system-default and managed auth', async () => { const { layout, snapshot } = runValidationModule<{ layout: { tempRoot: string } diff --git a/config/scripts/run-idle-cpu-benchmark.mjs b/config/scripts/run-idle-cpu-benchmark.mjs index baa061b35..53cabd338 100644 --- a/config/scripts/run-idle-cpu-benchmark.mjs +++ b/config/scripts/run-idle-cpu-benchmark.mjs @@ -483,7 +483,6 @@ async function main() { HOME: isolatedHome, USERPROFILE: isolatedHome, ORCA_E2E_HOME_DIR: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0', ...(options.headful ? { ORCA_E2E_HEADFUL: '1' } : { ORCA_E2E_HEADLESS: '1' }) } }) diff --git a/config/scripts/serve-headless-fresh-profile-pairing.mjs b/config/scripts/serve-headless-fresh-profile-pairing.mjs index 8865b8415..1cbfe9247 100755 --- a/config/scripts/serve-headless-fresh-profile-pairing.mjs +++ b/config/scripts/serve-headless-fresh-profile-pairing.mjs @@ -55,7 +55,6 @@ Object.assign(childEnv, { ORCA_DEV_USER_DATA_PATH: profileDir, HOME: isolatedHome, USERPROFILE: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0', ...(process.platform === 'linux' ? { ELECTRON_DISABLE_SANDBOX: process.env.ELECTRON_DISABLE_SANDBOX ?? '1' } : {}) diff --git a/config/scripts/verify-linux-wayland-gpu-sandbox.mjs b/config/scripts/verify-linux-wayland-gpu-sandbox.mjs index ef35b6f7f..a36f81db8 100644 --- a/config/scripts/verify-linux-wayland-gpu-sandbox.mjs +++ b/config/scripts/verify-linux-wayland-gpu-sandbox.mjs @@ -219,7 +219,6 @@ async function runValidation(mode) { ORCA_DEV_USER_DATA_PATH: userDataPath, HOME: isolatedHome, USERPROFILE: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0', ELECTRON_ENABLE_LOGGING: '1', ELECTRON_ENABLE_STACK_DUMPING: '1', ELECTRON_OZONE_PLATFORM_HINT: 'wayland', diff --git a/config/scripts/windows-apphang-repro/electron-dev-session.mjs b/config/scripts/windows-apphang-repro/electron-dev-session.mjs index 0aaead723..be09b9701 100644 --- a/config/scripts/windows-apphang-repro/electron-dev-session.mjs +++ b/config/scripts/windows-apphang-repro/electron-dev-session.mjs @@ -63,7 +63,6 @@ export function launchDevApp({ cdpPort, userDataDir }) { ORCA_DEV_USER_DATA_PATH: userDataDir, HOME: isolatedHome, USERPROFILE: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0', ORCA_SKIP_DEV_WEB_PREPARE: '1', ORCA_STARTUP_DIAGNOSTICS: '1', REMOTE_DEBUGGING_PORT: String(cdpPort), diff --git a/src/main/codex-accounts/runtime-home-mirrored-status-home.test.ts b/src/main/codex-accounts/runtime-home-mirrored-status-home.test.ts index 19bc71dac..d137a6563 100644 --- a/src/main/codex-accounts/runtime-home-mirrored-status-home.test.ts +++ b/src/main/codex-accounts/runtime-home-mirrored-status-home.test.ts @@ -20,12 +20,7 @@ beforeEach(() => { testState.home = mkdtempSync(join(tmpdir(), 'orca-codex-status-home-')) // Why: the real-home check consults CODEX_HOME and the shell rc, so a // developer who exports one would otherwise fail this suite locally. - for (const key of [ - 'ORCA_USER_DATA_PATH', - 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME', - 'CODEX_HOME', - 'ORCA_CODEX_HOME' - ]) { + for (const key of ['ORCA_USER_DATA_PATH', 'CODEX_HOME', 'ORCA_CODEX_HOME']) { previousEnv[key] = process.env[key] delete process.env[key] } @@ -91,8 +86,8 @@ describe('CodexRuntimeHomeService.getMirroredHostHomePathForStatus', () => { expect(service.getMirroredHostHomePathForStatus()).toBe(account.managedHomePath) }) - it('returns the shared runtime home when the real-home lane is off', async () => { - process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME = '0' + it('returns the shared runtime home when a custom CODEX_HOME keeps the mirror lane', async () => { + process.env.CODEX_HOME = join(testState.home, 'custom-codex-home') const { CodexRuntimeHomeService } = await import('./runtime-home-service') const { getOrcaManagedCodexHomePath } = await import('../codex/codex-home-paths') const service = new CodexRuntimeHomeService(createStore([], null) as never) diff --git a/src/main/codex-accounts/runtime-home-service-per-account-migration.test.ts b/src/main/codex-accounts/runtime-home-service-per-account-migration.test.ts index 4012cf3b1..0efe90bb7 100644 --- a/src/main/codex-accounts/runtime-home-service-per-account-migration.test.ts +++ b/src/main/codex-accounts/runtime-home-service-per-account-migration.test.ts @@ -21,7 +21,6 @@ beforeEach(() => { testState.home = mkdtempSync(join(tmpdir(), 'orca-codex-e-home-')) for (const key of [ 'ORCA_USER_DATA_PATH', - 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME', 'ORCA_DISABLE_CODEX_TRUST_RPC', 'CODEX_HOME', 'ORCA_CODEX_HOME' diff --git a/src/main/codex-accounts/runtime-home-service.test.ts b/src/main/codex-accounts/runtime-home-service.test.ts index 693ac8db7..8d3a52fa8 100644 --- a/src/main/codex-accounts/runtime-home-service.test.ts +++ b/src/main/codex-accounts/runtime-home-service.test.ts @@ -17,13 +17,13 @@ import { import { tmpdir } from 'node:os' import { join } from 'node:path' import type { CodexManagedAccount, GlobalSettings } from '../../shared/types' -import type * as NodeFs from 'node:fs' import type * as ShellStartupEnv from '../pty/shell-startup-env' const testState = { userDataDir: '', fakeHomeDir: '', - previousUserDataPath: undefined as string | undefined + previousUserDataPath: undefined as string | undefined, + shellStartupEnvProbeSupported: true } vi.mock('electron', () => ({ @@ -40,34 +40,24 @@ vi.mock('node:os', async () => { } }) -// Why: the shipped code no longer reads a settings flag — the legacy mirror -// lane is reachable only through the test-rig env override. Route the old -// per-test override key to that env var so this suite's lane coverage and -// mid-test flips keep exercising real transitions. +// Why: the shared system-default mirror is still live wherever the shell-startup +// probe is unavailable (Windows), so drive this suite's lane coverage and +// mid-test flips through that real gate rather than a test-only override. type TestSettingsOverrides = Partial & { - codexSystemDefaultRealHomeEnabled?: boolean + shellStartupEnvProbeSupported?: boolean } -function setRealHomeLaneForTest(enabled: boolean): void { - process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME = enabled ? '1' : '0' +function setShellStartupEnvProbeSupportedForTest(enabled: boolean): void { + testState.shellStartupEnvProbeSupported = enabled } -const initialRealHomeLaneEnv = process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME -afterEach(() => { - if (initialRealHomeLaneEnv === undefined) { - delete process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME - } else { - process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME = initialRealHomeLaneEnv - } -}) - function createSettings(overrides: TestSettingsOverrides = {}): GlobalSettings { const appFontFamily = overrides.appFontFamily ?? 'Geist' const agentStatusHooksEnabled = overrides.agentStatusHooksEnabled ?? true const tabAutoGenerateTitle = overrides.tabAutoGenerateTitle ?? false - // Managed-home tests assert the mirror path; production is real-home always, - // so opt these managed cases out unless a test overrides it. - setRealHomeLaneForTest(overrides.codexSystemDefaultRealHomeEnabled ?? false) + // Mirror-path tests assert the shared runtime home, which production still uses + // on Windows; opt these cases onto that lane unless a test overrides it. + setShellStartupEnvProbeSupportedForTest(overrides.shellStartupEnvProbeSupported ?? false) return { workspaceDir: testState.fakeHomeDir, nestWorkspaces: false, @@ -320,9 +310,10 @@ describe('CodexRuntimeHomeService', () => { beforeEach(() => { vi.resetModules() vi.clearAllMocks() + testState.shellStartupEnvProbeSupported = true vi.doMock('../pty/shell-startup-env', async () => ({ ...(await vi.importActual('../pty/shell-startup-env')), - isShellStartupEnvProbeSupported: () => true + isShellStartupEnvProbeSupported: () => testState.shellStartupEnvProbeSupported })) testState.userDataDir = mkdtempSync(join(tmpdir(), 'orca-runtime-home-')) testState.fakeHomeDir = mkdtempSync(join(tmpdir(), 'orca-codex-home-')) @@ -367,503 +358,6 @@ describe('CodexRuntimeHomeService', () => { } }) - it('materializes the active managed account auth into the runtime home on startup', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"account":"managed"}\n' - ) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - ) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"account":"managed"}\n') - expect( - existsSync(join(testState.userDataDir, 'codex-runtime-home', 'system-default-auth.json')) - ).toBe(false) - }) - - it('deselects a shared-home account on settled credential-free JSON', async () => { - const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') - const managedAuth = createCodexAuthJson('user@example.com', 'acct-user', 'managed') - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-user', - workspaceLabel: null, - workspaceAccountId: 'acct-user', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - store.updateSettings.mockClear() - - writeFileSync(join(managedHomePath, 'auth.json'), '{}\n', 'utf-8') - service.syncForCurrentSelection() - - expect(store.getSettings().activeCodexManagedAccountId).toBeNull() - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBeNull() - expect(readFileSync(join(managedHomePath, 'auth.json'), 'utf-8')).toBe('{}\n') - expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(systemAuth) - expect(warnSpy).toHaveBeenCalledWith( - '[codex-runtime-home] Active managed account credential is unavailable, restoring system default' - ) - }) - - it('deselects a shared-home account when unreadable auth outlives the grace window', async () => { - const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') - const managedAuth = createCodexAuthJson('user@example.com', 'acct-user', 'managed') - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-user', - workspaceLabel: null, - workspaceAccountId: 'acct-user', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - store.updateSettings.mockClear() - writeFileSync(join(managedHomePath, 'auth.json'), '{"tokens":{"acc', 'utf-8') - const observedAt = Date.now() - const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(observedAt) - - service.syncForCurrentSelection() - expect(store.getSettings().activeCodexManagedAccountId).toBe('account-1') - expect(store.updateSettings).not.toHaveBeenCalled() - - nowSpy.mockReturnValue(observedAt + 6_000) - service.syncForCurrentSelection() - nowSpy.mockRestore() - expect(store.getSettings().activeCodexManagedAccountId).toBeNull() - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBeNull() - }) - - it.each([ - ['missing', (authPath: string) => rmSync(authPath, { force: true })], - [ - 'unreadable', - (authPath: string) => { - chmodSync(authPath, 0o000) - } - ] - ])( - 'never launches the previously synced account when the selected account auth is %s', - async (label, breakAuth) => { - if (label === 'unreadable' && (process.platform === 'win32' || process.getuid?.() === 0)) { - return - } - const runtimeAuthPath = getRuntimeCodexAuthPath() - const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') - const authA = createCodexAuthJson('a@example.com', 'acct-a', 'a') - const authB = createCodexAuthJson('b@example.com', 'acct-b', 'b') - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth(testState.userDataDir, 'account-b', authB) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-a', - email: 'a@example.com', - managedHomePath: homeA, - providerAccountId: 'acct-a', - workspaceLabel: null, - workspaceAccountId: 'acct-a', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-b', - email: 'b@example.com', - managedHomePath: homeB, - providerAccountId: 'acct-b', - workspaceLabel: null, - workspaceAccountId: 'acct-b', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-a', - activeCodexManagedAccountIdsByRuntime: { host: 'account-a', wsl: {} } - }) - ) - const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(authA) - - store.updateSettings({ - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - breakAuth(join(homeB, 'auth.json')) - - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - - // The selection survives the grace window, but the launch must never run - // as account A while the UI says account B. - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-b') - expect(existsSync(runtimeAuthPath) ? readFileSync(runtimeAuthPath, 'utf-8') : null).not.toBe( - authA - ) - expect(warnSpy).toHaveBeenCalledWith( - '[codex-runtime-home] Active managed account auth.json unavailable while the runtime home holds another account, clearing runtime auth' - ) - } - ) - - it.each([ - ['missing', (authPath: string) => rmSync(authPath, { force: true })], - [ - 'unreadable', - (authPath: string) => { - chmodSync(authPath, 0o000) - } - ] - ])( - 'preserves the mirrored refresh of the account the runtime home actually holds when the selected account auth is %s', - async (label, breakAuth) => { - if (label === 'unreadable' && (process.platform === 'win32' || process.getuid?.() === 0)) { - return - } - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const authA = createCodexAuthJson('a@example.com', 'acct-a', 'a', 1) - const authARefreshed = createCodexAuthJson('a@example.com', 'acct-a', 'a-refreshed', 2) - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth( - testState.userDataDir, - 'account-b', - createCodexAuthJson('b@example.com', 'acct-b', 'b') - ) - // A crash left account A's refreshed tokens in the mirror while settings - // already select account B, whose own auth.json cannot be read. - writeFileSync(runtimeAuthPath, authARefreshed, 'utf-8') - writeFileSync( - getSharedRuntimeAuthProvenancePath(), - `${JSON.stringify({ owner: 'managed', accountId: 'account-a' })}\n`, - 'utf-8' - ) - breakAuth(join(homeB, 'auth.json')) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-a', - email: 'a@example.com', - managedHomePath: homeA, - providerAccountId: 'acct-a', - workspaceLabel: null, - workspaceAccountId: 'acct-a', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-b', - email: 'b@example.com', - managedHomePath: homeB, - providerAccountId: 'acct-b', - workspaceLabel: null, - workspaceAccountId: 'acct-b', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(existsSync(runtimeAuthPath)).toBe(false) - expect(readFileSync(join(homeA, 'auth.json'), 'utf-8')).toBe(authARefreshed) - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-b') - } - ) - - it('keeps the runtime auth through the grace window while the selected account rotates', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') - const managedAuth = createCodexAuthJson('user@example.com', 'acct-user', 'managed') - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-user', - workspaceLabel: null, - workspaceAccountId: 'acct-user', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(managedAuth) - - // Codex rewrites the selected account's auth.json in place: the runtime home - // already holds that same account, so its credentials must survive the race. - writeFileSync(join(managedHomePath, 'auth.json'), '{"tokens":{"acc', 'utf-8') - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(managedAuth) - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-1') - }) - - it('keeps runtime auth the selected account still owns when provenance is unreadable', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const managedAuth = createCodexAuthJson('user@example.com', 'acct-user', 'managed') - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - // Cold start: the mirror holds the selected account's own credential, but a - // torn provenance file can no longer say so and its auth.json reads torn. - mkdirSync(getRuntimeCodexHomePath(), { recursive: true }) - writeFileSync(runtimeAuthPath, managedAuth, 'utf-8') - writeFileSync(getSharedRuntimeAuthProvenancePath(), 'not-json', 'utf-8') - writeFileSync(join(managedHomePath, 'auth.json'), '{"tokens":{"acc', 'utf-8') - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-1', 'user@example.com', 'acct-user', managedHomePath) - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(managedAuth) - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-1') - }) - - it.each([ - ['no provenance', (path: string) => rmSync(path, { force: true })], - [ - 'selected-account provenance', - (path: string) => - writeFileSync( - path, - `${JSON.stringify({ owner: 'managed', accountId: 'account-b' })}\n`, - 'utf-8' - ) - ] - ])('never launches another account on a cold start with %s', async (_label, setProvenance) => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const authA = createCodexAuthJson('a@example.com', 'acct-a', 'a') - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth( - testState.userDataDir, - 'account-b', - createCodexAuthJson('b@example.com', 'acct-b', 'b') - ) - // A retained pane can overwrite the mirror after B's provenance commits. - // Neither missing nor stale provenance can overrule the current bytes. - mkdirSync(getRuntimeCodexHomePath(), { recursive: true }) - writeFileSync(runtimeAuthPath, authA, 'utf-8') - setProvenance(getSharedRuntimeAuthProvenancePath()) - rmSync(join(homeB, 'auth.json'), { force: true }) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-a', 'a@example.com', 'acct-a', homeA), - createCodexAccountRecord('account-b', 'b@example.com', 'acct-b', homeB) - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - expect(existsSync(runtimeAuthPath) ? readFileSync(runtimeAuthPath, 'utf-8') : null).not.toBe( - authA - ) - expect(readFileSync(join(homeA, 'auth.json'), 'utf-8')).toBe(authA) - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-b') - }) - - it('persists a mirror-only system-default refresh before dropping unproven runtime auth', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system', 1) - const systemAuthRefreshed = createCodexAuthJson( - 'system@example.com', - 'acct-system', - 'system-refreshed', - 2 - ) - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const homeB = createManagedAuth( - testState.userDataDir, - 'account-b', - createCodexAuthJson('b@example.com', 'acct-b', 'b') - ) - // Codex rotated the system-default credential inside the mirror; ~/.codex is - // still the older copy Orca mirrored, so the refresh lives only here. - mkdirSync(getRuntimeCodexHomePath(), { recursive: true }) - writeFileSync(runtimeAuthPath, systemAuthRefreshed, 'utf-8') - writeFileSync( - getSharedRuntimeAuthProvenancePath(), - `${JSON.stringify({ owner: 'system-default', authJson: systemAuth })}\n`, - 'utf-8' - ) - rmSync(join(homeB, 'auth.json'), { force: true }) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-b', 'b@example.com', 'acct-b', homeB) - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(getSystemCodexAuthPath(), 'utf-8')).toBe(systemAuthRefreshed) - expect(existsSync(runtimeAuthPath)).toBe(false) - }) - - it('blocks launch when a readable stale runtime auth cannot be deleted', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const authA = createCodexAuthJson('a@example.com', 'acct-a', 'a') - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth( - testState.userDataDir, - 'account-b', - createCodexAuthJson('b@example.com', 'acct-b', 'b') - ) - // A Windows sharing violation can deny delete while still allowing Codex to - // read the credential, so model those operations independently. - writeFileSync(runtimeAuthPath, authA, 'utf-8') - writeFileSync( - getSharedRuntimeAuthProvenancePath(), - `${JSON.stringify({ owner: 'managed', accountId: 'account-a' })}\n`, - 'utf-8' - ) - rmSync(join(homeB, 'auth.json'), { force: true }) - vi.doMock('node:fs', async () => { - const actual = await vi.importActual('node:fs') - return { - ...actual, - rmSync: (path: Parameters[0], options?: Parameters[1]) => { - if (path === runtimeAuthPath) { - throw new Error('simulated Windows sharing violation') - } - return actual.rmSync(path, options) - } - } - }) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-a', 'a@example.com', 'acct-a', homeA), - createCodexAccountRecord('account-b', 'b@example.com', 'acct-b', homeB) - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(() => service.prepareForCodexLaunch()).toThrow( - 'Cannot safely launch Codex while stale runtime auth remains.' - ) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(authA) - expect(JSON.parse(readFileSync(getSharedRuntimeAuthProvenancePath(), 'utf-8'))).toEqual({ - owner: 'fenced' - }) - }) - it('refuses to read runtime auth back into a duplicate account while a home is unreadable', async () => { if (process.platform === 'win32' || process.getuid?.() === 0) { return @@ -911,153 +405,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(join(homeX2, 'auth.json'), 'utf-8')).toBe(authX) }) - it('drops another account from the mirror even when the fence write fails', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const authA = createCodexAuthJson('a@example.com', 'acct-a', 'a') - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth( - testState.userDataDir, - 'account-b', - createCodexAuthJson('b@example.com', 'acct-b', 'b') - ) - // Stands in for a Windows AV lock on the provenance file: the fence cannot - // be written, while auth.json itself is perfectly deletable. - mkdirSync(getRuntimeCodexHomePath(), { recursive: true }) - writeFileSync(runtimeAuthPath, authA, 'utf-8') - rmSync(getSharedRuntimeAuthProvenancePath(), { force: true }) - mkdirSync(getSharedRuntimeAuthProvenancePath(), { recursive: true }) - rmSync(join(homeB, 'auth.json'), { force: true }) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-a', 'a@example.com', 'acct-a', homeA), - createCodexAccountRecord('account-b', 'b@example.com', 'acct-b', homeB) - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - expect(existsSync(runtimeAuthPath) ? readFileSync(runtimeAuthPath, 'utf-8') : null).not.toBe( - authA - ) - }) - - it('keeps an unattributable api-key credential Orca mirrored in the same run', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const apiKeyAuth = `${JSON.stringify({ auth_mode: 'apikey', OPENAI_API_KEY: 'sk-managed' })}\n` - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', apiKeyAuth) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-1', 'user@example.com', 'acct-user', managedHomePath) - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - // Exact same-run bytes prove ownership even without identity claims. - writeFileSync(join(managedHomePath, 'auth.json'), '{"OPENAI_API_K', 'utf-8') - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(apiKeyAuth) - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-1') - }) - - it('drops a pre-provenance api-key credential when the selected owner cannot be proven', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const authA = `${JSON.stringify({ auth_mode: 'apikey', OPENAI_API_KEY: 'sk-a' })}\n` - const authB = `${JSON.stringify({ auth_mode: 'apikey', OPENAI_API_KEY: 'sk-b' })}\n` - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth(testState.userDataDir, 'account-b', authB) - writeFileSync(runtimeAuthPath, authA, 'utf-8') - rmSync(getSharedRuntimeAuthProvenancePath(), { force: true }) - rmSync(join(homeB, 'auth.json'), { force: true }) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-a', 'a@example.com', 'acct-a', homeA), - createCodexAccountRecord('account-b', 'b@example.com', 'acct-b', homeB) - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - expect(existsSync(runtimeAuthPath)).toBe(false) - expect(readFileSync(join(homeA, 'auth.json'), 'utf-8')).toBe(authA) - expect(store.getSettings().activeCodexManagedAccountIdsByRuntime?.host).toBe('account-b') - }) - - it('reads a renamed account refresh back into its own home despite a stale record email', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync( - getSystemCodexAuthPath(), - createCodexAuthJson('system@example.com', 'acct-system', 'system'), - 'utf-8' - ) - const authA = createCodexAuthJson('new@example.com', 'acct-a', 'a', 1) - const authARefreshed = createCodexAuthJson('new@example.com', 'acct-a', 'a-refreshed', 2) - const homeA = createManagedAuth(testState.userDataDir, 'account-a', authA) - const homeB = createManagedAuth( - testState.userDataDir, - 'account-b', - createCodexAuthJson('b@example.com', 'acct-b', 'b') - ) - // Account A was renamed on the ChatGPT side after it was added, so its record - // email is stale while the mirrored refresh carries the new one. - writeFileSync(runtimeAuthPath, authARefreshed, 'utf-8') - writeFileSync( - getSharedRuntimeAuthProvenancePath(), - `${JSON.stringify({ owner: 'managed', accountId: 'account-a' })}\n`, - 'utf-8' - ) - rmSync(join(homeB, 'auth.json'), { force: true }) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - createCodexAccountRecord('account-a', 'old@example.com', 'acct-a', homeA), - createCodexAccountRecord('account-b', 'b@example.com', 'acct-b', homeB) - ], - activeCodexManagedAccountId: 'account-b', - activeCodexManagedAccountIdsByRuntime: { host: 'account-b', wsl: {} } - }) - ) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(join(homeA, 'auth.json'), 'utf-8')).toBe(authARefreshed) - expect(existsSync(runtimeAuthPath)).toBe(false) - }) - it('keeps the mirror of a renamed account whose record email is stale', async () => { const runtimeAuthPath = getRuntimeCodexAuthPath() writeFileSync( @@ -1108,29 +455,7 @@ describe('CodexRuntimeHomeService', () => { process.platform === 'win32' ? 'junction' : undefined ) writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"account":"managed"}\n' - ) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - ) + const store = createStore(createSettings()) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) @@ -1139,7 +464,7 @@ describe('CodexRuntimeHomeService', () => { normalizeLinkTarget(getRuntimeCodexHomePath()) ) expect(readFileSync(join(legacyActiveHomePath, 'auth.json'), 'utf-8')).toBe( - '{"account":"managed"}\n' + '{"account":"system"}\n' ) }) @@ -1540,42 +865,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"account":"system"}\n') }) - it('removes runtime auth when restoring a no-login system default', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"account":"managed"}\n' - ) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"account":"managed"}\n') - - settings.activeCodexManagedAccountId = null - service.syncForCurrentSelection() - - expect(existsSync(runtimeAuthPath)).toBe(false) - }) - it('removes runtime auth when deselecting with a missing system-default snapshot', async () => { const runtimeAuthPath = getRuntimeCodexAuthPath() const managedAuth = createCodexAuthJson('user@example.com', 'acct-1', 'managed') @@ -1652,9 +941,7 @@ describe('CodexRuntimeHomeService', () => { }) }) - it('clears an invalid active account selection and removes untrusted runtime auth', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') + it('clears an active account selection whose self-contained home is missing', async () => { const missingManagedHomePath = join( testState.userDataDir, 'codex-accounts', @@ -1686,47 +973,6 @@ describe('CodexRuntimeHomeService', () => { expect(store.updateSettings).toHaveBeenCalledWith( expect.objectContaining({ activeCodexManagedAccountId: null }) ) - expect(existsSync(runtimeAuthPath)).toBe(false) - expect(warnSpy).toHaveBeenCalled() - }) - - it('clears an invalid active account selection and restores live system default auth', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const systemAuth = '{"account":"system"}\n' - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - rmSync(runtimeAuthPath, { force: true }) - const missingManagedHomePath = join( - testState.userDataDir, - 'codex-accounts', - 'account-1', - 'home' - ) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath: missingManagedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(store.updateSettings).toHaveBeenCalledWith( - expect.objectContaining({ activeCodexManagedAccountId: null }) - ) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(systemAuth) expect(warnSpy).toHaveBeenCalled() }) @@ -1760,14 +1006,15 @@ describe('CodexRuntimeHomeService', () => { const service = new CodexRuntimeHomeService(store as never) expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - expect(existsSync(markerPath)).toBe(false) + // Why: a mirror launch never leaves the real home, so its backfill stays valid. + expect(existsSync(markerPath)).toBe(true) expect(service.prepareForRateLimitFetch()).toBe(getRuntimeCodexHomePath()) expect(service.getHostCodexHomePathsForSessionDiscovery()).toEqual([getRuntimeCodexHomePath()]) expect(existsSync(getRuntimeCodexHomePath())).toBe(true) }) - it('routes host system default to the real home when the flag is ON', async () => { - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: true })) + it('routes host system default to the real home', async () => { + const store = createStore(createSettings({ shellStartupEnvProbeSupported: true })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) @@ -1843,7 +1090,7 @@ describe('CodexRuntimeHomeService', () => { it('seeds shared auth for a pane-local custom home on the real-home lane', async () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: true })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: true })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) const customHome = join(testState.fakeHomeDir, 'pane-custom-codex-home') @@ -1878,7 +1125,7 @@ describe('CodexRuntimeHomeService', () => { `${JSON.stringify({ owner: 'system-default', authJson: retainedAuth })}\n`, 'utf-8' ) - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: true })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: true })) try { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) @@ -1909,12 +1156,12 @@ describe('CodexRuntimeHomeService', () => { '' ].join('\n') writeFileSync(getSystemCodexAuthPath(), oldSystemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(oldSystemAuth) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') writeFileSync(join(getSystemCodexHomePath(), 'config.toml'), systemConfig, 'utf-8') writeFileSync( @@ -1940,12 +1187,12 @@ describe('CodexRuntimeHomeService', () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') const managedAuth = createCodexAuthJson('managed@example.com', 'acct-managed', 'managed') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) writeFileSync(getRuntimeCodexAuthPath(), managedAuth, 'utf-8') - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) const restartedService = new CodexRuntimeHomeService(store as never) restartedService.setRealHomeLaneGate(() => true) @@ -1954,43 +1201,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(getSystemCodexAuthPath(), 'utf-8')).toBe(systemAuth) }) - it('preserves same-identity retained managed auth after restart and source logout', async () => { - const systemAuth = createCodexAuthJson('shared@example.com', 'acct-shared', 'system') - const managedAuth = createCodexAuthJson('shared@example.com', 'acct-shared', 'managed') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'shared@example.com', - managedHomePath, - providerAccountId: 'acct-shared', - workspaceLabel: null, - workspaceAccountId: 'acct-shared', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ] - }) - const store = createStore(settings) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - settings.activeCodexManagedAccountId = 'account-1' - settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-1', wsl: {} } - service.syncForCurrentSelection() - - settings.activeCodexManagedAccountId = null - settings.activeCodexManagedAccountIdsByRuntime = { host: null, wsl: {} } - setRealHomeLaneForTest(true) - rmSync(getSystemCodexAuthPath()) - const restartedService = new CodexRuntimeHomeService(store as never) - - expect(restartedService.prepareForCodexLaunch()).toBeNull() - expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(managedAuth) - }) - it('fences retained shared auth when a self-contained managed transition begins', async () => { const systemAuth = createCodexAuthJson('shared@example.com', 'acct-shared', 'system') const managedAuth = createCodexAuthJson('shared@example.com', 'acct-shared', 'managed') @@ -2015,7 +1225,7 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) settings.activeCodexManagedAccountId = 'account-1' settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-1', wsl: {} } service.syncForCurrentSelection() @@ -2062,7 +1272,7 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) settings.activeCodexManagedAccountId = 'account-1' settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-1', wsl: {} } service.syncForCurrentSelection() @@ -2100,14 +1310,14 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) settings.activeCodexManagedAccountId = 'account-1' settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-1', wsl: {} } service.syncForCurrentSelection() writeFileSync(getRuntimeCodexAuthPath(), managedAuth, 'utf-8') settings.activeCodexManagedAccountId = null settings.activeCodexManagedAccountIdsByRuntime = { host: null, wsl: {} } - setRealHomeLaneForTest(false) + setShellStartupEnvProbeSupportedForTest(false) service.syncForCurrentSelection() expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(systemAuth) @@ -2121,12 +1331,12 @@ describe('CodexRuntimeHomeService', () => { 'refreshed-token' ) writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(systemAuth) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) writeFileSync(getSystemCodexAuthPath(), refreshedSystemAuth, 'utf-8') expect(service.prepareForRateLimitFetch()).toBe(getSystemCodexHomePath()) @@ -2136,13 +1346,13 @@ describe('CodexRuntimeHomeService', () => { it('does not rewrite retained-auth provenance during unchanged rate polling', async () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) const provenancePath = getSharedRuntimeAuthProvenancePath() const originalInode = statSync(provenancePath).ino - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) service.prepareForRateLimitFetch() service.prepareForRateLimitFetch() @@ -2152,10 +1362,10 @@ describe('CodexRuntimeHomeService', () => { it('does not rewrite completed retained logout metadata during rate polling', async () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) rmSync(getSystemCodexAuthPath()) service.prepareForRateLimitFetch() const metadataPaths = [ @@ -2213,7 +1423,7 @@ describe('CodexRuntimeHomeService', () => { ) settings.activeCodexManagedAccountId = null settings.activeCodexManagedAccountIdsByRuntime = { host: null, wsl: {} } - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) service.syncForCurrentSelection() writeFileSync(getSystemCodexAuthPath(), refreshedSystemAuth, 'utf-8') @@ -2232,7 +1442,7 @@ describe('CodexRuntimeHomeService', () => { 'refreshed-token' ) writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: true })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: true })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) writeFileSync(getRuntimeCodexAuthPath(), retainedAuth, 'utf-8') @@ -2247,11 +1457,11 @@ describe('CodexRuntimeHomeService', () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'old-token') const retainedAuth = createCodexAuthJson('system@example.com', 'acct-system', 'retained-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) const service = new CodexRuntimeHomeService(store as never) writeFileSync(getRuntimeCodexAuthPath(), retainedAuth, 'utf-8') rmSync(getSystemCodexAuthPath()) @@ -2268,7 +1478,7 @@ describe('CodexRuntimeHomeService', () => { 'refreshed-token' ) writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) writeFileSync( @@ -2280,7 +1490,7 @@ describe('CodexRuntimeHomeService', () => { })}\n` ) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) writeFileSync(getSystemCodexAuthPath(), refreshedSystemAuth, 'utf-8') expect(service.prepareForRateLimitFetch()).toBe(getSystemCodexHomePath()) expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(refreshedSystemAuth) @@ -2289,14 +1499,14 @@ describe('CodexRuntimeHomeService', () => { it('recovers runtime auth quarantined by an interrupted guarded update', async () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) const runtimeAuthPath = getRuntimeCodexAuthPath() const heldAuthPath = `${runtimeAuthPath}.orca-guarded` renameSync(runtimeAuthPath, heldAuthPath) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) new CodexRuntimeHomeService(store as never) expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(systemAuth) @@ -2307,7 +1517,7 @@ describe('CodexRuntimeHomeService', () => { const systemAuth = createCodexAuthJson('shared@example.com', 'acct-shared', 'system') const retainedAuth = createCodexAuthJson('shared@example.com', 'acct-shared', 'retained') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) writeFileSync( @@ -2320,7 +1530,7 @@ describe('CodexRuntimeHomeService', () => { ) writeFileSync(getRuntimeCodexAuthPath(), retainedAuth, 'utf-8') - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) rmSync(getSystemCodexAuthPath()) expect(service.prepareForRateLimitFetch()).toBe(getSystemCodexHomePath()) expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(retainedAuth) @@ -2334,12 +1544,12 @@ describe('CodexRuntimeHomeService', () => { 'refreshed-token' ) writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) writeFileSync(getSharedRuntimeAuthProvenancePath(), '{"owner":"pending"}\n') - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) writeFileSync(getSystemCodexAuthPath(), refreshedSystemAuth, 'utf-8') expect(service.prepareForRateLimitFetch()).toBe(getSystemCodexHomePath()) expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(systemAuth) @@ -2349,11 +1559,11 @@ describe('CodexRuntimeHomeService', () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'old-token') const reloginAuth = createCodexAuthJson('system@example.com', 'acct-system', 'relogin-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) const service = new CodexRuntimeHomeService(store as never) rmSync(getSystemCodexAuthPath()) expect(service.prepareForRateLimitFetch()).toBe(getSystemCodexHomePath()) @@ -2373,11 +1583,11 @@ describe('CodexRuntimeHomeService', () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'old-token') const reloginAuth = createCodexAuthJson('system@example.com', 'acct-system', 'relogin-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) rmSync(getSystemCodexAuthPath()) rmSync(getRuntimeCodexAuthPath()) if (removeProvenance) { @@ -2408,7 +1618,7 @@ describe('CodexRuntimeHomeService', () => { createCodexAuthJson('managed@example.com', 'acct-managed', 'managed-token') ) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: false, + shellStartupEnvProbeSupported: false, codexManagedAccounts: [ { id: 'account-1', @@ -2428,7 +1638,7 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) rmSync(getSystemCodexAuthPath()) rmSync(getRuntimeCodexAuthPath()) rmSync( @@ -2458,14 +1668,14 @@ describe('CodexRuntimeHomeService', () => { const systemConfigPath = join(getSystemCodexHomePath(), 'config.toml') const runtimeConfigPath = join(getRuntimeCodexHomePath(), 'config.toml') writeFileSync(systemConfigPath, 'model = "baseline"\n', 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) writeFileSync(runtimeConfigPath, 'model = "runtime-change"\n', 'utf-8') - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) service.setRealHomeLaneGate(() => false) service.reconcileLegacySharedHomeForRetainedPanes() expect(readFileSync(systemConfigPath, 'utf-8')).toBe('model = "baseline"\n') @@ -2476,7 +1686,7 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(runtimeConfigPath, 'utf-8')).toBe('model = "runtime-change"\n') }) - it('routes a host MANAGED account to its own self-contained home when the flag is ON', async () => { + it('routes a host MANAGED account to its own self-contained home', async () => { writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') const runtimeAuthPath = getRuntimeCodexAuthPath() const managedHomePath = createManagedAuth( @@ -2486,7 +1696,7 @@ describe('CodexRuntimeHomeService', () => { ) const store = createStore( createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2507,7 +1717,7 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - // Flag ON + host managed account = the account's own home is CODEX_HOME. + // A host managed account's own home is its CODEX_HOME. expect(service.isHostSystemDefaultRealHome()).toBe(false) expect(service.prepareForCodexLaunch()).toBe(managedHomePath) // The per-account home keeps its own auth in place; the shared mirror's @@ -2520,14 +1730,14 @@ describe('CodexRuntimeHomeService', () => { expect(service.getHostCodexHomePathsForSessionDiscovery()).toContain(managedHomePath) }) - it('gives two managed accounts distinct homes without racing one auth.json (flag ON)', async () => { + it('gives two managed accounts distinct homes without racing one auth.json', async () => { writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') const account1Auth = createCodexAuthJson('one@example.com', 'acct-1', 'one') const account2Auth = createCodexAuthJson('two@example.com', 'acct-2', 'two') const home1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) const home2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2579,7 +1789,7 @@ describe('CodexRuntimeHomeService', () => { expect(existsSync(getRuntimeCodexAuthPath())).toBe(false) }) - it('materializes resources and config into the per-account home on launch (flag ON)', async () => { + it('materializes resources and config into the per-account home on launch', async () => { writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') mkdirSync(join(getSystemCodexHomePath(), 'skills', 'review'), { recursive: true }) writeFileSync( @@ -2599,7 +1809,7 @@ describe('CodexRuntimeHomeService', () => { ) const store = createStore( createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2629,11 +1839,11 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(getSystemCodexAuthPath(), 'utf-8')).toBe('{"account":"system"}\n') }) - it('points the rate-limit fetch at the per-account home when the flag is ON', async () => { + it('points the rate-limit fetch at the per-account home', async () => { const home1 = createManagedAuth(testState.userDataDir, 'account-1', '{"account":"managed"}\n') const store = createStore( createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2657,14 +1867,14 @@ describe('CodexRuntimeHomeService', () => { expect(service.prepareForRateLimitFetch()).toBe(home1) }) - it('preserves a managed selection whose auth.json is temporarily missing (flag ON)', async () => { + it('preserves a managed selection whose auth.json is temporarily missing', async () => { writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') // A managed home that has lost its auth.json (only the marker remains). const brokenHome = join(testState.userDataDir, 'codex-accounts', 'account-1', 'home') mkdirSync(brokenHome, { recursive: true }) writeFileSync(join(brokenHome, '.orca-managed-home'), 'account-1\n', 'utf-8') const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2690,41 +1900,9 @@ describe('CodexRuntimeHomeService', () => { expect(store.getSettings().activeCodexManagedAccountId).toBe('account-1') }) - it('keeps the shared runtime home + auth hot-swap for managed accounts when the flag is OFF', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('one@example.com', 'acct-1', 'one') - const home1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const store = createStore( - createSettings({ - codexSystemDefaultRealHomeEnabled: false, - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: home1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - // Flag OFF is byte-identical to today: shared mirror home + hot-swapped auth. - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account1Auth) - }) - - it('keeps pre-E shared-mirror sessions discoverable alongside per-account rollouts (flag ON)', async () => { + it('keeps pre-E shared-mirror sessions discoverable alongside per-account rollouts', async () => { // Pre-E history lives in the shared runtime mirror; after upgrading to - // per-account homes (flag ON) new rollouts land in the account's own home. + // per-account homes, new rollouts land in the account's own home. const sharedSessionsDir = join(getRuntimeCodexHomePath(), 'sessions', '2026', '07', '16') mkdirSync(sharedSessionsDir, { recursive: true }) writeFileSync(join(sharedSessionsDir, 'rollout-pre-e.jsonl'), '{"record":"pre-e"}\n', 'utf-8') @@ -2742,7 +1920,7 @@ describe('CodexRuntimeHomeService', () => { ) const store = createStore( createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2770,9 +1948,9 @@ describe('CodexRuntimeHomeService', () => { expect(discovery).toContain(home1) }) - it('surfaces per-account rollouts for session discovery after opting out (flag OFF)', async () => { - // The account ran with the flag ON and accumulated rollouts in its own home, - // then the user opted back out (flag OFF, byte-identical launch path). + it('surfaces per-account rollouts for session discovery on the mirror lane', async () => { + // A Windows host keeps the shared system-default mirror, but its managed + // accounts still launch from their own homes and accumulate rollouts there. const home1 = createManagedAuth( testState.userDataDir, 'account-1', @@ -2783,7 +1961,7 @@ describe('CodexRuntimeHomeService', () => { writeFileSync(join(rolloutDir, 'rollout-e-era.jsonl'), '{"record":"e-era"}\n', 'utf-8') const store = createStore( createSettings({ - codexSystemDefaultRealHomeEnabled: false, + shellStartupEnvProbeSupported: false, codexManagedAccounts: [ { id: 'account-1', @@ -2804,118 +1982,10 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - // Opting out must not hide rollouts that already live in the per-account home. + // The mirror lane must not hide rollouts living in the per-account home. expect(service.getHostCodexHomePathsForSessionDiscovery()).toContain(home1) }) - it('does not scan an opted-out never-enabled account home that holds no rollouts', async () => { - // A pure never-enabled install keeps its per-account homes credential-only, so - // opt-out discovery must stay byte-identical to today (mirror home only). - const home1 = createManagedAuth( - testState.userDataDir, - 'account-1', - createCodexAuthJson('one@example.com', 'acct-1', 'one') - ) - const store = createStore( - createSettings({ - codexSystemDefaultRealHomeEnabled: false, - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: home1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(service.getHostCodexHomePathsForSessionDiscovery()).not.toContain(home1) - }) - - it('preserves a fresh per-account credential and propagates it to the shared mirror on opt-out', async () => { - // Flag ON refreshed the account's token in its own home; the shared mirror's - // auth is frozen from before the ON period. Opting out (flag OFF) must not let - // the stale mirror token clobber the fresher per-account credential. - const freshAuth = createCodexAuthJson('one@example.com', 'acct-1', 'fresh', 4_000) - const staleAuth = createCodexAuthJson('one@example.com', 'acct-1', 'stale', 1_000) - const home1 = createManagedAuth(testState.userDataDir, 'account-1', freshAuth) - // A stale mirror auth left over from before the account ran with the flag ON. - writeFileSync(getRuntimeCodexAuthPath(), staleAuth, 'utf-8') - const store = createStore( - createSettings({ - codexSystemDefaultRealHomeEnabled: false, - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: home1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - ) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - // Constructor runs the startup opt-out sync (read-back + hot-swap). - new CodexRuntimeHomeService(store as never) - - // The fresher per-account credential is preserved (never overwritten by the - // stale mirror read-back) and becomes the mirror's auth for the opted-out launch. - expect(readFileSync(join(home1, 'auth.json'), 'utf-8')).toBe(freshAuth) - expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(freshAuth) - }) - - it('rolls a live self-contained account back without adopting newer shared bytes', async () => { - const accountAuth = createCodexAuthJson('one@example.com', 'acct-1', 'in-place', 2_000) - const laterShared = createCodexAuthJson('one@example.com', 'acct-1', 'shared', 3_000) - const home1 = createManagedAuth(testState.userDataDir, 'account-1', accountAuth) - const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: home1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - const store = createStore(settings) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - expect(service.prepareForCodexLaunch()).toBe(home1) - writeFileSync(getRuntimeCodexAuthPath(), laterShared, 'utf-8') - - setRealHomeLaneForTest(false) - service.syncForCurrentSelection() - - expect(readFileSync(join(home1, 'auth.json'), 'utf-8')).toBe(accountAuth) - expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(accountAuth) - }) - it('keeps per-account auth canonical when the real-home lane takes over', async () => { const runtimeAuthPath = getRuntimeCodexAuthPath() const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'system') @@ -2929,7 +1999,7 @@ describe('CodexRuntimeHomeService', () => { writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -2950,7 +2020,7 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - // Flag ON launches the account from its own home without populating the + // Launching the account from its own home never populates the // legacy shared mirror. expect(service.isHostSystemDefaultRealHome()).toBe(false) expect(service.prepareForCodexLaunch()).toBe(managedHomePath) @@ -2983,7 +2053,7 @@ describe('CodexRuntimeHomeService', () => { writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -3031,7 +2101,7 @@ describe('CodexRuntimeHomeService', () => { createCodexAuthJson('wsl@example.com', 'acct-wsl', 'wsl') ) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -3138,7 +2208,7 @@ describe('CodexRuntimeHomeService', () => { const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', accountAuth) const store = createStore( createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -3199,7 +2269,7 @@ describe('CodexRuntimeHomeService', () => { writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -3245,7 +2315,7 @@ describe('CodexRuntimeHomeService', () => { writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, + shellStartupEnvProbeSupported: true, codexManagedAccounts: [ { id: 'account-1', @@ -3281,328 +2351,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(join(managedHomePath, 'auth.json'), 'utf-8')).toBe(managedAuth) }) - it('uses the same host CODEX_HOME after switching managed Codex accounts', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('one@example.com', 'acct-1', 'one') - const account2Auth = createCodexAuthJson('two@example.com', 'acct-2', 'two') - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-2', - workspaceLabel: null, - workspaceAccountId: 'acct-2', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - const store = createStore(settings) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - const account1Home = service.prepareForCodexLaunch() - settings.activeCodexManagedAccountId = 'account-2' - settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-2', wsl: {} } - const account2Home = service.prepareForCodexLaunch() - - expect(account1Home).toBe(getRuntimeCodexHomePath()) - expect(account2Home).toBe(getRuntimeCodexHomePath()) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account2Auth) - }) - - it('new host Codex launches get the selected account after preserving outgoing refreshes', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('one@example.com', 'acct-1', 'one', 1) - const account1RefreshedAuth = createCodexAuthJson( - 'one@example.com', - 'acct-1', - 'one-refreshed', - 2 - ) - const account2Auth = createCodexAuthJson('two@example.com', 'acct-2', 'two', 1) - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-2', - workspaceLabel: null, - workspaceAccountId: 'acct-2', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - const store = createStore(settings) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - settings.activeCodexManagedAccountId = 'account-2' - settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-2', wsl: {} } - - expect(service.prepareForCodexLaunch()).toBe(getRuntimeCodexHomePath()) - expect(readFileSync(join(managedHomePath1, 'auth.json'), 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account2Auth) - }) - - it('reads back selected-account refreshes without ambiguity from duplicate identities', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('same@example.com', 'acct-same', 'one', 1) - const account1RefreshedAuth = createCodexAuthJson( - 'same@example.com', - 'acct-same', - 'one-refreshed', - 2 - ) - const account2Auth = createCodexAuthJson('same@example.com', 'acct-same', 'two', 1) - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'same@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'same@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - const store = createStore(settings) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(join(managedHomePath1, 'auth.json'), 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(join(managedHomePath2, 'auth.json'), 'utf-8')).toBe(account2Auth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account1RefreshedAuth) - }) - - it('keeps fresher selected-account startup refreshes when duplicate identities exist', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('same@example.com', 'acct-same', 'one', 1) - const account1RefreshedAuth = createCodexAuthJson( - 'same@example.com', - 'acct-same', - 'one-refreshed', - 2 - ) - const account2Auth = createCodexAuthJson('same@example.com', 'acct-same', 'two', 1) - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'same@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'same@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(join(managedHomePath1, 'auth.json'), 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(join(managedHomePath2, 'auth.json'), 'utf-8')).toBe(account2Auth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account1RefreshedAuth) - }) - - it('routes stale live-pane startup refreshes to the matching account before restoring selected auth', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('one@example.com', 'acct-1', 'one', 1) - const account1RefreshedAuth = createCodexAuthJson( - 'one@example.com', - 'acct-1', - 'one-refreshed', - 2 - ) - const account2Auth = createCodexAuthJson('two@example.com', 'acct-2', 'two', 1) - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-2', - workspaceLabel: null, - workspaceAccountId: 'acct-2', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-2', - activeCodexManagedAccountIdsByRuntime: { host: 'account-2', wsl: {} } - }) - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(join(managedHomePath1, 'auth.json'), 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(join(managedHomePath2, 'auth.json'), 'utf-8')).toBe(account2Auth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account2Auth) - }) - - it('preserves duplicate-identity outgoing refreshes before switching to another account', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const account1Auth = createCodexAuthJson('same@example.com', 'acct-same', 'one', 1) - const account1RefreshedAuth = createCodexAuthJson( - 'same@example.com', - 'acct-same', - 'one-refreshed', - 2 - ) - const account2Auth = createCodexAuthJson('same@example.com', 'acct-same', 'two', 1) - const account3Auth = createCodexAuthJson('three@example.com', 'acct-3', 'three', 1) - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const managedHomePath3 = createManagedAuth(testState.userDataDir, 'account-3', account3Auth) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'same@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'same@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - }, - { - id: 'account-3', - email: 'three@example.com', - managedHomePath: managedHomePath3, - providerAccountId: 'acct-3', - workspaceLabel: null, - workspaceAccountId: 'acct-3', - createdAt: 3, - updatedAt: 3, - lastAuthenticatedAt: 3 - } - ], - activeCodexManagedAccountId: 'account-1', - activeCodexManagedAccountIdsByRuntime: { host: 'account-1', wsl: {} } - }) - const store = createStore(settings) - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - settings.activeCodexManagedAccountId = 'account-3' - settings.activeCodexManagedAccountIdsByRuntime = { host: 'account-3', wsl: {} } - service.syncForCurrentSelection() - - expect(readFileSync(join(managedHomePath1, 'auth.json'), 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(join(managedHomePath2, 'auth.json'), 'utf-8')).toBe(account2Auth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account3Auth) - }) - it('mirrors later system Codex config changes before launch', async () => { const systemCodexHome = getSystemCodexHomePath() mkdirSync(systemCodexHome, { recursive: true }) @@ -3632,7 +2380,7 @@ describe('CodexRuntimeHomeService', () => { '' ].join('\n') writeFileSync(canonicalConfigPath, canonicalConfig, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: false })) + const store = createStore(createSettings({ shellStartupEnvProbeSupported: false })) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) @@ -4129,7 +2877,6 @@ describe('CodexRuntimeHomeService', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) - expect(readFileSync(getRuntimeCodexAuthPath(), 'utf-8')).toBe(hostAuth) expect(service.prepareForCodexLaunch({ runtime: 'wsl', wslDistro: 'Ubuntu' })).toBe( wslRuntimeHomePath ) @@ -4935,38 +3682,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(systemAuth) }) - it('removes untrusted runtime auth on restart when persisted active account is invalid', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath: join(testState.userDataDir, 'codex-accounts', 'account-1', 'home'), - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(store.updateSettings).toHaveBeenCalledWith( - expect.objectContaining({ activeCodexManagedAccountId: null }) - ) - expect(existsSync(runtimeAuthPath)).toBe(false) - expect(warnSpy).toHaveBeenCalled() - }) - it('imports legacy managed-home history into the shared runtime history', async () => { const runtimeHomePath = getRuntimeCodexHomePath() const runtimeHistoryPath = join(runtimeHomePath, 'history.jsonl') @@ -5000,30 +3715,8 @@ describe('CodexRuntimeHomeService', () => { } const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"account":"managed"}\n' - ) - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - ) + writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') + const store = createStore(createSettings()) const { CodexRuntimeHomeService } = await import('./runtime-home-service') new CodexRuntimeHomeService(store as never) @@ -5038,29 +3731,8 @@ describe('CodexRuntimeHomeService', () => { } const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"account":"managed"}\n' - ) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) + writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') + const store = createStore(createSettings()) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) @@ -5143,385 +3815,6 @@ describe('CodexRuntimeHomeService', () => { expect(existsSync(snapshotPath)).toBe(false) }) - it('reads back CLI-refreshed tokens into managed storage on subsequent sync', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const originalAuth = createCodexAuthJson('user@example.com', 'acct-1', 'original') - const refreshedAuth = createCodexAuthJson('user@example.com', 'acct-1', 'refreshed') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', originalAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - // Simulate CLI refreshing the token in runtime CODEX_HOME/auth.json. - writeFileSync(runtimeAuthPath, refreshedAuth, 'utf-8') - - // Next sync should read back the refreshed token to managed storage - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(refreshedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(refreshedAuth) - }) - - it('rejects runtime read-back from a different Codex identity', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const selectedAuth = createCodexAuthJson('selected@example.com', 'acct-selected', 'selected') - const staleLivePtyAuth = createCodexAuthJson('stale@example.com', 'acct-stale', 'stale') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', selectedAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'selected@example.com', - managedHomePath, - providerAccountId: 'acct-selected', - workspaceLabel: null, - workspaceAccountId: 'acct-selected', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - // Simulate an old live Codex PTY from another account refreshing the - // shared runtime auth after Orca has already selected account-1. - writeFileSync(runtimeAuthPath, staleLivePtyAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(selectedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(selectedAuth) - }) - - it('routes runtime read-back from a different Codex identity to its matching account', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const account1Auth = createCodexAuthJson('one@example.com', 'acct-one', 'one') - const account1RefreshedAuth = createCodexAuthJson( - 'one@example.com', - 'acct-one', - 'one-refreshed' - ) - const account2Auth = createCodexAuthJson('two@example.com', 'acct-two', 'two') - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const managedAuthPath1 = join(managedHomePath1, 'auth.json') - const managedAuthPath2 = join(managedHomePath2, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-one', - workspaceLabel: null, - workspaceAccountId: 'acct-one', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-two', - workspaceLabel: null, - workspaceAccountId: 'acct-two', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-2' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - // An older account-1 Codex process refreshed the shared runtime file after - // Orca selected account-2. Persist the refresh to account-1, then restore - // the selected account in runtime CODEX_HOME. - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath1, 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(managedAuthPath2, 'utf-8')).toBe(account2Auth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account2Auth) - }) - - it('rejects ambiguous Codex read-back instead of choosing a managed account', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const originalAuth = createCodexAuthJson('same@example.com', 'acct-same', 'original') - const refreshedAuth = createCodexAuthJson('same@example.com', 'acct-same', 'refreshed') - const activeAuth = createCodexAuthJson('active@example.com', 'acct-active', 'active') - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', originalAuth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', originalAuth) - const managedHomePath3 = createManagedAuth(testState.userDataDir, 'account-3', activeAuth) - const managedAuthPath1 = join(managedHomePath1, 'auth.json') - const managedAuthPath2 = join(managedHomePath2, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'same@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'same@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-same', - workspaceLabel: null, - workspaceAccountId: 'acct-same', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - }, - { - id: 'account-3', - email: 'active@example.com', - managedHomePath: managedHomePath3, - providerAccountId: 'acct-active', - workspaceLabel: null, - workspaceAccountId: 'acct-active', - createdAt: 3, - updatedAt: 3, - lastAuthenticatedAt: 3 - } - ], - activeCodexManagedAccountId: 'account-3' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, refreshedAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath1, 'utf-8')).toBe(originalAuth) - expect(readFileSync(managedAuthPath2, 'utf-8')).toBe(originalAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(activeAuth) - }) - - it('rejects runtime read-back without a positive selected-account identity match', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const selectedAuth = createCodexAuthJson('selected@example.com', 'acct-selected', 'selected') - const accountOnlyAuth = `${JSON.stringify({ - tokens: { - account_id: 'acct-stale', - refresh_token: 'stale' - } - })}\n` - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', selectedAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'selected@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, accountOnlyAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(selectedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(selectedAuth) - }) - - it('rejects same-email runtime read-back when account ids differ from sparse managed metadata', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const selectedAuth = createCodexAuthJson('user@example.com', 'acct-selected', 'selected') - const staleLivePtyAuth = createCodexAuthJson('user@example.com', 'acct-stale', 'stale') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', selectedAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, staleLivePtyAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(selectedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(selectedAuth) - }) - - it('reads back same-account refreshes for sparse managed metadata using stored auth identity', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const originalAuth = createCodexAuthJson('user@example.com', 'acct-selected', 'original') - const refreshedAuth = createCodexAuthJson('user@example.com', 'acct-selected', 'refreshed') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', originalAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, refreshedAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(refreshedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(refreshedAuth) - }) - - it('reads back strong account-id refreshes when the runtime auth has no email', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const originalAuth = createCodexAuthJson('user@example.com', 'acct-1', 'original') - const refreshedAuth = `${JSON.stringify({ - tokens: { - account_id: 'acct-1', - refresh_token: 'refreshed' - } - })}\n` - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', originalAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, refreshedAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(refreshedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(refreshedAuth) - }) - - it('rejects unverifiable Codex read-back on first sync after restart', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"credential":"refreshed-while-down"}\n', 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"credential":"original"}\n' - ) - const managedAuthPath = join(managedHomePath, 'auth.json') - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - ) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe('{"credential":"original"}\n') - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"credential":"original"}\n') - }) - it('reads back verified same-account refreshes on first sync after restart', async () => { const runtimeAuthPath = getRuntimeCodexAuthPath() const originalAuth = createCodexAuthJson('user@example.com', 'acct-1', 'original', 1_000) @@ -5555,201 +3848,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(refreshedAuth) }) - it('rejects older same-account Codex auth on first sync after restart', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - const staleRuntimeAuth = createCodexAuthJson('user@example.com', 'acct-1', 'stale', 1_000) - const managedAuth = createCodexAuthJson('user@example.com', 'acct-1', 'managed-newer', 2_000) - writeFileSync(runtimeAuthPath, staleRuntimeAuth, 'utf-8') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const store = createStore( - createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - ) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - new CodexRuntimeHomeService(store as never) - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(managedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(managedAuth) - }) - - it('does not contaminate the incoming Codex account during account switch', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const managedHomePath1 = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"credential":"account1"}\n' - ) - const managedHomePath2 = createManagedAuth( - testState.userDataDir, - 'account-2', - '{"credential":"account2"}\n' - ) - const managedAuthPath2 = join(managedHomePath2, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user1@example.com', - managedHomePath: managedHomePath1, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'user2@example.com', - managedHomePath: managedHomePath2, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - settings.activeCodexManagedAccountId = 'account-2' - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath2, 'utf-8')).toBe('{"credential":"account2"}\n') - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"credential":"account2"}\n') - }) - - it('does not carry the reauth read-back skip across Codex account switches', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const account1Auth = createCodexAuthJson('one@example.com', 'acct-one', 'one') - const account2Auth = createCodexAuthJson('two@example.com', 'acct-two', 'two') - const account2RefreshedAuth = createCodexAuthJson( - 'two@example.com', - 'acct-two', - 'two-refreshed' - ) - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const managedAuthPath2 = join(managedHomePath2, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-one', - workspaceLabel: null, - workspaceAccountId: 'acct-one', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-two', - workspaceLabel: null, - workspaceAccountId: 'acct-two', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - service.clearLastWrittenAuthJson() - settings.activeCodexManagedAccountId = 'account-2' - service.syncForCurrentSelection() - - writeFileSync(runtimeAuthPath, account2RefreshedAuth, 'utf-8') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath2, 'utf-8')).toBe(account2RefreshedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account2RefreshedAuth) - }) - - it('does not apply inactive-account Codex reauth skip to the active account', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const account1Auth = createCodexAuthJson('one@example.com', 'acct-one', 'one') - const account1RefreshedAuth = createCodexAuthJson( - 'one@example.com', - 'acct-one', - 'one-refreshed' - ) - const account2Auth = createCodexAuthJson('two@example.com', 'acct-two', 'two') - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Auth) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const managedAuthPath1 = join(managedHomePath1, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-one', - workspaceLabel: null, - workspaceAccountId: 'acct-one', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-two', - workspaceLabel: null, - workspaceAccountId: 'acct-two', - createdAt: 2, - updatedAt: 2, - lastAuthenticatedAt: 2 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, account1RefreshedAuth, 'utf-8') - service.clearLastWrittenAuthJson('account-2') - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath1, 'utf-8')).toBe(account1RefreshedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account1RefreshedAuth) - }) - it('restores system default when unverified runtime auth appears before deselect', async () => { const runtimeAuthPath = getRuntimeCodexAuthPath() writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') @@ -5795,44 +3893,6 @@ describe('CodexRuntimeHomeService', () => { ).toBe(true) }) - it('restores system default after same-identity managed Codex refresh on deselect', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(getSystemCodexAuthPath(), '{"account":"system-old"}\n', 'utf-8') - const managedAuth = createCodexAuthJson('user@example.com', 'acct-1', 'managed') - const externalAuth = createCodexAuthJson('user@example.com', 'acct-1', 'external') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', managedAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ] - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - settings.activeCodexManagedAccountId = 'account-1' - service.syncForCurrentSelection() - - writeFileSync(runtimeAuthPath, externalAuth, 'utf-8') - settings.activeCodexManagedAccountId = null - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(externalAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"account":"system-old"}\n') - }) - it('restores system default when stale Codex credentials are rejected on deselect', async () => { const runtimeAuthPath = getRuntimeCodexAuthPath() writeFileSync(getSystemCodexAuthPath(), '{"account":"system-old"}\n', 'utf-8') @@ -5907,78 +3967,19 @@ describe('CodexRuntimeHomeService', () => { expect(existsSync(runtimeAuthPath)).toBe(false) }) - it('keeps external system-default logout when managed runtime auth still exists', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(getSystemCodexAuthPath(), '{"account":"system-old"}\n', 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - '{"account":"managed"}\n' - ) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"account":"managed"}\n') - rmSync(getSystemCodexAuthPath(), { force: true }) - settings.activeCodexManagedAccountId = null - service.syncForCurrentSelection() - - expect(existsSync(runtimeAuthPath)).toBe(false) - }) - - it('recreates retained auth after switching from managed to logged-out system default', async () => { + it('recreates retained auth after a logged-out system default logs back in', async () => { const systemAuth = createCodexAuthJson('system@example.com', 'acct-system', 'old-token') const reloginAuth = createCodexAuthJson('system@example.com', 'acct-system', 'relogin-token') writeFileSync(getSystemCodexAuthPath(), systemAuth, 'utf-8') - const managedHomePath = createManagedAuth( - testState.userDataDir, - 'account-1', - createCodexAuthJson('managed@example.com', 'acct-managed', 'managed-token') - ) - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'managed@example.com', - managedHomePath, - providerAccountId: 'acct-managed', - workspaceLabel: null, - workspaceAccountId: 'acct-managed', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) + const store = createStore(createSettings()) const { CodexRuntimeHomeService } = await import('./runtime-home-service') const service = new CodexRuntimeHomeService(store as never) rmSync(getSystemCodexAuthPath()) - settings.activeCodexManagedAccountId = null service.syncForCurrentSelection() expect(existsSync(getRuntimeCodexAuthPath())).toBe(false) - setRealHomeLaneForTest(true) + setShellStartupEnvProbeSupportedForTest(true) service.setRealHomeLaneGate(() => true) writeFileSync(getSystemCodexAuthPath(), reloginAuth, 'utf-8') service.reconcileLegacySharedHomeForRetainedPanes() @@ -6027,95 +4028,6 @@ describe('CodexRuntimeHomeService', () => { expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe('{"account":"system-2"}\n') }) - it('reads back refreshed tokens for the outgoing Codex account before switching', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const account1Original = createCodexAuthJson('one@example.com', 'acct-1', 'one-original') - const account1Refreshed = createCodexAuthJson('one@example.com', 'acct-1', 'one-refreshed') - const account2Auth = createCodexAuthJson('two@example.com', 'acct-2', 'two') - const managedHomePath1 = createManagedAuth(testState.userDataDir, 'account-1', account1Original) - const managedHomePath2 = createManagedAuth(testState.userDataDir, 'account-2', account2Auth) - const managedAuthPath1 = join(managedHomePath1, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'one@example.com', - managedHomePath: managedHomePath1, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - }, - { - id: 'account-2', - email: 'two@example.com', - managedHomePath: managedHomePath2, - providerAccountId: 'acct-2', - workspaceLabel: null, - workspaceAccountId: 'acct-2', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - writeFileSync(runtimeAuthPath, account1Refreshed, 'utf-8') - settings.activeCodexManagedAccountId = 'account-2' - service.syncForCurrentSelection() - - expect(readFileSync(managedAuthPath1, 'utf-8')).toBe(account1Refreshed) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(account2Auth) - }) - - it('does not clobber fresh tokens after clearLastWrittenAuthJson', async () => { - const runtimeAuthPath = getRuntimeCodexAuthPath() - writeFileSync(runtimeAuthPath, '{"account":"system"}\n', 'utf-8') - const originalAuth = createCodexAuthJson('user@example.com', 'acct-1', 'original') - const reauthedAuth = createCodexAuthJson('user@example.com', 'acct-1', 'reauthed') - const managedHomePath = createManagedAuth(testState.userDataDir, 'account-1', originalAuth) - const managedAuthPath = join(managedHomePath, 'auth.json') - const settings = createSettings({ - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: 'acct-1', - workspaceLabel: null, - workspaceAccountId: 'acct-1', - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ], - activeCodexManagedAccountId: 'account-1' - }) - const store = createStore(settings) - - const { CodexRuntimeHomeService } = await import('./runtime-home-service') - const service = new CodexRuntimeHomeService(store as never) - - // Simulate re-auth: managed storage gets fresh tokens - writeFileSync(managedAuthPath, reauthedAuth, 'utf-8') - - // Clear tracking before sync (as CodexAccountService would) - service.clearLastWrittenAuthJson() - service.syncForCurrentSelection() - - // Fresh re-auth tokens should survive — not be clobbered by stale runtime read-back - expect(readFileSync(managedAuthPath, 'utf-8')).toBe(reauthedAuth) - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(reauthedAuth) - }) - it('preserves conflicting legacy session files under deterministic names', async () => { const runtimeSessionsDir = join(getRuntimeCodexHomePath(), 'sessions') mkdirSync(runtimeSessionsDir, { recursive: true }) diff --git a/src/main/codex-accounts/runtime-home-service.ts b/src/main/codex-accounts/runtime-home-service.ts index fa2f27798..c2b99b52c 100644 --- a/src/main/codex-accounts/runtime-home-service.ts +++ b/src/main/codex-accounts/runtime-home-service.ts @@ -67,7 +67,6 @@ import { type CodexAccountSelectionTarget } from './runtime-selection' import { getDefaultWslDistro, getWslHome } from '../wsl' -import { isCodexSystemDefaultRealHomeEnabled } from '../codex/codex-real-home-flag' import { hasCustomCodexHomeOverrideForLaunch } from '../codex/codex-real-home-path' import { invalidateCodexSessionBackfillMarker } from '../codex/codex-session-backfill-marker' import { assertOwnedHostCodexManagedHomePath } from './host-codex-managed-home-ownership' @@ -176,8 +175,8 @@ export class CodexRuntimeHomeService { private readonly lastSyncedWslAccountIdByDistro = new Map() private readonly wslRuntimeHomePathByDistro = new Map() private skipNextReadBackForAccountId: string | null = null - // Why: a flag-ON host account refreshes auth in its own home. Remember that - // provenance so a later deselect/rollback never adopts stale shared bytes. + // Why: a managed host account refreshes auth in its own home. Remember that + // provenance so a later deselect never adopts stale shared bytes. private lastHostAccountUsedSelfContainedHome = false private sharedAuthRefreshBlockedByManagedTransition = false // Why: transient auth.json read/parse failures must not deselect an account. @@ -236,7 +235,7 @@ export class CodexRuntimeHomeService { // system default without injecting a path Orca cannot prove it owns. } if (this.isHostSystemDefaultRealHome(launchEnv)) { - // Why (flag ON, system default): run Codex on the user's own ~/.codex. + // Why: the system default runs Codex on the user's own ~/.codex. // Returning null tells the PTY/env layer to inject no managed CODEX_HOME; // the retired mirror is refreshed only for pre-rollout PTYs. this.reconcileLegacySharedHomeForRetainedPanes() @@ -254,17 +253,12 @@ export class CodexRuntimeHomeService { return this.getRuntimeHomePath() } - // Why: with the real-home flag ON, a managed HOST account runs against its own - // self-contained CODEX_HOME (codex-accounts//home) instead of the shared - // runtime mirror. Its auth.json lives there and codex refreshes it in place, - // so two accounts never race one auth.json (GAP-5) and the mirror can be - // deleted once no lane still injects it (GAP-1). WSL accounts keep their - // per-distro lane; the flag-OFF opt-out keeps the shared-home hot-swap. + // Why: a managed HOST account runs against its own self-contained CODEX_HOME + // (codex-accounts//home) rather than the shared runtime mirror. Its + // auth.json lives there and codex refreshes it in place, so two accounts never + // race one auth.json. WSL accounts keep their per-distro lane. private getSelfContainedManagedHostAccount(): CodexManagedAccount | null { const settings = this.store.getSettings() - if (!isCodexSystemDefaultRealHomeEnabled()) { - return null - } const account = this.getActiveAccount( settings.codexManagedAccounts, normalizeCodexRuntimeSelection(settings).host @@ -276,22 +270,17 @@ export class CodexRuntimeHomeService { } // Why: session discovery must surface a managed account's own rollouts wherever - // they physically live. Flag ON makes every host managed home a live CODEX_HOME, - // so scan them all. Flag OFF (opt-out/rollback) hands launches back to the shared - // mirror, but a home that already accumulated rollouts while the flag was ON must - // still surface them — otherwise opting out silently hides history that is safe on - // disk. Gate the flag-OFF case on a sessions/ tree so a never-enabled install stays - // byte-identical to today (its per-account homes hold only auth, no rollouts). + // they physically live. Every host managed home is a live CODEX_HOME, so scan + // them all. private getManagedHostAccountHomesForSessionDiscovery(): string[] { const settings = this.store.getSettings() - const flagEnabled = isCodexSystemDefaultRealHomeEnabled() const homes: string[] = [] for (const account of settings.codexManagedAccounts) { if (this.getWslManagedHomePath(account)) { continue } const trustedHome = this.getTrustedSelfContainedManagedHomePath(account) - if (trustedHome && (flagEnabled || existsSync(join(trustedHome, 'sessions')))) { + if (trustedHome) { homes.push(trustedHome) } } @@ -420,8 +409,9 @@ export class CodexRuntimeHomeService { if (normalizeCodexRuntimeSelection(settings).host !== null) { return } - const realHomeSelected = this.isHostSystemDefaultRealHomeSelected(launchEnv) - if (realHomeSelected || !isCodexSystemDefaultRealHomeEnabled()) { + // Why: reached only when the real-home lane is selected but its gate is off, + // so the launch runs on the mirror and the backfill marker is stale. + if (this.isHostSystemDefaultRealHomeSelected(launchEnv)) { invalidateCodexSessionBackfillMarker( join(getCodexSessionBackfillStateDirPath(), 'backfill-complete.json') ) @@ -463,10 +453,9 @@ export class CodexRuntimeHomeService { // mirror, so include the real root for both directly-routed host lanes. homes.push(getSystemCodexHomePath()) } - // Why: flag ON routes each managed host account to its own self-contained - // home, so its rollouts live there rather than in the shared mirror. Scan - // every such home — plus any that retained rollouts across an opt-out — so - // account-scoped sessions still surface in the AI Vault. + // Why: each managed host account runs in its own self-contained home, so + // its rollouts live there rather than in the shared mirror. Scan every such + // home so account-scoped sessions still surface in the AI Vault. for (const perAccountHome of this.getManagedHostAccountHomesForSessionDiscovery()) { homes.push(perAccountHome) } @@ -475,9 +464,8 @@ export class CodexRuntimeHomeService { /** * The account-owned CODEX_HOME the current HOST selection runs against, or - * null when the selection is not routed to one (system default, or the - * flag-OFF shared mirror, which every account hot-swaps and so names no - * account). + * null when the selection is not routed to one (system default, or a WSL + * account, whose home lives inside the distro). * * Read-only on purpose: session discovery ranks homes with this before any * launch prep, so it must create no directories and sync no auth. @@ -505,13 +493,13 @@ export class CodexRuntimeHomeService { this.realHomeLaneGate = gate } - // Why: real-home routing applies only to the host system-default selection - // with the staged flag ON. Managed accounts keep hot-swap isolation; custom - // CODEX_HOMEs stay managed until phase 1 can track cleanup across old homes. + // Why: real-home routing applies only to the host system-default selection. + // Managed accounts run in their own homes; Windows (no shell-startup probe) + // and custom CODEX_HOMEs stay on the mirror until cleanup can be tracked + // across old homes. isHostSystemDefaultRealHomeSelected(launchEnv?: NodeJS.ProcessEnv): boolean { const settings = this.store.getSettings() if ( - !isCodexSystemDefaultRealHomeEnabled() || normalizeCodexRuntimeSelection(settings).host !== null || !isShellStartupEnvProbeSupported() ) { @@ -640,9 +628,9 @@ export class CodexRuntimeHomeService { } const settings = this.store.getSettings() if (this.lastHostAccountUsedSelfContainedHome) { - // Why: E auth is already canonical in the per-account home. Reset the - // legacy mirror baseline without reading it; flag-OFF can then seed the - // mirror from canonical storage, while real-home deselect needs no sync. + // Why: the account's auth is already canonical in its own home. Reset the + // legacy mirror baseline without reading it; a real-home deselect needs no + // further sync, and the mirror lane below re-seeds from canonical storage. this.lastHostAccountUsedSelfContainedHome = false this.lastSyncedAccountId = null this.lastWrittenAuthJson = null @@ -668,105 +656,16 @@ export class CodexRuntimeHomeService { settings.codexManagedAccounts, normalizeCodexRuntimeSelection(settings).host ) - const previousAccount = this.getActiveAccount( - settings.codexManagedAccounts, - this.lastSyncedAccountId - ) - if (this.getWslManagedHomePath(activeAccount)) { - const previousWasHostManaged = previousAccount && !this.getWslManagedHomePath(previousAccount) - const outgoingReadBackResult = previousWasHostManaged - ? this.readBackRefreshedTokensForAccount(previousAccount, { - updateLastWrittenAuthJson: false - }) - : 'unchanged' - if (previousWasHostManaged) { - this.restoreSystemDefaultSnapshot({ - detectExternalLogin: outgoingReadBackResult !== 'rejected' - }) - } + if (activeAccount) { + // Why: only a WSL-managed account can reach here — every host account was + // routed to its own self-contained home above. Its auth lives in the + // distro-local runtime home, so the host mirror only drops its baseline. this.lastSyncedAccountId = null this.lastWrittenAuthJson = null this.skipNextReadBackForAccountId = null return } - let outgoingReadBackResult: CodexReadBackResult = 'unchanged' - if (previousAccount && previousAccount.id !== activeAccount?.id) { - outgoingReadBackResult = this.readBackRefreshedTokensForAccount(previousAccount, { - updateLastWrittenAuthJson: true - }) - } - if (!activeAccount) { - if (normalizeCodexRuntimeSelection(settings).host) { - this.store.updateSettings({ - activeCodexManagedAccountId: null, - activeCodexManagedAccountIdsByRuntime: { - ...normalizeCodexRuntimeSelection(settings), - host: null - } - }) - } - // Why: only restore the system-default mirror when leaving a managed account; otherwise later syncs mirror current ~/.codex instead of replaying an old snapshot. - if (this.lastSyncedAccountId !== null) { - this.restoreSystemDefaultSnapshot({ - detectExternalLogin: outgoingReadBackResult !== 'rejected' - }) - this.lastSyncedAccountId = null - } else if (!runtimeAuthExistedBeforeSync) { - const logoutMarkerStatus = this.getRuntimeLogoutMarkerStatus() - if (logoutMarkerStatus.kind === 'applies') { - this.lastWrittenAuthJson = null - } else if ( - logoutMarkerStatus.kind === 'system-default-changed' && - logoutMarkerStatus.systemDefaultAuthJson !== null - ) { - this.restoreSystemDefaultSnapshot({ detectExternalLogin: false }) - } else if (logoutMarkerStatus.kind === 'system-default-changed') { - // Why: a real ~/.codex logout after a local runtime logout should keep runtime auth absent, not restore the stale snapshot. - this.captureSystemDefaultSnapshot({ force: true }) - this.persistRuntimeLogoutMarker(null) - this.lastWrittenAuthJson = null - } else if (this.lastWrittenAuthJson === null) { - // Why: unmanaged sessions use an Orca-owned CODEX_HOME; seed it once from system-default auth so terminals stay logged in without mutating ~/.codex. - this.restoreSystemDefaultSnapshot({ detectExternalLogin: false }) - } else { - this.persistRuntimeLogoutMarker() - } - } else { - this.clearRuntimeLogoutMarker() - this.syncRuntimeAuthWithSystemDefault() - } - return - } - - const activeAuthPath = join(activeAccount.managedHomePath, 'auth.json') - const authAbsence = this.credentialAbsenceGrace.assess(activeAuthPath) - if (authAbsence.state !== 'present' && authAbsence.state !== 'incomplete') { - if (!authAbsence.durable) { - if (this.sharedRuntimeAuthBelongsToAccount(activeAccount)) { - // Why: mid-rotation reads look missing/unreadable for a moment; skip - // this sync without deselecting and let a settled read decide later. - console.warn( - '[codex-runtime-home] Active managed account auth.json unavailable, keeping selection through grace window' - ) - return - } - // Why: the runtime home still holds another account, so riding out the - // grace would launch that account under this selection. Not being able - // to read the selected account is no license to run a different one. - console.warn( - '[codex-runtime-home] Active managed account auth.json unavailable while the runtime home holds another account, clearing runtime auth' - ) - this.clearRuntimeAuthForUnprovenSelection() - return - } - console.warn( - '[codex-runtime-home] Active managed account credential is unavailable, restoring system default' - ) - // Why: valid credential-free JSON is an explicit logout; never revive it - // from stale shared-home bytes while clearing the selection. - if (authAbsence.state !== 'no-credential' && this.lastSyncedAccountId === activeAccount.id) { - outgoingReadBackResult = this.recoverRefreshForMissingActiveAccount(activeAccount) - } + if (normalizeCodexRuntimeSelection(settings).host) { this.store.updateSettings({ activeCodexManagedAccountId: null, activeCodexManagedAccountIdsByRuntime: { @@ -774,38 +673,35 @@ export class CodexRuntimeHomeService { host: null } }) - if (this.lastSyncedAccountId !== null) { - this.restoreSystemDefaultSnapshot({ - detectExternalLogin: outgoingReadBackResult !== 'rejected' - }) - this.lastSyncedAccountId = null - } - return } - - if (this.lastSyncedAccountId === null) { - this.captureSystemDefaultSnapshot({ force: true }) - } - - // Why: Codex refreshes OAuth tokens in the runtime auth.json; if it differs from Orca's last write, read those back to managed storage before overwriting. - if (this.lastSyncedAccountId === activeAccount.id) { - if (this.skipNextReadBackForAccountId === activeAccount.id) { - this.skipNextReadBackForAccountId = null + // Why: only restore the system-default mirror when leaving a managed account; otherwise later syncs mirror current ~/.codex instead of replaying an old snapshot. + if (this.lastSyncedAccountId !== null) { + this.restoreSystemDefaultSnapshot({ detectExternalLogin: true }) + this.lastSyncedAccountId = null + } else if (!runtimeAuthExistedBeforeSync) { + const logoutMarkerStatus = this.getRuntimeLogoutMarkerStatus() + if (logoutMarkerStatus.kind === 'applies') { + this.lastWrittenAuthJson = null + } else if ( + logoutMarkerStatus.kind === 'system-default-changed' && + logoutMarkerStatus.systemDefaultAuthJson !== null + ) { + this.restoreSystemDefaultSnapshot({ detectExternalLogin: false }) + } else if (logoutMarkerStatus.kind === 'system-default-changed') { + // Why: a real ~/.codex logout after a local runtime logout should keep runtime auth absent, not restore the stale snapshot. + this.captureSystemDefaultSnapshot({ force: true }) + this.persistRuntimeLogoutMarker(null) + this.lastWrittenAuthJson = null + } else if (this.lastWrittenAuthJson === null) { + // Why: unmanaged sessions use an Orca-owned CODEX_HOME; seed it once from system-default auth so terminals stay logged in without mutating ~/.codex. + this.restoreSystemDefaultSnapshot({ detectExternalLogin: false }) } else { - this.readBackRefreshedTokens({ - updateLastWrittenAuthJson: true - }) + this.persistRuntimeLogoutMarker() } + } else { + this.clearRuntimeLogoutMarker() + this.syncRuntimeAuthWithSystemDefault() } - - if (this.lastSyncedAccountId !== activeAccount.id) { - this.skipNextReadBackForAccountId = null - } - this.lastSyncedAccountId = activeAccount.id - this.writeRuntimeAuth(readFileSync(activeAuthPath, 'utf-8'), { - owner: 'managed', - accountId: activeAccount.id - }) } // Why: re-auth/add-account write fresh managed tokens, so skip the next read-back to avoid clobbering them with stale runtime tokens. @@ -818,26 +714,6 @@ export class CodexRuntimeHomeService { this.skipNextReadBackForAccountId = accountId } - private readBackRefreshedTokens(options: { - updateLastWrittenAuthJson: boolean - }): CodexReadBackResult { - const selectedAccountId = normalizeCodexRuntimeSelection(this.store.getSettings()).host - if (selectedAccountId) { - const selectedAccountResult = this.readBackRefreshedTokensFromPath( - this.getRuntimeAuthPath(), - { - ...options, - expectedAccountId: selectedAccountId - } - ) - if (selectedAccountResult !== 'rejected') { - return selectedAccountResult - } - } - - return this.readBackRefreshedTokensFromPath(this.getRuntimeAuthPath(), options) - } - private readBackRefreshedTokensFromPath( runtimeAuthPath: string, options: { @@ -895,119 +771,6 @@ export class CodexRuntimeHomeService { } } - private readBackRefreshedTokensForAccount( - account: CodexManagedAccount, - options: { updateLastWrittenAuthJson: boolean } - ): CodexReadBackResult { - return this.readBackRefreshedTokensFromPath(this.getRuntimeAuthPath(), { - ...options, - expectedAccountId: account.id - }) - } - - private recoverRefreshForMissingActiveAccount(account: CodexManagedAccount): CodexReadBackResult { - try { - const runtimeAuthPath = this.getRuntimeAuthPath() - if (!existsSync(runtimeAuthPath) || this.lastWrittenAuthJson === null) { - return 'rejected' - } - const runtimeContents = readFileSync(runtimeAuthPath, 'utf-8') - if (runtimeContents === this.lastWrittenAuthJson) { - return 'unchanged' - } - // Why: the canonical file is gone, so the exact in-memory bytes Orca - // previously mirrored are the only safe identity baseline for recovery. - if (!codexAuthMatchesManagedAccount(runtimeContents, account, this.lastWrittenAuthJson)) { - return 'rejected' - } - writeFileAtomically(join(account.managedHomePath, 'auth.json'), runtimeContents, { - mode: 0o600 - }) - this.lastWrittenAuthJson = runtimeContents - return 'persisted' - } catch (error) { - console.warn('[codex-runtime-home] Failed to recover missing managed auth:', error) - return 'rejected' - } - } - - // Why: stale panes can overwrite the mirror after provenance is committed, so - // launch ownership needs current-byte identity or Orca's exact same-run write. - private sharedRuntimeAuthBelongsToAccount(account: CodexManagedAccount): boolean { - if (!existsSync(this.getRuntimeAuthPath())) { - return true - } - const runtimeAuth = this.readRuntimeAuthForProvenance() - if (runtimeAuth !== null) { - if (codexAuthMatchesManagedAccount(runtimeAuth, account, null)) { - return true - } - // Why: Orca itself mirrored these exact bytes for this account this run. - if (this.lastSyncedAccountId === account.id && this.lastWrittenAuthJson === runtimeAuth) { - return true - } - } - return false - } - - // Why: the absence may still heal, so keep the selection — but leave no other - // identity's credentials behind for the launch. Logged out beats logged in as - // someone else, and fencing stops later syncs adopting the removed bytes. - private clearRuntimeAuthForUnprovenSelection(): void { - const runtimeAuthPath = this.getRuntimeAuthPath() - try { - // Why: a refresh Codex wrote into the mirror belongs to whoever owns - // those bytes; persist it to that owner's home — managed or ~/.codex — - // first, then fence so later syncs cannot adopt the removed bytes. - const readBackResult = this.readBackRefreshedTokensFromPath(runtimeAuthPath, { - updateLastWrittenAuthJson: false - }) - if (readBackResult === 'rejected') { - this.readBackRefreshedSystemDefaultAuth() - } - this.persistSharedRuntimeAuthProvenance({ owner: 'fenced' }) - } catch (error) { - // Why: rescue and metadata are best-effort; neither may leave another - // identity's credentials in the home returned to the launch. - console.warn('[codex-runtime-home] Failed to rescue or fence unproven runtime auth:', error) - } - this.lastWrittenAuthJson = null - try { - rmSync(runtimeAuthPath, { force: true }) - } catch (error) { - // Why: a fence is Orca metadata that Codex does not read. If Windows or - // another host keeps auth.json locked, failing launch is the safe result. - throw new Error('Cannot safely launch Codex while stale runtime auth remains.', { - cause: error - }) - } - } - - // Why: a token Codex refreshed inside the mirror has no managed home to fall - // back to when the mirror holds the user's own ~/.codex credential, so persist - // it there before the unproven mirror is dropped. - private readBackRefreshedSystemDefaultAuth(): void { - const runtimeAuth = this.readRuntimeAuthForProvenance() - const systemDefaultAuth = this.readSystemDefaultAuth() - if (runtimeAuth === null || systemDefaultAuth === null || runtimeAuth === systemDefaultAuth) { - return - } - const claim = this.resolveSystemDefaultMirrorClaim( - runtimeAuth, - this.resolveSharedRuntimeAuthProvenanceStatus() - ) - if ( - !claim.ownershipProven || - claim.mirroredAuthJson === null || - systemDefaultAuth !== claim.mirroredAuthJson || - !this.runtimeAuthMatchesSystemDefaultIdentity(runtimeAuth, systemDefaultAuth) - ) { - return - } - this.writeSystemDefaultAuth(runtimeAuth) - this.captureSystemDefaultSnapshot({ force: true }) - } - // Why: which ~/.codex bytes the mirror was seeded from, and whether the system // default can be proven to own the mirror at all. private resolveSystemDefaultMirrorClaim( @@ -1399,9 +1162,6 @@ export class CodexRuntimeHomeService { private safeMigrateLegacySharedAuth(): void { const settings = this.store.getSettings() - if (!isCodexSystemDefaultRealHomeEnabled()) { - return - } try { migrateLegacySharedAuthToPerAccountHome({ activeHostAccountId: normalizeCodexRuntimeSelection(settings).host, diff --git a/src/main/codex-accounts/runtime-home-windows-profile-ownership.test.ts b/src/main/codex-accounts/runtime-home-windows-profile-ownership.test.ts index a1a66a847..54ab5d5f0 100644 --- a/src/main/codex-accounts/runtime-home-windows-profile-ownership.test.ts +++ b/src/main/codex-accounts/runtime-home-windows-profile-ownership.test.ts @@ -3,7 +3,6 @@ import type { GlobalSettings } from '../../shared/types' import { CodexRuntimeHomeService } from './runtime-home-service' const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') -const originalRealHomeOverride = process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME const originalCodexHome = process.env.CODEX_HOME const originalOrcaCodexHome = process.env.ORCA_CODEX_HOME @@ -11,7 +10,6 @@ afterEach(() => { if (originalPlatform) { Object.defineProperty(process, 'platform', originalPlatform) } - restoreEnv('ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME', originalRealHomeOverride) restoreEnv('CODEX_HOME', originalCodexHome) restoreEnv('ORCA_CODEX_HOME', originalOrcaCodexHome) }) @@ -19,7 +17,6 @@ afterEach(() => { describe('Windows System Default Codex home ownership', () => { it('stays managed when PowerShell profile state cannot be inspected', () => { Object.defineProperty(process, 'platform', { configurable: true, value: 'win32' }) - process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME = '1' delete process.env.CODEX_HOME delete process.env.ORCA_CODEX_HOME diff --git a/src/main/codex-accounts/service.test.ts b/src/main/codex-accounts/service.test.ts index 175a42e6d..47fd0c678 100644 --- a/src/main/codex-accounts/service.test.ts +++ b/src/main/codex-accounts/service.test.ts @@ -46,33 +46,10 @@ function decodeEncodedWslBashCommand(command: string): string { return encoded ? Buffer.from(encoded, 'base64').toString('utf8') : command } -// Why: the shipped code no longer reads a settings flag — the legacy mirror -// lane is reachable only through the test-rig env override. Route the old -// per-test override key to that env var so lane coverage keeps working. -type TestSettingsOverrides = Partial & { - codexSystemDefaultRealHomeEnabled?: boolean -} - -function setRealHomeLaneForTest(enabled: boolean): void { - process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME = enabled ? '1' : '0' -} - -const initialRealHomeLaneEnv = process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME -afterEach(() => { - if (initialRealHomeLaneEnv === undefined) { - delete process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME - } else { - process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME = initialRealHomeLaneEnv - } -}) - -function createSettings(overrides: TestSettingsOverrides = {}): GlobalSettings { +function createSettings(overrides: Partial = {}): GlobalSettings { const appFontFamily = overrides.appFontFamily ?? 'Geist' const agentStatusHooksEnabled = overrides.agentStatusHooksEnabled ?? true const tabAutoGenerateTitle = overrides.tabAutoGenerateTitle ?? false - // Config-sync/hot-swap tests assert the shared-mirror path; production is - // real-home always, so opt these managed cases out unless a test overrides it. - setRealHomeLaneForTest(overrides.codexSystemDefaultRealHomeEnabled ?? false) return { workspaceDir: testState.fakeHomeDir, nestWorkspaces: false, @@ -430,7 +407,6 @@ describe('CodexAccountService config sync', () => { 'approval_policy = "on-request"\n' ) const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: true, codexManagedAccounts: [ { id: 'account-1', @@ -476,43 +452,6 @@ describe('CodexAccountService config sync', () => { expectSanitizedManagedConfig() }) - it('keeps flag-off config mirroring byte-identical', async () => { - const fixture = await createCanonicalHookTrustFixture() - const canonicalConfigPath = join(testState.fakeHomeDir, '.codex', 'config.toml') - writeFileSync(canonicalConfigPath, fixture.config, 'utf-8') - const managedHomePath = createManagedHome( - testState.userDataDir, - 'account-1', - 'approval_policy = "on-request"\n' - ) - const settings = createSettings({ - codexSystemDefaultRealHomeEnabled: false, - codexManagedAccounts: [ - { - id: 'account-1', - email: 'user@example.com', - managedHomePath, - providerAccountId: null, - workspaceLabel: null, - workspaceAccountId: null, - createdAt: 1, - updatedAt: 1, - lastAuthenticatedAt: 1 - } - ] - }) - - const { CodexAccountService } = await import('./service') - new CodexAccountService( - createStore(settings) as never, - createRateLimits() as never, - createRuntimeHome() as never - ) - - expect(readFileSync(join(managedHomePath, 'config.toml'), 'utf-8')).toBe(fixture.config) - expect(readFileSync(canonicalConfigPath, 'utf-8')).toBe(fixture.config) - }) - it('rewrites relative path config values when syncing into managed homes', async () => { const canonicalConfigPath = join(testState.fakeHomeDir, '.codex', 'config.toml') writeFileSync( @@ -556,7 +495,7 @@ describe('CodexAccountService config sync', () => { expect(managedConfig).toContain('sandbox_mode = "danger-full-access"') }) - it('does not rewrite managed configs that already match canonical config', async () => { + it('does not rewrite a managed config the previous mirror pass already settled', async () => { const canonicalConfigPath = join(testState.fakeHomeDir, '.codex', 'config.toml') const { escapeTomlString } = await import('../codex/config-toml-trust') const userHookKey = `${join(testState.fakeHomeDir, '.codex', 'user-hooks.json')}:stop:0:0` @@ -575,8 +514,6 @@ describe('CodexAccountService config sync', () => { '{"account":"managed"}\n' ) const managedConfigPath = join(managedHomePath, 'config.toml') - const oldDate = new Date('2024-01-01T00:00:00.000Z') - utimesSync(managedConfigPath, oldDate, oldDate) const settings = createSettings({ codexManagedAccounts: [ { @@ -600,6 +537,15 @@ describe('CodexAccountService config sync', () => { const { CodexAccountService } = await import('./service') new CodexAccountService(store as never, rateLimits as never, runtimeHome as never) + // The first pass remaps the user hook-trust entry into this home; once that + // has settled, a later pass must leave the file completely untouched. + const settledConfig = readFileSync(managedConfigPath, 'utf-8') + const oldDate = new Date('2024-01-01T00:00:00.000Z') + utimesSync(managedConfigPath, oldDate, oldDate) + + new CodexAccountService(store as never, rateLimits as never, runtimeHome as never) + + expect(readFileSync(managedConfigPath, 'utf-8')).toBe(settledConfig) expect(statSync(managedConfigPath).mtimeMs).toBeLessThan(Date.now() - 60_000) }) @@ -659,8 +605,7 @@ describe('CodexAccountService config sync', () => { it('re-syncs config when selecting an account', async () => { const canonicalConfigPath = join(testState.fakeHomeDir, '.codex', 'config.toml') - const canonicalConfig = 'approval_policy = "never"\nsandbox_mode = "danger-full-access"\n' - writeFileSync(canonicalConfigPath, canonicalConfig, 'utf-8') + writeFileSync(canonicalConfigPath, 'sandbox_mode = "danger-full-access"\n', 'utf-8') const managedHomePath = createManagedHome( testState.userDataDir, 'account-1', @@ -696,7 +641,11 @@ describe('CodexAccountService config sync', () => { await service.selectAccount('account-1') - expect(readFileSync(join(managedHomePath, 'config.toml'), 'utf-8')).toBe(canonicalConfig) + // Selecting merges canonical settings into the account's own home rather + // than overwriting it, so its local approval_policy survives the re-sync. + expect(readFileSync(join(managedHomePath, 'config.toml'), 'utf-8')).toBe( + 'sandbox_mode = "danger-full-access"\napproval_policy = "untrusted"\n' + ) expect(rateLimits.refreshForCodexAccountChange).toHaveBeenCalledTimes(1) expect(runtimeHome.syncForCurrentSelection).toHaveBeenCalledTimes(1) }) @@ -855,7 +804,7 @@ describe('CodexAccountService config sync', () => { readHookTrustEntries = (await import('../codex/config-toml-trust')).readHookTrustEntries writeFileSync(join(testState.fakeHomeDir, '.codex', 'config.toml'), fixture.config, 'utf-8') - const store = createStore(createSettings({ codexSystemDefaultRealHomeEnabled: true })) + const store = createStore(createSettings()) const rateLimits = createRateLimits() const runtimeHome = createRuntimeHome() const { CodexAccountService } = await import('./service') @@ -1842,7 +1791,7 @@ describe('CodexAccountService config sync', () => { expect(onHostSystemDefaultSelected).toHaveBeenCalledOnce() }) - it('selectAccount immediately rewrites the shared runtime auth for existing terminals', async () => { + it('selectAccount switches managed accounts without routing auth through the shared mirror', async () => { const firstAuth = createCodexAuthJson('one@example.com', 'acct-one', 'one') const secondAuth = createCodexAuthJson('two@example.com', 'acct-two', 'two') const firstManagedHomePath = createManagedHome( @@ -1890,7 +1839,7 @@ describe('CodexAccountService config sync', () => { const { CodexRuntimeHomeService } = await import('./runtime-home-service') const runtimeHome = new CodexRuntimeHomeService(store as never) const runtimeAuthPath = join(testState.userDataDir, 'codex-runtime-home', 'home', 'auth.json') - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(firstAuth) + expect(existsSync(runtimeAuthPath)).toBe(false) const { CodexAccountService } = await import('./service') const service = new CodexAccountService( @@ -1901,7 +1850,11 @@ describe('CodexAccountService config sync', () => { await service.selectAccount('account-2') - expect(readFileSync(runtimeAuthPath, 'utf-8')).toBe(secondAuth) + // Each managed host account launches against its own home, so a switch must + // leave both credential files alone and never copy either into the mirror. + expect(existsSync(runtimeAuthPath)).toBe(false) + expect(readFileSync(join(firstManagedHomePath, 'auth.json'), 'utf-8')).toBe(firstAuth) + expect(readFileSync(join(secondManagedHomePath, 'auth.json'), 'utf-8')).toBe(secondAuth) expect(existsSync(join(testState.userDataDir, 'codex-runtime-home', 'launch'))).toBe(false) expect(existsSync(join(testState.userDataDir, 'codex-runtime-home', 'active'))).toBe(false) }) diff --git a/src/main/codex-accounts/service.ts b/src/main/codex-accounts/service.ts index 3618f1381..b55c9b503 100644 --- a/src/main/codex-accounts/service.ts +++ b/src/main/codex-accounts/service.ts @@ -30,7 +30,6 @@ import type { CodexRuntimeHomeService } from './runtime-home-service' import { writeFileAtomically } from './fs-utils' import { rewriteRelativePathConfigValues } from '../codex/codex-config-path-reference-rewrite' import { stripCodexManagedHookTrustEntriesFromConfig } from '../codex/codex-managed-trust-reconciliation' -import { isCodexSystemDefaultRealHomeEnabled } from '../codex/codex-real-home-flag' import { getCodexManagedHookInstallMaterial } from '../codex/hook-service' import { syncSystemConfigIntoManagedCodexHome } from '../codex/codex-config-mirror' import { getSystemCodexHomePath } from '../codex/codex-home-paths' @@ -1238,9 +1237,9 @@ export class CodexAccountService { } private isSelfContainedHostManagedHome(managedHomePath: string): boolean { - // Why: flag ON makes each host account home its own launch CODEX_HOME. WSL - // homes keep their distro-local seed lane; the flag-OFF opt-out is unchanged. - return isCodexSystemDefaultRealHomeEnabled() && !parseWslUncPath(managedHomePath) + // Why: each host account home is its own launch CODEX_HOME. WSL homes keep + // their distro-local seed lane. + return !parseWslUncPath(managedHomePath) } private syncCanonicalConfigIntoManagedHome( @@ -1270,18 +1269,15 @@ export class CodexAccountService { // account while preserving consistent Codex behavior. Managed homes are // real CODEX_HOMEs for `codex login`, so relative path-valued settings // must keep resolving against the home the config was read from. - let sanitizedConfig = canonicalConfig.contents - if (isCodexSystemDefaultRealHomeEnabled()) { - const material = getCodexManagedHookInstallMaterial() - // Why: source-home Orca trust is foreign to each managed home's hooks.json. - sanitizedConfig = stripCodexManagedHookTrustEntriesFromConfig(canonicalConfig.contents, { - runtimeHomePath: canonicalConfig.sourceHomePath, - sourcePath: canonicalConfig.sourceHooksPath, - command: material.command, - managedEventLabels: new Set(Object.values(material.eventLabel)), - timeoutSec: MANAGED_HOOK_TIMEOUT_SECONDS - }) - } + const material = getCodexManagedHookInstallMaterial() + // Why: source-home Orca trust is foreign to each managed home's hooks.json. + const sanitizedConfig = stripCodexManagedHookTrustEntriesFromConfig(canonicalConfig.contents, { + runtimeHomePath: canonicalConfig.sourceHomePath, + sourcePath: canonicalConfig.sourceHooksPath, + command: material.command, + managedEventLabels: new Set(Object.values(material.eventLabel)), + timeoutSec: MANAGED_HOOK_TIMEOUT_SECONDS + }) this.writeManagedConfig( trustedManagedHomePath, rewriteRelativePathConfigValues(sanitizedConfig, canonicalConfig.sourceHomePath) diff --git a/src/main/codex/codex-real-home-flag.test.ts b/src/main/codex/codex-real-home-flag.test.ts deleted file mode 100644 index 63b6889a7..000000000 --- a/src/main/codex/codex-real-home-flag.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { isCodexSystemDefaultRealHomeEnabled } from './codex-real-home-flag' - -const ENV_FLAG = 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME' -let previousEnvFlag: string | undefined - -beforeEach(() => { - previousEnvFlag = process.env[ENV_FLAG] - delete process.env[ENV_FLAG] -}) - -afterEach(() => { - if (previousEnvFlag === undefined) { - delete process.env[ENV_FLAG] - } else { - process.env[ENV_FLAG] = previousEnvFlag - } -}) - -describe('isCodexSystemDefaultRealHomeEnabled', () => { - it('is unconditionally ON in production (no settings consulted)', () => { - expect(isCodexSystemDefaultRealHomeEnabled()).toBe(true) - }) - - it('lets the test-rig env override force ON explicitly', () => { - for (const raw of ['1', 'true', 'on', 'TRUE', ' On ']) { - process.env[ENV_FLAG] = raw - expect(isCodexSystemDefaultRealHomeEnabled()).toBe(true) - } - }) - - it('lets the test-rig env override pin the legacy managed lane OFF', () => { - for (const raw of ['0', 'false', 'off']) { - process.env[ENV_FLAG] = raw - expect(isCodexSystemDefaultRealHomeEnabled()).toBe(false) - } - }) - - it('ignores an unrecognized env value and stays ON', () => { - process.env[ENV_FLAG] = 'maybe' - expect(isCodexSystemDefaultRealHomeEnabled()).toBe(true) - }) -}) diff --git a/src/main/codex/codex-real-home-flag.ts b/src/main/codex/codex-real-home-flag.ts deleted file mode 100644 index 541dd98ef..000000000 --- a/src/main/codex/codex-real-home-flag.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Routing truth for the SYSTEM-DEFAULT Codex account: it always runs against - * the user's real ~/.codex; managed (multi-account) selections always get - * their own self-contained homes. There is no user-facing setting — the - * feature ships unconditionally. - * - * The env override exists only for test rigs (containment harness, e2e home - * isolation, CDP verification) that must pin the legacy managed-home lane or - * force the real-home lane inside a disposable HOME. It never appears in any - * UI and no production path sets it. - */ -const CODEX_REAL_HOME_ENV_FLAG = 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME' - -export function isCodexSystemDefaultRealHomeEnabled(): boolean { - const envOverride = readCodexRealHomeEnvOverride() - if (envOverride !== null) { - return envOverride - } - return true -} - -function readCodexRealHomeEnvOverride(): boolean | null { - const raw = process.env[CODEX_REAL_HOME_ENV_FLAG] - if (raw === undefined) { - return null - } - const normalized = raw.trim().toLowerCase() - if (normalized === '1' || normalized === 'true' || normalized === 'on') { - return true - } - if (normalized === '0' || normalized === 'false' || normalized === 'off') { - return false - } - return null -} diff --git a/src/main/ipc/pty.ts b/src/main/ipc/pty.ts index 62448ffd5..e4f50a625 100644 --- a/src/main/ipc/pty.ts +++ b/src/main/ipc/pty.ts @@ -198,7 +198,6 @@ import { } from '../codex/codex-pane-account-registry' import { resolveCodexPaneLaunchAccount } from '../codex/codex-pane-launch-account' import { getSystemCodexHomePath } from '../codex/codex-home-paths' -import { isCodexSystemDefaultRealHomeEnabled } from '../codex/codex-real-home-flag' import { environmentCodexHomeOverrideContextsEqual, getCustomCodexHomeOverrideForLaunch, @@ -1117,10 +1116,7 @@ function shouldStripInheritedOrcaCodexHome(args: { settings: GlobalSettings | undefined }): boolean { return ( - args.target.runtime === 'host' && - args.selectedCodexHomePath === null && - !args.skipCodexHomeEnv && - isCodexSystemDefaultRealHomeEnabled() + args.target.runtime === 'host' && args.selectedCodexHomePath === null && !args.skipCodexHomeEnv ) } diff --git a/tests/e2e/electron-home-isolation.spec.ts b/tests/e2e/electron-home-isolation.spec.ts index 79af51146..65aa1b7dc 100644 --- a/tests/e2e/electron-home-isolation.spec.ts +++ b/tests/e2e/electron-home-isolation.spec.ts @@ -14,12 +14,13 @@ async function readElectronHomeState(electronApp: ElectronApplication) { home: process.env.HOME, userProfile: process.env.USERPROFILE, codexHome: process.env.CODEX_HOME, - orcaCodexHome: process.env.ORCA_CODEX_HOME, - realHomeFlag: process.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME + orcaCodexHome: process.env.ORCA_CODEX_HOME } }) } +// Codex always routes to the real home now, so this single case covers both the +// HOME boundary and that real-home routing lands inside the disposable profile. test('isolates Electron and Codex from the developer home by default', async ({ electronApp }) => { const state = await readElectronHomeState(electronApp) const expectedHome = path.join(state.userDataDir!, 'home') @@ -30,17 +31,4 @@ test('isolates Electron and Codex from the developer home by default', async ({ expect(state.userProfile).toBe(expectedHome) expect(state.codexHome).toBeUndefined() expect(state.orcaCodexHome).toBeUndefined() - expect(state.realHomeFlag).toBe('0') -}) - -test.describe('sandboxed real-home routing', () => { - test.use({ codexRealHomeEnabled: true }) - - test('keeps flag-ON routing inside the disposable home', async ({ electronApp }) => { - const state = await readElectronHomeState(electronApp) - - expect(state.appHome).toBe(path.join(state.userDataDir!, 'home')) - expect(state.nodeHome).toBe(path.join(state.userDataDir!, 'home')) - expect(state.realHomeFlag).toBe('1') - }) }) diff --git a/tests/e2e/headless-serve-desktop-activation.spec.ts b/tests/e2e/headless-serve-desktop-activation.spec.ts index e19e0dabf..1d4b4a0f8 100644 --- a/tests/e2e/headless-serve-desktop-activation.spec.ts +++ b/tests/e2e/headless-serve-desktop-activation.spec.ts @@ -53,8 +53,7 @@ function createHeadlessLaunchIsolation(userDataDir: string): ElectronHomeIsolati ORCA_E2E_ENFORCE_SINGLE_INSTANCE_LOCK: '1' }, extraEnv: {}, - userDataDir, - codexRealHomeEnabled: false + userDataDir }) } diff --git a/tests/e2e/helpers/computer-cli-driver.ts b/tests/e2e/helpers/computer-cli-driver.ts index 7e9d8b1a6..a96b55d5f 100644 --- a/tests/e2e/helpers/computer-cli-driver.ts +++ b/tests/e2e/helpers/computer-cli-driver.ts @@ -174,8 +174,7 @@ async function createComputerE2ERuntimeEnv(): Promise { inheritedEnv, launchEnv: {}, extraEnv: {}, - userDataDir, - codexRealHomeEnabled: false + userDataDir }) return { ...isolation.env, diff --git a/tests/e2e/helpers/electron-home-isolation.ts b/tests/e2e/helpers/electron-home-isolation.ts index fd526a36e..e81cbae19 100644 --- a/tests/e2e/helpers/electron-home-isolation.ts +++ b/tests/e2e/helpers/electron-home-isolation.ts @@ -9,7 +9,6 @@ const RESTRICTED_ENV_KEYS = new Set([ 'HOMEPATH', 'CODEX_HOME', 'ORCA_CODEX_HOME', - 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME', 'ORCA_E2E_USER_DATA_DIR', 'ORCA_E2E_HOME_DIR', 'ZDOTDIR', @@ -23,7 +22,6 @@ type ElectronHomeIsolationOptions = { launchEnv: NodeJS.ProcessEnv extraEnv: Record userDataDir: string - codexRealHomeEnabled: boolean realHome?: string } @@ -50,9 +48,7 @@ function assertOverlayDoesNotReplaceIsolation( RESTRICTED_ENV_KEYS.has(key.toUpperCase()) ) if (restrictedKey) { - throw new Error( - `${overlayName}.${restrictedKey} cannot override the E2E home boundary; use codexRealHomeEnabled for sandboxed real-home coverage` - ) + throw new Error(`${overlayName}.${restrictedKey} cannot override the E2E home boundary`) } } @@ -67,7 +63,6 @@ export function createElectronHomeIsolation({ launchEnv, extraEnv, userDataDir, - codexRealHomeEnabled, realHome = os.homedir() }: ElectronHomeIsolationOptions): ElectronHomeIsolation { assertOverlayDoesNotReplaceIsolation(launchEnv, 'launchEnv') @@ -95,8 +90,7 @@ export function createElectronHomeIsolation({ HOME: isolatedHome, USERPROFILE: isolatedHome, ORCA_E2E_USER_DATA_DIR: userDataDir, - ORCA_E2E_HOME_DIR: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: codexRealHomeEnabled ? '1' : '0' + ORCA_E2E_HOME_DIR: isolatedHome } } } diff --git a/tests/e2e/helpers/electron-home-isolation.unit.test.ts b/tests/e2e/helpers/electron-home-isolation.unit.test.ts index ab1ed9901..b84770bcd 100644 --- a/tests/e2e/helpers/electron-home-isolation.unit.test.ts +++ b/tests/e2e/helpers/electron-home-isolation.unit.test.ts @@ -37,7 +37,6 @@ describe('createElectronHomeIsolation', () => { launchEnv: { TEST_TOKEN: 'safe' }, extraEnv: { EXTRA_TEST_FLAG: '1' }, userDataDir, - codexRealHomeEnabled: false, realHome: '/real/home' }) @@ -51,12 +50,16 @@ describe('createElectronHomeIsolation', () => { EXTRA_TEST_FLAG: '1', HOME: canonicalHome, USERPROFILE: canonicalHome, - ORCA_E2E_USER_DATA_DIR: userDataDir, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0' + ORCA_E2E_USER_DATA_DIR: userDataDir }) expect(isolation.env.CODEX_HOME).toBeUndefined() expect(isolation.env.ORCA_CODEX_HOME).toBeUndefined() expect(isolation.env.ZDOTDIR).toBeUndefined() + // Codex always routes to the resolved home, so the post-launch guard must + // accept the boundary this env produces. + expect(() => + assertElectronResolvedIsolatedHome(isolation.isolatedHome, isolation) + ).not.toThrow() }) it('rejects generic fixture overlays that could escape the boundary', () => { @@ -66,7 +69,6 @@ describe('createElectronHomeIsolation', () => { launchEnv: { CODEX_HOME: '/unsafe' }, extraEnv: {}, userDataDir: createUserDataDir(), - codexRealHomeEnabled: false, realHome: '/real/home' }) ).toThrow(/launchEnv\.CODEX_HOME/) @@ -77,28 +79,11 @@ describe('createElectronHomeIsolation', () => { launchEnv: {}, extraEnv: { ORCA_E2E_USER_DATA_DIR: '/unsafe' }, userDataDir: createUserDataDir(), - codexRealHomeEnabled: false, realHome: '/real/home' }) ).toThrow(/orcaAppExtraEnv\.ORCA_E2E_USER_DATA_DIR/) }) - it('keeps real-home routing inside the disposable home when explicitly enabled', () => { - const isolation = createElectronHomeIsolation({ - inheritedEnv: {}, - launchEnv: {}, - extraEnv: {}, - userDataDir: createUserDataDir(), - codexRealHomeEnabled: true, - realHome: '/real/home' - }) - - expect(isolation.env.ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME).toBe('1') - expect(() => - assertElectronResolvedIsolatedHome(isolation.isolatedHome, isolation) - ).not.toThrow() - }) - it('compares Windows home paths case-insensitively', () => { expect(areSameHomePath('C:\\Users\\Alice', 'c:\\users\\alice', 'win32')).toBe(true) }) diff --git a/tests/e2e/helpers/headless-paired-runtime-host.ts b/tests/e2e/helpers/headless-paired-runtime-host.ts index 9159154b2..dec596829 100644 --- a/tests/e2e/helpers/headless-paired-runtime-host.ts +++ b/tests/e2e/helpers/headless-paired-runtime-host.ts @@ -201,8 +201,7 @@ export async function launchHeadlessPairedRuntimeHost(): Promise({ launchEnv, orcaAppExtraEnv, orcaAppExtraArgs, - codexRealHomeEnabled, registerPostElectronShutdownCleanup }, provideFixture, @@ -212,8 +208,7 @@ export const test = base.extend({ inheritedEnv: cleanEnv, launchEnv, extraEnv: orcaAppExtraEnv, - userDataDir, - codexRealHomeEnabled + userDataDir }) // Why: ORCA_E2E_SLOWMO_MS adds a pause between every Playwright action so a // developer running with ORCA_E2E_FORCE_HEADFUL=1 can actually watch what @@ -281,7 +276,6 @@ export const test = base.extend({ launchEnv: [{}, { option: true }], orcaAppExtraEnv: [{}, { option: true }], orcaAppExtraArgs: [[], { option: true }], - codexRealHomeEnabled: [false, { option: true }], // Test-scoped: grab the first BrowserWindow, add the test repo, and wait // until the session is fully ready with a worktree active. diff --git a/tests/e2e/helpers/orca-restart.ts b/tests/e2e/helpers/orca-restart.ts index 609ff1797..c7a93f814 100644 --- a/tests/e2e/helpers/orca-restart.ts +++ b/tests/e2e/helpers/orca-restart.ts @@ -120,8 +120,7 @@ function createRestartLaunchIsolation( ...(headful ? { ORCA_E2E_HEADFUL: '1' } : { ORCA_E2E_HEADLESS: '1' }) }, extraEnv: {}, - userDataDir, - codexRealHomeEnabled: false + userDataDir }) } diff --git a/tests/e2e/helpers/paired-electron-client.ts b/tests/e2e/helpers/paired-electron-client.ts index c33764a24..07bb46778 100644 --- a/tests/e2e/helpers/paired-electron-client.ts +++ b/tests/e2e/helpers/paired-electron-client.ts @@ -155,8 +155,7 @@ export async function launchPairedElectronClient( inheritedEnv: cleanEnv, launchEnv: {}, extraEnv: {}, - userDataDir, - codexRealHomeEnabled: false + userDataDir }) const mainPath = path.join(process.cwd(), 'out', 'main', 'index.js') const app = await electron.launch({ diff --git a/tests/tools/benchmarks/daemon-coldstart-bench.mjs b/tests/tools/benchmarks/daemon-coldstart-bench.mjs index eebc02a3d..5e234d8b6 100644 --- a/tests/tools/benchmarks/daemon-coldstart-bench.mjs +++ b/tests/tools/benchmarks/daemon-coldstart-bench.mjs @@ -177,7 +177,6 @@ function runIteration({ exe, fixtureDir, timeoutMs, lingerMs }) { HOME: isolatedHome, USERPROFILE: isolatedHome, ORCA_E2E_HOME_DIR: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0', ORCA_E2E_HEADLESS: '1' } delete env.CODEX_HOME diff --git a/tests/tools/benchmarks/main-thread-jank-bench.mjs b/tests/tools/benchmarks/main-thread-jank-bench.mjs index 914c72a67..a64eecaf9 100644 --- a/tests/tools/benchmarks/main-thread-jank-bench.mjs +++ b/tests/tools/benchmarks/main-thread-jank-bench.mjs @@ -289,8 +289,7 @@ async function main() { ORCA_E2E_USER_DATA_DIR: fixtureDir, HOME: isolatedHome, USERPROFILE: isolatedHome, - ORCA_E2E_HOME_DIR: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0' + ORCA_E2E_HOME_DIR: isolatedHome } delete env.CODEX_HOME delete env.ORCA_CODEX_HOME diff --git a/tests/tools/benchmarks/startup-time-bench.mjs b/tests/tools/benchmarks/startup-time-bench.mjs index 3e64ee4a8..29363432c 100644 --- a/tests/tools/benchmarks/startup-time-bench.mjs +++ b/tests/tools/benchmarks/startup-time-bench.mjs @@ -364,7 +364,6 @@ function buildLaunchEnvironment({ fixtureDir, githubRepos, ghShimDir }) { HOME: isolatedHome, USERPROFILE: isolatedHome, ORCA_E2E_HOME_DIR: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0', ORCA_E2E_HEADLESS: '1' } delete env.CODEX_HOME diff --git a/tests/tools/win-update-e2e/app-driver.mjs b/tests/tools/win-update-e2e/app-driver.mjs index 72603fba9..d95e7f2c3 100644 --- a/tests/tools/win-update-e2e/app-driver.mjs +++ b/tests/tools/win-update-e2e/app-driver.mjs @@ -35,7 +35,6 @@ const RESTRICTED_E2E_ENV_KEYS = new Set([ 'USERPROFILE', 'CODEX_HOME', 'ORCA_CODEX_HOME', - 'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME', 'ORCA_E2E_HOME_DIR', 'ORCA_E2E_USER_DATA_DIR' ]) @@ -92,8 +91,7 @@ export async function launchInstalledApp({ ORCA_E2E_USER_DATA_DIR: userDataDir, HOME: isolatedHome, USERPROFILE: isolatedHome, - ORCA_E2E_HOME_DIR: isolatedHome, - ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME: '0' + ORCA_E2E_HOME_DIR: isolatedHome } }) // If firstWindow times out (the launched main never shows a window), the