@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,219 @@
1
+ /**
2
+ * Predict — applies trend analysis to finding snapshots to
3
+ * forecast remediation timelines and regression-prone files.
4
+ *
5
+ * All data from local snapshot history.
6
+ */
7
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
8
+ import { join } from "path";
9
+ // ─── Analysis ───────────────────────────────────────────────────────────────
10
+ function loadSnapshots() {
11
+ const paths = [
12
+ join(".judges-snapshots", "history.json"),
13
+ ".judges-snapshots.json",
14
+ join(".judges-burndown", "snapshots.json"),
15
+ ];
16
+ for (const p of paths) {
17
+ if (!existsSync(p))
18
+ continue;
19
+ try {
20
+ const data = JSON.parse(readFileSync(p, "utf-8"));
21
+ if (Array.isArray(data))
22
+ return data;
23
+ if (data.snapshots)
24
+ return data.snapshots;
25
+ }
26
+ catch {
27
+ /* skip */
28
+ }
29
+ }
30
+ return [];
31
+ }
32
+ function linearRegression(points) {
33
+ const n = points.length;
34
+ if (n < 2)
35
+ return { slope: 0, intercept: points[0]?.y || 0, r2: 0 };
36
+ const sumX = points.reduce((s, p) => s + p.x, 0);
37
+ const sumY = points.reduce((s, p) => s + p.y, 0);
38
+ const sumXY = points.reduce((s, p) => s + p.x * p.y, 0);
39
+ const sumX2 = points.reduce((s, p) => s + p.x * p.x, 0);
40
+ const sumY2 = points.reduce((s, p) => s + p.y * p.y, 0);
41
+ const denom = n * sumX2 - sumX * sumX;
42
+ if (denom === 0)
43
+ return { slope: 0, intercept: sumY / n, r2: 0 };
44
+ const slope = (n * sumXY - sumX * sumY) / denom;
45
+ const intercept = (sumY - slope * sumX) / n;
46
+ // R²
47
+ const yMean = sumY / n;
48
+ const ssTot = sumY2 - n * yMean * yMean;
49
+ const ssRes = points.reduce((s, p) => s + Math.pow(p.y - (slope * p.x + intercept), 2), 0);
50
+ const r2 = ssTot === 0 ? 0 : Math.max(0, 1 - ssRes / ssTot);
51
+ return { slope, intercept, r2 };
52
+ }
53
+ function predictMetric(snapshots, field) {
54
+ if (snapshots.length < 2) {
55
+ return {
56
+ metric: field,
57
+ currentValue: snapshots[0]?.[field] || 0,
58
+ trend: "stable",
59
+ ratePerDay: 0,
60
+ estimatedZeroDate: null,
61
+ confidence: 0,
62
+ };
63
+ }
64
+ const t0 = new Date(snapshots[0].timestamp).getTime();
65
+ const points = snapshots.map((s) => ({
66
+ x: (new Date(s.timestamp).getTime() - t0) / (1000 * 60 * 60 * 24), // days
67
+ y: s[field],
68
+ }));
69
+ const { slope, r2 } = linearRegression(points);
70
+ const current = points[points.length - 1].y;
71
+ let trend = "stable";
72
+ if (slope < -0.1)
73
+ trend = "decreasing";
74
+ else if (slope > 0.1)
75
+ trend = "increasing";
76
+ let estimatedZeroDate = null;
77
+ if (slope < 0 && current > 0) {
78
+ const daysToZero = -current / slope;
79
+ const zeroDate = new Date(Date.now() + daysToZero * 24 * 60 * 60 * 1000);
80
+ estimatedZeroDate = zeroDate.toISOString().split("T")[0];
81
+ }
82
+ return {
83
+ metric: field,
84
+ currentValue: current,
85
+ trend,
86
+ ratePerDay: Math.round(slope * 100) / 100,
87
+ estimatedZeroDate,
88
+ confidence: Math.round(r2 * 100),
89
+ };
90
+ }
91
+ function loadRegressionData() {
92
+ const paths = [".judges-regressions.json", join(".judges-regression-alert", "history.json")];
93
+ for (const p of paths) {
94
+ if (!existsSync(p))
95
+ continue;
96
+ try {
97
+ const data = JSON.parse(readFileSync(p, "utf-8"));
98
+ const files = Array.isArray(data) ? data : data.regressions || [];
99
+ const counts = new Map();
100
+ for (const r of files) {
101
+ const file = r.file || r.path || "unknown";
102
+ counts.set(file, (counts.get(file) || 0) + 1);
103
+ }
104
+ return [...counts.entries()]
105
+ .map(([file, count]) => ({
106
+ file,
107
+ regressionCount: count,
108
+ risk: count > 3 ? "high" : count > 1 ? "medium" : "low",
109
+ }))
110
+ .sort((a, b) => b.regressionCount - a.regressionCount);
111
+ }
112
+ catch {
113
+ /* skip */
114
+ }
115
+ }
116
+ return [];
117
+ }
118
+ // ─── CLI ────────────────────────────────────────────────────────────────────
119
+ const STORE = ".judges-predictions";
120
+ export function runPredict(argv) {
121
+ if (argv.includes("--help") || argv.includes("-h")) {
122
+ console.log(`
123
+ judges predict — Forecast remediation timelines and regression risk
124
+
125
+ Usage:
126
+ judges predict
127
+ judges predict --metric critical
128
+ judges predict --regressions
129
+ judges predict --save
130
+
131
+ Options:
132
+ --metric <name> Predict specific metric (findings, critical, high, medium, low)
133
+ --regressions Show regression-prone files prediction
134
+ --save Save predictions to ${STORE}/
135
+ --format json JSON output
136
+ --help, -h Show this help
137
+ `);
138
+ return;
139
+ }
140
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
141
+ const snapshots = loadSnapshots();
142
+ if (snapshots.length < 2 && !argv.includes("--regressions")) {
143
+ console.log(" Need at least 2 snapshots for predictions.");
144
+ console.log(" Run scans over time and they'll be recorded automatically.");
145
+ return;
146
+ }
147
+ // Single metric
148
+ const metricName = argv.find((_a, i) => argv[i - 1] === "--metric");
149
+ if (metricName) {
150
+ const pred = predictMetric(snapshots, metricName);
151
+ if (format === "json") {
152
+ console.log(JSON.stringify(pred, null, 2));
153
+ }
154
+ else {
155
+ console.log(`\n Prediction: ${pred.metric}\n ──────────────────────────`);
156
+ console.log(` Current: ${pred.currentValue}`);
157
+ console.log(` Trend: ${pred.trend} (${pred.ratePerDay >= 0 ? "+" : ""}${pred.ratePerDay}/day)`);
158
+ console.log(` Confidence: ${pred.confidence}%`);
159
+ if (pred.estimatedZeroDate)
160
+ console.log(` Estimated zero: ${pred.estimatedZeroDate}`);
161
+ console.log("");
162
+ }
163
+ return;
164
+ }
165
+ // Regressions
166
+ if (argv.includes("--regressions")) {
167
+ const regressions = loadRegressionData();
168
+ if (format === "json") {
169
+ console.log(JSON.stringify(regressions, null, 2));
170
+ }
171
+ else {
172
+ console.log(`\n Regression-Prone Files\n ──────────────────────────`);
173
+ if (regressions.length === 0) {
174
+ console.log(` No regression data found.\n`);
175
+ return;
176
+ }
177
+ for (const r of regressions.slice(0, 15)) {
178
+ console.log(` [${r.risk.toUpperCase().padEnd(6)}] ${r.file} (${r.regressionCount} regressions)`);
179
+ }
180
+ console.log("");
181
+ }
182
+ return;
183
+ }
184
+ // Full prediction
185
+ const metrics = ["findings", "critical", "high", "medium", "low"];
186
+ const predictions = metrics.map((m) => predictMetric(snapshots, m));
187
+ const regressions = loadRegressionData();
188
+ const report = {
189
+ predictions,
190
+ regressionRisk: regressions.slice(0, 10),
191
+ timestamp: new Date().toISOString(),
192
+ };
193
+ if (argv.includes("--save")) {
194
+ if (!existsSync(STORE))
195
+ mkdirSync(STORE, { recursive: true });
196
+ writeFileSync(join(STORE, "prediction-report.json"), JSON.stringify(report, null, 2));
197
+ console.log(` Saved to ${STORE}/prediction-report.json`);
198
+ }
199
+ if (format === "json") {
200
+ console.log(JSON.stringify(report, null, 2));
201
+ }
202
+ else {
203
+ console.log(`\n Prediction Report (${snapshots.length} snapshots)`);
204
+ console.log(` ──────────────────────────`);
205
+ for (const p of predictions) {
206
+ const arrow = p.trend === "decreasing" ? "↓" : p.trend === "increasing" ? "↑" : "→";
207
+ const zero = p.estimatedZeroDate ? ` → zero by ${p.estimatedZeroDate}` : "";
208
+ console.log(` ${p.metric.padEnd(12)} ${String(p.currentValue).padEnd(6)} ${arrow} ${p.ratePerDay >= 0 ? "+" : ""}${p.ratePerDay}/day (${p.confidence}% conf)${zero}`);
209
+ }
210
+ if (regressions.length > 0) {
211
+ console.log(`\n Regression-Prone Files:`);
212
+ for (const r of regressions.slice(0, 5)) {
213
+ console.log(` [${r.risk.toUpperCase().padEnd(6)}] ${r.file}`);
214
+ }
215
+ }
216
+ console.log("");
217
+ }
218
+ }
219
+ //# sourceMappingURL=predict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predict.js","sourceRoot":"","sources":["../../src/commands/predict.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Risk heatmap — generates a file/directory risk heatmap
3
+ * combining finding density, severity, and test coverage.
4
+ *
5
+ * All data from local files.
6
+ */
7
+ export declare function runRiskHeatmap(argv: string[]): void;
8
+ //# sourceMappingURL=risk-heatmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk-heatmap.d.ts","sourceRoot":"","sources":["../../src/commands/risk-heatmap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwJH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+FnD"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Risk heatmap — generates a file/directory risk heatmap
3
+ * combining finding density, severity, and test coverage.
4
+ *
5
+ * All data from local files.
6
+ */
7
+ import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } from "fs";
8
+ import { join, dirname, relative } from "path";
9
+ // ─── Data Loading ───────────────────────────────────────────────────────────
10
+ function loadFindings() {
11
+ const paths = [".judges-findings.json", "judges-report.json"];
12
+ for (const p of paths) {
13
+ if (!existsSync(p))
14
+ continue;
15
+ try {
16
+ const data = JSON.parse(readFileSync(p, "utf-8"));
17
+ if (Array.isArray(data))
18
+ return data;
19
+ if (data.findings)
20
+ return data.findings;
21
+ }
22
+ catch {
23
+ /* skip */
24
+ }
25
+ }
26
+ return [];
27
+ }
28
+ function getProjectFiles(dir, maxFiles) {
29
+ const result = [];
30
+ const skipDirs = new Set(["node_modules", ".git", "dist", "build", "coverage", ".next", "__pycache__"]);
31
+ function walk(d) {
32
+ if (result.length >= maxFiles)
33
+ return;
34
+ let names;
35
+ try {
36
+ names = readdirSync(d);
37
+ }
38
+ catch {
39
+ return;
40
+ }
41
+ for (const name of names) {
42
+ if (result.length >= maxFiles)
43
+ return;
44
+ if (skipDirs.has(name))
45
+ continue;
46
+ const full = join(d, name);
47
+ try {
48
+ const sub = readdirSync(full);
49
+ void sub;
50
+ walk(full);
51
+ }
52
+ catch {
53
+ result.push(relative(dir, full));
54
+ }
55
+ }
56
+ }
57
+ walk(dir);
58
+ return result;
59
+ }
60
+ // ─── Heatmap ────────────────────────────────────────────────────────────────
61
+ function buildHeatmap(findings) {
62
+ const fileMap = new Map();
63
+ for (const f of findings) {
64
+ const file = f.file || "unknown";
65
+ if (!fileMap.has(file))
66
+ fileMap.set(file, { findings: 0, critical: 0, high: 0 });
67
+ const entry = fileMap.get(file);
68
+ entry.findings++;
69
+ if (f.severity === "critical")
70
+ entry.critical++;
71
+ if (f.severity === "high")
72
+ entry.high++;
73
+ }
74
+ // Also aggregate by directory
75
+ const dirMap = new Map();
76
+ for (const [file, data] of fileMap) {
77
+ const dir = dirname(file);
78
+ if (!dirMap.has(dir))
79
+ dirMap.set(dir, { findings: 0, critical: 0, high: 0 });
80
+ const entry = dirMap.get(dir);
81
+ entry.findings += data.findings;
82
+ entry.critical += data.critical;
83
+ entry.high += data.high;
84
+ }
85
+ const entries = [];
86
+ for (const [path, data] of [...fileMap, ...dirMap]) {
87
+ const riskScore = data.critical * 10 + data.high * 5 + (data.findings - data.critical - data.high) * 2;
88
+ let riskLevel = "clean";
89
+ if (riskScore > 30)
90
+ riskLevel = "critical";
91
+ else if (riskScore > 15)
92
+ riskLevel = "high";
93
+ else if (riskScore > 5)
94
+ riskLevel = "medium";
95
+ else if (riskScore > 0)
96
+ riskLevel = "low";
97
+ entries.push({
98
+ path,
99
+ findingCount: data.findings,
100
+ criticalCount: data.critical,
101
+ highCount: data.high,
102
+ riskScore,
103
+ riskLevel,
104
+ });
105
+ }
106
+ return entries.sort((a, b) => b.riskScore - a.riskScore);
107
+ }
108
+ function renderHeatmapHtml(entries) {
109
+ const rows = entries
110
+ .slice(0, 50)
111
+ .map((e) => {
112
+ const color = e.riskLevel === "critical"
113
+ ? "#dc3545"
114
+ : e.riskLevel === "high"
115
+ ? "#fd7e14"
116
+ : e.riskLevel === "medium"
117
+ ? "#ffc107"
118
+ : e.riskLevel === "low"
119
+ ? "#28a745"
120
+ : "#6c757d";
121
+ return `<tr><td>${e.path}</td><td style="background:${color};color:white;text-align:center">${e.riskScore}</td><td>${e.findingCount}</td><td>${e.criticalCount}</td><td>${e.highCount}</td></tr>`;
122
+ })
123
+ .join("\n");
124
+ return `<!DOCTYPE html>
125
+ <html><head><title>Risk Heatmap</title>
126
+ <style>body{font-family:system-ui;margin:2rem}table{border-collapse:collapse;width:100%}th,td{padding:8px 12px;border:1px solid #ddd;text-align:left}th{background:#f5f5f5}tr:hover{background:#f0f0f0}</style>
127
+ </head><body>
128
+ <h1>Risk Heatmap</h1>
129
+ <p>Generated: ${new Date().toISOString()}</p>
130
+ <table><thead><tr><th>Path</th><th>Risk Score</th><th>Findings</th><th>Critical</th><th>High</th></tr></thead>
131
+ <tbody>${rows}</tbody></table>
132
+ </body></html>`;
133
+ }
134
+ // ─── CLI ────────────────────────────────────────────────────────────────────
135
+ const STORE = ".judges-risk-heatmap";
136
+ export function runRiskHeatmap(argv) {
137
+ if (argv.includes("--help") || argv.includes("-h")) {
138
+ console.log(`
139
+ judges risk-heatmap — File/directory risk visualization
140
+
141
+ Usage:
142
+ judges risk-heatmap
143
+ judges risk-heatmap --risk critical,high
144
+ judges risk-heatmap --html
145
+ judges risk-heatmap --dirs-only
146
+
147
+ Options:
148
+ --risk <levels> Filter by risk level (comma-separated)
149
+ --html Generate HTML heatmap report
150
+ --dirs-only Show directory-level aggregation only
151
+ --top <n> Show top N riskiest entries
152
+ --save Save report to ${STORE}/
153
+ --format json JSON output
154
+ --help, -h Show this help
155
+ `);
156
+ return;
157
+ }
158
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
159
+ const findings = loadFindings();
160
+ if (findings.length === 0) {
161
+ console.log(" No findings data found. Run a scan first to populate findings.");
162
+ return;
163
+ }
164
+ let entries = buildHeatmap(findings);
165
+ // Filters
166
+ if (argv.includes("--dirs-only")) {
167
+ entries = entries.filter((e) => !e.path.includes(".") || e.path === ".");
168
+ }
169
+ const riskFilter = argv.find((_a, i) => argv[i - 1] === "--risk");
170
+ if (riskFilter) {
171
+ const allowed = riskFilter.split(",");
172
+ entries = entries.filter((e) => allowed.includes(e.riskLevel));
173
+ }
174
+ const topN = argv.find((_a, i) => argv[i - 1] === "--top");
175
+ if (topN)
176
+ entries = entries.slice(0, parseInt(topN, 10));
177
+ const totalFindings = findings.length;
178
+ const hotspots = entries.filter((e) => e.riskLevel === "critical").map((e) => e.path);
179
+ const _projectFiles = getProjectFiles(".", 1000);
180
+ const report = {
181
+ entries,
182
+ totalFiles: entries.length,
183
+ totalFindings,
184
+ hotspots,
185
+ timestamp: new Date().toISOString(),
186
+ };
187
+ // HTML output
188
+ if (argv.includes("--html")) {
189
+ if (!existsSync(STORE))
190
+ mkdirSync(STORE, { recursive: true });
191
+ const html = renderHeatmapHtml(entries);
192
+ const htmlPath = join(STORE, "heatmap.html");
193
+ writeFileSync(htmlPath, html);
194
+ console.log(` HTML heatmap saved to ${htmlPath}`);
195
+ return;
196
+ }
197
+ // Save
198
+ if (argv.includes("--save")) {
199
+ if (!existsSync(STORE))
200
+ mkdirSync(STORE, { recursive: true });
201
+ writeFileSync(join(STORE, "heatmap.json"), JSON.stringify(report, null, 2));
202
+ console.log(` Report saved to ${STORE}/heatmap.json`);
203
+ }
204
+ if (format === "json") {
205
+ console.log(JSON.stringify(report, null, 2));
206
+ }
207
+ else {
208
+ console.log(`\n Risk Heatmap — ${totalFindings} findings across ${entries.length} locations`);
209
+ console.log(` ──────────────────────────`);
210
+ if (hotspots.length > 0) {
211
+ console.log(`\n 🔥 Critical hotspots: ${hotspots.slice(0, 5).join(", ")}`);
212
+ }
213
+ console.log("");
214
+ for (const e of entries.slice(0, 25)) {
215
+ const bar = "█".repeat(Math.min(e.riskScore, 20));
216
+ const label = e.riskLevel.toUpperCase().padEnd(8);
217
+ console.log(` [${label}] ${e.path.padEnd(40)} ${bar} ${e.riskScore} (${e.findingCount} findings)`);
218
+ }
219
+ if (entries.length > 25)
220
+ console.log(` ... and ${entries.length - 25} more`);
221
+ console.log("");
222
+ }
223
+ }
224
+ //# sourceMappingURL=risk-heatmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk-heatmap.js","sourceRoot":"","sources":["../../src/commands/risk-heatmap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * SBOM export — generates Software Bill of Materials in
3
+ * CycloneDX-compatible JSON from project manifests.
4
+ *
5
+ * All data from local project files.
6
+ */
7
+ export declare function runSbomExport(argv: string[]): void;
8
+ //# sourceMappingURL=sbom-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sbom-export.d.ts","sourceRoot":"","sources":["../../src/commands/sbom-export.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyIH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAkDlD"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * SBOM export — generates Software Bill of Materials in
3
+ * CycloneDX-compatible JSON from project manifests.
4
+ *
5
+ * All data from local project files.
6
+ */
7
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
8
+ import { join, basename } from "path";
9
+ // ─── Parsers ────────────────────────────────────────────────────────────────
10
+ function parsePackageJson() {
11
+ if (!existsSync("package.json"))
12
+ return [];
13
+ try {
14
+ const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
15
+ const components = [];
16
+ for (const [name, ver] of Object.entries(pkg.dependencies || {})) {
17
+ components.push({
18
+ type: "library",
19
+ name,
20
+ version: String(ver).replace(/^[\^~>=<]+/, ""),
21
+ purl: `pkg:npm/${name.replace("/", "%2F")}@${String(ver).replace(/^[\^~>=<]+/, "")}`,
22
+ scope: "required",
23
+ licenses: [],
24
+ });
25
+ }
26
+ for (const [name, ver] of Object.entries(pkg.devDependencies || {})) {
27
+ components.push({
28
+ type: "library",
29
+ name,
30
+ version: String(ver).replace(/^[\^~>=<]+/, ""),
31
+ purl: `pkg:npm/${name.replace("/", "%2F")}@${String(ver).replace(/^[\^~>=<]+/, "")}`,
32
+ scope: "optional",
33
+ licenses: [],
34
+ });
35
+ }
36
+ return components;
37
+ }
38
+ catch {
39
+ return [];
40
+ }
41
+ }
42
+ function parseRequirements() {
43
+ if (!existsSync("requirements.txt"))
44
+ return [];
45
+ try {
46
+ const lines = readFileSync("requirements.txt", "utf-8").split("\n");
47
+ const components = [];
48
+ for (const line of lines) {
49
+ const match = /^([a-zA-Z0-9_-]+)==(.+)/.exec(line.trim());
50
+ if (match) {
51
+ components.push({
52
+ type: "library",
53
+ name: match[1],
54
+ version: match[2],
55
+ purl: `pkg:pypi/${match[1]}@${match[2]}`,
56
+ scope: "required",
57
+ licenses: [],
58
+ });
59
+ }
60
+ }
61
+ return components;
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ }
67
+ function parseGoMod() {
68
+ if (!existsSync("go.mod"))
69
+ return [];
70
+ try {
71
+ const lines = readFileSync("go.mod", "utf-8").split("\n");
72
+ const components = [];
73
+ for (const line of lines) {
74
+ const match = /^\s+([\w./\-@]+)\s+(v[\d.]+)/.exec(line);
75
+ if (match) {
76
+ components.push({
77
+ type: "library",
78
+ name: match[1],
79
+ version: match[2],
80
+ purl: `pkg:golang/${match[1]}@${match[2]}`,
81
+ scope: "required",
82
+ licenses: [],
83
+ });
84
+ }
85
+ }
86
+ return components;
87
+ }
88
+ catch {
89
+ return [];
90
+ }
91
+ }
92
+ function buildSbom() {
93
+ const projectName = existsSync("package.json")
94
+ ? JSON.parse(readFileSync("package.json", "utf-8")).name || basename(process.cwd())
95
+ : basename(process.cwd());
96
+ const projectVersion = existsSync("package.json")
97
+ ? JSON.parse(readFileSync("package.json", "utf-8")).version || "0.0.0"
98
+ : "0.0.0";
99
+ const components = [...parsePackageJson(), ...parseRequirements(), ...parseGoMod()];
100
+ return {
101
+ bomFormat: "CycloneDX",
102
+ specVersion: "1.5",
103
+ version: 1,
104
+ metadata: {
105
+ timestamp: new Date().toISOString(),
106
+ component: { type: "application", name: projectName, version: projectVersion },
107
+ tools: [{ name: "@kevinrabun/judges", version: "3.48.0" }],
108
+ },
109
+ components,
110
+ };
111
+ }
112
+ // ─── CLI ────────────────────────────────────────────────────────────────────
113
+ const STORE = ".judges-sbom";
114
+ export function runSbomExport(argv) {
115
+ if (argv.includes("--help") || argv.includes("-h")) {
116
+ console.log(`
117
+ judges sbom-export — Generate Software Bill of Materials
118
+
119
+ Usage:
120
+ judges sbom-export
121
+ judges sbom-export --save
122
+ judges sbom-export --summary
123
+
124
+ Options:
125
+ --save Save SBOM to ${STORE}/sbom.json
126
+ --summary Show component summary only
127
+ --format json JSON output (default for SBOM)
128
+ --help, -h Show this help
129
+
130
+ Supports: package.json, requirements.txt, go.mod
131
+ `);
132
+ return;
133
+ }
134
+ const sbom = buildSbom();
135
+ if (argv.includes("--save")) {
136
+ if (!existsSync(STORE))
137
+ mkdirSync(STORE, { recursive: true });
138
+ writeFileSync(join(STORE, "sbom.json"), JSON.stringify(sbom, null, 2));
139
+ console.log(` SBOM saved to ${STORE}/sbom.json (${sbom.components.length} components)`);
140
+ return;
141
+ }
142
+ if (argv.includes("--summary")) {
143
+ const required = sbom.components.filter((c) => c.scope === "required").length;
144
+ const optional = sbom.components.filter((c) => c.scope === "optional").length;
145
+ const types = new Map();
146
+ for (const c of sbom.components) {
147
+ const ecosystem = c.purl.split(":")[1]?.split("/")[0] || "unknown";
148
+ types.set(ecosystem, (types.get(ecosystem) || 0) + 1);
149
+ }
150
+ console.log(`\n SBOM Summary — ${sbom.metadata.component.name}@${sbom.metadata.component.version}`);
151
+ console.log(` ──────────────────────────`);
152
+ console.log(` Total components: ${sbom.components.length}`);
153
+ console.log(` Required: ${required} Optional: ${optional}`);
154
+ for (const [eco, count] of types)
155
+ console.log(` ${eco}: ${count}`);
156
+ console.log(`\n Run --save to export full CycloneDX SBOM\n`);
157
+ return;
158
+ }
159
+ // Default: print full SBOM
160
+ console.log(JSON.stringify(sbom, null, 2));
161
+ }
162
+ //# sourceMappingURL=sbom-export.js.map