diff --git a/tests/claude-integration/claude-intercept-local-ca-files.test.ts b/tests/claude-integration/claude-intercept-local-ca-files.test.ts index 5c3c99c8ab5..44b5f10c696 100644 --- a/tests/claude-integration/claude-intercept-local-ca-files.test.ts +++ b/tests/claude-integration/claude-intercept-local-ca-files.test.ts @@ -6,6 +6,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { claudeInterceptCaCertPath, claudeInterceptStateDir, ensureLocalInterceptCa } from "../../src/claude/intercept/local-ca"; import { setLocalCaFileHooksForTests } from "../../src/claude/intercept/local-ca-files"; +import { hardenSecretDir } from "../../src/lib/windows-secret-acl"; const roots: string[] = []; function fixture(): string { @@ -87,6 +88,7 @@ test("local CA ignores predictable predecessor temp names and leaves external fi const root = fixture(); const dir = claudeInterceptStateDir(root); mkdirSync(dir, { mode: 0o700 }); + hardenSecretDir(dir, { required: true }); const oldTemp = join(dir, `ca.key.${process.pid}.tmp`); writeFileSync(oldTemp, "reserved predecessor", { mode: 0o600 }); const ca = ensureLocalInterceptCa(root); diff --git a/tests/codex-integration/codex-affinity-debug.test.ts b/tests/codex-integration/codex-affinity-debug.test.ts index d2c25c536ce..d4febf690e3 100644 --- a/tests/codex-integration/codex-affinity-debug.test.ts +++ b/tests/codex-integration/codex-affinity-debug.test.ts @@ -13,12 +13,20 @@ function diagnosticPayload(): Record { return JSON.parse(line.slice(prefix.length)) as Record; } +let savedDebug: string | undefined; +let savedFramesDebug: string | undefined; beforeEach(() => { + savedDebug = process.env.OCX_DEBUG; + savedFramesDebug = process.env.OCX_DEBUG_FRAMES; + delete process.env.OCX_DEBUG; + delete process.env.OCX_DEBUG_FRAMES; resetDebugSettingsForTests(); resetDebugLogBufferForTests(); }); afterEach(() => { + if (savedDebug === undefined) delete process.env.OCX_DEBUG; else process.env.OCX_DEBUG = savedDebug; + if (savedFramesDebug === undefined) delete process.env.OCX_DEBUG_FRAMES; else process.env.OCX_DEBUG_FRAMES = savedFramesDebug; resetDebugSettingsForTests(); resetDebugLogBufferForTests(); }); diff --git a/tests/codex-integration/codex-app-server-processes.test.ts b/tests/codex-integration/codex-app-server-processes.test.ts index e36f91c22e0..ffc8dd87f02 100644 --- a/tests/codex-integration/codex-app-server-processes.test.ts +++ b/tests/codex-integration/codex-app-server-processes.test.ts @@ -1,8 +1,8 @@ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "bun:test"; -import { spawn } from "node:child_process"; +import { execFileSync, spawn } from "node:child_process"; import { readFileSync } from "node:fs"; import { join } from "node:path"; -import { setTrustedWindowsElevationExecutablesForTests } from "../../src/lib/windows-elevation"; +import { resolveTrustedWindowsPowerShellExe, setTrustedWindowsElevationExecutablesForTests } from "../../src/lib/windows-elevation"; import { createWindowsPowerShellFixture, probeWindowsPowerShellFixture, @@ -956,39 +956,45 @@ describe("Windows Win32_Process owner enumeration (#476)", () => { () => { // Keep a live process whose CommandLine contains a Codex basename token. const child = spawn( - "powershell.exe", + resolveTrustedWindowsPowerShellExe(), [ "-NoProfile", "-NoLogo", "-NonInteractive", "-Command", - "Start-Sleep -Seconds 45 # codex app-server integration-probe", + "Start-Sleep -Seconds 90 # codex app-server integration-probe", ], { stdio: "ignore", windowsHide: true }, ); try { expect(child.pid).toBeGreaterThan(1); - // Brief settle so Win32_Process can observe the child. A loaded Windows - // runner can also exhaust one CIM enumeration deadline, so tolerate one - // transient empty result OR one thrown deadline (ETIMEDOUT propagates by - // design) while keeping the production timeout unchanged. - Bun.sleepSync(250); - const enumerate = (): ReturnType | undefined => { - try { - return listWindowsSnapshots(); - } catch { - return undefined; // transient CIM deadline on a contended runner - } - }; - let snapshots = enumerate() ?? []; + // This verifies native enumeration, not the product's 8s latency bound. + // Limit the native query to this fixture; host job count must not set its cost. + // Keep the trusted executable, owner/candidate checks and parser unchanged; + // the fixture's explicit finally owns its lifetime, and lookup errors propagate. + const deadline = performance.now() + 55_000; + const enumerate = () => listWindowsSnapshots(psCommand => { + const query = "Get-CimInstance Win32_Process -ErrorAction Stop"; + expect(psCommand).toContain(query); + const fixtureCommand = psCommand.replace(query, + `Get-CimInstance Win32_Process -Filter "ProcessId=${child.pid}" -ErrorAction Stop`); + const executable = resolveTrustedWindowsPowerShellExe(); + const remaining = Math.floor(deadline - performance.now()); + if (remaining <= 0) throw new Error("native enumeration fixture deadline expired"); + return execFileSync( + executable, + ["-NoProfile", "-NoLogo", "-NonInteractive", "-Command", fixtureCommand], + { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: Math.min(45_000, remaining), windowsHide: true }, + ); + }); + let snapshots = enumerate(); let match = snapshots.find(snapshot => snapshot.pid === child.pid); - if (!match) { - Bun.sleepSync(250); - snapshots = enumerate() ?? []; - match = snapshots.find(snapshot => snapshot.pid === child.pid); - } - if (!match) { - Bun.sleepSync(1_000); - snapshots = enumerate() ?? []; - match = snapshots.find(snapshot => snapshot.pid === child.pid); + // Only a successful scan missing this PID is retried; errors propagate. + // Both scans and the visibility delay share the same monotonic budget. + if (!match && performance.now() < deadline) { + Bun.sleepSync(Math.min(250, Math.max(0, Math.floor(deadline - performance.now())))); + if (performance.now() < deadline) { + snapshots = enumerate(); + match = snapshots.find(snapshot => snapshot.pid === child.pid); + } } expect(match).toBeDefined(); expect(match!.owner).toMatch(/\\/); @@ -1002,7 +1008,7 @@ describe("Windows Win32_Process owner enumeration (#476)", () => { } } }, - { timeout: 35_000 }, + { timeout: 60_000 }, ); }); diff --git a/tests/codex-integration/project-config-warnings.test.ts b/tests/codex-integration/project-config-warnings.test.ts index c4ebe5cff97..90479b38f44 100644 --- a/tests/codex-integration/project-config-warnings.test.ts +++ b/tests/codex-integration/project-config-warnings.test.ts @@ -352,11 +352,11 @@ describe("collectProjectCodexConfigWarnings", () => { }); test("skips untrusted projects even when they define bypass config", () => { - const escaped = testDir.replace(/\\/g, "\\\\"); const projectDir = join(testDir, "proj"); const codexConfigPath = join(process.env.CODEX_HOME!, "config.toml"); + // A TOML literal string keeps the platform path verbatim, so the key matches on every OS. writeGlobalRoutingConfig(` -[projects.'${escaped}\\proj'] +[projects.'${projectDir}'] trust_level = "untrusted" `); mkdirSync(join(projectDir, ".codex"), { recursive: true }); @@ -365,7 +365,15 @@ model_provider = "anthropic" [model_providers.anthropic] name = "anthropic" `); - expect(collectProjectCodexConfigWarnings({ cwd: testDir, codexConfigPath })).toEqual([]); + const warnings = collectProjectCodexConfigWarnings({ cwd: testDir, codexConfigPath }); + expect(warnings.filter(warning => warning.path === join(projectDir, ".codex", "config.toml"))).toEqual([]); + writeGlobalRoutingConfig(` +[projects.'${projectDir}'] +trust_level = "trusted" +`); + expect(collectProjectCodexConfigWarnings({ cwd: testDir, codexConfigPath }) + .filter(warning => warning.path === join(projectDir, ".codex", "config.toml")) + .map(warning => warning.code)).toEqual(["model_providers_table"]); }); test("uncached collection reflects project config changes", () => {