test(04-04): the BA7/BA8 drift gates + the search-tree GEO3 pin + the destination-preload capture leg
- BA7: the shipped JS must carry EVERY committed gazetteer id (the web half of bot/web id-set parity, T-04-39) — RED against the pre-gazetteer bundle, green after the resolver lands in the build - BA8: the shipped JS carries NO deep-link crypto (JS assets only — the official Telegram SDK is external, D-11/T-04-40) - no-storage: explicit web/src/search memory-only + no-crypto pin - capture.mjs: the ARAHARAH-DEST signal race + the 'dest' wait mode (state=resolved asserted, then the rendered card's text is waited on — the card mounts at live, T-04-42) + the shell-dest-preload leg; 8/8 expected captures
This commit is contained in:
@@ -24,6 +24,17 @@
|
||||
* BA5 pointed there would invert the gate it exists to enforce.
|
||||
* BA6 no emitted HTML carries the runner page's /api/session or
|
||||
* /api/location-fallback fetch stubs (same dead-code-elimination proof)
|
||||
* BA7 the shipped JS carries EVERY gazetteer id from the committed
|
||||
* dataset (search/src/data/kl-gazetteer.json) — the WEB half of the
|
||||
* bot/web id-set parity gate (T-04-39): a stale web bundle ships
|
||||
* without an id the bot just deep-linked, and the webview could
|
||||
* never resolve it
|
||||
* BA8 the shipped JS carries NO deep-link crypto (createHmac,
|
||||
* crypto.subtle, sha256, HMAC() — the deep link is a plain public id
|
||||
* (D-11, T-04-40). Scans the JS ASSETS only, never the HTML: the
|
||||
* OFFICIAL Telegram SDK script is loaded EXTERNALLY from
|
||||
* telegram.org (not bundled) and may contain crypto internals of
|
||||
* its own.
|
||||
*
|
||||
* If web/dist does not exist, every case fails with a build-first message.
|
||||
*/
|
||||
@@ -33,6 +44,7 @@ import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "node:path";
|
||||
import { test } from "./harness.mjs";
|
||||
import gazetteer from "../../search/src/data/kl-gazetteer.json" with { type: "json" };
|
||||
|
||||
const WEB = path.join(fileURLToPath(new URL(import.meta.url)), "..", "..");
|
||||
const DIST = join(WEB, "dist");
|
||||
@@ -133,3 +145,32 @@ test("BA6 production HTML carries NO runner-page fetch stub endpoints", () => {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("BA7 the shipped bundle carries EVERY gazetteer id (the bot/web id-set parity gate, T-04-39)", () => {
|
||||
assert.ok(existsSync(DIST_ASSETS), claimBuildFirst().message);
|
||||
const bundle = jsFiles
|
||||
.filter((f) => f.startsWith(DIST_ASSETS))
|
||||
.map((f) => readFileSync(f, "utf8"))
|
||||
.join("");
|
||||
assert.ok(gazetteer.entries.length >= 30, `scanned a real dataset (found ${gazetteer.entries.length} entries)`);
|
||||
for (const entry of gazetteer.entries) {
|
||||
assert.ok(
|
||||
bundle.includes(entry.id),
|
||||
`gazetteer id "${entry.id}" is MISSING from the shipped web bundle — a stale bundle the webview cannot resolve against (T-04-39); ids are never renamed, only added`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("BA8 the shipped bundle carries NO deep-link crypto (D-11, T-04-40)", () => {
|
||||
assert.ok(existsSync(DIST_ASSETS), claimBuildFirst().message);
|
||||
const bundle = jsFiles
|
||||
.filter((f) => f.startsWith(DIST_ASSETS))
|
||||
.map((f) => readFileSync(f, "utf8"))
|
||||
.join("");
|
||||
for (const token of ["createHmac", "crypto.subtle", "sha256", "HMAC("]) {
|
||||
assert.ok(
|
||||
!bundle.includes(token),
|
||||
`"${token}" found in a web/dist JS asset — the deep link is a PLAIN public id, no crypto anywhere in the path (D-11)`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* tokens appear — code occurrences only.
|
||||
*/
|
||||
import { strict as assert } from "node:assert";
|
||||
import { readFileSync, readdirSync, statSync } from "node:fs";
|
||||
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { test } from "./harness.mjs";
|
||||
@@ -77,3 +77,28 @@ test("GEO3 web/src/session/store.ts assigns nothing to any storage object (the D
|
||||
// ...and keeps the named TTL constant the client revalidates against (D-03).
|
||||
assert.ok(code.includes("SESSION_TTL_SECONDS = 900"), "the 900s TTL mirror by name is present");
|
||||
});
|
||||
|
||||
test("GEO3 web/src/search/ holds no persistence surface and no deep-link crypto", () => {
|
||||
// The ONBD-02 tree (04-04): the resolved destination is user context and
|
||||
// stays MEMORY-ONLY (GEO-03/D-07), and the deep-link path is a plain
|
||||
// public id with NO crypto (D-11). The whole-tree GEO3 gate above already
|
||||
// walks this directory; this explicit case pins the new tree + the
|
||||
// no-crypto law so a future file there fails HERE, by name.
|
||||
const searchDir = path.join(SRC, "search");
|
||||
assert.ok(existsSync(searchDir), "web/src/search exists (the ONBD-02 resolver tree)");
|
||||
for (const file of listFiles(searchDir, [".ts"])) {
|
||||
const code = codeText(file);
|
||||
for (const banned of BANNED) {
|
||||
assert.ok(
|
||||
!code.includes(banned),
|
||||
`${path.relative(process.cwd(), file)} references ${banned} — GEO-03 violated (web/src/search must stay memory-only)`,
|
||||
);
|
||||
}
|
||||
for (const token of ["createHmac", "crypto.subtle", "sha256"]) {
|
||||
assert.ok(
|
||||
!code.includes(token),
|
||||
`${path.relative(process.cwd(), file)} references ${token} — D-11 forbids crypto in the deep-link path`,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user