mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-20 11:52:20 +02:00
Merge remote-tracking branch 'origin/main' into garrytan/gbrain-code-smell-audit
# Conflicts: # CHANGELOG.md # browse/test/dual-listener.test.ts # browse/test/fixtures/security-bench-haiku-responses.json # browse/test/sidebar-tabs.test.ts # browse/test/sidebar-ux.test.ts # browse/test/terminal-agent.test.ts # claude/SKILL.md.tmpl # scripts/gen-skill-docs.ts # scripts/proactive-suggestions.json # spec/SKILL.md # test/gen-skill-docs.test.ts # test/host-config.test.ts
This commit is contained in:
@@ -126,11 +126,14 @@ beforeAll(async () => {
|
||||
await bm.launch();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Force kill browser instead of graceful close (avoids hang)
|
||||
afterAll(async () => {
|
||||
try { testServer.server.stop(); } catch {}
|
||||
// bm.close() can hang — just let process exit handle it
|
||||
setTimeout(() => process.exit(0), 500);
|
||||
// Close only this file's own browser — never process.exit(): bun test runs
|
||||
// all files in one process, so a delayed exit kills the whole suite
|
||||
// (see test/no-suicide-exit.test.ts). close() can hang when the browser
|
||||
// already died, and its internal 5s timeout ties bun's 5s hook timeout —
|
||||
// so race it at 3s and abandon; the child is reaped at process exit.
|
||||
try { await Promise.race([bm?.close(), new Promise((resolve) => setTimeout(resolve, 3000))]); } catch {}
|
||||
});
|
||||
|
||||
// ─── Navigation ─────────────────────────────────────────────────
|
||||
@@ -913,7 +916,10 @@ describe('CLI lifecycle', () => {
|
||||
cliEnv.BROWSE_STATE_FILE = stateFile;
|
||||
const result = await new Promise<{ code: number; stdout: string; stderr: string }>((resolve) => {
|
||||
const proc = spawn('bun', ['run', cliPath, 'status'], {
|
||||
timeout: 15000,
|
||||
// Must exceed the CLI's startup budget (resolveStartTimeout, 15s
|
||||
// non-CI POSIX) or a slow cold boot under full-suite load gets the
|
||||
// child killed at the exact moment the CLI would have succeeded.
|
||||
timeout: 18000,
|
||||
env: cliEnv,
|
||||
});
|
||||
let stdout = '';
|
||||
@@ -2315,6 +2321,19 @@ describe('load-html', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('load-html rejects .svg files', async () => {
|
||||
const svgPath = path.join(tmpDir, `load-html-test-${Date.now()}.svg`);
|
||||
fs.writeFileSync(svgPath, '<svg xmlns="http://www.w3.org/2000/svg"><text>hi</text></svg>');
|
||||
try {
|
||||
await handleWriteCommand('load-html', [svgPath], bm);
|
||||
expect(true).toBe(false);
|
||||
} catch (err: any) {
|
||||
expect(err.message).toMatch(/does not appear to be HTML/);
|
||||
} finally {
|
||||
try { fs.unlinkSync(svgPath); } catch {}
|
||||
}
|
||||
});
|
||||
|
||||
test('load-html rejects file outside safe dirs', async () => {
|
||||
try {
|
||||
await handleWriteCommand('load-html', ['/etc/passwd.html'], bm);
|
||||
|
||||
Reference in New Issue
Block a user