"use strict"; const crypto = require("node:crypto"); const PROFILE_DEFINITIONS = Object.freeze({ minimal: { label: "Minimal", requiredScore: 55, severities: ["error"], allowSuppressions: true, maxSuppressionDays: 180 }, standard: { label: "Standard", requiredScore: 70, severities: ["error", "warning"], allowSuppressions: true, maxSuppressionDays: 90 }, strict: { label: "Strict", requiredScore: 82, severities: ["error", "warning"], allowSuppressions: true, maxSuppressionDays: 30 }, production: { label: "Production", requiredScore: 90, severities: ["error", "warning"], allowSuppressions: true, maxSuppressionDays: 14 }, }); function normalizePolicy(policy = {}) { const id = String(policy.id || policy.profile || "standard").toLowerCase(); const base = PROFILE_DEFINITIONS[id] || PROFILE_DEFINITIONS.standard; const custom = id === "organization" ? policy : {}; return { id, label: custom.label || base.label || "Organization custom", requiredScore: Math.min(100, Math.max(0, Number(custom.requiredScore ?? base.requiredScore ?? 80))), enabledChecks: Array.isArray(custom.enabledChecks) ? [...new Set(custom.enabledChecks.map(String))] : null, severityOverrides: custom.severityOverrides && typeof custom.severityOverrides === "object" ? { ...custom.severityOverrides } : {}, blockingChecks: [...new Set((custom.blockingChecks || policy.blockingChecks || []).map(String))], blockingSeverities: [...new Set((custom.blockingSeverities || policy.blockingSeverities || base.severities || ["error"]).map(String))] .filter((severity) => ["warning", "error"].includes(severity)), allowSuppressions: custom.allowSuppressions ?? base.allowSuppressions ?? true, maxSuppressionDays: Math.max(1, Number(custom.maxSuppressionDays ?? base.maxSuppressionDays ?? 30)), }; } function validateSuppression(input, policy, now = new Date()) { if (!policy.allowSuppressions) throw new Error("The selected policy does not allow suppressions."); const checkId = String(input?.checkId || "").trim(); const reason = String(input?.reason || "").trim(); const author = String(input?.author || "").trim(); const scope = String(input?.scope || "repository").trim(); const evidence = String(input?.evidence || "").trim(); const expiresAt = new Date(input?.expiresAt || ""); if (!checkId || reason.length < 10 || !author || !evidence) throw new Error("A suppression requires a check ID, author, evidence and a reason of at least 10 characters."); if (!Number.isFinite(expiresAt.getTime()) || expiresAt <= now) throw new Error("A suppression expiry must be in the future."); const maximum = new Date(now.getTime() + policy.maxSuppressionDays * 86_400_000); if (expiresAt > maximum) throw new Error(`This policy permits suppressions for at most ${policy.maxSuppressionDays} days.`); return { id: crypto.randomUUID(), checkId, reason, author, createdAt: now.toISOString(), ticket: String(input.ticket || "").trim() || null, expiresAt: expiresAt.toISOString(), scope, evidence, }; } function applyPolicy(checks, policyInput, suppressions = [], now = new Date()) { const policy = normalizePolicy(policyInput); const enabled = policy.enabledChecks ? new Set(policy.enabledChecks) : null; const relevant = checks.filter((check) => !enabled || enabled.has(check.id)).map((check) => { const status = policy.severityOverrides[check.id] || check.status; const suppression = suppressions.find((item) => item.checkId === check.id && new Date(item.expiresAt) > now); const expiredSuppression = suppressions.find((item) => item.checkId === check.id && new Date(item.expiresAt) <= now); return { ...check, status, suppressed: Boolean(suppression), suppression: suppression || null, expiredSuppression: expiredSuppression || null, blocking: !suppression && status !== "pass" && (policy.blockingSeverities.includes(status) || policy.blockingChecks.includes(check.id)), }; }); return { policy, checks: relevant }; } function buildTrend(previous, report) { const prior = new Map((previous?.checks || []).map((check) => [check.id, check])); const current = new Map(report.checks.map((check) => [check.id, check])); const active = (check) => check && check.status !== "pass" && !check.suppressed; const newlyFound = [...current.values()].filter((check) => active(check) && !active(prior.get(check.id))).map((check) => check.id); const resolved = [...prior.values()].filter((check) => active(check) && !active(current.get(check.id))).map((check) => check.id); const regressions = [...current.values()].filter((check) => active(check) && prior.get(check.id)?.status === "warning" && check.status === "error").map((check) => check.id); return { score: report.score, categories: report.categories, newlyFound, resolved, regressions, suppressions: report.checks.filter((check) => check.suppressed).map((check) => check.id), checkedAt: report.checkedAt, commitSha: report.commitSha || null, checks: report.checks.map(({ id, status, suppressed }) => ({ id, status, suppressed })) }; } function exportReport(report, format = "json") { if (format === "json") return { extension: "json", mimeType: "application/json", content: `${JSON.stringify(report, null, 2)}\n` }; const rows = report.checks.map((check) => `| ${check.id} | ${check.category} | ${check.status}${check.suppressed ? " (suppressed)" : ""} | ${String(check.detail).replace(/\|/g, "\\|")} |`).join("\n"); const markdown = `# Git assurance report — ${report.repository}\n\nPolicy: **${report.policy.label}** · Score: **${report.score}/100** · Commit: \`${report.commitSha || "unknown"}\`\n\n| Check | Category | Status | Evidence |\n|---|---|---|---|\n${rows}\n`; if (format === "markdown") return { extension: "md", mimeType: "text/markdown", content: markdown }; if (format !== "html") throw new Error("Unsupported Git Validator export format."); const escape = (value) => String(value).replace(/[&<>"']/g, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]); const htmlRows = report.checks.map((check) => `
Policy: ${escape(report.policy.label)} · Score: ${report.score}/100 · Commit: ${escape(report.commitSha || "unknown")}
| Check | Category | Status | Evidence |
|---|