assert scan coverage in check:drop — an empty tree passed with a confident PASS line
This commit is contained in:
parent
0a80b075cb
commit
727e3ee8ad
1 changed files with 20 additions and 1 deletions
|
|
@ -43,12 +43,16 @@ const ATTR_RE = /(?:src|href)\s*=\s*"(\/(?!\/)[^"]*)"/g; // src="/..."
|
|||
const JSON_RE = /"(?:iframeUrl|scriptUrl|url|embedUrl|output)"\s*:\s*"(\/(?!\/)[^"]*)"/g;
|
||||
|
||||
const findings = [];
|
||||
// ★ COVERAGE COUNTER — see the MIN_FILES assertion below for why this exists.
|
||||
let scanned = 0;
|
||||
|
||||
function scan(dir) {
|
||||
for (const e of readdirSync(dir)) {
|
||||
const p = join(dir, e);
|
||||
const st = statSync(p);
|
||||
if (st.isDirectory()) { scan(p); continue; }
|
||||
if (!/\.(html|json)$/.test(e)) continue;
|
||||
scanned++;
|
||||
const text = readFileSync(p, 'utf8');
|
||||
const rel = relative(treeDir, p);
|
||||
for (const re of [ATTR_RE, JSON_RE]) {
|
||||
|
|
@ -60,6 +64,21 @@ function scan(dir) {
|
|||
}
|
||||
scan(treeDir);
|
||||
|
||||
// ★ COVERAGE ASSERTION — "no root-relative refs found" and "nothing was searched" are the SAME
|
||||
// EXIT CODE without this. Verified 2026-09-20: pointed at an EMPTY directory, this script printed
|
||||
// its confident PASS line and exited 0. A tree gutted by a per-bundle `BUNDLE=x vite build` (which
|
||||
// empties other bundles' leaf pages) would therefore sail straight through check:drop, exactly as
|
||||
// it sails through check:sri — a gate that walks only what EXISTS is structurally blind to absence.
|
||||
// This is the LIVENESS-vs-CORRECTNESS class: "the scan ran" is not "the tree is portable".
|
||||
// Found by APPLYING that rule to the other gates, not by hitting the bug in production.
|
||||
const MIN_FILES = Number(process.env.MIN_FILES || 20);
|
||||
if (scanned < MIN_FILES) {
|
||||
console.error(`DROP-PORTABILITY: FAIL — scanned only ${scanned} html/json file(s) (expected >=${MIN_FILES}).`);
|
||||
console.error(' A near-empty tree cannot demonstrate portability; it just has nothing to find.');
|
||||
console.error(' Run a FULL build (`bun run build`), or set MIN_FILES if this tree is legitimately small.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (findings.length) {
|
||||
console.error(`DROP-PORTABILITY: FAIL — ${findings.length} root-relative ref(s); tree breaks under subpath hosting (Cloudflare-Drop class):`);
|
||||
const byFile = {};
|
||||
|
|
@ -72,4 +91,4 @@ if (findings.length) {
|
|||
console.error('FIX: make intra-tree refs RELATIVE (./bundle/profile/...); absolute embed snippets are computed at RUNTIME from location.');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`DROP-PORTABILITY: PASS — no root-relative refs; tree is position-independent (file://, Drop, subpath, Railway all behave identically).`);
|
||||
console.log(`DROP-PORTABILITY: PASS — ${scanned} html/json file(s) scanned, no root-relative refs; tree is position-independent (file://, Drop, subpath, Railway all behave identically).`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue