/** * Hermetic HOME for snapshot / byte-stability tests. * * The COL collision-scanner and the CLAUDE.md cascade resolve ~/.claude from * process.env.HOME (see scanners/lib/active-config-reader.mjs — enumeratePlugins, * enumerateSkills, walkClaudeMdCascade). A CLI spawned with the developer's real * HOME picks up their installed plugins/skills and user CLAUDE.md, which makes * byte-snapshots machine- and time-dependent: the snapshots seeded on one machine * drift the moment another machine (or the same machine, later) has a different * ~/.claude. Pointing HOME at an empty temp dir isolates every snapshot/byte test * from user state, exactly as tests/scanners/collision.test.mjs already does for * the COL unit test. * * Writes any CLI may make under HOME (sessions, baselines) land in the temp dir, * never in the repo. */ import { mkdtempSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; export const HERMETIC_HOME = mkdtempSync(join(tmpdir(), 'config-audit-hermetic-home-')); /** Subprocess env with HOME/USERPROFILE redirected to the empty hermetic dir. */ export function hermeticEnv(extra = {}) { return { ...process.env, HOME: HERMETIC_HOME, USERPROFILE: HERMETIC_HOME, ...extra }; } /** Run an in-process callback with process.env.HOME pointed at the hermetic dir. */ export async function withHermeticHome(fn) { const originalHome = process.env.HOME; const originalProfile = process.env.USERPROFILE; process.env.HOME = HERMETIC_HOME; process.env.USERPROFILE = HERMETIC_HOME; try { return await fn(); } finally { if (originalHome === undefined) delete process.env.HOME; else process.env.HOME = originalHome; if (originalProfile === undefined) delete process.env.USERPROFILE; else process.env.USERPROFILE = originalProfile; } }