mirror of https://github.com/garrytan/gstack.git
47 lines
1.7 KiB
JavaScript
47 lines
1.7 KiB
JavaScript
#!/usr/bin/env node
|
|
import { spawn } from "node:child_process";
|
|
|
|
const child = spawn("bun", [
|
|
"bin/gstack-redact",
|
|
"--repo-visibility", "public",
|
|
"--json",
|
|
"--max-bytes", "16000000",
|
|
], { shell: false, windowsHide: true, stdio: ["pipe", "pipe", "inherit"] });
|
|
let diff = "";
|
|
process.stdin.setEncoding("utf8");
|
|
process.stdin.on("data", (chunk) => { diff += chunk; });
|
|
process.stdin.once("end", () => {
|
|
const additions = diff
|
|
.split(/\r?\n/)
|
|
.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 = "";
|
|
child.stdout.setEncoding("utf8");
|
|
child.stdout.on("data", (chunk) => { stdout += chunk; });
|
|
child.once("error", (error) => { throw error; });
|
|
child.once("close", (code) => {
|
|
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`);
|
|
process.exitCode = high > 0 || report.oversize || ![0, 2, 3].includes(code) ? 1 : 0;
|
|
});
|