diff --git a/tests/env-isolation-declarations.test.ts b/tests/env-isolation-declarations.test.ts new file mode 100644 index 00000000..76b8b886 --- /dev/null +++ b/tests/env-isolation-declarations.test.ts @@ -0,0 +1,41 @@ +// Static guard: every PROVIDER_ENV_VARS entry must be CLEARED or REDIRECTED +// by tests/setup/env-isolation.ts. A data-dir override that is fingerprinted +// for cache invalidation but not isolated in tests leaks the developer's real +// sessions into fixture parses — green on CI (no HERMES_HOME), red on a +// Hermes-shell laptop. The named hole was HERMES_HOME; the class is every +// sibling override that session-cache already knows about. +import { describe, expect, it } from 'vitest' +import { readFileSync } from 'fs' +import { dirname, join } from 'path' +import { fileURLToPath } from 'url' + +import { PROVIDER_ENV_VARS } from '../src/session-cache.js' + +const SETUP_PATH = join(dirname(fileURLToPath(import.meta.url)), 'setup', 'env-isolation.ts') + +function extractConstStringArray(source: string, name: string): string[] { + const match = source.match(new RegExp(`const ${name} = \\[([\\s\\S]*?)\\] as const`)) + if (!match) { + throw new Error(`tests/setup/env-isolation.ts: const ${name} = [...] as const not found`) + } + return [...match[1]!.matchAll(/'([A-Z0-9_]+)'/g)].map(m => m[1]!) +} + +describe('env-isolation covers PROVIDER_ENV_VARS', () => { + it('clears or redirects every provider data-dir override so a developer shell cannot leak real sessions into fixtures', () => { + const source = readFileSync(SETUP_PATH, 'utf8') + const isolated = new Set([ + ...extractConstStringArray(source, 'CLEARED'), + ...extractConstStringArray(source, 'REDIRECTED'), + ]) + + const missing: string[] = [] + for (const [provider, vars] of Object.entries(PROVIDER_ENV_VARS)) { + for (const varName of vars) { + if (!isolated.has(varName)) missing.push(`${provider}:${varName}`) + } + } + + expect(missing).toEqual([]) + }) +}) diff --git a/tests/setup/env-isolation.ts b/tests/setup/env-isolation.ts index 6a3326ec..4c557a68 100644 --- a/tests/setup/env-isolation.ts +++ b/tests/setup/env-isolation.ts @@ -1,12 +1,13 @@ // Vitest setup file: isolates every test from the developer's shell environment. // // codeburn discovers sessions through a long list of provider-specific env -// vars (CLAUDE_CONFIG_DIR, CODEX_HOME, CRUSH_GLOBAL_DATA, …) and via HOME / -// XDG_* / APPDATA / LOCALAPPDATA. Without this file, any value set in the -// developer's shell (e.g. CLAUDE_CONFIG_DIRS=/Users/me/.claude:…) bleeds into +// vars (CLAUDE_CONFIG_DIR, CODEX_HOME, HERMES_HOME, CRUSH_GLOBAL_DATA, …) and +// via HOME / XDG_* / APPDATA / LOCALAPPDATA. Without this file, any value set +// in the developer's shell (e.g. HERMES_HOME=/Users/me/.hermes) bleeds into // fixture-based tests: the parser reads the developer's REAL sessions instead // of the temp-dir fixture, producing nonsense totals and false failures that -// pass on a clean CI runner. +// pass on a clean CI runner. tests/env-isolation-declarations.test.ts fails +// closed if PROVIDER_ENV_VARS grows a data-dir override that is not listed. // // What this file does: // 1. Mints an empty sandbox temp dir once per worker. @@ -56,26 +57,36 @@ const CLEARED = [ 'CODEWHALE_HOME', 'CRUSH_GLOBAL_DATA', 'CODEBUFF_DATA_DIR', + 'DSH_HOME', 'FACTORY_DIR', 'GOOSE_PATH_ROOT', 'GROK_HOME', + 'HERMES_HOME', 'KIRO_HOME', + 'KIMI_CODE_HOME', 'KIMI_SHARE_DIR', + 'LINGTAI_HOME', + 'LINGTAI_TUI_GLOBAL_DIR', + 'LINGTAI_TUI_HOME', 'MUX_ROOT', 'OPENCODE_DATA_DIR', 'OPENCODE_DB_PREFIX', + 'QUICKWORK_HOME', 'QWEN_DATA_DIR', 'VIBE_HOME', 'WARP_DB_PATH', 'ZS_DATA_DIR', // codeburn override dirs / paths 'CODEBURN_CACHE_DIR', + 'CODEBURN_COPILOT_GLOBAL_STORAGE_DIR', 'CODEBURN_COPILOT_JETBRAINS_DIR', 'CODEBURN_COPILOT_OTEL_DB', 'CODEBURN_COPILOT_SESSION_STATE_DIR', 'CODEBURN_COPILOT_WS_STORAGE_DIR', 'CODEBURN_DESKTOP_SESSIONS_DIR', 'CODEBURN_MUX_DIR', + 'CODEBURN_OPEN_DESIGN_DIR', + 'CODEBURN_OPENCLAUDE_DIR', 'CODEBURN_ANTIGRAVITY_SETTINGS_PATH', // codeburn behavior toggles (set by the dev to tweak local runs) 'CODEBURN_COPILOT_DISABLE_OTEL',