mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-17 10:25:33 +02:00
fix(test): scope rendered-output tripwires to repo sources; stop cdp-e2e's env leak
Two hermeticity holes surfaced by the wave's final gate. (1) The three T6 tripwires (branch-slug, codex-flag, empty-find) enumerated the whole tree including the workspace-local .claude/ install, which is not generated output and can carry dangling symlinks from unrelated sessions — one ENOENT there failed all three. They now scan repo sources only. (2) browse/test/cdp-e2e.test.ts mutated process.env.GSTACK_HOME at module scope without restore; in one-process shard runs that leaks into every later test file — observed baking cdp-e2e's temp render path into artifacts that outlived it (53 dangling SKILL.md symlinks in a workspace install). The original value is now restored in afterAll. The exact test that performed the polluted relink remains unattributed; both known leak vectors are closed and the workspace was repaired via an explicit gstack-relink. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a19cdd69ba
commit
4da5be24a6
@@ -18,6 +18,12 @@ import { startTestServer } from './test-server';
|
|||||||
import { BrowserManager } from '../src/browser-manager';
|
import { BrowserManager } from '../src/browser-manager';
|
||||||
|
|
||||||
const TMP_HOME = path.join(os.tmpdir(), `gstack-cdp-e2e-${process.pid}-${Date.now()}`);
|
const TMP_HOME = path.join(os.tmpdir(), `gstack-cdp-e2e-${process.pid}-${Date.now()}`);
|
||||||
|
// Shard runs execute many test files in ONE bun process: a module-scope env
|
||||||
|
// mutation without restore leaks into every LATER file in the shard. This
|
||||||
|
// exact leak once pointed a sibling test's GSTACK_HOME at our temp dir,
|
||||||
|
// which then got baked into artifacts that outlived it (dangling symlinks
|
||||||
|
// into a deleted render dir). Save + restore in afterAll.
|
||||||
|
const ORIGINAL_GSTACK_HOME = process.env.GSTACK_HOME;
|
||||||
process.env.GSTACK_HOME = TMP_HOME;
|
process.env.GSTACK_HOME = TMP_HOME;
|
||||||
process.env.GSTACK_TELEMETRY_OFF = '1'; // don't pollute analytics during tests
|
process.env.GSTACK_TELEMETRY_OFF = '1'; // don't pollute analytics during tests
|
||||||
|
|
||||||
@@ -36,6 +42,8 @@ beforeAll(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
if (ORIGINAL_GSTACK_HOME === undefined) delete process.env.GSTACK_HOME;
|
||||||
|
else process.env.GSTACK_HOME = ORIGINAL_GSTACK_HOME;
|
||||||
try { await bm.cleanup?.(); } catch {}
|
try { await bm.cleanup?.(); } catch {}
|
||||||
try { testServer.server.stop(); } catch {}
|
try { testServer.server.stop(); } catch {}
|
||||||
await fs.rm(TMP_HOME, { recursive: true, force: true });
|
await fs.rm(TMP_HOME, { recursive: true, force: true });
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const FILENAME_PREFIX = /\$\{?_BRANCH\}?[A-Za-z0-9._-]*\.(?:jsonl|json|md|txt|lo
|
|||||||
|
|
||||||
function renderedSkillFiles(): string[] {
|
function renderedSkillFiles(): string[] {
|
||||||
const out = execSync(
|
const out = execSync(
|
||||||
`find "${ROOT}" -name 'SKILL.md' -not -path '*/node_modules/*' ; find "${ROOT}" -path '*/sections/*.md' -not -path '*/node_modules/*'`,
|
`find "${ROOT}" -name 'SKILL.md' -not -path '*/node_modules/*' -not -path '*/.claude/*' ; find "${ROOT}" -path '*/sections/*.md' -not -path '*/node_modules/*' -not -path '*/.claude/*'`,
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8' },
|
||||||
);
|
);
|
||||||
return out.split('\n').filter(Boolean);
|
return out.split('\n').filter(Boolean);
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ function grepRepo(pattern: string, includes: string[]): string[] {
|
|||||||
.split('\n')
|
.split('\n')
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.filter((f) => !f.includes('node_modules'))
|
.filter((f) => !f.includes('node_modules'))
|
||||||
|
// The workspace-local .claude/ install is not generated output and can
|
||||||
|
// carry dangling symlinks from unrelated sessions.
|
||||||
|
.filter((f) => !f.includes('/.claude/'))
|
||||||
.filter((f) => !f.endsWith('test/codex-web-search-flag.test.ts'));
|
.filter((f) => !f.endsWith('test/codex-web-search-flag.test.ts'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,10 @@ describe('empty find must not fall through to cwd (#2483)', () => {
|
|||||||
const hits = out
|
const hits = out
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.filter((f) => !f.includes('node_modules'));
|
.filter((f) => !f.includes('node_modules'))
|
||||||
|
// The workspace-local .claude/ install is not generated output and can
|
||||||
|
// carry dangling symlinks from unrelated sessions.
|
||||||
|
.filter((f) => !f.includes('/.claude/'));
|
||||||
expect(hits).toEqual([]);
|
expect(hits).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user