From b89ce2677cba8ecbd68a5c200e2c0ec09c985873 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 12 Jun 2026 11:18:22 -0700 Subject: [PATCH] feat: codex/gemini runners spawn hermetic children Same allowlist scrub as the claude runners, with each provider's auth surface re-admitted via extraAllow (codex: OPENAI_API_KEY/CODEX_* plus its tempHome .codex copy; gemini: GEMINI_*/GOOGLE_* with real HOME for ~/.gemini auth). The gemini spawn previously inherited the full operator env with no env property at all. Co-Authored-By: Claude Fable 5 --- test/helpers/codex-session-runner.ts | 14 +++++++++----- test/helpers/gemini-session-runner.ts | 8 +++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/test/helpers/codex-session-runner.ts b/test/helpers/codex-session-runner.ts index 0be9dd7d6..404aa6bb2 100644 --- a/test/helpers/codex-session-runner.ts +++ b/test/helpers/codex-session-runner.ts @@ -15,6 +15,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; +import { hermeticChildEnv } from './hermetic-env'; // --- Interfaces --- @@ -201,15 +202,18 @@ export async function runCodexSkill(opts: { // Build codex exec command const args = ['exec', prompt, '--json', '-s', sandbox]; - // Spawn codex with temp HOME so it discovers our installed skill + // Spawn codex with temp HOME so it discovers our installed skill. + // Hermetic scrub (test/helpers/hermetic-env.ts) with codex's auth surface + // re-admitted: codex auths from $HOME/.codex (copied into tempHome above) + // plus OPENAI_API_KEY/CODEX_* when present. HOME override merges last. const proc = Bun.spawn(['codex', ...args], { cwd: cwd || skillDir, stdout: 'pipe', stderr: 'pipe', - env: { - ...process.env, - HOME: tempHome, - }, + env: hermeticChildEnv( + { HOME: tempHome }, + { extraAllow: ['OPENAI_API_KEY', 'CODEX_*'] }, + ), }); // Race against timeout diff --git a/test/helpers/gemini-session-runner.ts b/test/helpers/gemini-session-runner.ts index 06393c383..4f2f040e3 100644 --- a/test/helpers/gemini-session-runner.ts +++ b/test/helpers/gemini-session-runner.ts @@ -14,6 +14,7 @@ */ import * as path from 'path'; +import { hermeticChildEnv } from './hermetic-env'; // --- Interfaces --- @@ -122,11 +123,16 @@ export async function runGeminiSkill(opts: { // Build gemini command const args = ['-p', prompt, '--output-format', 'stream-json', '--yolo']; - // Spawn gemini — uses real HOME for auth, cwd for skill discovery + // Spawn gemini — uses real HOME for auth (~/.gemini; HOME is allowlisted), + // cwd for skill discovery. Hermetic scrub with gemini's auth surface + // re-admitted (previously this spawn inherited the full operator env). const proc = Bun.spawn(['gemini', ...args], { cwd: cwd || process.cwd(), stdout: 'pipe', stderr: 'pipe', + env: hermeticChildEnv(undefined, { + extraAllow: ['GEMINI_API_KEY', 'GOOGLE_API_KEY', 'GOOGLE_APPLICATION_CREDENTIALS', 'GOOGLE_CLOUD_*', 'GEMINI_*'], + }), }); // Race against timeout