fix(ci): SHA-pin dependency-review; the secret gate fails closed without a report

dependency-review.yml rode mutable refs (@v4 resolves to a BRANCH on
that repo) inside the one workflow whose job is supply-chain hygiene —
now commit-pinned like its siblings, with dependabot keeping the pins
fresh. gate-secret-scan.mjs crashed with an unhandled EPIPE on
oversize diffs (the designed report.oversize branch was unreachable:
the scanner emits no JSON on refusal) — the pipe write now tolerates
early exit and a missing report is an explicit fail-closed exit 1.
Oversize + broken-scanner legs pinned.
This commit is contained in:
Garry Tan
2026-08-14 17:15:48 -07:00
parent 13b6c5c87b
commit 2fd506a4e0
3 changed files with 80 additions and 5 deletions
+16 -1
View File
@@ -16,6 +16,12 @@ process.stdin.once("end", () => {
.filter((line) => line.startsWith("+") && !line.startsWith("+++"))
.map((line) => line.slice(1))
.join("\n");
// The scanner may exit before consuming an oversize payload (it refuses
// stdin over --max-bytes and reports oversize:true). EPIPE here is that
// refusal in flight, not a failure — the report + exit code carry the verdict.
child.stdin.on("error", (error) => {
if (error.code !== "EPIPE") throw error;
});
child.stdin.end(additions);
});
let stdout = "";
@@ -23,7 +29,16 @@ child.stdout.setEncoding("utf8");
child.stdout.on("data", (chunk) => { stdout += chunk; });
child.once("error", (error) => { throw error; });
child.once("close", (code) => {
const report = JSON.parse(stdout);
let report;
try {
report = JSON.parse(stdout);
} catch {
// No parseable report: the oversize refusal prints only to stderr and
// exits 3, and a crashed scanner emits nothing. Both fail closed.
console.log(`credential scan: 1 high, 0 advisory (scanner emitted no report, exit ${code} — fail-closed)`);
process.exitCode = 1;
return;
}
const high = Number(report.counts?.HIGH ?? 0);
const medium = Number(report.counts?.MEDIUM ?? 0);
console.log(`credential scan: ${high} high, ${medium} advisory`);