From 294be2dfcd7ef104d3120a0fd315e000a529519a Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:18:41 -0700 Subject: [PATCH] test(codex): run validation modules through native node --- .../codex-primary-home-tripwire.test.ts | 86 ++++++++++++------ .../run-codex-real-account-validation.test.ts | 90 ++++++++++++------- 2 files changed, 118 insertions(+), 58 deletions(-) diff --git a/config/scripts/codex-primary-home-tripwire.test.ts b/config/scripts/codex-primary-home-tripwire.test.ts index 584d70f31a0..7ad37585119 100644 --- a/config/scripts/codex-primary-home-tripwire.test.ts +++ b/config/scripts/codex-primary-home-tripwire.test.ts @@ -1,16 +1,13 @@ -import { spawn } from 'node:child_process' +import { execFileSync, spawn } from 'node:child_process' import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises' import os from 'node:os' import path from 'node:path' -import { fileURLToPath } from 'node:url' +import { pathToFileURL } from 'node:url' import { afterEach, describe, expect, it } from 'vitest' -import { - describeCodexHomeChange, - snapshotCodexHome, - startCodexPrimaryHomeTripwire -} from './codex-primary-home-tripwire.mjs' const cleanupPaths: string[] = [] +const tripwireScriptPath = path.resolve('config/scripts/codex-primary-home-tripwire.mjs') +const tripwireModuleUrl = pathToFileURL(tripwireScriptPath).href afterEach(async () => { await Promise.all( @@ -28,8 +25,7 @@ async function createPrimaryHome(): Promise { describe('Codex primary-home tripwire', () => { it('keeps the standalone monitor alive until it is stopped', async () => { const primaryHome = await createPrimaryHome() - const scriptPath = fileURLToPath(new URL('./codex-primary-home-tripwire.mjs', import.meta.url)) - const child = spawn(process.execPath, [scriptPath, '--primary-home', primaryHome], { + const child = spawn(process.execPath, [tripwireScriptPath, '--primary-home', primaryHome], { stdio: ['ignore', 'pipe', 'pipe'] }) @@ -44,33 +40,69 @@ describe('Codex primary-home tripwire', () => { it('detects a write without reading file contents', async () => { const primaryHome = await createPrimaryHome() - const tripwire = await startCodexPrimaryHomeTripwire({ primaryHome, intervalMs: 25 }) - - await writeFile(path.join(primaryHome, '.codex', 'hooks.json'), '{"secret":"not-read"}\n') - await expect.poll(() => tripwire.getStatus().events.length, { timeout: 2_000 }).toBe(1) - - const status = await tripwire.stop() + const status = runTripwireModule<{ + clean: boolean + events: { changedPaths: string[] }[] + }>( + ` + import path from 'node:path' + import { writeFile } from 'node:fs/promises' + const { startCodexPrimaryHomeTripwire } = await import(process.argv[1]) + const tripwire = await startCodexPrimaryHomeTripwire({ + primaryHome: process.argv[2], + intervalMs: 25 + }) + await writeFile(path.join(process.argv[2], '.codex', 'hooks.json'), '{"secret":"not-read"}\\n') + await tripwire.scan() + console.log(JSON.stringify(await tripwire.stop())) + `, + [primaryHome] + ) expect(status.clean).toBe(false) expect(status.events[0].changedPaths).toContain('hooks.json') expect(JSON.stringify(status)).not.toContain('not-read') }) - it('does not follow symlinks outside the watched home', async () => { - const primaryHome = await createPrimaryHome() - const externalRoot = await mkdtemp(path.join(os.tmpdir(), 'orca-codex-tripwire-external-')) - cleanupPaths.push(externalRoot) - const externalFile = path.join(externalRoot, 'credential.txt') - await writeFile(externalFile, 'before') - await symlink(externalFile, path.join(primaryHome, '.codex', 'linked-credential')) - const before = await snapshotCodexHome(path.join(primaryHome, '.codex')) + // Why: ordinary Windows CI tokens cannot create file symlinks without Developer Mode. + it.skipIf(process.platform === 'win32')( + 'does not follow symlinks outside the watched home', + async () => { + const primaryHome = await createPrimaryHome() + const externalRoot = await mkdtemp(path.join(os.tmpdir(), 'orca-codex-tripwire-external-')) + cleanupPaths.push(externalRoot) + const externalFile = path.join(externalRoot, 'credential.txt') + await writeFile(externalFile, 'before') + await symlink(externalFile, path.join(primaryHome, '.codex', 'linked-credential')) + const codexHome = path.join(primaryHome, '.codex') + const before = snapshotCodexHome(codexHome) - await writeFile(externalFile, 'after-with-a-different-size') - const after = await snapshotCodexHome(path.join(primaryHome, '.codex')) + await writeFile(externalFile, 'after-with-a-different-size') + const after = snapshotCodexHome(codexHome) - expect(describeCodexHomeChange(before, after)).toBeNull() - }) + expect(after.digest).toBe(before.digest) + } + ) }) +function runTripwireModule(source: string, args: string[]): T { + const stdout = execFileSync( + process.execPath, + ['--input-type=module', '--eval', source, tripwireModuleUrl, ...args], + { encoding: 'utf8' } + ) + return JSON.parse(stdout.trim()) as T +} + +function snapshotCodexHome(codexHome: string): { digest: string } { + return runTripwireModule<{ digest: string }>( + ` + const { snapshotCodexHome } = await import(process.argv[1]) + console.log(JSON.stringify(await snapshotCodexHome(process.argv[2]))) + `, + [codexHome] + ) +} + function waitForStdout(child: ReturnType, expectedText: string): Promise { return new Promise((resolve, reject) => { const timeout = setTimeout( diff --git a/config/scripts/run-codex-real-account-validation.test.ts b/config/scripts/run-codex-real-account-validation.test.ts index d9c49974456..74f5ae98664 100644 --- a/config/scripts/run-codex-real-account-validation.test.ts +++ b/config/scripts/run-codex-real-account-validation.test.ts @@ -1,14 +1,14 @@ -import { mkdir, rm, writeFile } from 'node:fs/promises' +import { execFileSync } from 'node:child_process' +import { rm } from 'node:fs/promises' import os from 'node:os' import path from 'node:path' +import { pathToFileURL } from 'node:url' import { afterEach, describe, expect, it } from 'vitest' -import { - createValidationEnv, - createValidationLayout, - snapshotValidationState -} from './run-codex-real-account-validation.mjs' const cleanupPaths: string[] = [] +const validationModuleUrl = pathToFileURL( + path.resolve('config/scripts/run-codex-real-account-validation.mjs') +).href afterEach(async () => { await Promise.all( @@ -19,19 +19,27 @@ afterEach(async () => { describe('Codex real-account validation harness', () => { it('forces home and Codex routing variables after stripping ambient values', async () => { const primaryHome = path.join(os.tmpdir(), 'orca-primary-home-sentinel') - const layout = await createValidationLayout({ primaryHome }) - cleanupPaths.push(layout.tempRoot) - const env = createValidationEnv( - { - HOME: primaryHome, - USERPROFILE: primaryHome, - CODEX_HOME: '/unsafe/codex', - ORCA_CODEX_HOME: '/unsafe/orca-codex', - ZDOTDIR: '/unsafe/zsh', - SAFE_VALUE: 'preserved' - }, - layout + const { layout, env } = runValidationModule<{ + layout: { tempRoot: string; homeDir: string } + env: Record + }>( + ` + const { createValidationEnv, createValidationLayout } = await import(process.argv[1]) + const primaryHome = process.argv[2] + const layout = await createValidationLayout({ primaryHome }) + const env = createValidationEnv({ + HOME: primaryHome, + USERPROFILE: primaryHome, + CODEX_HOME: '/unsafe/codex', + ORCA_CODEX_HOME: '/unsafe/orca-codex', + ZDOTDIR: '/unsafe/zsh', + SAFE_VALUE: 'preserved' + }, layout) + console.log(JSON.stringify({ layout, env })) + `, + [primaryHome] ) + cleanupPaths.push(layout.tempRoot) expect(env.HOME).toBe(layout.homeDir) expect(env.USERPROFILE).toBe(layout.homeDir) @@ -43,20 +51,31 @@ describe('Codex real-account validation harness', () => { }) it('records only fingerprints for system-default and managed auth', async () => { - const layout = await createValidationLayout({ - primaryHome: path.join(os.tmpdir(), 'orca-primary-home-sentinel') - }) + const { layout, snapshot } = runValidationModule<{ + layout: { tempRoot: string } + snapshot: { + throwawayCodex: { auth: { sha256?: string } } + managedHomes: { auth: { sha256?: string } }[] + } + }>( + ` + import path from 'node:path' + import { mkdir, writeFile } from 'node:fs/promises' + const { createValidationLayout, snapshotValidationState } = await import(process.argv[1]) + const layout = await createValidationLayout({ primaryHome: process.argv[2] }) + const systemHome = path.join(layout.homeDir, '.codex') + const managedHome = path.join(layout.userDataDir, 'codex-accounts', 'account-1', 'home') + await Promise.all([ + mkdir(systemHome, { recursive: true }), + mkdir(managedHome, { recursive: true }) + ]) + await writeFile(path.join(systemHome, 'auth.json'), '{"refresh_token":"system-secret"}\\n') + await writeFile(path.join(managedHome, 'auth.json'), '{"refresh_token":"never-report-me"}\\n') + console.log(JSON.stringify({ layout, snapshot: await snapshotValidationState(layout) })) + `, + [path.join(os.tmpdir(), 'orca-primary-home-sentinel')] + ) cleanupPaths.push(layout.tempRoot) - const systemHome = path.join(layout.homeDir, '.codex') - const managedHome = path.join(layout.userDataDir, 'codex-accounts', 'account-1', 'home') - await Promise.all([ - mkdir(systemHome, { recursive: true }), - mkdir(managedHome, { recursive: true }) - ]) - await writeFile(path.join(systemHome, 'auth.json'), '{"refresh_token":"system-secret"}\n') - await writeFile(path.join(managedHome, 'auth.json'), '{"refresh_token":"never-report-me"}\n') - - const snapshot = await snapshotValidationState(layout) expect(snapshot.throwawayCodex.auth.sha256).toMatch(/^[a-f0-9]{64}$/) expect(snapshot.managedHomes[0].auth.sha256).toMatch(/^[a-f0-9]{64}$/) @@ -64,3 +83,12 @@ describe('Codex real-account validation harness', () => { expect(JSON.stringify(snapshot)).not.toContain('never-report-me') }) }) + +function runValidationModule(source: string, args: string[]): T { + const stdout = execFileSync( + process.execPath, + ['--input-type=module', '--eval', source, validationModuleUrl, ...args], + { encoding: 'utf8' } + ) + return JSON.parse(stdout.trim()) as T +}