@kevinrabun/judges 3.97.0 → 3.98.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.
- package/CHANGELOG.md +13 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +63 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/finding-cwe-lookup.d.ts +5 -0
- package/dist/commands/finding-cwe-lookup.d.ts.map +1 -0
- package/dist/commands/finding-cwe-lookup.js +149 -0
- package/dist/commands/finding-cwe-lookup.js.map +1 -0
- package/dist/commands/finding-duplicate-detect.d.ts +5 -0
- package/dist/commands/finding-duplicate-detect.d.ts.map +1 -0
- package/dist/commands/finding-duplicate-detect.js +114 -0
- package/dist/commands/finding-duplicate-detect.js.map +1 -0
- package/dist/commands/finding-patch-preview.d.ts +5 -0
- package/dist/commands/finding-patch-preview.d.ts.map +1 -0
- package/dist/commands/finding-patch-preview.js +104 -0
- package/dist/commands/finding-patch-preview.js.map +1 -0
- package/dist/commands/finding-priority-matrix.d.ts +5 -0
- package/dist/commands/finding-priority-matrix.d.ts.map +1 -0
- package/dist/commands/finding-priority-matrix.js +103 -0
- package/dist/commands/finding-priority-matrix.js.map +1 -0
- package/dist/commands/review-cicd-integrate.d.ts +5 -0
- package/dist/commands/review-cicd-integrate.d.ts.map +1 -0
- package/dist/commands/review-cicd-integrate.js +123 -0
- package/dist/commands/review-cicd-integrate.js.map +1 -0
- package/dist/commands/review-language-profile.d.ts +5 -0
- package/dist/commands/review-language-profile.d.ts.map +1 -0
- package/dist/commands/review-language-profile.js +73 -0
- package/dist/commands/review-language-profile.js.map +1 -0
- package/dist/commands/review-org-dashboard.d.ts +5 -0
- package/dist/commands/review-org-dashboard.d.ts.map +1 -0
- package/dist/commands/review-org-dashboard.js +69 -0
- package/dist/commands/review-org-dashboard.js.map +1 -0
- package/dist/commands/review-report-archive.d.ts +5 -0
- package/dist/commands/review-report-archive.d.ts.map +1 -0
- package/dist/commands/review-report-archive.js +101 -0
- package/dist/commands/review-report-archive.js.map +1 -0
- package/dist/commands/review-sla-config.d.ts +5 -0
- package/dist/commands/review-sla-config.d.ts.map +1 -0
- package/dist/commands/review-sla-config.js +89 -0
- package/dist/commands/review-sla-config.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-cwe-lookup.d.ts","sourceRoot":"","sources":["../../src/commands/finding-cwe-lookup.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8EH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA0FxD"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-cwe-lookup — Look up CWE details for finding rule IDs.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CWE database (embedded subset) ────────────────────────────────────────
|
|
6
|
+
const CWE_DB = {
|
|
7
|
+
"sql-injection": {
|
|
8
|
+
id: "CWE-89",
|
|
9
|
+
name: "SQL Injection",
|
|
10
|
+
description: "Improper neutralization of special elements used in an SQL command",
|
|
11
|
+
mitigation: "Use parameterized queries or prepared statements",
|
|
12
|
+
},
|
|
13
|
+
xss: {
|
|
14
|
+
id: "CWE-79",
|
|
15
|
+
name: "Cross-site Scripting",
|
|
16
|
+
description: "Improper neutralization of input during web page generation",
|
|
17
|
+
mitigation: "Sanitize output and use Content Security Policy",
|
|
18
|
+
},
|
|
19
|
+
"path-traversal": {
|
|
20
|
+
id: "CWE-22",
|
|
21
|
+
name: "Path Traversal",
|
|
22
|
+
description: "Improper limitation of a pathname to a restricted directory",
|
|
23
|
+
mitigation: "Validate and canonicalize file paths",
|
|
24
|
+
},
|
|
25
|
+
"command-injection": {
|
|
26
|
+
id: "CWE-78",
|
|
27
|
+
name: "OS Command Injection",
|
|
28
|
+
description: "Improper neutralization of special elements used in an OS command",
|
|
29
|
+
mitigation: "Avoid shell commands; use safe APIs",
|
|
30
|
+
},
|
|
31
|
+
"hardcoded-secret": {
|
|
32
|
+
id: "CWE-798",
|
|
33
|
+
name: "Hardcoded Credentials",
|
|
34
|
+
description: "Use of hard-coded credentials in source code",
|
|
35
|
+
mitigation: "Use environment variables or secret managers",
|
|
36
|
+
},
|
|
37
|
+
"insecure-deserialization": {
|
|
38
|
+
id: "CWE-502",
|
|
39
|
+
name: "Insecure Deserialization",
|
|
40
|
+
description: "Deserialization of untrusted data",
|
|
41
|
+
mitigation: "Validate serialized data or use safe alternatives",
|
|
42
|
+
},
|
|
43
|
+
"broken-auth": {
|
|
44
|
+
id: "CWE-287",
|
|
45
|
+
name: "Improper Authentication",
|
|
46
|
+
description: "Missing or improper authentication mechanism",
|
|
47
|
+
mitigation: "Implement robust authentication with MFA",
|
|
48
|
+
},
|
|
49
|
+
ssrf: {
|
|
50
|
+
id: "CWE-918",
|
|
51
|
+
name: "Server-Side Request Forgery",
|
|
52
|
+
description: "Server-side request to unintended location",
|
|
53
|
+
mitigation: "Validate and restrict outbound requests",
|
|
54
|
+
},
|
|
55
|
+
"open-redirect": {
|
|
56
|
+
id: "CWE-601",
|
|
57
|
+
name: "Open Redirect",
|
|
58
|
+
description: "URL redirection to untrusted site",
|
|
59
|
+
mitigation: "Validate redirect URLs against allowlist",
|
|
60
|
+
},
|
|
61
|
+
xxe: {
|
|
62
|
+
id: "CWE-611",
|
|
63
|
+
name: "XML External Entities",
|
|
64
|
+
description: "Improper restriction of XML external entity reference",
|
|
65
|
+
mitigation: "Disable external entity processing",
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
69
|
+
export function runFindingCweLookup(argv) {
|
|
70
|
+
const reportIdx = argv.indexOf("--report");
|
|
71
|
+
const ruleIdx = argv.indexOf("--rule");
|
|
72
|
+
const formatIdx = argv.indexOf("--format");
|
|
73
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
74
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
75
|
+
console.log(`
|
|
76
|
+
judges finding-cwe-lookup — Look up CWE details for findings
|
|
77
|
+
|
|
78
|
+
Usage:
|
|
79
|
+
judges finding-cwe-lookup [--report <path>] [--rule <ruleId>]
|
|
80
|
+
[--format table|json]
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
--report <path> Report file to look up CWEs for all findings
|
|
84
|
+
--rule <ruleId> Look up a single rule ID
|
|
85
|
+
--format <fmt> Output format: table (default), json
|
|
86
|
+
--help, -h Show this help
|
|
87
|
+
`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Single rule lookup
|
|
91
|
+
if (ruleIdx >= 0) {
|
|
92
|
+
const ruleId = argv[ruleIdx + 1];
|
|
93
|
+
const key = ruleId.split("/").pop() ?? ruleId;
|
|
94
|
+
const cwe = CWE_DB[key] ?? null;
|
|
95
|
+
if (format === "json") {
|
|
96
|
+
console.log(JSON.stringify({ ruleId, cwe }, null, 2));
|
|
97
|
+
}
|
|
98
|
+
else if (cwe !== null) {
|
|
99
|
+
console.log(`\n ${cwe.id}: ${cwe.name}`);
|
|
100
|
+
console.log(` ${cwe.description}`);
|
|
101
|
+
console.log(` Mitigation: ${cwe.mitigation}`);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
console.log(` No CWE mapping found for: ${ruleId}`);
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Report lookup
|
|
109
|
+
if (reportIdx < 0) {
|
|
110
|
+
console.error("Supply --report <path> or --rule <ruleId>");
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const reportPath = argv[reportIdx + 1];
|
|
115
|
+
if (!existsSync(reportPath)) {
|
|
116
|
+
console.error(`Report not found: ${reportPath}`);
|
|
117
|
+
process.exitCode = 1;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const report = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
121
|
+
const findings = report.findings ?? [];
|
|
122
|
+
const results = findings.map((f) => {
|
|
123
|
+
const key = f.ruleId.split("/").pop() ?? f.ruleId;
|
|
124
|
+
return { ruleId: f.ruleId, title: f.title, cwe: CWE_DB[key] ?? null };
|
|
125
|
+
});
|
|
126
|
+
if (format === "json") {
|
|
127
|
+
console.log(JSON.stringify(results, null, 2));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
console.log(`\nCWE Lookup`);
|
|
131
|
+
console.log("═".repeat(70));
|
|
132
|
+
const mapped = results.filter((r) => r.cwe !== null);
|
|
133
|
+
const unmapped = results.filter((r) => r.cwe === null);
|
|
134
|
+
if (mapped.length > 0) {
|
|
135
|
+
console.log(" Mapped:");
|
|
136
|
+
for (const r of mapped) {
|
|
137
|
+
console.log(` ${r.ruleId.padEnd(25)} → ${r.cwe.id} (${r.cwe.name})`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (unmapped.length > 0) {
|
|
141
|
+
console.log(" No CWE mapping:");
|
|
142
|
+
for (const r of unmapped) {
|
|
143
|
+
console.log(` ${r.ruleId.padEnd(25)} ${r.title}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
console.log(`\n Coverage: ${mapped.length}/${results.length} findings mapped to CWEs`);
|
|
147
|
+
console.log("═".repeat(70));
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=finding-cwe-lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-cwe-lookup.js","sourceRoot":"","sources":["../../src/commands/finding-cwe-lookup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-duplicate-detect.d.ts","sourceRoot":"","sources":["../../src/commands/finding-duplicate-detect.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+G9D"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-duplicate-detect — Detect duplicate or near-duplicate findings.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
6
|
+
export function runFindingDuplicateDetect(argv) {
|
|
7
|
+
const reportIdx = argv.indexOf("--report");
|
|
8
|
+
const thresholdIdx = argv.indexOf("--threshold");
|
|
9
|
+
const formatIdx = argv.indexOf("--format");
|
|
10
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
11
|
+
const threshold = thresholdIdx >= 0 ? parseFloat(argv[thresholdIdx + 1]) : 0.8;
|
|
12
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
13
|
+
console.log(`
|
|
14
|
+
judges finding-duplicate-detect — Detect duplicate findings
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
judges finding-duplicate-detect --report <path> [--threshold <n>]
|
|
18
|
+
[--format table|json]
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--report <path> Report file with findings
|
|
22
|
+
--threshold <n> Similarity threshold 0-1 (default: 0.8)
|
|
23
|
+
--format <fmt> Output format: table (default), json
|
|
24
|
+
--help, -h Show this help
|
|
25
|
+
`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (reportIdx < 0) {
|
|
29
|
+
console.error("Missing --report <path>");
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const reportPath = argv[reportIdx + 1];
|
|
34
|
+
if (!existsSync(reportPath)) {
|
|
35
|
+
console.error(`Report not found: ${reportPath}`);
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const report = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
40
|
+
const findings = report.findings ?? [];
|
|
41
|
+
if (findings.length < 2) {
|
|
42
|
+
console.log("Need at least 2 findings to detect duplicates.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Group by exact ruleId match first
|
|
46
|
+
const ruleGroups = {};
|
|
47
|
+
for (let i = 0; i < findings.length; i++) {
|
|
48
|
+
const key = findings[i].ruleId;
|
|
49
|
+
if (ruleGroups[key] === undefined) {
|
|
50
|
+
ruleGroups[key] = [];
|
|
51
|
+
}
|
|
52
|
+
ruleGroups[key].push(i);
|
|
53
|
+
}
|
|
54
|
+
// Then check title similarity within different rules
|
|
55
|
+
const duplicates = [];
|
|
56
|
+
// Exact rule duplicates
|
|
57
|
+
for (const [ruleId, indices] of Object.entries(ruleGroups)) {
|
|
58
|
+
if (indices.length > 1) {
|
|
59
|
+
duplicates.push({
|
|
60
|
+
representativeRule: ruleId,
|
|
61
|
+
title: findings[indices[0]].title,
|
|
62
|
+
count: indices.length,
|
|
63
|
+
indices,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Near-duplicate by title similarity across different rules
|
|
68
|
+
const checked = new Set();
|
|
69
|
+
for (let i = 0; i < findings.length; i++) {
|
|
70
|
+
for (let j = i + 1; j < findings.length; j++) {
|
|
71
|
+
if (findings[i].ruleId === findings[j].ruleId)
|
|
72
|
+
continue;
|
|
73
|
+
const key = `${i}:${j}`;
|
|
74
|
+
if (checked.has(key))
|
|
75
|
+
continue;
|
|
76
|
+
checked.add(key);
|
|
77
|
+
const sim = jaccardSimilarity(findings[i].title, findings[j].title);
|
|
78
|
+
if (sim >= threshold) {
|
|
79
|
+
duplicates.push({
|
|
80
|
+
representativeRule: `${findings[i].ruleId} ~ ${findings[j].ruleId}`,
|
|
81
|
+
title: findings[i].title,
|
|
82
|
+
count: 2,
|
|
83
|
+
indices: [i, j],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (format === "json") {
|
|
89
|
+
console.log(JSON.stringify({ threshold, duplicates }, null, 2));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log(`\nDuplicate Detection (threshold: ${threshold})`);
|
|
93
|
+
console.log("═".repeat(65));
|
|
94
|
+
if (duplicates.length === 0) {
|
|
95
|
+
console.log(" No duplicates detected.");
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
for (const d of duplicates) {
|
|
99
|
+
console.log(` [${d.count}x] ${d.representativeRule}`);
|
|
100
|
+
console.log(` "${d.title}"`);
|
|
101
|
+
console.log(` Indices: ${d.indices.join(", ")}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
console.log(`\n Total findings: ${findings.length} | Duplicate groups: ${duplicates.length}`);
|
|
105
|
+
console.log("═".repeat(65));
|
|
106
|
+
}
|
|
107
|
+
function jaccardSimilarity(a, b) {
|
|
108
|
+
const setA = new Set(a.toLowerCase().split(/\s+/));
|
|
109
|
+
const setB = new Set(b.toLowerCase().split(/\s+/));
|
|
110
|
+
const intersection = new Set([...setA].filter((x) => setB.has(x)));
|
|
111
|
+
const union = new Set([...setA, ...setB]);
|
|
112
|
+
return union.size === 0 ? 0 : intersection.size / union.size;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=finding-duplicate-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-duplicate-detect.js","sourceRoot":"","sources":["../../src/commands/finding-duplicate-detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-patch-preview.d.ts","sourceRoot":"","sources":["../../src/commands/finding-patch-preview.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA0H3D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-patch-preview — Preview how patches would modify source files.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
6
|
+
export function runFindingPatchPreview(argv) {
|
|
7
|
+
const reportIdx = argv.indexOf("--report");
|
|
8
|
+
const sourceIdx = argv.indexOf("--source");
|
|
9
|
+
const contextIdx = argv.indexOf("--context");
|
|
10
|
+
const formatIdx = argv.indexOf("--format");
|
|
11
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
12
|
+
const contextLines = contextIdx >= 0 ? parseInt(argv[contextIdx + 1], 10) : 3;
|
|
13
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
14
|
+
console.log(`
|
|
15
|
+
judges finding-patch-preview — Preview patch modifications
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
judges finding-patch-preview --report <path> --source <path>
|
|
19
|
+
[--context <n>] [--format table|json]
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--report <path> Report file with findings
|
|
23
|
+
--source <path> Source file to preview patches against
|
|
24
|
+
--context <n> Context lines around changes (default: 3)
|
|
25
|
+
--format <fmt> Output format: table (default), json
|
|
26
|
+
--help, -h Show this help
|
|
27
|
+
`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (reportIdx < 0 || sourceIdx < 0) {
|
|
31
|
+
console.error("Missing --report <path> and --source <path>");
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const reportPath = argv[reportIdx + 1];
|
|
36
|
+
const sourcePath = argv[sourceIdx + 1];
|
|
37
|
+
if (!existsSync(reportPath)) {
|
|
38
|
+
console.error(`Report not found: ${reportPath}`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!existsSync(sourcePath)) {
|
|
43
|
+
console.error(`Source not found: ${sourcePath}`);
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const report = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
48
|
+
const findings = (report.findings ?? []).filter((f) => f.patch !== undefined && f.patch !== null);
|
|
49
|
+
const sourceContent = readFileSync(sourcePath, "utf-8");
|
|
50
|
+
const sourceLines = sourceContent.split("\n");
|
|
51
|
+
if (findings.length === 0) {
|
|
52
|
+
console.log("No findings with patches to preview.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const previews = [];
|
|
56
|
+
for (const f of findings) {
|
|
57
|
+
const patchStr = String(f.patch);
|
|
58
|
+
const patchLines = patchStr.split("\n");
|
|
59
|
+
const firstLine = patchLines[0] ?? "";
|
|
60
|
+
const lineIdx = sourceLines.findIndex((l) => l.includes(firstLine.trim()));
|
|
61
|
+
const applicable = lineIdx >= 0;
|
|
62
|
+
const start = Math.max(0, lineIdx - contextLines);
|
|
63
|
+
const end = Math.min(sourceLines.length - 1, lineIdx + contextLines);
|
|
64
|
+
const affectedLines = [];
|
|
65
|
+
if (applicable) {
|
|
66
|
+
for (let i = start; i <= end; i++) {
|
|
67
|
+
affectedLines.push(i + 1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const snippet = applicable
|
|
71
|
+
? sourceLines
|
|
72
|
+
.slice(start, end + 1)
|
|
73
|
+
.map((l, i) => {
|
|
74
|
+
const lineNum = start + i + 1;
|
|
75
|
+
const marker = lineNum === lineIdx + 1 ? ">" : " ";
|
|
76
|
+
return `${marker} ${String(lineNum).padStart(4)} | ${l}`;
|
|
77
|
+
})
|
|
78
|
+
.join("\n")
|
|
79
|
+
: "(patch target not found in source)";
|
|
80
|
+
previews.push({
|
|
81
|
+
ruleId: f.ruleId,
|
|
82
|
+
title: f.title,
|
|
83
|
+
patchSnippet: snippet,
|
|
84
|
+
applicable,
|
|
85
|
+
affectedLines,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (format === "json") {
|
|
89
|
+
console.log(JSON.stringify(previews, null, 2));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log(`\nPatch Preview — ${sourcePath}`);
|
|
93
|
+
console.log("═".repeat(70));
|
|
94
|
+
for (const p of previews) {
|
|
95
|
+
const status = p.applicable ? "APPLICABLE" : "NOT FOUND";
|
|
96
|
+
console.log(`\n [${status}] ${p.ruleId} — ${p.title}`);
|
|
97
|
+
console.log(" " + "─".repeat(60));
|
|
98
|
+
console.log(p.patchSnippet);
|
|
99
|
+
}
|
|
100
|
+
const applicableCount = previews.filter((p) => p.applicable).length;
|
|
101
|
+
console.log(`\n ${applicableCount}/${previews.length} patches applicable`);
|
|
102
|
+
console.log("═".repeat(70));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=finding-patch-preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-patch-preview.js","sourceRoot":"","sources":["../../src/commands/finding-patch-preview.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-priority-matrix.d.ts","sourceRoot":"","sources":["../../src/commands/finding-priority-matrix.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmCH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAgG7D"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-priority-matrix — Create a priority matrix (urgency × impact) for findings.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── Matrix model ───────────────────────────────────────────────────────────
|
|
6
|
+
const URGENCY = {
|
|
7
|
+
critical: 5,
|
|
8
|
+
high: 4,
|
|
9
|
+
medium: 3,
|
|
10
|
+
low: 2,
|
|
11
|
+
info: 1,
|
|
12
|
+
};
|
|
13
|
+
function classifyPriority(score) {
|
|
14
|
+
if (score >= 20)
|
|
15
|
+
return "P0-Immediate";
|
|
16
|
+
if (score >= 12)
|
|
17
|
+
return "P1-High";
|
|
18
|
+
if (score >= 6)
|
|
19
|
+
return "P2-Medium";
|
|
20
|
+
if (score >= 3)
|
|
21
|
+
return "P3-Low";
|
|
22
|
+
return "P4-Backlog";
|
|
23
|
+
}
|
|
24
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
25
|
+
export function runFindingPriorityMatrix(argv) {
|
|
26
|
+
const reportIdx = argv.indexOf("--report");
|
|
27
|
+
const priorityIdx = argv.indexOf("--priority");
|
|
28
|
+
const formatIdx = argv.indexOf("--format");
|
|
29
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
30
|
+
const priorityFilter = priorityIdx >= 0 ? argv[priorityIdx + 1] : "";
|
|
31
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
32
|
+
console.log(`
|
|
33
|
+
judges finding-priority-matrix — Create urgency × impact priority matrix
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
judges finding-priority-matrix --report <path> [--priority <level>]
|
|
37
|
+
[--format table|json]
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
--report <path> Report file with findings
|
|
41
|
+
--priority <level> Filter: P0-Immediate, P1-High, P2-Medium, P3-Low, P4-Backlog
|
|
42
|
+
--format <fmt> Output format: table (default), json
|
|
43
|
+
--help, -h Show this help
|
|
44
|
+
`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (reportIdx < 0) {
|
|
48
|
+
console.error("Missing --report <path>");
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const reportPath = argv[reportIdx + 1];
|
|
53
|
+
if (!existsSync(reportPath)) {
|
|
54
|
+
console.error(`Report not found: ${reportPath}`);
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const report = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
59
|
+
const findings = report.findings ?? [];
|
|
60
|
+
if (findings.length === 0) {
|
|
61
|
+
console.log("No findings to prioritize.");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const entries = findings.map((f) => {
|
|
65
|
+
const urgency = URGENCY[f.severity] ?? 1;
|
|
66
|
+
const conf = f.confidence ?? 0.5;
|
|
67
|
+
const impact = Math.round(urgency * conf * 2);
|
|
68
|
+
const score = urgency * impact;
|
|
69
|
+
return {
|
|
70
|
+
ruleId: f.ruleId,
|
|
71
|
+
title: f.title,
|
|
72
|
+
severity: f.severity,
|
|
73
|
+
urgency,
|
|
74
|
+
impact,
|
|
75
|
+
priority: classifyPriority(score),
|
|
76
|
+
score,
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
entries.sort((a, b) => b.score - a.score);
|
|
80
|
+
const display = priorityFilter.length > 0 ? entries.filter((e) => e.priority === priorityFilter) : entries;
|
|
81
|
+
if (format === "json") {
|
|
82
|
+
console.log(JSON.stringify(display, null, 2));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.log(`\nPriority Matrix`);
|
|
86
|
+
console.log("═".repeat(80));
|
|
87
|
+
console.log(` ${"Priority".padEnd(15)} ${"Score".padEnd(7)} ${"Urgency".padEnd(9)} ${"Impact".padEnd(8)} ${"Rule".padEnd(22)} Title`);
|
|
88
|
+
console.log(" " + "─".repeat(75));
|
|
89
|
+
for (const e of display) {
|
|
90
|
+
console.log(` ${e.priority.padEnd(15)} ${String(e.score).padEnd(7)} ${String(e.urgency).padEnd(9)} ${String(e.impact).padEnd(8)} ${e.ruleId.padEnd(22)} ${e.title}`);
|
|
91
|
+
}
|
|
92
|
+
// Summary counts
|
|
93
|
+
const counts = {};
|
|
94
|
+
for (const e of entries) {
|
|
95
|
+
counts[e.priority] = (counts[e.priority] ?? 0) + 1;
|
|
96
|
+
}
|
|
97
|
+
console.log(`\n Summary:`);
|
|
98
|
+
for (const [p, c] of Object.entries(counts).sort()) {
|
|
99
|
+
console.log(` ${p.padEnd(15)} ${c} finding(s)`);
|
|
100
|
+
}
|
|
101
|
+
console.log("═".repeat(80));
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=finding-priority-matrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-priority-matrix.js","sourceRoot":"","sources":["../../src/commands/finding-priority-matrix.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-cicd-integrate.d.ts","sourceRoot":"","sources":["../../src/commands/review-cicd-integrate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiEH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAiE3D"}
|