@kevinrabun/judges 3.47.0 → 3.49.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 (70) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +112 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/audit-trail.d.ts +18 -0
  6. package/dist/commands/audit-trail.d.ts.map +1 -0
  7. package/dist/commands/audit-trail.js +155 -0
  8. package/dist/commands/audit-trail.js.map +1 -0
  9. package/dist/commands/auto-fix.d.ts +18 -0
  10. package/dist/commands/auto-fix.d.ts.map +1 -0
  11. package/dist/commands/auto-fix.js +241 -0
  12. package/dist/commands/auto-fix.js.map +1 -0
  13. package/dist/commands/dep-correlate.d.ts +9 -0
  14. package/dist/commands/dep-correlate.d.ts.map +1 -0
  15. package/dist/commands/dep-correlate.js +208 -0
  16. package/dist/commands/dep-correlate.js.map +1 -0
  17. package/dist/commands/doc-gen.d.ts +8 -0
  18. package/dist/commands/doc-gen.d.ts.map +1 -0
  19. package/dist/commands/doc-gen.js +209 -0
  20. package/dist/commands/doc-gen.js.map +1 -0
  21. package/dist/commands/incident-response.d.ts +8 -0
  22. package/dist/commands/incident-response.d.ts.map +1 -0
  23. package/dist/commands/incident-response.js +255 -0
  24. package/dist/commands/incident-response.js.map +1 -0
  25. package/dist/commands/judge-author.d.ts +8 -0
  26. package/dist/commands/judge-author.d.ts.map +1 -0
  27. package/dist/commands/judge-author.js +261 -0
  28. package/dist/commands/judge-author.js.map +1 -0
  29. package/dist/commands/learning-path.d.ts +9 -0
  30. package/dist/commands/learning-path.d.ts.map +1 -0
  31. package/dist/commands/learning-path.js +326 -0
  32. package/dist/commands/learning-path.js.map +1 -0
  33. package/dist/commands/license-scan.d.ts +9 -0
  34. package/dist/commands/license-scan.d.ts.map +1 -0
  35. package/dist/commands/license-scan.js +180 -0
  36. package/dist/commands/license-scan.js.map +1 -0
  37. package/dist/commands/org-policy.d.ts +8 -0
  38. package/dist/commands/org-policy.d.ts.map +1 -0
  39. package/dist/commands/org-policy.js +208 -0
  40. package/dist/commands/org-policy.js.map +1 -0
  41. package/dist/commands/pattern-registry.d.ts +23 -0
  42. package/dist/commands/pattern-registry.d.ts.map +1 -0
  43. package/dist/commands/pattern-registry.js +227 -0
  44. package/dist/commands/pattern-registry.js.map +1 -0
  45. package/dist/commands/perf-hotspot.d.ts +8 -0
  46. package/dist/commands/perf-hotspot.d.ts.map +1 -0
  47. package/dist/commands/perf-hotspot.js +274 -0
  48. package/dist/commands/perf-hotspot.js.map +1 -0
  49. package/dist/commands/predict.d.ts +8 -0
  50. package/dist/commands/predict.d.ts.map +1 -0
  51. package/dist/commands/predict.js +219 -0
  52. package/dist/commands/predict.js.map +1 -0
  53. package/dist/commands/risk-heatmap.d.ts +8 -0
  54. package/dist/commands/risk-heatmap.d.ts.map +1 -0
  55. package/dist/commands/risk-heatmap.js +224 -0
  56. package/dist/commands/risk-heatmap.js.map +1 -0
  57. package/dist/commands/sbom-export.d.ts +8 -0
  58. package/dist/commands/sbom-export.d.ts.map +1 -0
  59. package/dist/commands/sbom-export.js +162 -0
  60. package/dist/commands/sbom-export.js.map +1 -0
  61. package/dist/commands/security-maturity.d.ts +8 -0
  62. package/dist/commands/security-maturity.d.ts.map +1 -0
  63. package/dist/commands/security-maturity.js +313 -0
  64. package/dist/commands/security-maturity.js.map +1 -0
  65. package/dist/commands/test-correlate.d.ts +8 -0
  66. package/dist/commands/test-correlate.d.ts.map +1 -0
  67. package/dist/commands/test-correlate.js +222 -0
  68. package/dist/commands/test-correlate.js.map +1 -0
  69. package/package.json +1 -1
  70. package/server.json +2 -2
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Audit trail — chain-of-custody tracking for findings,
3
+ * recording who reviewed, voted, suppressed, or resolved each finding.
4
+ *
5
+ * All data stored locally in .judges-audit-trail/.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
8
+ import { join } from "path";
9
+ const TRAIL_DIR = ".judges-audit-trail";
10
+ const TRAIL_FILE = join(TRAIL_DIR, "trail.json");
11
+ // ─── Core ───────────────────────────────────────────────────────────────────
12
+ function ensureDir() {
13
+ if (!existsSync(TRAIL_DIR))
14
+ mkdirSync(TRAIL_DIR, { recursive: true });
15
+ }
16
+ function loadStore() {
17
+ if (!existsSync(TRAIL_FILE))
18
+ return { events: [], updatedAt: new Date().toISOString() };
19
+ try {
20
+ return JSON.parse(readFileSync(TRAIL_FILE, "utf-8"));
21
+ }
22
+ catch {
23
+ return { events: [], updatedAt: new Date().toISOString() };
24
+ }
25
+ }
26
+ function saveStore(store) {
27
+ ensureDir();
28
+ store.updatedAt = new Date().toISOString();
29
+ writeFileSync(TRAIL_FILE, JSON.stringify(store, null, 2));
30
+ }
31
+ function generateId() {
32
+ return `evt-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
33
+ }
34
+ export function recordEvent(findingId, action, actor, detail) {
35
+ const event = {
36
+ id: generateId(),
37
+ findingId,
38
+ action,
39
+ actor,
40
+ detail,
41
+ timestamp: new Date().toISOString(),
42
+ };
43
+ const store = loadStore();
44
+ store.events.push(event);
45
+ if (store.events.length > 2000)
46
+ store.events = store.events.slice(-2000);
47
+ saveStore(store);
48
+ return event;
49
+ }
50
+ // ─── CLI ────────────────────────────────────────────────────────────────────
51
+ export function runAuditTrail(argv) {
52
+ if (argv.includes("--help") || argv.includes("-h")) {
53
+ console.log(`
54
+ judges audit-trail — Finding chain-of-custody tracking
55
+
56
+ Usage:
57
+ judges audit-trail --record --finding SEC-001 --action reviewed --actor "alice@co.com" --detail "Confirmed valid"
58
+ judges audit-trail --finding SEC-001
59
+ judges audit-trail --actor "alice@co.com"
60
+ judges audit-trail --summary
61
+ judges audit-trail --export
62
+
63
+ Options:
64
+ --record Record a new audit event
65
+ --finding <id> Filter by finding/rule ID
66
+ --action <type> Event type: created, reviewed, suppressed, resolved, reopened, escalated, voted
67
+ --actor <name> Who performed the action
68
+ --detail <text> Additional context
69
+ --summary Show audit trail summary
70
+ --export Export full audit trail
71
+ --format json JSON output
72
+ --help, -h Show this help
73
+ `);
74
+ return;
75
+ }
76
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
77
+ // Record event
78
+ if (argv.includes("--record")) {
79
+ const finding = argv.find((_a, i) => argv[i - 1] === "--finding") || "unknown";
80
+ const action = (argv.find((_a, i) => argv[i - 1] === "--action") ||
81
+ "reviewed");
82
+ const actor = argv.find((_a, i) => argv[i - 1] === "--actor") || "anonymous";
83
+ const detail = argv.find((_a, i) => argv[i - 1] === "--detail") || "";
84
+ const event = recordEvent(finding, action, actor, detail);
85
+ if (format === "json") {
86
+ console.log(JSON.stringify(event, null, 2));
87
+ }
88
+ else {
89
+ console.log(` ✅ Audit event recorded: ${event.id}`);
90
+ console.log(` ${event.action} ${event.findingId} by ${event.actor}`);
91
+ }
92
+ return;
93
+ }
94
+ // Summary
95
+ if (argv.includes("--summary")) {
96
+ const store = loadStore();
97
+ const actionCounts = new Map();
98
+ const actorCounts = new Map();
99
+ for (const e of store.events) {
100
+ actionCounts.set(e.action, (actionCounts.get(e.action) || 0) + 1);
101
+ actorCounts.set(e.actor, (actorCounts.get(e.actor) || 0) + 1);
102
+ }
103
+ if (format === "json") {
104
+ console.log(JSON.stringify({
105
+ totalEvents: store.events.length,
106
+ actions: Object.fromEntries(actionCounts),
107
+ actors: Object.fromEntries(actorCounts),
108
+ }, null, 2));
109
+ }
110
+ else {
111
+ console.log(`\n Audit Trail Summary\n ──────────────────────────`);
112
+ console.log(` Total events: ${store.events.length}`);
113
+ if (actionCounts.size > 0) {
114
+ console.log(`\n By action:`);
115
+ for (const [action, count] of actionCounts) {
116
+ console.log(` ${action.padEnd(15)} ${count}`);
117
+ }
118
+ }
119
+ if (actorCounts.size > 0) {
120
+ console.log(`\n By actor:`);
121
+ for (const [actor, count] of actorCounts) {
122
+ console.log(` ${actor.padEnd(25)} ${count} events`);
123
+ }
124
+ }
125
+ console.log("");
126
+ }
127
+ return;
128
+ }
129
+ // Export
130
+ if (argv.includes("--export")) {
131
+ const store = loadStore();
132
+ console.log(JSON.stringify(store, null, 2));
133
+ return;
134
+ }
135
+ // Filter by finding
136
+ const findingFilter = argv.find((_a, i) => argv[i - 1] === "--finding");
137
+ const actorFilter = argv.find((_a, i) => argv[i - 1] === "--actor");
138
+ const store = loadStore();
139
+ let events = store.events;
140
+ if (findingFilter)
141
+ events = events.filter((e) => e.findingId === findingFilter);
142
+ if (actorFilter)
143
+ events = events.filter((e) => e.actor === actorFilter);
144
+ if (format === "json") {
145
+ console.log(JSON.stringify(events, null, 2));
146
+ }
147
+ else {
148
+ console.log(`\n Audit Trail (${events.length} events)\n ──────────────────────────`);
149
+ for (const e of events.slice(-20)) {
150
+ console.log(` ${e.timestamp.slice(0, 16)} ${e.action.padEnd(12)} ${e.findingId.padEnd(12)} ${e.actor} ${e.detail ? `— ${e.detail}` : ""}`);
151
+ }
152
+ console.log("");
153
+ }
154
+ }
155
+ //# sourceMappingURL=audit-trail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-trail.js","sourceRoot":"","sources":["../../src/commands/audit-trail.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAkB5B,MAAM,SAAS,GAAG,qBAAqB,CAAC;AACxC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAEjD,+EAA+E;AAE/E,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IACxF,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAsB;IACvC,SAAS,EAAE,CAAC;IACZ,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,SAAiB,EACjB,MAA4B,EAC5B,KAAa,EACb,MAAc;IAEd,MAAM,KAAK,GAAe;QACxB,EAAE,EAAE,UAAU,EAAE;QAChB,SAAS;QACT,MAAM;QACN,KAAK;QACL,MAAM;QACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI;QAAE,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IACzE,SAAS,CAAC,KAAK,CAAC,CAAC;IAEjB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;CAoBf,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;IAE1F,eAAe;IACf,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,WAAW,CAAC,IAAI,SAAS,CAAC;QAC/F,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC;YAC9E,UAAU,CAAyB,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,WAAW,CAAC;QAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;QAEtF,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,6BAA6B,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO;IACT,CAAC;IAED,UAAU;IACV,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC/C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;gBACE,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;gBAChC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC;gBACzC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC;aACxC,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;YACrE,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACtD,IAAI,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;gBAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;oBAC3C,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YACD,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBAC7B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;oBACzC,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,SAAS;IACT,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,oBAAoB;IACpB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC;IACxF,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAEpF,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,IAAI,aAAa;QAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,aAAa,CAAC,CAAC;IAChF,IAAI,WAAW;QAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC;IAExE,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,MAAM,wCAAwC,CAAC,CAAC;QACvF,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CACT,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAClI,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Auto-fix — generates safe, automated fix suggestions for
3
+ * common finding patterns. All processing is local.
4
+ */
5
+ interface FixSuggestion {
6
+ ruleId: string;
7
+ title: string;
8
+ file: string;
9
+ line: number;
10
+ before: string;
11
+ after: string;
12
+ confidence: number;
13
+ timestamp: string;
14
+ }
15
+ export declare function suggestFix(ruleId: string, file: string, line: number): FixSuggestion | null;
16
+ export declare function runAutoFix(argv: string[]): void;
17
+ export {};
18
+ //# sourceMappingURL=auto-fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-fix.d.ts","sourceRoot":"","sources":["../../src/commands/auto-fix.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqHD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAqB3F;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoH/C"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Auto-fix — generates safe, automated fix suggestions for
3
+ * common finding patterns. All processing is local.
4
+ */
5
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
6
+ import { join } from "path";
7
+ const FIX_DIR = ".judges-auto-fix";
8
+ const FIX_FILE = join(FIX_DIR, "fix-history.json");
9
+ // ─── Fix template library ───────────────────────────────────────────────────
10
+ const FIX_TEMPLATES = [
11
+ {
12
+ rulePattern: "SQL-",
13
+ title: "Use parameterized queries",
14
+ description: "Replace string concatenation in SQL with parameterized queries",
15
+ before: 'db.query("SELECT * FROM users WHERE id = " + userId)',
16
+ after: 'db.query("SELECT * FROM users WHERE id = $1", [userId])',
17
+ language: "typescript",
18
+ },
19
+ {
20
+ rulePattern: "XSS-",
21
+ title: "Use textContent instead of innerHTML",
22
+ description: "Replace innerHTML with textContent to prevent XSS",
23
+ before: "element.innerHTML = userInput",
24
+ after: "element.textContent = userInput",
25
+ language: "typescript",
26
+ },
27
+ {
28
+ rulePattern: "CMD-",
29
+ title: "Use execFile with argument array",
30
+ description: "Replace exec with execFile and separate arguments",
31
+ before: 'exec("git " + command)',
32
+ after: 'execFile("git", [command])',
33
+ language: "typescript",
34
+ },
35
+ {
36
+ rulePattern: "CRYPTO-",
37
+ title: "Replace MD5 with SHA-256",
38
+ description: "Use cryptographically secure hash function",
39
+ before: "crypto.createHash('md5').update(data).digest('hex')",
40
+ after: "crypto.createHash('sha256').update(data).digest('hex')",
41
+ language: "typescript",
42
+ },
43
+ {
44
+ rulePattern: "AUTH-",
45
+ title: "Add bcrypt password hashing",
46
+ description: "Hash passwords with bcrypt instead of plaintext storage",
47
+ before: "user.password = password",
48
+ after: "user.password = await bcrypt.hash(password, 12)",
49
+ language: "typescript",
50
+ },
51
+ {
52
+ rulePattern: "SEC-",
53
+ title: "Validate input before use",
54
+ description: "Add input validation before processing user data",
55
+ before: "const data = req.body",
56
+ after: "const data = validateInput(req.body, schema)",
57
+ language: "typescript",
58
+ },
59
+ {
60
+ rulePattern: "SSRF-",
61
+ title: "Validate URL against allowlist",
62
+ description: "Check URL against trusted domains before requesting",
63
+ before: "await fetch(userUrl)",
64
+ after: "if (isAllowedUrl(userUrl)) await fetch(userUrl)",
65
+ language: "typescript",
66
+ },
67
+ {
68
+ rulePattern: "PATH-",
69
+ title: "Sanitize file path",
70
+ description: "Resolve and validate file path within allowed directory",
71
+ before: 'readFileSync(userPath, "utf-8")',
72
+ after: 'readFileSync(path.resolve(SAFE_DIR, path.basename(userPath)), "utf-8")',
73
+ language: "typescript",
74
+ },
75
+ {
76
+ rulePattern: "ERR-",
77
+ title: "Use safe error response",
78
+ description: "Return generic error message instead of stack trace",
79
+ before: "res.status(500).json({ error: err.stack })",
80
+ after: 'res.status(500).json({ error: "Internal server error" })',
81
+ language: "typescript",
82
+ },
83
+ {
84
+ rulePattern: "CORS-",
85
+ title: "Restrict CORS origins",
86
+ description: "Replace wildcard CORS with specific trusted origins",
87
+ before: 'cors({ origin: "*" })',
88
+ after: 'cors({ origin: ["https://app.example.com"] })',
89
+ language: "typescript",
90
+ },
91
+ ];
92
+ // ─── Core ───────────────────────────────────────────────────────────────────
93
+ function ensureDir() {
94
+ if (!existsSync(FIX_DIR))
95
+ mkdirSync(FIX_DIR, { recursive: true });
96
+ }
97
+ function loadStore() {
98
+ if (!existsSync(FIX_FILE))
99
+ return { suggestions: [], applied: 0, updatedAt: new Date().toISOString() };
100
+ try {
101
+ return JSON.parse(readFileSync(FIX_FILE, "utf-8"));
102
+ }
103
+ catch {
104
+ return { suggestions: [], applied: 0, updatedAt: new Date().toISOString() };
105
+ }
106
+ }
107
+ function saveStore(store) {
108
+ ensureDir();
109
+ store.updatedAt = new Date().toISOString();
110
+ writeFileSync(FIX_FILE, JSON.stringify(store, null, 2));
111
+ }
112
+ export function suggestFix(ruleId, file, line) {
113
+ const template = FIX_TEMPLATES.find((t) => ruleId.startsWith(t.rulePattern));
114
+ if (!template)
115
+ return null;
116
+ const suggestion = {
117
+ ruleId,
118
+ title: template.title,
119
+ file,
120
+ line,
121
+ before: template.before,
122
+ after: template.after,
123
+ confidence: 75,
124
+ timestamp: new Date().toISOString(),
125
+ };
126
+ const store = loadStore();
127
+ store.suggestions.push(suggestion);
128
+ if (store.suggestions.length > 500)
129
+ store.suggestions = store.suggestions.slice(-500);
130
+ saveStore(store);
131
+ return suggestion;
132
+ }
133
+ // ─── CLI ────────────────────────────────────────────────────────────────────
134
+ export function runAutoFix(argv) {
135
+ if (argv.includes("--help") || argv.includes("-h")) {
136
+ console.log(`
137
+ judges auto-fix — Automated fix suggestions for findings
138
+
139
+ Usage:
140
+ judges auto-fix --rule SQL-001 --file src/db.ts --line 42
141
+ judges auto-fix --catalog
142
+ judges auto-fix --history
143
+ judges auto-fix --stats
144
+
145
+ Options:
146
+ --rule <id> Rule ID to generate fix for
147
+ --file <path> File containing the finding
148
+ --line <n> Line number of the finding
149
+ --catalog Show all available fix templates
150
+ --history Show past fix suggestions
151
+ --stats Show fix statistics
152
+ --format json JSON output
153
+ --help, -h Show this help
154
+ `);
155
+ return;
156
+ }
157
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
158
+ // Catalog
159
+ if (argv.includes("--catalog")) {
160
+ if (format === "json") {
161
+ console.log(JSON.stringify(FIX_TEMPLATES, null, 2));
162
+ }
163
+ else {
164
+ console.log(`\n Fix Template Catalog (${FIX_TEMPLATES.length})\n ──────────────────────────`);
165
+ for (const t of FIX_TEMPLATES) {
166
+ console.log(` [${t.rulePattern.padEnd(8)}] ${t.title}`);
167
+ console.log(` Before: ${t.before}`);
168
+ console.log(` After: ${t.after}`);
169
+ console.log("");
170
+ }
171
+ }
172
+ return;
173
+ }
174
+ // History
175
+ if (argv.includes("--history")) {
176
+ const store = loadStore();
177
+ if (format === "json") {
178
+ console.log(JSON.stringify(store.suggestions.slice(-20), null, 2));
179
+ }
180
+ else {
181
+ console.log(`\n Fix History (${store.suggestions.length} suggestions)\n ──────────────────────────`);
182
+ for (const s of store.suggestions.slice(-15)) {
183
+ console.log(` ${s.timestamp.slice(0, 16)} ${s.ruleId.padEnd(10)} ${s.title} ${s.file}:${s.line}`);
184
+ }
185
+ console.log("");
186
+ }
187
+ return;
188
+ }
189
+ // Stats
190
+ if (argv.includes("--stats")) {
191
+ const store = loadStore();
192
+ const byRule = new Map();
193
+ for (const s of store.suggestions) {
194
+ const prefix = s.ruleId.split("-")[0] + "-";
195
+ byRule.set(prefix, (byRule.get(prefix) || 0) + 1);
196
+ }
197
+ if (format === "json") {
198
+ console.log(JSON.stringify({ total: store.suggestions.length, applied: store.applied, byRule: Object.fromEntries(byRule) }, null, 2));
199
+ }
200
+ else {
201
+ console.log(`\n Fix Statistics\n ──────────────────────────`);
202
+ console.log(` Total suggestions: ${store.suggestions.length}`);
203
+ console.log(` Applied: ${store.applied}`);
204
+ if (byRule.size > 0) {
205
+ console.log(`\n By category:`);
206
+ for (const [rule, count] of byRule) {
207
+ console.log(` ${rule.padEnd(10)} ${count} suggestions`);
208
+ }
209
+ }
210
+ console.log("");
211
+ }
212
+ return;
213
+ }
214
+ // Suggest fix
215
+ const ruleId = argv.find((_a, i) => argv[i - 1] === "--rule");
216
+ const file = argv.find((_a, i) => argv[i - 1] === "--file");
217
+ const line = parseInt(argv.find((_a, i) => argv[i - 1] === "--line") || "1", 10);
218
+ if (!ruleId) {
219
+ console.error(" Use --rule <id>, --catalog, --history, or --stats. --help for usage.");
220
+ return;
221
+ }
222
+ const suggestion = suggestFix(ruleId, file || "unknown", line);
223
+ if (!suggestion) {
224
+ console.log(` No fix template for rule: ${ruleId}`);
225
+ console.log(` Available patterns: ${FIX_TEMPLATES.map((t) => t.rulePattern).join(", ")}`);
226
+ return;
227
+ }
228
+ if (format === "json") {
229
+ console.log(JSON.stringify(suggestion, null, 2));
230
+ }
231
+ else {
232
+ console.log(`\n Fix Suggestion — ${suggestion.ruleId}`);
233
+ console.log(` ──────────────────────────`);
234
+ console.log(` Title: ${suggestion.title}`);
235
+ console.log(` File: ${suggestion.file}:${suggestion.line}`);
236
+ console.log(`\n Before: ${suggestion.before}`);
237
+ console.log(` After: ${suggestion.after}`);
238
+ console.log(`\n Confidence: ${suggestion.confidence}%\n`);
239
+ }
240
+ }
241
+ //# sourceMappingURL=auto-fix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-fix.js","sourceRoot":"","sources":["../../src/commands/auto-fix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Dependency vulnerability correlation — cross-references
3
+ * Judges findings with dependency versions to identify which
4
+ * dependencies contribute the most security findings.
5
+ *
6
+ * All data from local files (package.json, lock files).
7
+ */
8
+ export declare function runDepCorrelate(argv: string[]): void;
9
+ //# sourceMappingURL=dep-correlate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dep-correlate.d.ts","sourceRoot":"","sources":["../../src/commands/dep-correlate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiKH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsFpD"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Dependency vulnerability correlation — cross-references
3
+ * Judges findings with dependency versions to identify which
4
+ * dependencies contribute the most security findings.
5
+ *
6
+ * All data from local files (package.json, lock files).
7
+ */
8
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
9
+ import { join } from "path";
10
+ // ─── Dep parsing ────────────────────────────────────────────────────────────
11
+ function loadDeps() {
12
+ const deps = [];
13
+ // package.json (npm)
14
+ if (existsSync("package.json")) {
15
+ try {
16
+ const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
17
+ for (const [name, ver] of Object.entries(pkg.dependencies || {})) {
18
+ deps.push({ name, version: String(ver), type: "dependency" });
19
+ }
20
+ for (const [name, ver] of Object.entries(pkg.devDependencies || {})) {
21
+ deps.push({ name, version: String(ver), type: "devDependency" });
22
+ }
23
+ }
24
+ catch {
25
+ /* skip */
26
+ }
27
+ }
28
+ // requirements.txt (Python)
29
+ if (existsSync("requirements.txt")) {
30
+ try {
31
+ const lines = readFileSync("requirements.txt", "utf-8").split("\n");
32
+ for (const line of lines) {
33
+ const match = /^([a-zA-Z0-9_-]+)==(.+)/.exec(line.trim());
34
+ if (match)
35
+ deps.push({ name: match[1], version: match[2], type: "dependency" });
36
+ }
37
+ }
38
+ catch {
39
+ /* skip */
40
+ }
41
+ }
42
+ // go.mod (Go)
43
+ if (existsSync("go.mod")) {
44
+ try {
45
+ const content = readFileSync("go.mod", "utf-8");
46
+ const lines = content.split("\n");
47
+ for (const line of lines) {
48
+ const match = /^\s+([\w./-]+)\s+(v[\d.]+)/.exec(line);
49
+ if (match)
50
+ deps.push({ name: match[1], version: match[2], type: "dependency" });
51
+ }
52
+ }
53
+ catch {
54
+ /* skip */
55
+ }
56
+ }
57
+ return deps;
58
+ }
59
+ function loadFindings() {
60
+ // Try common finding output locations
61
+ const paths = [".judges-findings.json", join(".judges-audit-trail", "trail.json"), "judges-report.json"];
62
+ for (const p of paths) {
63
+ if (!existsSync(p))
64
+ continue;
65
+ try {
66
+ const data = JSON.parse(readFileSync(p, "utf-8"));
67
+ if (Array.isArray(data))
68
+ return data;
69
+ if (data.findings && Array.isArray(data.findings))
70
+ return data.findings;
71
+ if (data.events && Array.isArray(data.events)) {
72
+ return data.events
73
+ .filter((e) => e.type === "created")
74
+ .map((e) => e.finding || { ruleId: e.findingId, severity: "medium", title: String(e.findingId), description: "" });
75
+ }
76
+ }
77
+ catch {
78
+ /* skip */
79
+ }
80
+ }
81
+ return [];
82
+ }
83
+ // ─── Correlation ────────────────────────────────────────────────────────────
84
+ const KNOWN_VULN_PATTERNS = {
85
+ express: ["ssrf", "xss", "csrf", "header-injection"],
86
+ lodash: ["prototype-pollution", "command-injection"],
87
+ axios: ["ssrf", "redirect"],
88
+ jsonwebtoken: ["jwt", "auth", "token"],
89
+ helmet: ["header", "csp", "xss"],
90
+ sequelize: ["sql-injection", "nosql"],
91
+ mongoose: ["nosql-injection", "injection"],
92
+ mysql: ["sql-injection", "injection"],
93
+ pg: ["sql-injection", "injection"],
94
+ "crypto-js": ["crypto", "weak-cipher", "weak-hash"],
95
+ bcrypt: ["password", "hash"],
96
+ passport: ["auth", "authentication"],
97
+ cors: ["cors", "origin"],
98
+ multer: ["upload", "file", "path-traversal"],
99
+ child_process: ["command-injection", "exec"],
100
+ };
101
+ function correlate(deps, findings) {
102
+ const correlations = [];
103
+ for (const dep of deps) {
104
+ const patterns = KNOWN_VULN_PATTERNS[dep.name] || [];
105
+ const matched = findings.filter((f) => {
106
+ const text = `${f.ruleId} ${f.title} ${f.description || ""}`.toLowerCase();
107
+ return patterns.some((p) => text.includes(p));
108
+ });
109
+ if (matched.length > 0) {
110
+ const sevWeights = { critical: 10, high: 7, medium: 4, low: 1 };
111
+ const riskScore = matched.reduce((s, f) => s + (sevWeights[f.severity] || 2), 0);
112
+ correlations.push({
113
+ dependency: dep.name,
114
+ version: dep.version,
115
+ findingCount: matched.length,
116
+ findings: matched.map((f) => ({ ruleId: f.ruleId, severity: f.severity, title: f.title })),
117
+ riskScore,
118
+ upgradeRecommendation: riskScore > 20 ? "Urgent upgrade recommended" : riskScore > 10 ? "Upgrade recommended" : "Monitor",
119
+ });
120
+ }
121
+ }
122
+ return correlations.sort((a, b) => b.riskScore - a.riskScore);
123
+ }
124
+ // ─── CLI ────────────────────────────────────────────────────────────────────
125
+ const STORE = ".judges-dep-correlate";
126
+ export function runDepCorrelate(argv) {
127
+ if (argv.includes("--help") || argv.includes("-h")) {
128
+ console.log(`
129
+ judges dep-correlate — Dependency vulnerability correlation
130
+
131
+ Usage:
132
+ judges dep-correlate
133
+ judges dep-correlate --deps
134
+ judges dep-correlate --top 5
135
+
136
+ Options:
137
+ --deps List detected dependencies
138
+ --top <n> Show top N riskiest dependencies
139
+ --save Save report to ${STORE}/
140
+ --format json JSON output
141
+ --help, -h Show this help
142
+ `);
143
+ return;
144
+ }
145
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
146
+ const deps = loadDeps();
147
+ // List deps only
148
+ if (argv.includes("--deps")) {
149
+ if (format === "json") {
150
+ console.log(JSON.stringify(deps, null, 2));
151
+ }
152
+ else {
153
+ console.log(`\n Dependencies (${deps.length})\n ──────────────────────────`);
154
+ for (const d of deps) {
155
+ console.log(` ${d.name.padEnd(30)} ${d.version.padEnd(15)} ${d.type}`);
156
+ }
157
+ console.log("");
158
+ }
159
+ return;
160
+ }
161
+ if (deps.length === 0) {
162
+ console.log(" No dependencies found. Supports: package.json, requirements.txt, go.mod");
163
+ return;
164
+ }
165
+ const findings = loadFindings();
166
+ const correlations = correlate(deps, findings);
167
+ const topN = argv.find((_a, i) => argv[i - 1] === "--top");
168
+ const limit = topN ? parseInt(topN, 10) : correlations.length;
169
+ const report = {
170
+ correlations: correlations.slice(0, limit),
171
+ totalDeps: deps.length,
172
+ depsWithFindings: correlations.length,
173
+ timestamp: new Date().toISOString(),
174
+ };
175
+ // Save
176
+ if (argv.includes("--save")) {
177
+ if (!existsSync(STORE))
178
+ mkdirSync(STORE, { recursive: true });
179
+ writeFileSync(join(STORE, "correlation-report.json"), JSON.stringify(report, null, 2));
180
+ console.log(` Saved to ${STORE}/correlation-report.json`);
181
+ }
182
+ if (format === "json") {
183
+ console.log(JSON.stringify(report, null, 2));
184
+ }
185
+ else {
186
+ console.log(`\n Dependency Vulnerability Correlation`);
187
+ console.log(` Total dependencies: ${report.totalDeps} With correlated findings: ${report.depsWithFindings}`);
188
+ console.log(` ──────────────────────────`);
189
+ if (report.correlations.length === 0) {
190
+ console.log(` ✅ No dependency-finding correlations detected`);
191
+ if (findings.length === 0)
192
+ console.log(` (No findings data found — run a scan first)`);
193
+ console.log("");
194
+ return;
195
+ }
196
+ for (const c of report.correlations) {
197
+ console.log(`\n ${c.dependency}@${c.version} Risk: ${c.riskScore} Findings: ${c.findingCount}`);
198
+ console.log(` Recommendation: ${c.upgradeRecommendation}`);
199
+ for (const f of c.findings.slice(0, 3)) {
200
+ console.log(` - [${f.severity.toUpperCase()}] ${f.ruleId}: ${f.title}`);
201
+ }
202
+ if (c.findings.length > 3)
203
+ console.log(` ... and ${c.findings.length - 3} more`);
204
+ }
205
+ console.log("");
206
+ }
207
+ }
208
+ //# sourceMappingURL=dep-correlate.js.map