@kevinrabun/judges 3.81.0 → 3.83.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 +26 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +126 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/finding-age-tracker.d.ts +8 -0
- package/dist/commands/finding-age-tracker.d.ts.map +1 -0
- package/dist/commands/finding-age-tracker.js +153 -0
- package/dist/commands/finding-age-tracker.js.map +1 -0
- package/dist/commands/finding-category-stats.d.ts +5 -0
- package/dist/commands/finding-category-stats.d.ts.map +1 -0
- package/dist/commands/finding-category-stats.js +105 -0
- package/dist/commands/finding-category-stats.js.map +1 -0
- package/dist/commands/finding-compare-runs.d.ts +5 -0
- package/dist/commands/finding-compare-runs.d.ts.map +1 -0
- package/dist/commands/finding-compare-runs.js +106 -0
- package/dist/commands/finding-compare-runs.js.map +1 -0
- package/dist/commands/finding-duplicate-rule.d.ts +5 -0
- package/dist/commands/finding-duplicate-rule.d.ts.map +1 -0
- package/dist/commands/finding-duplicate-rule.js +104 -0
- package/dist/commands/finding-duplicate-rule.js.map +1 -0
- package/dist/commands/finding-hotfix-suggest.d.ts +8 -0
- package/dist/commands/finding-hotfix-suggest.d.ts.map +1 -0
- package/dist/commands/finding-hotfix-suggest.js +171 -0
- package/dist/commands/finding-hotfix-suggest.js.map +1 -0
- package/dist/commands/finding-line-blame.d.ts +8 -0
- package/dist/commands/finding-line-blame.d.ts.map +1 -0
- package/dist/commands/finding-line-blame.js +133 -0
- package/dist/commands/finding-line-blame.js.map +1 -0
- package/dist/commands/finding-summary-digest.d.ts +8 -0
- package/dist/commands/finding-summary-digest.d.ts.map +1 -0
- package/dist/commands/finding-summary-digest.js +146 -0
- package/dist/commands/finding-summary-digest.js.map +1 -0
- package/dist/commands/review-approval-gate.d.ts +8 -0
- package/dist/commands/review-approval-gate.d.ts.map +1 -0
- package/dist/commands/review-approval-gate.js +191 -0
- package/dist/commands/review-approval-gate.js.map +1 -0
- package/dist/commands/review-branch-compare.d.ts +5 -0
- package/dist/commands/review-branch-compare.d.ts.map +1 -0
- package/dist/commands/review-branch-compare.js +114 -0
- package/dist/commands/review-branch-compare.js.map +1 -0
- package/dist/commands/review-changelog-entry.d.ts +8 -0
- package/dist/commands/review-changelog-entry.d.ts.map +1 -0
- package/dist/commands/review-changelog-entry.js +110 -0
- package/dist/commands/review-changelog-entry.js.map +1 -0
- package/dist/commands/review-code-owner.d.ts +8 -0
- package/dist/commands/review-code-owner.d.ts.map +1 -0
- package/dist/commands/review-code-owner.js +165 -0
- package/dist/commands/review-code-owner.js.map +1 -0
- package/dist/commands/review-export-pdf.d.ts +8 -0
- package/dist/commands/review-export-pdf.d.ts.map +1 -0
- package/dist/commands/review-export-pdf.js +132 -0
- package/dist/commands/review-export-pdf.js.map +1 -0
- package/dist/commands/review-finding-link.d.ts +8 -0
- package/dist/commands/review-finding-link.d.ts.map +1 -0
- package/dist/commands/review-finding-link.js +116 -0
- package/dist/commands/review-finding-link.js.map +1 -0
- package/dist/commands/review-parallel-files.d.ts +8 -0
- package/dist/commands/review-parallel-files.d.ts.map +1 -0
- package/dist/commands/review-parallel-files.js +135 -0
- package/dist/commands/review-parallel-files.js.map +1 -0
- package/dist/commands/review-scope-lock.d.ts +8 -0
- package/dist/commands/review-scope-lock.d.ts.map +1 -0
- package/dist/commands/review-scope-lock.js +139 -0
- package/dist/commands/review-scope-lock.js.map +1 -0
- package/dist/commands/review-skip-list.d.ts +5 -0
- package/dist/commands/review-skip-list.d.ts.map +1 -0
- package/dist/commands/review-skip-list.js +136 -0
- package/dist/commands/review-skip-list.js.map +1 -0
- package/dist/commands/review-team-assign.d.ts +8 -0
- package/dist/commands/review-team-assign.d.ts.map +1 -0
- package/dist/commands/review-team-assign.js +212 -0
- package/dist/commands/review-team-assign.js.map +1 -0
- package/dist/commands/review-watch-mode.d.ts +8 -0
- package/dist/commands/review-watch-mode.d.ts.map +1 -0
- package/dist/commands/review-watch-mode.js +133 -0
- package/dist/commands/review-watch-mode.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-hotfix-suggest — Suggest quick hotfixes for common findings.
|
|
3
|
+
*
|
|
4
|
+
* Provides targeted one-liner or small code snippets to address
|
|
5
|
+
* frequently-encountered security and quality issues.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync } from "fs";
|
|
8
|
+
// ─── Hotfix Database ────────────────────────────────────────────────────────
|
|
9
|
+
const HOTFIX_PATTERNS = [
|
|
10
|
+
{
|
|
11
|
+
keywords: ["sql injection", "sql"],
|
|
12
|
+
category: "injection",
|
|
13
|
+
hotfix: "Use parameterized queries instead of string concatenation",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
keywords: ["xss", "cross-site scripting", "innerhtml"],
|
|
17
|
+
category: "xss",
|
|
18
|
+
hotfix: "Sanitize user input with DOMPurify or use textContent instead of innerHTML",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
keywords: ["eval", "code injection"],
|
|
22
|
+
category: "injection",
|
|
23
|
+
hotfix: "Replace eval() with JSON.parse() or a safe alternative",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
keywords: ["hardcoded", "password", "secret", "api key"],
|
|
27
|
+
category: "secrets",
|
|
28
|
+
hotfix: "Move secrets to environment variables or a secrets manager",
|
|
29
|
+
},
|
|
30
|
+
{ keywords: ["csrf", "cross-site request"], category: "csrf", hotfix: "Add CSRF token validation middleware" },
|
|
31
|
+
{
|
|
32
|
+
keywords: ["cors", "permissive"],
|
|
33
|
+
category: "cors",
|
|
34
|
+
hotfix: "Configure CORS with specific allowed origins instead of wildcard",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
keywords: ["md5", "sha1", "weak hash", "weak crypto"],
|
|
38
|
+
category: "crypto",
|
|
39
|
+
hotfix: "Use SHA-256 or bcrypt for password hashing",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
keywords: ["math.random", "insecure random"],
|
|
43
|
+
category: "crypto",
|
|
44
|
+
hotfix: "Use crypto.randomBytes() or crypto.getRandomValues() instead",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
keywords: ["path traversal", "directory traversal"],
|
|
48
|
+
category: "path",
|
|
49
|
+
hotfix: "Validate and sanitize file paths; use path.resolve() and check against base directory",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
keywords: ["command injection", "exec", "child_process"],
|
|
53
|
+
category: "injection",
|
|
54
|
+
hotfix: "Use execFile() with argument arrays instead of exec() with string interpolation",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
keywords: ["missing auth", "authentication", "unauthorized"],
|
|
58
|
+
category: "auth",
|
|
59
|
+
hotfix: "Add authentication middleware to protect the endpoint",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
keywords: ["missing rate limit", "rate limit"],
|
|
63
|
+
category: "availability",
|
|
64
|
+
hotfix: "Add express-rate-limit or similar middleware",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
keywords: ["information disclosure", "stack trace", "verbose error"],
|
|
68
|
+
category: "info-disclosure",
|
|
69
|
+
hotfix: "Use generic error messages in production; log details server-side only",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
keywords: ["insecure cookie", "cookie"],
|
|
73
|
+
category: "session",
|
|
74
|
+
hotfix: "Set cookie flags: httpOnly, secure, sameSite='strict'",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
keywords: ["tls", "ssl", "certificate", "rejectunauthorized"],
|
|
78
|
+
category: "transport",
|
|
79
|
+
hotfix: "Never disable TLS certificate verification in production",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
keywords: ["unused", "dead code"],
|
|
83
|
+
category: "quality",
|
|
84
|
+
hotfix: "Remove unused code to reduce attack surface and maintenance burden",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
keywords: ["logging sensitive", "log password"],
|
|
88
|
+
category: "logging",
|
|
89
|
+
hotfix: "Remove sensitive data from log statements; use structured logging with redaction",
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
function findHotfix(title, description) {
|
|
93
|
+
const combined = `${title} ${description}`.toLowerCase();
|
|
94
|
+
for (const p of HOTFIX_PATTERNS) {
|
|
95
|
+
if (p.keywords.some((kw) => combined.includes(kw))) {
|
|
96
|
+
return { category: p.category, hotfix: p.hotfix };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
102
|
+
export function runFindingHotfixSuggest(argv) {
|
|
103
|
+
const fileIdx = argv.indexOf("--file");
|
|
104
|
+
const formatIdx = argv.indexOf("--format");
|
|
105
|
+
const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
|
|
106
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
107
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
108
|
+
console.log(`
|
|
109
|
+
judges finding-hotfix-suggest — Suggest quick hotfixes for findings
|
|
110
|
+
|
|
111
|
+
Usage:
|
|
112
|
+
judges finding-hotfix-suggest --file <verdict.json> [--format table|json]
|
|
113
|
+
|
|
114
|
+
Options:
|
|
115
|
+
--file <path> Path to verdict JSON file (required)
|
|
116
|
+
--format <fmt> Output format: table (default), json
|
|
117
|
+
--help, -h Show this help
|
|
118
|
+
`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (!filePath) {
|
|
122
|
+
console.error("Error: --file required");
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!existsSync(filePath)) {
|
|
127
|
+
console.error(`Error: not found: ${filePath}`);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
let verdict;
|
|
132
|
+
try {
|
|
133
|
+
verdict = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
console.error("Error: invalid JSON");
|
|
137
|
+
process.exitCode = 1;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const suggestions = [];
|
|
141
|
+
for (const f of verdict.findings) {
|
|
142
|
+
const hotfix = findHotfix(f.title, f.description);
|
|
143
|
+
if (hotfix) {
|
|
144
|
+
suggestions.push({
|
|
145
|
+
ruleId: f.ruleId,
|
|
146
|
+
title: f.title,
|
|
147
|
+
severity: f.severity || "medium",
|
|
148
|
+
hotfix: hotfix.hotfix,
|
|
149
|
+
category: hotfix.category,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (format === "json") {
|
|
154
|
+
console.log(JSON.stringify(suggestions, null, 2));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (suggestions.length === 0) {
|
|
158
|
+
console.log("No hotfix suggestions available for current findings.");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
console.log(`\nHotfix Suggestions (${suggestions.length})`);
|
|
162
|
+
console.log("═".repeat(70));
|
|
163
|
+
for (const s of suggestions) {
|
|
164
|
+
console.log(`\n [${s.severity.toUpperCase()}] ${s.title}`);
|
|
165
|
+
console.log(` Category: ${s.category}`);
|
|
166
|
+
console.log(` Hotfix: ${s.hotfix}`);
|
|
167
|
+
}
|
|
168
|
+
console.log("\n" + "═".repeat(70));
|
|
169
|
+
console.log(`${suggestions.length} of ${verdict.findings.length} findings have suggested hotfixes`);
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=finding-hotfix-suggest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-hotfix-suggest.js","sourceRoot":"","sources":["../../src/commands/finding-hotfix-suggest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-line-blame — Map findings to git blame information.
|
|
3
|
+
*
|
|
4
|
+
* Shows who last modified lines associated with findings,
|
|
5
|
+
* helping attribute findings to specific changes/authors.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runFindingLineBlame(argv: string[]): void;
|
|
8
|
+
//# sourceMappingURL=finding-line-blame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-line-blame.d.ts","sourceRoot":"","sources":["../../src/commands/finding-line-blame.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2DH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoGxD"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-line-blame — Map findings to git blame information.
|
|
3
|
+
*
|
|
4
|
+
* Shows who last modified lines associated with findings,
|
|
5
|
+
* helping attribute findings to specific changes/authors.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync } from "fs";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
10
|
+
function getBlameForLines(file, lines) {
|
|
11
|
+
const results = [];
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
try {
|
|
14
|
+
const output = execSync(`git blame -L ${line},${line} --porcelain "${file}"`, {
|
|
15
|
+
encoding: "utf-8",
|
|
16
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
17
|
+
});
|
|
18
|
+
let author = "unknown";
|
|
19
|
+
let date = "";
|
|
20
|
+
let commit = "";
|
|
21
|
+
for (const blameLine of output.split("\n")) {
|
|
22
|
+
if (blameLine.startsWith("author "))
|
|
23
|
+
author = blameLine.slice(7);
|
|
24
|
+
else if (blameLine.startsWith("author-time ")) {
|
|
25
|
+
const ts = parseInt(blameLine.slice(12), 10);
|
|
26
|
+
date = new Date(ts * 1000).toISOString().split("T")[0];
|
|
27
|
+
}
|
|
28
|
+
else if (/^[0-9a-f]{40}/.test(blameLine)) {
|
|
29
|
+
commit = blameLine.split(" ")[0].slice(0, 8);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
results.push({ line, author, date, commit });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* skip lines that can't be blamed */
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
41
|
+
export function runFindingLineBlame(argv) {
|
|
42
|
+
const verdictIdx = argv.indexOf("--verdict");
|
|
43
|
+
const fileIdx = argv.indexOf("--file");
|
|
44
|
+
const formatIdx = argv.indexOf("--format");
|
|
45
|
+
const verdictPath = verdictIdx >= 0 ? argv[verdictIdx + 1] : undefined;
|
|
46
|
+
const sourceFile = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
|
|
47
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
48
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
49
|
+
console.log(`
|
|
50
|
+
judges finding-line-blame — Map findings to git blame
|
|
51
|
+
|
|
52
|
+
Usage:
|
|
53
|
+
judges finding-line-blame --verdict <verdict.json> --file <source>
|
|
54
|
+
[--format table|json]
|
|
55
|
+
|
|
56
|
+
Options:
|
|
57
|
+
--verdict <path> Path to verdict JSON file (required)
|
|
58
|
+
--file <path> Source file to blame (required)
|
|
59
|
+
--format <fmt> Output format: table (default), json
|
|
60
|
+
--help, -h Show this help
|
|
61
|
+
`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!verdictPath || !sourceFile) {
|
|
65
|
+
console.error("Error: --verdict and --file required");
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!existsSync(verdictPath)) {
|
|
70
|
+
console.error(`Error: verdict not found: ${verdictPath}`);
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!existsSync(sourceFile)) {
|
|
75
|
+
console.error(`Error: file not found: ${sourceFile}`);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
let verdict;
|
|
80
|
+
try {
|
|
81
|
+
verdict = JSON.parse(readFileSync(verdictPath, "utf-8"));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
console.error("Error: invalid verdict JSON");
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const results = [];
|
|
89
|
+
for (const f of verdict.findings) {
|
|
90
|
+
if (!f.lineNumbers || f.lineNumbers.length === 0)
|
|
91
|
+
continue;
|
|
92
|
+
const blameLines = getBlameForLines(sourceFile, f.lineNumbers);
|
|
93
|
+
if (blameLines.length > 0) {
|
|
94
|
+
results.push({
|
|
95
|
+
ruleId: f.ruleId,
|
|
96
|
+
title: f.title,
|
|
97
|
+
severity: f.severity || "medium",
|
|
98
|
+
blameLines,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (format === "json") {
|
|
103
|
+
console.log(JSON.stringify(results, null, 2));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (results.length === 0) {
|
|
107
|
+
console.log("No blame data available for findings.");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
console.log(`\nFinding Line Blame — ${sourceFile}`);
|
|
111
|
+
console.log("═".repeat(70));
|
|
112
|
+
for (const r of results) {
|
|
113
|
+
console.log(`\n [${r.severity.toUpperCase()}] ${r.title}`);
|
|
114
|
+
console.log(` Rule: ${r.ruleId}`);
|
|
115
|
+
for (const b of r.blameLines) {
|
|
116
|
+
console.log(` L${b.line}: ${b.author} (${b.date}) ${b.commit}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Author summary
|
|
120
|
+
const authorCounts = new Map();
|
|
121
|
+
for (const r of results) {
|
|
122
|
+
for (const b of r.blameLines) {
|
|
123
|
+
authorCounts.set(b.author, (authorCounts.get(b.author) || 0) + 1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
console.log("\n" + "─".repeat(70));
|
|
127
|
+
console.log("Author Summary:");
|
|
128
|
+
for (const [author, count] of [...authorCounts.entries()].sort((a, b) => b[1] - a[1])) {
|
|
129
|
+
console.log(` ${author}: ${count} finding line(s)`);
|
|
130
|
+
}
|
|
131
|
+
console.log("═".repeat(70));
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=finding-line-blame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-line-blame.js","sourceRoot":"","sources":["../../src/commands/finding-line-blame.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-summary-digest — Generate concise digests of finding summaries.
|
|
3
|
+
*
|
|
4
|
+
* Creates executive-style summaries of review results suitable for
|
|
5
|
+
* stakeholder communication and quick decision-making.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runFindingSummaryDigest(argv: string[]): void;
|
|
8
|
+
//# sourceMappingURL=finding-summary-digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-summary-digest.d.ts","sourceRoot":"","sources":["../../src/commands/finding-summary-digest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgGH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAmE5D"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-summary-digest — Generate concise digests of finding summaries.
|
|
3
|
+
*
|
|
4
|
+
* Creates executive-style summaries of review results suitable for
|
|
5
|
+
* stakeholder communication and quick decision-making.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync } from "fs";
|
|
8
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
9
|
+
function severityEmoji(severity) {
|
|
10
|
+
switch (severity.toLowerCase()) {
|
|
11
|
+
case "critical":
|
|
12
|
+
return "[CRIT]";
|
|
13
|
+
case "high":
|
|
14
|
+
return "[HIGH]";
|
|
15
|
+
case "medium":
|
|
16
|
+
return "[MED]";
|
|
17
|
+
case "low":
|
|
18
|
+
return "[LOW]";
|
|
19
|
+
default:
|
|
20
|
+
return "[INFO]";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function generateDigest(verdict) {
|
|
24
|
+
const lines = [];
|
|
25
|
+
const total = verdict.findings.length;
|
|
26
|
+
// Header
|
|
27
|
+
lines.push("REVIEW DIGEST");
|
|
28
|
+
lines.push("=".repeat(50));
|
|
29
|
+
// Status
|
|
30
|
+
const status = verdict.overallVerdict === "pass" ? "PASS" : "FAIL";
|
|
31
|
+
lines.push(`Status: ${status} | Score: ${verdict.overallScore} | Findings: ${total}`);
|
|
32
|
+
lines.push("");
|
|
33
|
+
// Severity distribution
|
|
34
|
+
const sevCounts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
35
|
+
for (const f of verdict.findings) {
|
|
36
|
+
const sev = (f.severity || "medium").toLowerCase();
|
|
37
|
+
sevCounts[sev] = (sevCounts[sev] || 0) + 1;
|
|
38
|
+
}
|
|
39
|
+
lines.push("Severity Distribution:");
|
|
40
|
+
for (const [sev, count] of Object.entries(sevCounts)) {
|
|
41
|
+
if (count > 0) {
|
|
42
|
+
const bar = "█".repeat(Math.min(count, 20));
|
|
43
|
+
lines.push(` ${sev.padEnd(10)} ${bar} ${count}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
lines.push("");
|
|
47
|
+
// Top findings by severity
|
|
48
|
+
const criticalAndHigh = verdict.findings
|
|
49
|
+
.filter((f) => ["critical", "high"].includes((f.severity || "medium").toLowerCase()))
|
|
50
|
+
.slice(0, 5);
|
|
51
|
+
if (criticalAndHigh.length > 0) {
|
|
52
|
+
lines.push("Priority Findings:");
|
|
53
|
+
for (const f of criticalAndHigh) {
|
|
54
|
+
lines.push(` ${severityEmoji(f.severity || "medium")} ${f.title}`);
|
|
55
|
+
if (f.recommendation) {
|
|
56
|
+
const rec = f.recommendation.length > 60 ? f.recommendation.slice(0, 60) + "…" : f.recommendation;
|
|
57
|
+
lines.push(` Fix: ${rec}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
lines.push("");
|
|
61
|
+
}
|
|
62
|
+
// Rule coverage
|
|
63
|
+
const rules = new Set(verdict.findings.map((f) => f.ruleId));
|
|
64
|
+
lines.push(`Rules triggered: ${rules.size}`);
|
|
65
|
+
// Judge participation
|
|
66
|
+
if (verdict.evaluations && verdict.evaluations.length > 0) {
|
|
67
|
+
const passing = verdict.evaluations.filter((e) => e.verdict === "pass").length;
|
|
68
|
+
lines.push(`Judges: ${passing}/${verdict.evaluations.length} passing`);
|
|
69
|
+
}
|
|
70
|
+
lines.push("");
|
|
71
|
+
lines.push("=".repeat(50));
|
|
72
|
+
// Action items
|
|
73
|
+
if (sevCounts["critical"] > 0) {
|
|
74
|
+
lines.push(`ACTION REQUIRED: ${sevCounts["critical"]} critical finding(s) must be addressed before merge.`);
|
|
75
|
+
}
|
|
76
|
+
else if (sevCounts["high"] > 0) {
|
|
77
|
+
lines.push(`RECOMMENDED: Address ${sevCounts["high"]} high-severity finding(s) before merge.`);
|
|
78
|
+
}
|
|
79
|
+
else if (total > 0) {
|
|
80
|
+
lines.push(`ADVISORY: ${total} finding(s) for review. No blockers detected.`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
lines.push("CLEAN: No findings detected.");
|
|
84
|
+
}
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
87
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
88
|
+
export function runFindingSummaryDigest(argv) {
|
|
89
|
+
const fileIdx = argv.indexOf("--file");
|
|
90
|
+
const formatIdx = argv.indexOf("--format");
|
|
91
|
+
const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
|
|
92
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "text";
|
|
93
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
94
|
+
console.log(`
|
|
95
|
+
judges finding-summary-digest — Generate concise finding digests
|
|
96
|
+
|
|
97
|
+
Usage:
|
|
98
|
+
judges finding-summary-digest --file <verdict.json> [--format text|json]
|
|
99
|
+
|
|
100
|
+
Options:
|
|
101
|
+
--file <path> Path to verdict JSON file (required)
|
|
102
|
+
--format <fmt> Output format: text (default), json
|
|
103
|
+
--help, -h Show this help
|
|
104
|
+
`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!filePath) {
|
|
108
|
+
console.error("Error: --file required");
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!existsSync(filePath)) {
|
|
113
|
+
console.error(`Error: file not found: ${filePath}`);
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
let verdict;
|
|
118
|
+
try {
|
|
119
|
+
verdict = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
console.error("Error: invalid JSON");
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (format === "json") {
|
|
127
|
+
const sevCounts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
128
|
+
for (const f of verdict.findings) {
|
|
129
|
+
const sev = (f.severity || "medium").toLowerCase();
|
|
130
|
+
sevCounts[sev] = (sevCounts[sev] || 0) + 1;
|
|
131
|
+
}
|
|
132
|
+
console.log(JSON.stringify({
|
|
133
|
+
status: verdict.overallVerdict,
|
|
134
|
+
score: verdict.overallScore,
|
|
135
|
+
totalFindings: verdict.findings.length,
|
|
136
|
+
severityCounts: sevCounts,
|
|
137
|
+
rulesTriggered: new Set(verdict.findings.map((f) => f.ruleId)).size,
|
|
138
|
+
topFindings: verdict.findings
|
|
139
|
+
.slice(0, 5)
|
|
140
|
+
.map((f) => ({ title: f.title, severity: f.severity, ruleId: f.ruleId })),
|
|
141
|
+
}, null, 2));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
console.log(generateDigest(verdict));
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=finding-summary-digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-summary-digest.js","sourceRoot":"","sources":["../../src/commands/finding-summary-digest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-approval-gate — Gate reviews with configurable approval criteria.
|
|
3
|
+
*
|
|
4
|
+
* Evaluates whether a review verdict meets predefined quality gates
|
|
5
|
+
* and provides pass/fail determination for CI/CD integration.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runReviewApprovalGate(argv: string[]): void;
|
|
8
|
+
//# sourceMappingURL=review-approval-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-approval-gate.d.ts","sourceRoot":"","sources":["../../src/commands/review-approval-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8EH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2I1D"}
|