mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 08:03:13 +00:00
test(codex): run validation modules through native node
This commit is contained in:
@@ -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<string> {
|
||||
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<T>(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<typeof spawn>, expectedText: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const timeout = setTimeout(
|
||||
|
||||
@@ -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<string, string | undefined>
|
||||
}>(
|
||||
`
|
||||
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<T>(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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user