Initial import from garrytan/gstack@026751e (main snapshot via local relay)
Some checks failed
Workflow Lint / actionlint (push) Has been cancelled
Build CI Image / build (push) Has been cancelled
Skill Docs Freshness / check-freshness (push) Has been cancelled
Periodic Evals / build-image (push) Has been cancelled
Periodic Evals / evals (map[file:test/codex-e2e.test.ts name:e2e-codex]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/gemini-e2e.test.ts name:e2e-gemini]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-design.test.ts name:e2e-design]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-plan.test.ts name:e2e-plan]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-qa-bugs.test.ts name:e2e-qa-bugs]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-qa-workflow.test.ts name:e2e-qa-workflow]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-review.test.ts name:e2e-review]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-workflow.test.ts name:e2e-workflow]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-routing-e2e.test.ts name:e2e-routing]) (push) Has been cancelled
Some checks failed
Workflow Lint / actionlint (push) Has been cancelled
Build CI Image / build (push) Has been cancelled
Skill Docs Freshness / check-freshness (push) Has been cancelled
Periodic Evals / build-image (push) Has been cancelled
Periodic Evals / evals (map[file:test/codex-e2e.test.ts name:e2e-codex]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/gemini-e2e.test.ts name:e2e-gemini]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-design.test.ts name:e2e-design]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-plan.test.ts name:e2e-plan]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-qa-bugs.test.ts name:e2e-qa-bugs]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-qa-workflow.test.ts name:e2e-qa-workflow]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-review.test.ts name:e2e-review]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-e2e-workflow.test.ts name:e2e-workflow]) (push) Has been cancelled
Periodic Evals / evals (map[file:test/skill-routing-e2e.test.ts name:e2e-routing]) (push) Has been cancelled
Source: https://github.com/garrytan/gstack/commit/026751e
This commit is contained in:
80
test/gbrain-exec-invariant.test.ts
Normal file
80
test/gbrain-exec-invariant.test.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Static-source invariant: every gbrain CLI invocation in the hot-path
|
||||
* sync code MUST route through `lib/gbrain-exec.ts` (or accept env via
|
||||
* the existing `lib/gbrain-sources.ts` opts surface). A future contributor
|
||||
* who adds a `spawnSync("gbrain", ...)` call directly in
|
||||
* `bin/gstack-gbrain-sync.ts` or `bin/gstack-memory-ingest.ts` silently
|
||||
* regresses the DATABASE_URL fix from #1508 + codex review #7 — gbrain's
|
||||
* dotenv autoload pulls a host project's `.env.local` value instead of
|
||||
* gbrain's own config.
|
||||
*
|
||||
* This test reads each source file directly and asserts zero direct
|
||||
* `spawnSync("gbrain"`, `spawn("gbrain"`, `execFileSync("gbrain"`, or
|
||||
* `execSync(...gbrain` matches. Bun runs TS directly so there is no
|
||||
* compiled artifact to grep — the .ts source is the truth.
|
||||
*
|
||||
* The check is intentionally narrow: only the two files where the bug
|
||||
* actually hurts users are guarded. Other gbrain spawn sites
|
||||
* (`lib/gbrain-sources.ts`, `lib/gbrain-local-status.ts`,
|
||||
* `lib/gstack-memory-helpers.ts`, `bin/gstack-brain-context-load.ts`)
|
||||
* either already accept env from callers or run probes that don't need
|
||||
* DATABASE_URL. Expanding the invariant to those files is a follow-up.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "bun:test";
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
const ROOT = join(import.meta.dir, "..");
|
||||
|
||||
const GUARDED_FILES = [
|
||||
"bin/gstack-gbrain-sync.ts",
|
||||
"bin/gstack-memory-ingest.ts",
|
||||
];
|
||||
|
||||
// Patterns that would bypass lib/gbrain-exec.ts. Match the literal `"gbrain"`
|
||||
// as the first argument since these helpers are the failure mode.
|
||||
const BANNED_PATTERNS: Array<{ name: string; regex: RegExp }> = [
|
||||
{ name: 'spawnSync("gbrain", ...)', regex: /spawnSync\s*\(\s*["']gbrain["']/g },
|
||||
{ name: 'spawn("gbrain", ...)', regex: /\bspawn\s*\(\s*["']gbrain["']/g },
|
||||
{ name: 'execFileSync("gbrain", ...)', regex: /execFileSync\s*\(\s*["']gbrain["']/g },
|
||||
{ name: 'execSync("...gbrain...")', regex: /execSync\s*\(\s*["'`][^"'`]*\bgbrain\b/g },
|
||||
];
|
||||
|
||||
describe("gbrain-exec invariant", () => {
|
||||
for (const relpath of GUARDED_FILES) {
|
||||
it(`${relpath} routes every gbrain spawn through lib/gbrain-exec.ts`, () => {
|
||||
const source = readFileSync(join(ROOT, relpath), "utf-8");
|
||||
// Strip block comments and line comments before scanning — a
|
||||
// documentation reference like `// spawnSync("gbrain", ...)` in a
|
||||
// comment shouldn't trip the invariant. The strip is approximate
|
||||
// (sufficient for the patterns we care about); production code
|
||||
// should match cleanly.
|
||||
const stripped = source
|
||||
.replace(/\/\*[\s\S]*?\*\//g, "")
|
||||
.replace(/\/\/.*$/gm, "");
|
||||
|
||||
for (const { name, regex } of BANNED_PATTERNS) {
|
||||
const matches = stripped.match(regex) || [];
|
||||
if (matches.length > 0) {
|
||||
// Find the line numbers to make the failure actionable.
|
||||
const lines = stripped.split("\n");
|
||||
const hits: string[] = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (new RegExp(regex.source).test(lines[i])) {
|
||||
hits.push(` ${relpath}:${i + 1}: ${lines[i].trim()}`);
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Found ${matches.length} direct gbrain invocation(s) in ${relpath} matching \`${name}\`:\n${hits.join("\n")}\n\n`
|
||||
+ `Route every gbrain spawn through \`spawnGbrain\`/\`execGbrainJson\`/\`execGbrainText\` `
|
||||
+ `in lib/gbrain-exec.ts so DATABASE_URL is seeded from gbrain's config.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Positive assertion: the file should import from lib/gbrain-exec.
|
||||
expect(source).toMatch(/from\s+["']\.\.\/lib\/gbrain-exec["']/);
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user