From 9ced72404e2593478b46019664cef68e3fcf37c1 Mon Sep 17 00:00:00 2001 From: deafsquad Date: Sun, 16 Aug 2026 12:43:59 +0200 Subject: [PATCH] absence-scan: run main() on Windows, where the entrypoint guard never matched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CLI exits 0 having done nothing on Windows, so the pre-push hook built on it passes everything — including the bytes the scanner exists to refuse. `import.meta.url === \`file://${process.argv[1]}\`` compares a URL against a string built from a native path. On POSIX those coincide. On Windows import.meta.url is file:///C:/... while process.argv[1] is C:\... with backslashes, so the template produces file://C:\... and the comparison is never true. main() is never called. pathToFileURL is the same helper proxy/pipeline.mjs already uses to turn an extension path into an import URL. Measured on Windows at 8ddd4f0, before and after: node tools/absence-scan.mjs exit 0, no output -> exit 1 + usage node tools/absence-scan.mjs exit 0, no output -> exit 2 + FINDING capture-uuid node tools/absence-scan.mjs exit 0, no output -> exit 0 + "absence-scan: clean" node --test test/absence-scan.test.mjs 11 pass / 8 fail -> 19 pass / 0 fail The eight failures are the existing CLI: and git-range: cases. They were already encoding the correct contract; nothing on Windows was running it. --- tools/absence-scan.mjs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/absence-scan.mjs b/tools/absence-scan.mjs index 5a6e3c38..5f42f3f3 100755 --- a/tools/absence-scan.mjs +++ b/tools/absence-scan.mjs @@ -34,6 +34,7 @@ import { readFileSync } from "node:fs"; import { execFileSync } from "node:child_process"; import { basename } from "node:path"; +import { pathToFileURL } from "node:url"; // --- Allowlist --------------------------------------------------------------- // @@ -467,7 +468,12 @@ function main(argv) { return 0; } -if (import.meta.url === `file://${process.argv[1]}`) { +// Entrypoint guard. pathToFileURL, NOT `file://${argv[1]}`: on Windows +// import.meta.url is file:///C:/... while argv[1] is C:\... with backslashes, +// so the template form never matches and main() never runs — the CLI becomes a +// silent exit-0 no-op, and the pre-push hook that depends on it passes +// everything. Same helper proxy/pipeline.mjs already uses for its loader. +if (import.meta.url === pathToFileURL(process.argv[1]).href) { let code; try { code = main(process.argv);