test(codex): cover realistic account-home migration

This commit is contained in:
Brennan Benson
2026-07-17 14:34:53 -07:00
parent 3a40e8b88a
commit bf5cb6477d
@@ -21,6 +21,7 @@ beforeEach(() => {
for (const key of [
'ORCA_USER_DATA_PATH',
'ORCA_CODEX_SYSTEM_DEFAULT_REAL_HOME',
'ORCA_DISABLE_CODEX_TRUST_RPC',
'CODEX_HOME',
'ORCA_CODEX_HOME'
]) {
@@ -28,6 +29,7 @@ beforeEach(() => {
delete process.env[key]
}
process.env.ORCA_USER_DATA_PATH = testState.userData
process.env.ORCA_DISABLE_CODEX_TRUST_RPC = '1'
mkdirSync(systemHome(), { recursive: true })
mkdirSync(sharedHome(), { recursive: true })
})
@@ -45,6 +47,79 @@ afterEach(() => {
})
describe('CodexRuntimeHomeService per-account takeover composition', () => {
it('upgrades a realistic two-account shared-home fixture without losing auth or sessions', async () => {
const accountOneStale = createAuth('one@example.com', 'acct-1', 'one-stale', 1_000)
const accountOneMigrated = createAuth('one@example.com', 'acct-1', 'one-migrated', 2_000)
const accountTwoAuth = createAuth('two@example.com', 'acct-2', 'two-current', 3_000)
const accountOne = createManagedAccount('account-1', 'acct-1', accountOneStale)
const accountTwo = createManagedAccount(
'account-2',
'acct-2',
accountTwoAuth,
'two@example.com'
)
const sharedSession = join(sharedHome(), 'sessions', '2026', '07', 'rollout.jsonl')
mkdirSync(join(systemHome(), 'skills', 'fixture-skill'), { recursive: true })
mkdirSync(join(systemHome(), 'hooks'), { recursive: true })
mkdirSync(join(sharedHome(), 'sessions', '2026', '07'), { recursive: true })
writeFileSync(join(systemHome(), 'skills', 'fixture-skill', 'SKILL.md'), 'fixture skill\n')
writeFileSync(join(systemHome(), 'hooks', 'user-hook.sh'), '#!/bin/sh\n')
writeFileSync(
join(systemHome(), 'config.toml'),
'model = "fixture-model"\n\n[hooks.state."stale-fixture"]\nenabled = true\n'
)
writeFileSync(sharedSession, '{"session":"legacy-shared"}\n')
writeFileSync(sharedAuthPath(), accountOneMigrated)
const { settings, store } = createStore([accountOne, accountTwo], accountOne.id)
const { CodexRuntimeHomeService } = await import('./runtime-home-service')
const { CodexHookService } = await import('../codex/hook-service')
const service = new CodexRuntimeHomeService(store as never)
const hookService = new CodexHookService()
expect(readFileSync(join(accountOne.managedHomePath, 'auth.json'), 'utf8')).toBe(
accountOneMigrated
)
expect(readFileSync(join(accountTwo.managedHomePath, 'auth.json'), 'utf8')).toBe(accountTwoAuth)
for (const account of [accountOne, accountTwo]) {
selectManagedAccount(settings, account.id)
service.syncForCurrentSelection()
expect(service.prepareForCodexLaunch()).toBe(account.managedHomePath)
expect(
readFileSync(join(account.managedHomePath, 'skills', 'fixture-skill', 'SKILL.md'), 'utf8')
).toBe('fixture skill\n')
expect(readFileSync(join(account.managedHomePath, 'hooks', 'user-hook.sh'), 'utf8')).toBe(
'#!/bin/sh\n'
)
const config = readFileSync(join(account.managedHomePath, 'config.toml'), 'utf8')
expect(config).toContain('model = "fixture-model"')
expect(config).not.toContain('[hooks.state')
expect(hookService.install(account.managedHomePath).state).toBe('installed')
expect(readFileSync(join(account.managedHomePath, 'hooks.json'), 'utf8')).toContain(
'codex-hook.sh'
)
expect(readFileSync(join(account.managedHomePath, 'config.toml'), 'utf8')).toContain(
'[hooks.state."'
)
}
const discoveryHomes = service.getHostCodexHomePathsForSessionDiscovery()
expect(discoveryHomes).toEqual(
expect.arrayContaining([
sharedHome(),
systemHome(),
accountOne.managedHomePath,
accountTwo.managedHomePath
])
)
expect(new Set(discoveryHomes).size).toBe(discoveryHomes.length)
expect(readFileSync(sharedSession, 'utf8')).toBe('{"session":"legacy-shared"}\n')
writeFileSync(sharedAuthPath(), createAuth('two@example.com', 'acct-2', 'later-shared', 4_000))
expect(service.prepareForCodexLaunch()).toBe(accountTwo.managedHomePath)
expect(readFileSync(join(accountTwo.managedHomePath, 'auth.json'), 'utf8')).toBe(accountTwoAuth)
})
it('migrates the one proven C-era refresh, launches E home, then ignores shared auth', async () => {
const stale = createAuth('one@example.com', 'acct-1', 'stale', 1_000)
const migrated = createAuth('one@example.com', 'acct-1', 'migrated', 2_000)
@@ -146,22 +221,28 @@ function createStore(accounts: CodexManagedAccount[], activeId: string | null) {
}
}
function createManagedAccount(id: string, providerId: string, auth: string): CodexManagedAccount {
function createManagedAccount(
id: string,
providerId: string,
auth: string,
email = 'one@example.com'
): CodexManagedAccount {
const home = join(testState.userData, 'codex-accounts', id, 'home')
mkdirSync(home, { recursive: true })
writeFileSync(join(home, '.orca-managed-home'), `${id}\n`, 'utf-8')
writeFileSync(join(home, 'auth.json'), auth, 'utf-8')
return managedAccountRecord(id, providerId, home)
return managedAccountRecord(id, providerId, home, email)
}
function managedAccountRecord(
id: string,
providerAccountId: string,
managedHomePath: string
managedHomePath: string,
email = 'one@example.com'
): CodexManagedAccount {
return {
id,
email: 'one@example.com',
email,
managedHomePath,
providerAccountId,
workspaceLabel: null,
@@ -172,6 +253,11 @@ function managedAccountRecord(
}
}
function selectManagedAccount(settings: GlobalSettings, accountId: string): void {
settings.activeCodexManagedAccountId = accountId
settings.activeCodexManagedAccountIdsByRuntime = { host: accountId, wsl: {} }
}
function systemHome(): string {
return join(testState.home, '.codex')
}