mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-13 16:38:56 +02:00
bin/gstack-design-detect.ts finds and runs an impeccable engine the user installed; it never installs, downloads, or executes anything that could download. `probe` reads only: config (design_detector off → DISABLED), IMPECCABLE_BIN (absolute, realpath outside the repo and cwd), a PATH walk (absolute entries outside the repo; a #! shim counts as launcher-present, never READY), the ~/.impeccable/bin/<newest semver>/ cache, and the engine installed beside a skill launcher (scripts/bin/<os>-<arch>/impeccable, the layout a real install produced). It reports IMPECCABLE_SKILL, host-aware IMPECCABLE_HOOK (+ HOOK_OTHER), the ignore lists from .impeccable/config*.json, IMPECCABLE_ENGINE_UNTESTED for versions outside the fixture set, and a hint only when a launcher exists without its engine. `scan` re-probes, refuses URLs and anything outside the repo root or the design-report allow-list (realpath, so symlinks cannot escape), derives `--changed <base>` targets NUL-safely through git and lib/frontend-scope.ts, batches 100 absolute paths per engine call with stdin ignored, a SIGKILL timeout, a 50 MB stdout cap, and sanitized length-capped fields, then prints one normalized JSON document (--format gstack) or the engine's bytes (--format raw); DETECT_TOP (fenced as untrusted content), DETECT_SUMMARY, and DETECT_EXIT go to stderr; exit code passes through with 1 over 2 over 0; exit 3 is a gstack bug. `rules` prints the mapped set. Every run appends a content-free line to the local analytics file. lib/design-detect-contract.ts owns every sentinel string, the limits, and the normalized-finding shape (pure module); test/design-detect-contract.test.ts asserts every sentinel-shaped token the agent can read exists there. lib/frontend-scope.ts mirrors gstack-diff-scope's frontend arm, pinned by a parity test that runs the bash script. bin/gstack-config gains design_detector (auto | off, default auto, invalid values rejected with the file unchanged). test/fixtures/fake-impeccable.ts is the env-driven engine stand-in; test/gstack-design-detect.test.ts covers READY/NOT_CACHED/ NOT_AVAILABLE/DISABLED, env trust (.env never loaded, in-repo IMPECCABLE_BIN ignored), newest-semver cache, hook and ignore detection, refusals, exit passthrough, raw byte-identity, normalization, the display cap, timeout, parse errors, diagnostics, --changed, and analytics. The egress scanner test records the wrapper as a documented non-sink. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
45 lines
2.1 KiB
TypeScript
Executable File
45 lines
2.1 KiB
TypeScript
Executable File
#!/usr/bin/env bun
|
|
/**
|
|
* fake-impeccable — a stand-in for the impeccable engine binary in tests.
|
|
*
|
|
* Behaves like `impeccable detect --json <targets>`: prints a findings JSON
|
|
* array on stdout and exits with the engine's code. Everything is driven by env
|
|
* so tests never edit this file:
|
|
* FAKE_IMPECCABLE_OUTPUT path of the JSON (default: impeccable-detect-sample.json beside this file)
|
|
* FAKE_IMPECCABLE_EXIT exit code (default 2 = findings)
|
|
* FAKE_IMPECCABLE_LOG append one JSON line per invocation: {argv, cwd, stdinIsTTY}
|
|
* FAKE_IMPECCABLE_SLEEP_MS sleep before printing (timeout tests)
|
|
* FAKE_IMPECCABLE_STDERR text to print on stderr (diagnostics tests)
|
|
* FAKE_IMPECCABLE_RAW print this exact text instead of the JSON file (parse-error tests)
|
|
* FAKE_IMPECCABLE_REPEAT repeat the sample findings N times (display-cap tests)
|
|
* Spawned directly (shebang), so the spawn-based tests are POSIX-only.
|
|
*/
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
const env = process.env;
|
|
if (env.FAKE_IMPECCABLE_LOG) {
|
|
fs.appendFileSync(env.FAKE_IMPECCABLE_LOG, JSON.stringify({ argv: process.argv.slice(2), cwd: process.cwd(), stdinIsTTY: Boolean(process.stdin.isTTY) }) + '\n');
|
|
}
|
|
const sleep = Number(env.FAKE_IMPECCABLE_SLEEP_MS ?? 0);
|
|
if (sleep > 0) Bun.sleepSync(sleep);
|
|
if (env.FAKE_IMPECCABLE_STDERR) process.stderr.write(env.FAKE_IMPECCABLE_STDERR + '\n');
|
|
|
|
if (env.FAKE_IMPECCABLE_RAW !== undefined) {
|
|
process.stdout.write(env.FAKE_IMPECCABLE_RAW);
|
|
} else {
|
|
const file = env.FAKE_IMPECCABLE_OUTPUT ?? path.join(import.meta.dir, 'impeccable-detect-sample.json');
|
|
const text = fs.readFileSync(file, 'utf-8');
|
|
const repeat = Number(env.FAKE_IMPECCABLE_REPEAT ?? 1);
|
|
if (repeat > 1) {
|
|
const arr = JSON.parse(text) as unknown[];
|
|
const out: unknown[] = [];
|
|
for (let i = 0; i < repeat; i++) for (const f of arr) out.push({ ...(f as object), line: i });
|
|
process.stdout.write(JSON.stringify(out, null, 2) + '\n');
|
|
} else {
|
|
process.stdout.write(text);
|
|
}
|
|
}
|
|
// exitCode, not process.exit(): large outputs must flush through the pipe first.
|
|
process.exitCode = Number(env.FAKE_IMPECCABLE_EXIT ?? 2);
|