Files
dev/third_party/pi/scripts/npm-audit.mjs
alexion 6081e3e325 chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree.

git-subtree-dir: third_party/pi

git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
2026-10-15 17:58:48 -04:00

84 lines
2.8 KiB
JavaScript

// Runs `npm audit --omit=dev` and fails on advisories at or above the audit
// level, except for advisories that were reviewed and accepted below. Every
// accepted advisory must name the affected package and explain why it does not
// apply. Remove an entry once a fixed version is installed; the script warns
// about entries that no longer match.
import { spawnSync } from "node:child_process";
const auditLevel = "moderate";
const severities = ["info", "low", "moderate", "high", "critical"];
/** @type {Record<string, { package: string; reason: string }>} */
const acceptedAdvisories = {
"GHSA-86w9-cpqp-85rv": {
package: "node-forge",
reason:
"No fixed node-forge release exists. It is only reachable through @earendil-works/gondolin in the private, " +
"unpublished gondolin example extension. Gondolin only verifies leaf certificates against its own locally " +
"generated CA (public exponent 65537), so the low-exponent signature forgery does not apply.",
},
};
const result = spawnSync("npm", ["audit", "--omit=dev", "--json"], { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
if (result.error) {
throw result.error;
}
let report;
try {
report = JSON.parse(result.stdout);
} catch {
process.stderr.write(result.stderr);
process.stderr.write(result.stdout);
console.error("npm audit did not produce a JSON report.");
process.exit(1);
}
if (report.error) {
console.error(`npm audit failed: ${report.error.summary ?? JSON.stringify(report.error)}`);
process.exit(1);
}
const minimumSeverity = severities.indexOf(auditLevel);
const seenAccepted = new Set();
const failures = new Map();
for (const vulnerability of Object.values(report.vulnerabilities ?? {})) {
for (const via of vulnerability.via) {
// String entries point at another vulnerable package, which is reported on its own.
if (typeof via === "string") {
continue;
}
const id = via.url?.split("/").pop() ?? String(via.source);
const accepted = acceptedAdvisories[id];
if (accepted && accepted.package === via.name) {
seenAccepted.add(id);
continue;
}
if (severities.indexOf(via.severity) >= minimumSeverity) {
failures.set(`${id}:${via.name}`, via);
}
}
}
for (const id of seenAccepted) {
console.log(`Accepted ${id} (${acceptedAdvisories[id].package}): ${acceptedAdvisories[id].reason}`);
}
for (const id of Object.keys(acceptedAdvisories)) {
if (!seenAccepted.has(id)) {
console.log(`::warning::Accepted advisory ${id} no longer matches; remove it from scripts/npm-audit.mjs.`);
}
}
if (failures.size > 0) {
console.error(`\nFound ${failures.size} unaccepted advisories at or above ${auditLevel}:`);
for (const via of failures.values()) {
console.error(`- ${via.name} ${via.range} [${via.severity}] ${via.title} ${via.url}`);
}
process.exit(1);
}
console.log(`No unaccepted advisories at or above ${auditLevel}.`);