mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test(codex): pin trust hash replacement during Windows upgrade
This commit is contained in:
@@ -707,10 +707,7 @@ describe('wrapWindowsHookCommand', () => {
|
||||
|
||||
describe('wrapWindowsCmdHookCommand', () => {
|
||||
it('returns the bare, directly-spawnable path for a cmd-safe managed script', () => {
|
||||
// Why: Codex/Antigravity/Devin launch the command as a program (argv[0]),
|
||||
// not via cmd.exe, so the launcher must be a single spawnable token — a bare
|
||||
// .cmd path. A cmd-builtin `if …` launcher has argv[0] = `if`, which is
|
||||
// unspawnable and fails every hook with exit 1 (#8430 regression).
|
||||
// Direct-spawn consumers need a launchable argv[0], not a cmd builtin such as `if`.
|
||||
const scriptPath = 'C:\\Users\\alice\\.orca\\agent-hooks\\codex-hook.cmd'
|
||||
const command = wrapWindowsCmdHookCommand(scriptPath)
|
||||
expect(command).toBe(scriptPath)
|
||||
@@ -721,12 +718,7 @@ describe('wrapWindowsCmdHookCommand', () => {
|
||||
it.skipIf(process.platform !== 'win32')(
|
||||
'resolves the launcher to a real executable file, not a shell fragment',
|
||||
() => {
|
||||
// Regression guard for #8430: Codex/Antigravity/Devin spawn the launcher as
|
||||
// a program (argv[0]), so it must be an existing, launchable file. The broken
|
||||
// `if exist … (call …)` form had argv[0] = `if` — a cmd builtin, not a file —
|
||||
// which is unspawnable and failed every hook. The bare path is the file.
|
||||
// win32-only: the real temp path is cmd-safe only with backslashes; a POSIX
|
||||
// tmpDir has `/`, which routes to the encoded fallback by design.
|
||||
// POSIX temp paths contain `/`, which selects the encoded fallback instead.
|
||||
const scriptPath = join(tmpDir, 'codex-hook.cmd')
|
||||
writeFileSync(scriptPath, '@echo off\r\nexit /b 0\r\n', 'utf-8')
|
||||
const command = wrapWindowsCmdHookCommand(scriptPath)
|
||||
|
||||
@@ -74,7 +74,7 @@ export function getManagedCommand(scriptPath: string): string {
|
||||
if (process.platform !== 'win32') {
|
||||
return wrapPosixHookCommand(scriptPath)
|
||||
}
|
||||
// Codex already hosts Windows hooks in PowerShell; a second interpreter only adds startup cost.
|
||||
// Codex's default native Windows hook host is PowerShell; reuse it to avoid a second interpreter.
|
||||
return WINDOWS_CMD_SAFE_PATH.test(scriptPath)
|
||||
? scriptPath
|
||||
: buildWindowsHookPowerShellCommand(scriptPath)
|
||||
|
||||
@@ -17,7 +17,11 @@ vi.mock('os', async (importOriginal) => ({
|
||||
import { CodexHookService } from './hook-service'
|
||||
import { CODEX_EVENTS, CODEX_EVENT_LABEL, getManagedCommand } from './codex-hook-definition'
|
||||
import { readHooksJson, wrapWindowsHookCommand } from '../agent-hooks/installer-utils'
|
||||
import { getCodexExplicitHomeHookSourcePath, upsertHookTrustEntries } from './config-toml-trust'
|
||||
import {
|
||||
computeTrustedHash,
|
||||
getCodexExplicitHomeHookSourcePath,
|
||||
upsertHookTrustEntries
|
||||
} from './config-toml-trust'
|
||||
|
||||
const homes = setupCodexHookHomes(homedirMock, getPathMock)
|
||||
|
||||
@@ -57,27 +61,36 @@ describe.skipIf(process.platform !== 'win32')('Unicode Windows hook upgrade', ()
|
||||
groupIndex: 0,
|
||||
handlerIndex: 0,
|
||||
command: oldCommand,
|
||||
timeout: 10
|
||||
timeoutSec: 10
|
||||
}))
|
||||
)
|
||||
const oldTrust = readFileSync(tomlPath, 'utf8')
|
||||
const service = new CodexHookService()
|
||||
expect(service.getStatus().state).not.toBe('installed')
|
||||
for (let pass = 0; pass < 2; pass++) {
|
||||
expect((await service.install()).state).toBe('installed')
|
||||
expect(service.getStatus().state).toBe('installed')
|
||||
const hooks = readHooksJson(configPath)?.hooks
|
||||
const trust = readFileSync(tomlPath, 'utf8')
|
||||
for (const event of CODEX_EVENTS) {
|
||||
const commands = hooks?.[event]?.flatMap((group) => group.hooks ?? []) ?? []
|
||||
expect(
|
||||
commands.filter((hook) => hook.command === getManagedCommand(scriptPath))
|
||||
).toHaveLength(1)
|
||||
expect(commands.some((hook) => hook.command === oldCommand)).toBe(false)
|
||||
const entry = {
|
||||
sourcePath: getCodexExplicitHomeHookSourcePath(configPath),
|
||||
eventLabel: CODEX_EVENT_LABEL[event],
|
||||
groupIndex: 0,
|
||||
handlerIndex: 0,
|
||||
command: getManagedCommand(scriptPath),
|
||||
timeoutSec: 10
|
||||
}
|
||||
expect(trust).toContain(computeTrustedHash(entry))
|
||||
expect(trust).not.toContain(computeTrustedHash({ ...entry, command: oldCommand }))
|
||||
}
|
||||
expect(
|
||||
hooks?.Stop?.some((group) => group.hooks?.some((hook) => hook.command === 'user-hook'))
|
||||
).toBe(true)
|
||||
expect(readFileSync(tomlPath, 'utf8')).not.toBe(oldTrust)
|
||||
expect(readFileSync(join(userHome, 'hooks.json'), 'utf8')).toBe(userConfig)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user