import assert from "node:assert/strict"; import crypto from "node:crypto"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const policyPath = path.join(root, "docs/web/dependency-severity-policy.json"); const inventoryPath = path.join(root, "tests/golden/M13-05C/dependency-inventory.json"); const reportPath = path.join(root, "tests/golden/M13-05D/dependency-severity-report.json"); const manifestPath = path.join(root, "tests/golden/M13-05D/manifest.json"); const sha256 = (bytes) => crypto.createHash("sha256").update(bytes).digest("hex"); const fileSha256 = (file) => sha256(fs.readFileSync(file)); const policy = JSON.parse(fs.readFileSync(policyPath, "utf8")); const inventory = JSON.parse(fs.readFileSync(inventoryPath, "utf8")); assert.equal(policy.schemaVersion, 1); assert.equal(policy.task, "M13-05D"); assert.deepEqual(policy.severityOrder, ["LOW", "MEDIUM", "HIGH", "BLOCKER"]); assert.deepEqual(policy.gates, { BLOCKER: "BLOCK", HIGH: "BLOCK", MEDIUM: "REVIEW", LOW: "TRACK" }); assert.deepEqual(policy.exceptionFields, ["owner", "expiresOn", "reason", "alternativeControl"]); assert.deepEqual(policy.findings, []); assert.deepEqual(policy.exceptions, []); assert.equal(inventory.task, "M13-05C"); assert.ok(inventory.packages.length > 0); const severityRank = new Map(policy.severityOrder.map((severity, index) => [severity, index])); function validateException(exception, today = "2026-08-19") { assert.equal(typeof exception.owner, "string"); assert.ok(exception.owner.trim().length > 0); assert.match(exception.expiresOn, /^\d{4}-\d{2}-\d{2}$/u); assert.ok(exception.expiresOn >= today, "exception is expired"); assert.equal(typeof exception.reason, "string"); assert.ok(exception.reason.trim().length > 0); assert.equal(typeof exception.alternativeControl, "string"); assert.ok(exception.alternativeControl.trim().length > 0); } const accepted = { owner: "security@example.invalid", expiresOn: "2026-12-31", reason: "upstream patch window", alternativeControl: "network egress deny and pinned lockfile" }; validateException(accepted); for (const invalid of [ { ...accepted, owner: "" }, { ...accepted, expiresOn: "2026-08-18" }, { ...accepted, reason: "" }, { ...accepted, alternativeControl: "" }, ]) assert.throws(() => validateException(invalid)); function evaluate(findings, exceptions) { const byId = new Map(exceptions.map((exception) => [exception.findingId, exception])); const decisions = findings.map((finding) => { assert.ok(severityRank.has(finding.severity)); const exception = byId.get(finding.id); if (!exception) return { id: finding.id, severity: finding.severity, decision: policy.gates[finding.severity], exception: false }; validateException(exception); return { id: finding.id, severity: finding.severity, decision: "EXCEPTION", exception: true }; }); const blocked = decisions.filter((decision) => decision.decision === "BLOCK"); const review = decisions.filter((decision) => decision.decision === "REVIEW"); return { decisions, blocked: blocked.length, review: review.length, status: blocked.length === 0 && review.length === 0 ? "PASS" : "BLOCKED" }; } const clean = evaluate(policy.findings, policy.exceptions); assert.deepEqual(clean, { decisions: [], blocked: 0, review: 0, status: "PASS" }); assert.equal(evaluate([{ id: "synthetic-high", severity: "HIGH" }], []).status, "BLOCKED"); assert.equal(evaluate([{ id: "synthetic-high", severity: "HIGH" }], [{ findingId: "synthetic-high", ...accepted }]).status, "PASS"); assert.equal(evaluate([{ id: "synthetic-medium", severity: "MEDIUM" }], []).status, "BLOCKED"); const report = { schemaVersion: 1, task: "M13-05D", operation: "DEPENDENCY_SEVERITY_POLICY", inventorySha256: fileSha256(inventoryPath), findings: policy.findings.length, exceptions: policy.exceptions.length, blocked: clean.blocked, review: clean.review, status: clean.status, negativeCases: { missingException: "BLOCKED", expiredException: "REJECTED", incompleteException: "REJECTED", completeException: "ACCEPTED" }, execution: "DISABLED", nextTask: "M13-05E" }; if (process.env.UPDATE_M13_05D_REPORT === "1") { fs.mkdirSync(path.dirname(reportPath), { recursive: true }); fs.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`); } assert.deepEqual(JSON.parse(fs.readFileSync(reportPath, "utf8")), report); const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); assert.deepEqual({ schemaVersion: manifest.schemaVersion, task: manifest.task, parentTask: manifest.parentTask, nextTask: manifest.nextTask }, { schemaVersion: 1, task: "M13-05D", parentTask: "M13-05C", nextTask: "M13-05E" }); for (const artifact of Object.values(manifest.artifacts)) assert.equal(fileSha256(path.join(root, artifact.path)), artifact.sha256, artifact.path); process.stdout.write("dependency-severity-policy-ok findings=0 exceptions=0 blocked=0 review=0 negativeCases=4 status=PASS execution=DISABLED next=M13-05E\n");