mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 16:03:26 +00:00
fix(codex): make Windows trust upgrade transactional
This commit is contained in:
@@ -4,6 +4,7 @@ import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import type { CodexManagedAccount, GlobalSettings } from '../../shared/types'
|
||||
import type * as NodeOs from 'node:os'
|
||||
import { readHookTrustEntries } from '../codex/config-toml-trust'
|
||||
|
||||
const testState = { userData: '', home: '' }
|
||||
const previousEnv: Record<string, string | undefined> = {}
|
||||
@@ -98,9 +99,9 @@ describe('CodexRuntimeHomeService per-account takeover composition', () => {
|
||||
expect(readFileSync(join(account.managedHomePath, 'hooks.json'), 'utf8')).toContain(
|
||||
process.platform === 'win32' ? 'codex-hook.cmd' : 'codex-hook.sh'
|
||||
)
|
||||
expect(readFileSync(join(account.managedHomePath, 'config.toml'), 'utf8')).toContain(
|
||||
'[hooks.state."'
|
||||
)
|
||||
expect(
|
||||
readHookTrustEntries(join(account.managedHomePath, 'config.toml')).size
|
||||
).toBeGreaterThan(0)
|
||||
}
|
||||
|
||||
const discoveryHomes = service.getHostCodexHomePathsForSessionDiscovery()
|
||||
|
||||
@@ -19,7 +19,9 @@ import {
|
||||
import { readCodexTrustGrantLedgerHome } from './codex-trust-grant-ledger'
|
||||
import {
|
||||
computeTrustKey,
|
||||
computeTrustedHash,
|
||||
normalizeHookTrustKeyForLookup,
|
||||
readHookTrustEntries,
|
||||
upsertHookTrustEntries,
|
||||
type CodexTrustEntry
|
||||
} from './config-toml-trust'
|
||||
@@ -133,6 +135,26 @@ describe('grantManagedCodexHookTrust', () => {
|
||||
expect(invocation.envToDelete).toContain('CODEX_HOME')
|
||||
})
|
||||
|
||||
it('removes equivalent Windows fallback keys before the RPC writes canonical trust', () => {
|
||||
const entry: CodexTrustEntry = {
|
||||
...managedEntry('stop'),
|
||||
sourcePath: String.raw`C:\Users\Alice\.codex\hooks.json`
|
||||
}
|
||||
const plan = buildPlan([entry])
|
||||
upsertHookTrustEntries(plan.tomlPath, [entry])
|
||||
expect(readHookTrustEntries(plan.tomlPath).get(computeTrustKey(entry))?.trustedHash).toBe(
|
||||
computeTrustedHash(entry)
|
||||
)
|
||||
const runner = vi.fn(() => {
|
||||
expect(readHookTrustEntries(plan.tomlPath).has(computeTrustKey(entry))).toBe(false)
|
||||
return grantedSessionResult([entry])
|
||||
})
|
||||
_internals.setGrantSessionRunnerSync(runner)
|
||||
|
||||
expect(grantManagedCodexHookTrust(plan)).toMatchObject({ lane: 'rpc' })
|
||||
expect(runner).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('skips the RPC session while the ledger grant still holds, and re-grants on config drift', () => {
|
||||
const entries = [managedEntry('session_start')]
|
||||
const runner = vi.fn(() => grantedSessionResult(entries))
|
||||
|
||||
@@ -15,8 +15,10 @@ import {
|
||||
} from './codex-trust-grant-ledger'
|
||||
import {
|
||||
computeTrustKey,
|
||||
computeTrustedHash,
|
||||
normalizeHookTrustKeyForLookup,
|
||||
readHookTrustEntries,
|
||||
removeHookTrustEntries,
|
||||
type CodexTrustEntry
|
||||
} from './config-toml-trust'
|
||||
import { getCodexHookTrustSignature } from './codex-hook-identity'
|
||||
@@ -149,6 +151,19 @@ function buildExpectedEntries(plan: CodexManagedTrustGrantPlan): ExpectedManaged
|
||||
}))
|
||||
}
|
||||
|
||||
function removeSelfComputedTrustBeforeGrant(plan: CodexManagedTrustGrantPlan): void {
|
||||
const trustStates = readHookTrustEntries(plan.tomlPath)
|
||||
const ownedKeys = plan.managedEntries
|
||||
.map((entry) => {
|
||||
const key = computeTrustKey(entry)
|
||||
return trustStates.get(key)?.trustedHash === computeTrustedHash(entry) ? key : null
|
||||
})
|
||||
.filter((key): key is string => key !== null)
|
||||
if (ownedKeys.length > 0) {
|
||||
removeHookTrustEntries(plan.tomlPath, ownedKeys)
|
||||
}
|
||||
}
|
||||
|
||||
function findLedgerGrant(
|
||||
plan: CodexManagedTrustGrantPlan,
|
||||
expected: ExpectedManagedEntry[],
|
||||
@@ -224,6 +239,9 @@ export function grantManagedCodexHookTrust(
|
||||
const configSnapshot = captureCodexTrustConfig(plan.tomlPath)
|
||||
let result: CodexHookTrustGrantSessionResult
|
||||
try {
|
||||
// Why: Windows fallback writes equivalent separator variants that Codex's
|
||||
// canonical RPC key may not overwrite, leaving conflicting logical trust.
|
||||
removeSelfComputedTrustBeforeGrant(plan)
|
||||
result = runSessionSync(
|
||||
resolvedHost.buildRequest({
|
||||
runtimeHomePath: plan.runtimeHomePath,
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
computeTrustKey,
|
||||
computeTrustedHash,
|
||||
escapeTomlString,
|
||||
normalizeHookTrustKeyForLookup,
|
||||
parseTrustKey,
|
||||
readHookTrustEntries,
|
||||
upsertHookTrustEntries,
|
||||
@@ -214,7 +215,7 @@ describe('CodexHookService app-server trust grant lane', () => {
|
||||
writeCodexTrustGrantLedgerHome(systemHome, {
|
||||
binary: null,
|
||||
entries: {
|
||||
[trustKey]: {
|
||||
[normalizeHookTrustKeyForLookup(trustKey)]: {
|
||||
signature: getCodexHookTrustSignature(entry),
|
||||
trustedHash
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user