import fs from "node:fs"; import { spawnSync } from "node:child_process"; const ADVISORY_URL = "https://github.com/advisories/GHSA-vfj7-8cjw-p6xm"; const EXPECTED_VULNERABILITIES = [ "@next/eslint-plugin-next", "braces", "eslint-config-next", "fast-glob", "micromatch", ].sort(); const EXPECTED_VERSIONS = new Map([ ["next", "16.3.8"], ["eslint-config-next", "16.3.8"], ["@next/eslint-plugin-next", "16.3.8"], ["fast-glob", "3.3.1"], ["micromatch", "4.0.8"], ["braces", "3.0.3"], ]); function fail(message) { console.error(`Dependency audit exception rejected: ${message}`); process.exit(1); } function packageVersion(lock, name) { const entry = lock.packages?.[`node_modules/${name}`]; return typeof entry?.version === "string" ? entry.version : null; } const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm"; const audit = spawnSync( npmCommand, ["audit", "--audit-level=moderate", "--json"], { encoding: "utf8", maxBuffer: 8 * 1024 * 1024, shell: process.platform === "win32", windowsHide: true, }, ); if (audit.error) { fail(`npm audit could not start: ${audit.error.name}`); } if (audit.status !== 0 && audit.status !== 1) { fail(`npm audit returned unexpected exit code ${audit.status}`); } let report; try { report = JSON.parse(audit.stdout); } catch { fail("npm audit returned invalid JSON"); } if (report.auditReportVersion !== 2 || typeof report.vulnerabilities !== "object") { fail("npm audit report schema changed"); } const names = Object.keys(report.vulnerabilities).sort(); if (audit.status === 0) { if (names.length !== 0) { fail("npm audit exited cleanly but still reported vulnerabilities"); } console.log("Full dependency audit is clean."); process.exit(0); } if (JSON.stringify(names) !== JSON.stringify(EXPECTED_VULNERABILITIES)) { fail(`unexpected vulnerability set: ${names.join(", ")}`); } const counts = report.metadata?.vulnerabilities; if ( !counts || counts.info !== 0 || counts.low !== 0 || counts.moderate !== 0 || counts.high !== 5 || counts.critical !== 0 || counts.total !== 5 ) { fail("vulnerability counts differ from the reviewed exception"); } const lock = JSON.parse(fs.readFileSync(new URL("../package-lock.json", import.meta.url), "utf8")); for (const [name, expected] of EXPECTED_VERSIONS) { const actual = packageVersion(lock, name); if (actual !== expected) { fail(`${name} changed from reviewed version ${expected} to ${actual ?? "missing"}`); } } const vulnerabilities = report.vulnerabilities; for (const name of EXPECTED_VULNERABILITIES) { const item = vulnerabilities[name]; if (!item || item.severity !== "high" || !Array.isArray(item.via)) { fail(`${name} no longer matches the reviewed high-severity audit shape`); } } const directNames = EXPECTED_VULNERABILITIES.filter( (name) => vulnerabilities[name].isDirect === true, ); if (JSON.stringify(directNames) !== JSON.stringify(["eslint-config-next"])) { fail(`unexpected direct dependency findings: ${directNames.join(", ") || "none"}`); } const expectedChain = new Map([ ["eslint-config-next", "@next/eslint-plugin-next"], ["@next/eslint-plugin-next", "fast-glob"], ["fast-glob", "micromatch"], ["micromatch", "braces"], ]); for (const [name, expectedVia] of expectedChain) { if (!vulnerabilities[name].via.includes(expectedVia)) { fail(`${name} no longer resolves through ${expectedVia}`); } } const bracesAdvisories = vulnerabilities.braces.via.filter( (entry) => entry && typeof entry === "object", ); if (bracesAdvisories.length !== 1) { fail("braces advisory count changed"); } const advisory = bracesAdvisories[0]; if ( String(advisory.source) !== "1240992" || advisory.name !== "braces" || advisory.severity !== "high" || advisory.range !== "<=3.0.3" || advisory.url !== ADVISORY_URL ) { fail("braces advisory identity or affected range changed"); } const fix = vulnerabilities["eslint-config-next"].fixAvailable; if ( !fix || typeof fix !== "object" || fix.name !== "eslint-config-next" || fix.version !== "14.2.35" || fix.isSemVerMajor !== true ) { fail("npm now reports a different remediation; review and remove/update this exception"); } console.log( "Accepted reviewed dev-tooling exception only: GHSA-vfj7-8cjw-p6xm via eslint-config-next -> @next/eslint-plugin-next -> fast-glob -> micromatch -> braces@3.0.3.", ); console.log("Production dependencies remain covered by the separate strict production audit.");