- RP1: zero /api/route + registerRoute/routeProxy tokens in comment-stripped bot/src — the Worker gains no route endpoint, even accidentally (T-05-16) - RP2: zero @araharah/routing specifiers in bot/src — routing lives in the webview bundle only; the Worker imports only @araharah/search - scans grow with the bot/src tree automatically (the PG-gate pattern) - TDD note: gates target an already-clean tree, so the RED run is a teeth proof — a planted violating file fails both gates; removed, both pass (74/0 bot suite green)
80 lines
3.4 KiB
JavaScript
80 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/*
|
|
* route-privacy.test.mjs — the D-05 Worker boundary, gated (05-05, T-05-16).
|
|
* ------------------------------------------------------------------------------
|
|
* D-05: "The Worker gains no /api/route this phase. Fixtures ride in the web
|
|
* bundle." The routing stack lives ENTIRELY in the webview — @araharah/routing
|
|
* is imported by web/src only; the Worker imports only @araharah/search.
|
|
* The pivot's privacy posture ("your coordinates were never sent anywhere")
|
|
* is true partly BECAUSE no route endpoint exists to send them to — so the
|
|
* abstinence is pinned by reading the source itself (the privacy.test.mjs /
|
|
* PG-gate pattern: comment-stripped, prefer-fail token scans):
|
|
*
|
|
* RP1 no route proxy — zero `/api/route` tokens AND zero
|
|
* `registerRoute` / `routeProxy` tokens anywhere in bot/src
|
|
* (comment-stripped): the Worker gains no route endpoint, not even
|
|
* an accidentally-named one
|
|
* RP2 no routing import — zero `@araharah/routing` specifiers in bot/src:
|
|
* routing workspace code cannot leak into the Worker bundle even as
|
|
* a dead import (the bundle would grow and the boundary would blur)
|
|
*
|
|
* The scans cover EVERY TypeScript file under bot/src and grow with the
|
|
* tree automatically — a future route proxy fails here at test time, not
|
|
* in review.
|
|
*/
|
|
import { strict as assert } from "node:assert";
|
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import path from "node:path";
|
|
import { test } from "./harness.mjs";
|
|
|
|
const SRC = path.join(fileURLToPath(new URL(import.meta.url)), "..", "..", "src");
|
|
|
|
function listFiles(dir, exts, acc = []) {
|
|
for (const entry of readdirSync(dir)) {
|
|
const full = path.join(dir, entry);
|
|
if (statSync(full).isDirectory()) listFiles(full, exts, acc);
|
|
else if (exts.some((e) => entry.endsWith(e))) acc.push(full);
|
|
}
|
|
return acc;
|
|
}
|
|
|
|
function stripComments(src) {
|
|
return src
|
|
.replace(/\/\*[\s\S]*?\*\//g, " ") // block comments
|
|
.replace(/(^|[^:\\])\/\/[^\n]*/g, "$1"); // line comments (not URLs inside strings — benign over-stripping, gate is prefer-fail reading)
|
|
}
|
|
|
|
function codeText(file) {
|
|
return stripComments(readFileSync(file, "utf8"));
|
|
}
|
|
|
|
/* ————— RP1 — the Worker gains no route endpoint (D-05, T-05-16) ————— */
|
|
|
|
test("RP1 no route proxy — zero /api/route + registerRoute/routeProxy tokens in bot/src (comment-stripped, D-05)", () => {
|
|
const files = listFiles(SRC, [".ts"]);
|
|
assert.ok(files.length >= 8, `scanned a real tree (found ${files.length} files)`);
|
|
for (const file of files) {
|
|
const code = codeText(file);
|
|
for (const banned of ["/api/route", "registerRoute", "routeProxy"]) {
|
|
assert.ok(
|
|
!code.includes(banned),
|
|
`${path.relative(process.cwd(), file)} references "${banned}" — D-05 forbids a Worker route proxy (T-05-16); fixtures ride the web bundle`,
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
/* ————— RP2 — routing workspace code never enters the Worker ————— */
|
|
|
|
test("RP2 no routing import — zero @araharah/routing specifiers in bot/src (D-05)", () => {
|
|
const files = listFiles(SRC, [".ts"]);
|
|
for (const file of files) {
|
|
const code = codeText(file);
|
|
assert.ok(
|
|
!code.includes("@araharah/routing"),
|
|
`${path.relative(process.cwd(), file)} imports @araharah/routing — routing lives in the webview bundle only; the Worker imports only @araharah/search (D-05)`,
|
|
);
|
|
}
|
|
});
|