Files
orca/config/scripts/test-runtime/environment/vitest-real-agent-cli-guard.ts
Neil c85d633837 test: fail unit tests that run a real agent CLI from PATH (#38961)
* test: stop unit tests from running the developer's real agent CLIs

A live relay test reached the host's real `claude --version` through the
inherited PATH. On a machine whose claude wrapper never exits, each run left
an orphaned loop behind (14 were found on one host, running for days).

- Add a unit-test setup guard that shadows agent CLI names on PATH with
  stand-ins that fail the test which ran them.
- Give the live relay test its own claude/codex stubs.
- Kill the whole process tree when the WSL guest's version probe times out.

* test: keep structured-session tests off the real codex CLI

These hosts get a scripted transport, but the at-rest `/` command read
spawns the resolved codex command directly, so on a machine with codex
installed each run started a real `codex app-server`. Point them at a
missing binary, as on CI.

* test: isolate agent discovery in session fixtures
2026-11-06 12:56:01 -08:00

104 lines
3.0 KiB
TypeScript

import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { delimiter, join } from 'node:path'
import { afterAll, afterEach } from 'vitest'
// Why: a test that inherits PATH can launch the developer's real agent CLI. A wrapper that never
// exits there (e.g. a version-manager shim that re-resolves itself) outlives the worker as an
// orphan loop, so stand-ins shadow those names and fail the test that reached them.
const AGENT_CLI_NAMES = [
'amp',
'auggie',
'claude',
'codex',
'copilot',
'crush',
'cursor-agent',
'droid',
'gemini',
'goose',
'grok',
'kimi',
'omp',
'opencode',
'pi',
'qwen'
]
// Real-agent opt-in suites intentionally run the installed CLIs.
const REAL_AGENT_CLI_SWITCHES = [
'ORCA_REAL_CLAUDE_CLI_TEST',
'ORCA_REAL_CLAUDE_SUPERVISED_STOP',
'ORCA_CODEX_CONTRACT_BINARY',
'ORCA_CODEX_NO_DAEMON_CONTRACT_BINARY',
'ORCA_CODEX_TRUST_CONTRACT_BINARY',
'ORCA_REPRO_CODEX_BINARY'
]
type GuardState = { dir: string; log: string }
function quoteSh(value: string): string {
return `'${value.replaceAll("'", `'\\''`)}'`
}
function install(): GuardState | null {
if (process.platform === 'win32' || REAL_AGENT_CLI_SWITCHES.some((name) => process.env[name])) {
return null
}
const dir = mkdtempSync(join(tmpdir(), 'orca-agent-cli-guard-'))
const log = join(dir, 'calls.log')
writeFileSync(log, '')
const script = [
'#!/bin/sh',
// Discovery is expected in daemon tests; report the CLI as unavailable.
'if [ "$#" -eq 1 ] && [ "$1" = "--version" ]; then exit 127; fi',
`printf '%s %s\\n' "\${0##*/}" "$*" >> ${quoteSh(log)}`,
`echo "[vitest real-agent-cli guard] blocked real \${0##*/}; give the test its own stub on PATH" >&2`,
'exit 127',
''
].join('\n')
for (const name of AGENT_CLI_NAMES) {
const path = join(dir, name)
writeFileSync(path, script)
chmodSync(path, 0o755)
}
process.env.PATH = process.env.PATH ? `${dir}${delimiter}${process.env.PATH}` : dir
process.once('exit', () => rmSync(dir, { recursive: true, force: true }))
return { dir, log }
}
declare global {
// Install once per process; per-file installs would stack PATH entries.
var orcaRealAgentCliGuard: GuardState | null | undefined
}
if (globalThis.orcaRealAgentCliGuard === undefined) {
globalThis.orcaRealAgentCliGuard = install()
}
const state = globalThis.orcaRealAgentCliGuard
/** Drains recorded calls; only the guard's own self-test should need this. */
export function takeRealAgentCliCalls(): string[] {
if (!state) {
return []
}
let text = ''
try {
text = readFileSync(state.log, 'utf8')
writeFileSync(state.log, '')
} catch {
return []
}
return text.split('\n').filter(Boolean)
}
function failOnCalls(): void {
const calls = takeRealAgentCliCalls()
if (calls.length > 0) {
throw new Error(
`[vitest real-agent-cli guard] test ran an agent CLI from the inherited PATH:\n${calls.join('\n')}`
)
}
}
afterEach(failOnCalls)
afterAll(failOnCalls)