@kevinrabun/judges 3.42.0 → 3.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +56 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/assign-findings.d.ts +37 -0
  6. package/dist/commands/assign-findings.d.ts.map +1 -0
  7. package/dist/commands/assign-findings.js +178 -0
  8. package/dist/commands/assign-findings.js.map +1 -0
  9. package/dist/commands/ci-template.d.ts +15 -0
  10. package/dist/commands/ci-template.d.ts.map +1 -0
  11. package/dist/commands/ci-template.js +212 -0
  12. package/dist/commands/ci-template.js.map +1 -0
  13. package/dist/commands/false-negatives.d.ts +35 -0
  14. package/dist/commands/false-negatives.d.ts.map +1 -0
  15. package/dist/commands/false-negatives.js +166 -0
  16. package/dist/commands/false-negatives.js.map +1 -0
  17. package/dist/commands/hook-install.d.ts +22 -0
  18. package/dist/commands/hook-install.d.ts.map +1 -0
  19. package/dist/commands/hook-install.js +143 -0
  20. package/dist/commands/hook-install.js.map +1 -0
  21. package/dist/commands/policy-audit.d.ts +53 -0
  22. package/dist/commands/policy-audit.d.ts.map +1 -0
  23. package/dist/commands/policy-audit.js +161 -0
  24. package/dist/commands/policy-audit.js.map +1 -0
  25. package/dist/commands/regression-alert.d.ts +32 -0
  26. package/dist/commands/regression-alert.d.ts.map +1 -0
  27. package/dist/commands/regression-alert.js +216 -0
  28. package/dist/commands/regression-alert.js.map +1 -0
  29. package/dist/commands/remediation.d.ts +21 -0
  30. package/dist/commands/remediation.d.ts.map +1 -0
  31. package/dist/commands/remediation.js +257 -0
  32. package/dist/commands/remediation.js.map +1 -0
  33. package/dist/commands/sla-track.d.ts +57 -0
  34. package/dist/commands/sla-track.d.ts.map +1 -0
  35. package/dist/commands/sla-track.js +269 -0
  36. package/dist/commands/sla-track.js.map +1 -0
  37. package/dist/commands/ticket-sync.d.ts +26 -0
  38. package/dist/commands/ticket-sync.d.ts.map +1 -0
  39. package/dist/commands/ticket-sync.js +236 -0
  40. package/dist/commands/ticket-sync.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +2 -2
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Policy audit trail — record which rules/judges were active at evaluation
3
+ * time, creating an immutable local audit log for compliance proof.
4
+ *
5
+ * Enables SOC2/ISO27001 auditors to verify that security policies were
6
+ * enforced at the time of each evaluation. All data stays local.
7
+ */
8
+ import type { TribunalVerdict, JudgesConfig } from "../types.js";
9
+ export interface PolicySnapshot {
10
+ /** SHA-256 hash of the combined policy state */
11
+ policyHash: string;
12
+ /** ISO timestamp */
13
+ timestamp: string;
14
+ /** Config file path */
15
+ configPath: string;
16
+ /** Active preset(s) */
17
+ presets: string[];
18
+ /** Judges that were enabled */
19
+ enabledJudges: string[];
20
+ /** Judges that were disabled */
21
+ disabledJudges: string[];
22
+ /** Disabled rules */
23
+ disabledRules: string[];
24
+ /** Rule overrides */
25
+ ruleOverrides: Record<string, unknown>;
26
+ /** Min severity threshold */
27
+ minSeverity: string;
28
+ /** Git commit at evaluation time */
29
+ gitCommit?: string;
30
+ /** Evaluator version */
31
+ version: string;
32
+ }
33
+ export interface AuditEntry {
34
+ id: string;
35
+ timestamp: string;
36
+ policySnapshot: PolicySnapshot;
37
+ verdictSummary: {
38
+ verdict: string;
39
+ score: number;
40
+ criticalCount: number;
41
+ highCount: number;
42
+ totalFindings: number;
43
+ };
44
+ filesEvaluated: number;
45
+ }
46
+ export interface AuditLog {
47
+ entries: AuditEntry[];
48
+ version: string;
49
+ }
50
+ export declare function capturePolicySnapshot(config: JudgesConfig, configPath: string, enabledJudges: string[], version: string): PolicySnapshot;
51
+ export declare function recordAuditEntry(policySnapshot: PolicySnapshot, verdict: TribunalVerdict, filesEvaluated: number): AuditEntry;
52
+ export declare function runPolicyAudit(argv: string[]): void;
53
+ //# sourceMappingURL=policy-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-audit.d.ts","sourceRoot":"","sources":["../../src/commands/policy-audit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIjE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gCAAgC;IAChC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qBAAqB;IACrB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,EAAE,MAAM,GACd,cAAc,CAoChB;AAuBD,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,eAAe,EACxB,cAAc,EAAE,MAAM,GACrB,UAAU,CA4BZ;AAID,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAgFnD"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Policy audit trail — record which rules/judges were active at evaluation
3
+ * time, creating an immutable local audit log for compliance proof.
4
+ *
5
+ * Enables SOC2/ISO27001 auditors to verify that security policies were
6
+ * enforced at the time of each evaluation. All data stays local.
7
+ */
8
+ import { createHash } from "crypto";
9
+ // ─── Policy Snapshot ────────────────────────────────────────────────────────
10
+ export function capturePolicySnapshot(config, configPath, enabledJudges, version) {
11
+ const { execSync } = require("child_process");
12
+ let gitCommit;
13
+ try {
14
+ gitCommit = execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim();
15
+ }
16
+ catch {
17
+ /* not in git */
18
+ }
19
+ const snapshot = {
20
+ policyHash: "",
21
+ timestamp: new Date().toISOString(),
22
+ configPath,
23
+ presets: config.preset ? [config.preset] : [],
24
+ enabledJudges,
25
+ disabledJudges: config.disabledJudges || [],
26
+ disabledRules: config.disabledRules || [],
27
+ ruleOverrides: config.ruleOverrides || {},
28
+ minSeverity: config.minSeverity || "info",
29
+ gitCommit,
30
+ version,
31
+ };
32
+ // Compute deterministic hash of policy state
33
+ const hashInput = JSON.stringify({
34
+ presets: snapshot.presets,
35
+ enabledJudges: snapshot.enabledJudges.sort(),
36
+ disabledJudges: snapshot.disabledJudges.sort(),
37
+ disabledRules: snapshot.disabledRules.sort(),
38
+ ruleOverrides: snapshot.ruleOverrides,
39
+ minSeverity: snapshot.minSeverity,
40
+ });
41
+ snapshot.policyHash = createHash("sha256").update(hashInput).digest("hex").slice(0, 16);
42
+ return snapshot;
43
+ }
44
+ // ─── Audit Log Management ──────────────────────────────────────────────────
45
+ const AUDIT_FILE = ".judges-audit.json";
46
+ function loadAuditLog() {
47
+ const { readFileSync, existsSync } = require("fs");
48
+ if (existsSync(AUDIT_FILE)) {
49
+ try {
50
+ return JSON.parse(readFileSync(AUDIT_FILE, "utf-8"));
51
+ }
52
+ catch {
53
+ /* corrupt file */
54
+ }
55
+ }
56
+ return { entries: [], version: "1.0" };
57
+ }
58
+ function saveAuditLog(log) {
59
+ const { writeFileSync } = require("fs");
60
+ writeFileSync(AUDIT_FILE, JSON.stringify(log, null, 2), "utf-8");
61
+ }
62
+ export function recordAuditEntry(policySnapshot, verdict, filesEvaluated) {
63
+ const entry = {
64
+ id: createHash("sha256")
65
+ .update(policySnapshot.timestamp + policySnapshot.policyHash)
66
+ .digest("hex")
67
+ .slice(0, 12),
68
+ timestamp: policySnapshot.timestamp,
69
+ policySnapshot,
70
+ verdictSummary: {
71
+ verdict: verdict.overallVerdict,
72
+ score: verdict.overallScore,
73
+ criticalCount: verdict.criticalCount,
74
+ highCount: verdict.highCount,
75
+ totalFindings: verdict.findings.length,
76
+ },
77
+ filesEvaluated,
78
+ };
79
+ const log = loadAuditLog();
80
+ log.entries.push(entry);
81
+ // Keep last 1000 entries
82
+ if (log.entries.length > 1000) {
83
+ log.entries = log.entries.slice(-1000);
84
+ }
85
+ saveAuditLog(log);
86
+ return entry;
87
+ }
88
+ // ─── CLI ────────────────────────────────────────────────────────────────────
89
+ export function runPolicyAudit(argv) {
90
+ if (argv.includes("--help") || argv.includes("-h")) {
91
+ console.log(`
92
+ judges policy-audit — View and manage the policy audit trail
93
+
94
+ Usage:
95
+ judges policy-audit Show recent audit entries
96
+ judges policy-audit --last 10 Show last 10 entries
97
+ judges policy-audit --diff Compare current policy to last evaluation
98
+ judges policy-audit --export audit.json Export full audit log
99
+
100
+ Options:
101
+ --last <n> Show last N entries (default: 5)
102
+ --diff Show policy changes since last evaluation
103
+ --export <path> Export audit log to file
104
+ --format json JSON output
105
+ --help, -h Show this help
106
+
107
+ The audit trail records which rules, judges, and configs were active at
108
+ each evaluation time. Useful for SOC2/ISO27001 compliance proof.
109
+ `);
110
+ return;
111
+ }
112
+ const { readFileSync, existsSync, writeFileSync } = require("fs");
113
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
114
+ const lastN = parseInt(argv.find((_a, i) => argv[i - 1] === "--last") || "5", 10);
115
+ const exportPath = argv.find((_a, i) => argv[i - 1] === "--export");
116
+ if (!existsSync(AUDIT_FILE)) {
117
+ console.log("\n No audit trail found. Run an evaluation first.\n");
118
+ return;
119
+ }
120
+ const log = JSON.parse(readFileSync(AUDIT_FILE, "utf-8"));
121
+ if (exportPath) {
122
+ writeFileSync(exportPath, JSON.stringify(log, null, 2), "utf-8");
123
+ console.log(` Exported ${log.entries.length} audit entries to ${exportPath}`);
124
+ return;
125
+ }
126
+ const entries = log.entries.slice(-lastN);
127
+ if (format === "json") {
128
+ console.log(JSON.stringify(entries, null, 2));
129
+ return;
130
+ }
131
+ if (argv.includes("--diff") && log.entries.length >= 2) {
132
+ const prev = log.entries[log.entries.length - 2].policySnapshot;
133
+ const curr = log.entries[log.entries.length - 1].policySnapshot;
134
+ console.log("\n Policy Diff (last two evaluations)\n");
135
+ if (prev.policyHash !== curr.policyHash) {
136
+ console.log(" ⚠️ Policy changed!\n");
137
+ const addedJudges = curr.enabledJudges.filter((j) => !prev.enabledJudges.includes(j));
138
+ const removedJudges = prev.enabledJudges.filter((j) => !curr.enabledJudges.includes(j));
139
+ if (addedJudges.length)
140
+ console.log(` + Added judges: ${addedJudges.join(", ")}`);
141
+ if (removedJudges.length)
142
+ console.log(` - Removed judges: ${removedJudges.join(", ")}`);
143
+ if (prev.minSeverity !== curr.minSeverity)
144
+ console.log(` ~ Severity: ${prev.minSeverity} → ${curr.minSeverity}`);
145
+ }
146
+ else {
147
+ console.log(" ✅ No policy changes\n");
148
+ }
149
+ console.log("");
150
+ return;
151
+ }
152
+ console.log(`\n Policy Audit Trail (last ${entries.length} of ${log.entries.length})\n`);
153
+ for (const e of entries) {
154
+ const v = e.verdictSummary;
155
+ console.log(` ${e.id} ${e.timestamp}`);
156
+ console.log(` Policy: ${e.policySnapshot.policyHash} Judges: ${e.policySnapshot.enabledJudges.length} Commit: ${e.policySnapshot.gitCommit?.slice(0, 8) || "N/A"}`);
157
+ console.log(` Verdict: ${v.verdict} Score: ${v.score} Critical: ${v.criticalCount} High: ${v.highCount} Findings: ${v.totalFindings}`);
158
+ console.log("");
159
+ }
160
+ }
161
+ //# sourceMappingURL=policy-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-audit.js","sourceRoot":"","sources":["../../src/commands/policy-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Regression alerting — compare current scan results against a saved
3
+ * baseline snapshot to detect quality regressions.
4
+ *
5
+ * Snapshots are stored locally in .judges-baseline.json.
6
+ */
7
+ import type { Finding } from "../types.js";
8
+ export interface BaselineSnapshot {
9
+ timestamp: string;
10
+ gitCommit?: string;
11
+ gitBranch?: string;
12
+ totalFindings: number;
13
+ bySeverity: Record<string, number>;
14
+ byRule: Record<string, number>;
15
+ findingIds: string[];
16
+ }
17
+ export interface RegressionReport {
18
+ status: "improved" | "stable" | "regressed";
19
+ newFindings: string[];
20
+ fixedFindings: string[];
21
+ delta: number;
22
+ severityDelta: Record<string, number>;
23
+ ruleDelta: Record<string, number>;
24
+ baseline: BaselineSnapshot;
25
+ current: BaselineSnapshot;
26
+ }
27
+ export declare function buildSnapshot(findings: Finding[]): BaselineSnapshot;
28
+ export declare function saveBaseline(snapshot: BaselineSnapshot, file?: string): void;
29
+ export declare function loadBaseline(file?: string): BaselineSnapshot | null;
30
+ export declare function compareSnapshots(baseline: BaselineSnapshot, current: BaselineSnapshot): RegressionReport;
31
+ export declare function runRegressionAlert(argv: string[]): Promise<void>;
32
+ //# sourceMappingURL=regression-alert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-alert.d.ts","sourceRoot":"","sources":["../../src/commands/regression-alert.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC5C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAqBD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAqBnE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,SAAgB,GAAG,IAAI,CAEnF;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAgB,GAAG,gBAAgB,GAAG,IAAI,CAG1E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CAmCxG;AAID,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ItE"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Regression alerting — compare current scan results against a saved
3
+ * baseline snapshot to detect quality regressions.
4
+ *
5
+ * Snapshots are stored locally in .judges-baseline.json.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync } from "fs";
8
+ const BASELINE_FILE = ".judges-baseline.json";
9
+ // ─── Helpers ────────────────────────────────────────────────────────────────
10
+ function makeFindingId(f) {
11
+ return `${f.ruleId}::${f.title}`;
12
+ }
13
+ function getGitInfo() {
14
+ try {
15
+ const { execSync } = require("child_process");
16
+ const commit = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
17
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
18
+ return { commit, branch };
19
+ }
20
+ catch {
21
+ return {};
22
+ }
23
+ }
24
+ export function buildSnapshot(findings) {
25
+ const git = getGitInfo();
26
+ const bySeverity = {};
27
+ const byRule = {};
28
+ const findingIds = [];
29
+ for (const f of findings) {
30
+ bySeverity[f.severity] = (bySeverity[f.severity] || 0) + 1;
31
+ byRule[f.ruleId] = (byRule[f.ruleId] || 0) + 1;
32
+ findingIds.push(makeFindingId(f));
33
+ }
34
+ return {
35
+ timestamp: new Date().toISOString(),
36
+ gitCommit: git.commit,
37
+ gitBranch: git.branch,
38
+ totalFindings: findings.length,
39
+ bySeverity,
40
+ byRule,
41
+ findingIds,
42
+ };
43
+ }
44
+ export function saveBaseline(snapshot, file = BASELINE_FILE) {
45
+ writeFileSync(file, JSON.stringify(snapshot, null, 2));
46
+ }
47
+ export function loadBaseline(file = BASELINE_FILE) {
48
+ if (!existsSync(file))
49
+ return null;
50
+ return JSON.parse(readFileSync(file, "utf-8"));
51
+ }
52
+ export function compareSnapshots(baseline, current) {
53
+ const baseSet = new Set(baseline.findingIds);
54
+ const currSet = new Set(current.findingIds);
55
+ const newFindings = current.findingIds.filter((id) => !baseSet.has(id));
56
+ const fixedFindings = baseline.findingIds.filter((id) => !currSet.has(id));
57
+ const delta = current.totalFindings - baseline.totalFindings;
58
+ const severityDelta = {};
59
+ const allSeverities = new Set([...Object.keys(baseline.bySeverity), ...Object.keys(current.bySeverity)]);
60
+ for (const sev of allSeverities) {
61
+ severityDelta[sev] = (current.bySeverity[sev] || 0) - (baseline.bySeverity[sev] || 0);
62
+ }
63
+ const ruleDelta = {};
64
+ const allRules = new Set([...Object.keys(baseline.byRule), ...Object.keys(current.byRule)]);
65
+ for (const rule of allRules) {
66
+ const d = (current.byRule[rule] || 0) - (baseline.byRule[rule] || 0);
67
+ if (d !== 0)
68
+ ruleDelta[rule] = d;
69
+ }
70
+ let status = "stable";
71
+ if (delta > 0 || newFindings.length > 0)
72
+ status = "regressed";
73
+ else if (delta < 0 || fixedFindings.length > 0)
74
+ status = "improved";
75
+ return {
76
+ status,
77
+ newFindings,
78
+ fixedFindings,
79
+ delta,
80
+ severityDelta,
81
+ ruleDelta,
82
+ baseline,
83
+ current,
84
+ };
85
+ }
86
+ // ─── CLI ────────────────────────────────────────────────────────────────────
87
+ export async function runRegressionAlert(argv) {
88
+ if (argv.includes("--help") || argv.includes("-h")) {
89
+ console.log(`
90
+ judges regression-alert — Detect quality regressions between scans
91
+
92
+ Usage:
93
+ judges regression-alert --save --input results.json Save current results as baseline
94
+ judges regression-alert --check --input results.json Compare current results against baseline
95
+ judges regression-alert --show Show current baseline
96
+
97
+ Options:
98
+ --save Save current results as the baseline
99
+ --check Compare against saved baseline
100
+ --show Display stored baseline info
101
+ --input <path> Results JSON file
102
+ --fail-on-regression Exit with code 1 if regressions detected (CI mode)
103
+ --threshold <n> Only alert if >= n new findings (default: 1)
104
+ --format json JSON output
105
+ --help, -h Show this help
106
+ `);
107
+ return;
108
+ }
109
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
110
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
111
+ const failOnRegression = argv.includes("--fail-on-regression");
112
+ const thresholdStr = argv.find((_a, i) => argv[i - 1] === "--threshold");
113
+ const threshold = thresholdStr ? parseInt(thresholdStr, 10) : 1;
114
+ // Show baseline
115
+ if (argv.includes("--show")) {
116
+ const baseline = loadBaseline();
117
+ if (!baseline) {
118
+ console.log("\n No baseline saved. Run with --save first.\n");
119
+ return;
120
+ }
121
+ if (format === "json") {
122
+ console.log(JSON.stringify(baseline, null, 2));
123
+ }
124
+ else {
125
+ console.log(`
126
+ Baseline Snapshot
127
+ ─────────────────
128
+ Saved: ${baseline.timestamp}
129
+ Commit: ${baseline.gitCommit || "unknown"}
130
+ Branch: ${baseline.gitBranch || "unknown"}
131
+ Findings: ${baseline.totalFindings}
132
+ `);
133
+ for (const [sev, count] of Object.entries(baseline.bySeverity)) {
134
+ console.log(` ${sev.padEnd(10)} ${count}`);
135
+ }
136
+ console.log("");
137
+ }
138
+ return;
139
+ }
140
+ // Both --save and --check need input
141
+ if (!inputPath) {
142
+ console.error("Error: --input <path> required");
143
+ process.exit(1);
144
+ }
145
+ if (!existsSync(inputPath)) {
146
+ console.error(`Error: file not found: ${inputPath}`);
147
+ process.exit(1);
148
+ }
149
+ const data = JSON.parse(readFileSync(inputPath, "utf-8"));
150
+ const findings = data.evaluations
151
+ ? data.evaluations.flatMap((e) => e.findings || [])
152
+ : data.findings || data;
153
+ const snapshot = buildSnapshot(findings);
154
+ // Save baseline
155
+ if (argv.includes("--save")) {
156
+ saveBaseline(snapshot);
157
+ if (format === "json") {
158
+ console.log(JSON.stringify(snapshot, null, 2));
159
+ }
160
+ else {
161
+ console.log(`\n Baseline saved: ${snapshot.totalFindings} findings (${snapshot.gitCommit || "no git"})\n`);
162
+ }
163
+ return;
164
+ }
165
+ // Check against baseline
166
+ if (argv.includes("--check")) {
167
+ const baseline = loadBaseline();
168
+ if (!baseline) {
169
+ console.error("Error: No baseline saved. Run with --save first.");
170
+ process.exit(1);
171
+ }
172
+ const report = compareSnapshots(baseline, snapshot);
173
+ if (format === "json") {
174
+ console.log(JSON.stringify(report, null, 2));
175
+ }
176
+ else {
177
+ const icon = report.status === "improved" ? "✅" : report.status === "regressed" ? "🚨" : "➖";
178
+ console.log(`\n ${icon} Status: ${report.status.toUpperCase()} (delta: ${report.delta >= 0 ? "+" : ""}${report.delta})`);
179
+ console.log(` Baseline: ${baseline.totalFindings} findings (${baseline.gitCommit || "?"})`);
180
+ console.log(` Current: ${snapshot.totalFindings} findings (${snapshot.gitCommit || "?"})\n`);
181
+ if (report.newFindings.length > 0) {
182
+ console.log(` New findings (${report.newFindings.length}):`);
183
+ for (const id of report.newFindings.slice(0, 20)) {
184
+ console.log(` + ${id}`);
185
+ }
186
+ if (report.newFindings.length > 20) {
187
+ console.log(` ... and ${report.newFindings.length - 20} more`);
188
+ }
189
+ }
190
+ if (report.fixedFindings.length > 0) {
191
+ console.log(`\n Fixed findings (${report.fixedFindings.length}):`);
192
+ for (const id of report.fixedFindings.slice(0, 20)) {
193
+ console.log(` - ${id}`);
194
+ }
195
+ if (report.fixedFindings.length > 20) {
196
+ console.log(` ... and ${report.fixedFindings.length - 20} more`);
197
+ }
198
+ }
199
+ if (Object.keys(report.severityDelta).length > 0) {
200
+ console.log("\n By severity:");
201
+ for (const [sev, d] of Object.entries(report.severityDelta)) {
202
+ if (d !== 0)
203
+ console.log(` ${sev.padEnd(10)} ${d >= 0 ? "+" : ""}${d}`);
204
+ }
205
+ }
206
+ console.log("");
207
+ }
208
+ if (failOnRegression && report.newFindings.length >= threshold) {
209
+ console.error(` ❌ Regression detected: ${report.newFindings.length} new finding(s) (threshold: ${threshold})`);
210
+ process.exit(1);
211
+ }
212
+ return;
213
+ }
214
+ console.log("Use --save, --check, or --show. See --help for details.");
215
+ }
216
+ //# sourceMappingURL=regression-alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-alert.js","sourceRoot":"","sources":["../../src/commands/regression-alert.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AA0B7D,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAE9C,+EAA+E;AAE/E,SAAS,aAAa,CAAC,CAAU;IAC/B,OAAO,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;AACnC,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,4BAA4B,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACpF,MAAM,MAAM,GAAG,QAAQ,CAAC,iCAAiC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACzF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAmB;IAC/C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3D,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/C,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,GAAG,CAAC,MAAM;QACrB,SAAS,EAAE,GAAG,CAAC,MAAM;QACrB,aAAa,EAAE,QAAQ,CAAC,MAAM;QAC9B,UAAU;QACV,MAAM;QACN,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAA0B,EAAE,IAAI,GAAG,aAAa;IAC3E,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAI,GAAG,aAAa;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAA0B,EAAE,OAAyB;IACpF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5C,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;IAE7D,MAAM,aAAa,GAA2B,EAAE,CAAC;IACjD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACzG,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5F,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,MAAM,GAA+B,QAAQ,CAAC;IAClD,IAAI,KAAK,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,GAAG,WAAW,CAAC;SACzD,IAAI,KAAK,GAAG,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,GAAG,UAAU,CAAC;IAEpE,OAAO;QACL,MAAM;QACN,WAAW;QACX,aAAa;QACb,KAAK;QACL,aAAa;QACb,SAAS;QACT,QAAQ;QACR,OAAO;KACR,CAAC;AACJ,CAAC;AAED,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAc;IACrD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;CAiBf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,MAAM,CAAC;IAC1F,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAClF,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC;IACzF,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhE,gBAAgB;IAChB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC;;;eAGH,QAAQ,CAAC,SAAS;eAClB,QAAQ,CAAC,SAAS,IAAI,SAAS;eAC/B,QAAQ,CAAC,SAAS,IAAI,SAAS;eAC/B,QAAQ,CAAC,aAAa;CACpC,CAAC,CAAC;YACG,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAc,IAAI,CAAC,WAAW;QAC1C,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAA2B,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;QAC7E,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;IAE1B,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAEzC,gBAAgB;IAChB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,YAAY,CAAC,QAAQ,CAAC,CAAC;QACvB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uBAAuB,QAAQ,CAAC,aAAa,cAAc,QAAQ,CAAC,SAAS,IAAI,QAAQ,KAAK,CAAC,CAAC;QAC9G,CAAC;QACD,OAAO;IACT,CAAC;IAED,yBAAyB;IACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;YAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEpD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7F,OAAO,CAAC,GAAG,CACT,OAAO,IAAI,YAAY,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,GAAG,CAC7G,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,aAAa,cAAc,QAAQ,CAAC,SAAS,IAAI,GAAG,GAAG,CAAC,CAAC;YAC7F,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,aAAa,cAAc,QAAQ,CAAC,SAAS,IAAI,GAAG,KAAK,CAAC,CAAC;YAE/F,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,CAAC;gBAC9D,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;oBACjD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAC7B,CAAC;gBACD,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;oBACnC,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;gBACpE,CAAC;YACH,CAAC;YAED,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,aAAa,CAAC,MAAM,IAAI,CAAC,CAAC;gBACpE,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;oBACnD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAC7B,CAAC;gBACD,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;oBACrC,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;gBACtE,CAAC;YACH,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;gBAChC,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;oBAC5D,IAAI,CAAC,KAAK,CAAC;wBAAE,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7E,CAAC;YACH,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,gBAAgB,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;YAC/D,OAAO,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,WAAW,CAAC,MAAM,+BAA+B,SAAS,GAAG,CAAC,CAAC;YAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Remediation guides — provide step-by-step fix guidance for common
3
+ * finding categories, linked from finding output.
4
+ *
5
+ * Each guide includes: description, risk level, fix steps,
6
+ * code examples (before/after), and references.
7
+ */
8
+ export interface RemediationGuide {
9
+ rulePrefix: string;
10
+ title: string;
11
+ category: string;
12
+ risk: string;
13
+ steps: string[];
14
+ beforeCode?: string;
15
+ afterCode?: string;
16
+ references: string[];
17
+ }
18
+ export declare function findGuide(ruleId: string): RemediationGuide | undefined;
19
+ export declare function listGuides(): RemediationGuide[];
20
+ export declare function runRemediationGuide(argv: string[]): void;
21
+ //# sourceMappingURL=remediation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../../src/commands/remediation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA6KD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGtE;AAED,wBAAgB,UAAU,IAAI,gBAAgB,EAAE,CAE/C;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAmFxD"}