@kevinrabun/judges 3.41.0 → 3.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -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/assign-findings.d.ts +37 -0
- package/dist/commands/assign-findings.d.ts.map +1 -0
- package/dist/commands/assign-findings.js +178 -0
- package/dist/commands/assign-findings.js.map +1 -0
- package/dist/commands/auto-triage.d.ts +32 -0
- package/dist/commands/auto-triage.d.ts.map +1 -0
- package/dist/commands/auto-triage.js +126 -0
- package/dist/commands/auto-triage.js.map +1 -0
- package/dist/commands/ci-template.d.ts +15 -0
- package/dist/commands/ci-template.d.ts.map +1 -0
- package/dist/commands/ci-template.js +212 -0
- package/dist/commands/ci-template.js.map +1 -0
- package/dist/commands/coverage-map.d.ts +23 -0
- package/dist/commands/coverage-map.d.ts.map +1 -0
- package/dist/commands/coverage-map.js +223 -0
- package/dist/commands/coverage-map.js.map +1 -0
- package/dist/commands/diff-only.d.ts +34 -0
- package/dist/commands/diff-only.d.ts.map +1 -0
- package/dist/commands/diff-only.js +152 -0
- package/dist/commands/diff-only.js.map +1 -0
- package/dist/commands/false-negatives.d.ts +35 -0
- package/dist/commands/false-negatives.d.ts.map +1 -0
- package/dist/commands/false-negatives.js +166 -0
- package/dist/commands/false-negatives.js.map +1 -0
- package/dist/commands/group-findings.d.ts +23 -0
- package/dist/commands/group-findings.d.ts.map +1 -0
- package/dist/commands/group-findings.js +155 -0
- package/dist/commands/group-findings.js.map +1 -0
- package/dist/commands/hook-install.d.ts +22 -0
- package/dist/commands/hook-install.d.ts.map +1 -0
- package/dist/commands/hook-install.js +143 -0
- package/dist/commands/hook-install.js.map +1 -0
- package/dist/commands/policy-audit.d.ts +53 -0
- package/dist/commands/policy-audit.d.ts.map +1 -0
- package/dist/commands/policy-audit.js +161 -0
- package/dist/commands/policy-audit.js.map +1 -0
- package/dist/commands/pr-summary.d.ts +26 -0
- package/dist/commands/pr-summary.d.ts.map +1 -0
- package/dist/commands/pr-summary.js +188 -0
- package/dist/commands/pr-summary.js.map +1 -0
- package/dist/commands/profile.d.ts +38 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +102 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/regression-alert.d.ts +32 -0
- package/dist/commands/regression-alert.d.ts.map +1 -0
- package/dist/commands/regression-alert.js +216 -0
- package/dist/commands/regression-alert.js.map +1 -0
- package/dist/commands/remediation.d.ts +21 -0
- package/dist/commands/remediation.d.ts.map +1 -0
- package/dist/commands/remediation.js +257 -0
- package/dist/commands/remediation.js.map +1 -0
- package/dist/commands/sla-track.d.ts +57 -0
- package/dist/commands/sla-track.d.ts.map +1 -0
- package/dist/commands/sla-track.js +269 -0
- package/dist/commands/sla-track.js.map +1 -0
- package/dist/commands/smart-select.d.ts +27 -0
- package/dist/commands/smart-select.d.ts.map +1 -0
- package/dist/commands/smart-select.js +346 -0
- package/dist/commands/smart-select.js.map +1 -0
- package/dist/commands/ticket-sync.d.ts +26 -0
- package/dist/commands/ticket-sync.d.ts.map +1 -0
- package/dist/commands/ticket-sync.js +236 -0
- package/dist/commands/ticket-sync.js.map +1 -0
- package/dist/commands/upload.d.ts +14 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +173 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/commands/validate-config.d.ts +17 -0
- package/dist/commands/validate-config.d.ts.map +1 -0
- package/dist/commands/validate-config.js +268 -0
- package/dist/commands/validate-config.js.map +1 -0
- package/dist/commands/warm-cache.d.ts +31 -0
- package/dist/commands/warm-cache.d.ts.map +1 -0
- package/dist/commands/warm-cache.js +166 -0
- package/dist/commands/warm-cache.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule coverage map — show which rules apply to which languages,
|
|
3
|
+
* helping teams understand their coverage and identify gaps.
|
|
4
|
+
*/
|
|
5
|
+
// ─── Rules-to-Language Mapping ──────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* Universal rules applicable to all programming languages.
|
|
8
|
+
*/
|
|
9
|
+
const UNIVERSAL_RULES = [
|
|
10
|
+
{ pattern: "SEC-", judge: "cybersecurity", severity: "high" },
|
|
11
|
+
{ pattern: "ERR-", judge: "error-handling", severity: "medium" },
|
|
12
|
+
{ pattern: "MAINT-", judge: "maintainability", severity: "low" },
|
|
13
|
+
{ pattern: "DOC-", judge: "documentation", severity: "low" },
|
|
14
|
+
{ pattern: "STRUCT-", judge: "code-structure", severity: "medium" },
|
|
15
|
+
{ pattern: "TEST-", judge: "testing", severity: "medium" },
|
|
16
|
+
{ pattern: "LOG-", judge: "logging-privacy", severity: "medium" },
|
|
17
|
+
{ pattern: "AI-", judge: "ai-code-safety", severity: "high" },
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Language-specific rules with limited applicability.
|
|
21
|
+
*/
|
|
22
|
+
const LANGUAGE_RULES = [
|
|
23
|
+
{
|
|
24
|
+
pattern: "INJECT-SQL",
|
|
25
|
+
judge: "cybersecurity",
|
|
26
|
+
severity: "critical",
|
|
27
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "php", "ruby", "go"],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
pattern: "INJECT-CMD",
|
|
31
|
+
judge: "cybersecurity",
|
|
32
|
+
severity: "critical",
|
|
33
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "php", "ruby", "go", "rust"],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
pattern: "XSS-",
|
|
37
|
+
judge: "cybersecurity",
|
|
38
|
+
severity: "high",
|
|
39
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "php", "ruby"],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
pattern: "SSRF-",
|
|
43
|
+
judge: "cybersecurity",
|
|
44
|
+
severity: "high",
|
|
45
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "go", "ruby"],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pattern: "CRYPTO-",
|
|
49
|
+
judge: "cybersecurity",
|
|
50
|
+
severity: "high",
|
|
51
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "go", "rust", "c", "cpp"],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
pattern: "AUTH-",
|
|
55
|
+
judge: "authentication",
|
|
56
|
+
severity: "high",
|
|
57
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "go", "ruby", "php"],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
pattern: "PERF-",
|
|
61
|
+
judge: "performance",
|
|
62
|
+
severity: "medium",
|
|
63
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "go", "rust", "c", "cpp"],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
pattern: "DB-",
|
|
67
|
+
judge: "database",
|
|
68
|
+
severity: "medium",
|
|
69
|
+
languages: ["typescript", "javascript", "python", "java", "csharp", "go", "ruby", "sql"],
|
|
70
|
+
},
|
|
71
|
+
{ pattern: "IAC-", judge: "iac-security", severity: "high", languages: ["terraform", "bicep", "yaml", "dockerfile"] },
|
|
72
|
+
{ pattern: "CICD-", judge: "ci-cd", severity: "high", languages: ["yaml", "dockerfile", "bash", "powershell"] },
|
|
73
|
+
{
|
|
74
|
+
pattern: "CONCUR-",
|
|
75
|
+
judge: "concurrency",
|
|
76
|
+
severity: "high",
|
|
77
|
+
languages: ["go", "rust", "java", "csharp", "python", "c", "cpp"],
|
|
78
|
+
},
|
|
79
|
+
{ pattern: "A11Y-", judge: "accessibility", severity: "medium", languages: ["typescript", "javascript", "html"] },
|
|
80
|
+
{
|
|
81
|
+
pattern: "I18N-",
|
|
82
|
+
judge: "internationalization",
|
|
83
|
+
severity: "low",
|
|
84
|
+
languages: ["typescript", "javascript", "python", "java", "csharp"],
|
|
85
|
+
},
|
|
86
|
+
{ pattern: "FW-REACT", judge: "framework-safety", severity: "high", languages: ["typescript", "javascript"] },
|
|
87
|
+
{ pattern: "FW-EXPRESS", judge: "framework-safety", severity: "high", languages: ["typescript", "javascript"] },
|
|
88
|
+
{ pattern: "FW-DJANGO", judge: "framework-safety", severity: "high", languages: ["python"] },
|
|
89
|
+
{ pattern: "FW-FLASK", judge: "framework-safety", severity: "high", languages: ["python"] },
|
|
90
|
+
{ pattern: "FW-SPRING", judge: "framework-safety", severity: "high", languages: ["java", "kotlin"] },
|
|
91
|
+
{ pattern: "FW-RAILS", judge: "framework-safety", severity: "high", languages: ["ruby"] },
|
|
92
|
+
{ pattern: "FW-NEXT", judge: "framework-safety", severity: "high", languages: ["typescript", "javascript"] },
|
|
93
|
+
{ pattern: "FW-FASTAPI", judge: "framework-safety", severity: "high", languages: ["python"] },
|
|
94
|
+
];
|
|
95
|
+
const ALL_LANGUAGES = [
|
|
96
|
+
"typescript",
|
|
97
|
+
"javascript",
|
|
98
|
+
"python",
|
|
99
|
+
"java",
|
|
100
|
+
"csharp",
|
|
101
|
+
"go",
|
|
102
|
+
"rust",
|
|
103
|
+
"ruby",
|
|
104
|
+
"php",
|
|
105
|
+
"c",
|
|
106
|
+
"cpp",
|
|
107
|
+
"kotlin",
|
|
108
|
+
"scala",
|
|
109
|
+
"swift",
|
|
110
|
+
"dart",
|
|
111
|
+
"bash",
|
|
112
|
+
"powershell",
|
|
113
|
+
"sql",
|
|
114
|
+
"terraform",
|
|
115
|
+
"bicep",
|
|
116
|
+
"yaml",
|
|
117
|
+
"dockerfile",
|
|
118
|
+
"html",
|
|
119
|
+
];
|
|
120
|
+
// ─── Coverage Computation ───────────────────────────────────────────────────
|
|
121
|
+
export function buildCoverageMap(languages) {
|
|
122
|
+
const langs = languages || ALL_LANGUAGES;
|
|
123
|
+
const rules = [];
|
|
124
|
+
const matrix = {};
|
|
125
|
+
// Universal rules
|
|
126
|
+
for (const r of UNIVERSAL_RULES) {
|
|
127
|
+
const coverage = {
|
|
128
|
+
ruleId: r.pattern.replace(/-$/, ""),
|
|
129
|
+
languages: [...langs],
|
|
130
|
+
severity: r.severity,
|
|
131
|
+
judge: r.judge,
|
|
132
|
+
};
|
|
133
|
+
rules.push(coverage);
|
|
134
|
+
matrix[coverage.ruleId] = {};
|
|
135
|
+
for (const l of langs)
|
|
136
|
+
matrix[coverage.ruleId][l] = true;
|
|
137
|
+
}
|
|
138
|
+
// Language-specific rules
|
|
139
|
+
for (const r of LANGUAGE_RULES) {
|
|
140
|
+
const applicableLangs = r.languages.filter((l) => langs.includes(l));
|
|
141
|
+
const coverage = {
|
|
142
|
+
ruleId: r.pattern.replace(/-$/, ""),
|
|
143
|
+
languages: applicableLangs,
|
|
144
|
+
severity: r.severity,
|
|
145
|
+
judge: r.judge,
|
|
146
|
+
};
|
|
147
|
+
rules.push(coverage);
|
|
148
|
+
matrix[coverage.ruleId] = {};
|
|
149
|
+
for (const l of langs)
|
|
150
|
+
matrix[coverage.ruleId][l] = applicableLangs.includes(l);
|
|
151
|
+
}
|
|
152
|
+
// Statistics
|
|
153
|
+
const byLanguage = {};
|
|
154
|
+
const byJudge = {};
|
|
155
|
+
for (const r of rules) {
|
|
156
|
+
byJudge[r.judge] = (byJudge[r.judge] || 0) + 1;
|
|
157
|
+
for (const l of r.languages) {
|
|
158
|
+
byLanguage[l] = (byLanguage[l] || 0) + 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
languages: langs,
|
|
163
|
+
rules,
|
|
164
|
+
matrix,
|
|
165
|
+
stats: { totalRules: rules.length, byLanguage, byJudge },
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
169
|
+
export function runCoverageMap(argv) {
|
|
170
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
171
|
+
console.log(`
|
|
172
|
+
judges coverage-map — Show which rules apply to which languages
|
|
173
|
+
|
|
174
|
+
Usage:
|
|
175
|
+
judges coverage-map Full coverage matrix
|
|
176
|
+
judges coverage-map --languages typescript,python Focus on specific languages
|
|
177
|
+
judges coverage-map --judge cybersecurity Filter by judge
|
|
178
|
+
|
|
179
|
+
Options:
|
|
180
|
+
--languages <list> Comma-separated languages to show
|
|
181
|
+
--judge <id> Filter rules by judge
|
|
182
|
+
--format json JSON output
|
|
183
|
+
--help, -h Show this help
|
|
184
|
+
`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const langsArg = argv.find((_a, i) => argv[i - 1] === "--languages");
|
|
188
|
+
const judgeFilter = argv.find((_a, i) => argv[i - 1] === "--judge");
|
|
189
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
190
|
+
const languages = langsArg ? langsArg.split(",").map((s) => s.trim()) : undefined;
|
|
191
|
+
const map = buildCoverageMap(languages);
|
|
192
|
+
let rules = map.rules;
|
|
193
|
+
if (judgeFilter) {
|
|
194
|
+
rules = rules.filter((r) => r.judge === judgeFilter);
|
|
195
|
+
}
|
|
196
|
+
if (format === "json") {
|
|
197
|
+
console.log(JSON.stringify({ ...map, rules }, null, 2));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
console.log(`\n Rule Coverage Map\n`);
|
|
201
|
+
console.log(` Total rules: ${rules.length} | Languages: ${map.languages.length}\n`);
|
|
202
|
+
// Show compact matrix
|
|
203
|
+
const displayLangs = map.languages.slice(0, 12); // limit width
|
|
204
|
+
const header = " " + "Rule".padEnd(20) + displayLangs.map((l) => l.slice(0, 4).padEnd(5)).join("");
|
|
205
|
+
console.log(header);
|
|
206
|
+
console.log(" " + "─".repeat(header.length - 2));
|
|
207
|
+
for (const r of rules) {
|
|
208
|
+
const row = displayLangs.map((l) => (r.languages.includes(l) ? " ✓ " : " · ")).join("");
|
|
209
|
+
console.log(` ${r.ruleId.padEnd(20)}${row}`);
|
|
210
|
+
}
|
|
211
|
+
console.log(`\n Coverage by language:`);
|
|
212
|
+
const sorted = Object.entries(map.stats.byLanguage).sort((a, b) => b[1] - a[1]);
|
|
213
|
+
for (const [lang, count] of sorted) {
|
|
214
|
+
const pct = ((count / rules.length) * 100).toFixed(0);
|
|
215
|
+
console.log(` ${lang.padEnd(15)} ${String(count).padStart(3)} rules (${pct}%)`);
|
|
216
|
+
}
|
|
217
|
+
console.log(`\n Coverage by judge:`);
|
|
218
|
+
for (const [judge, count] of Object.entries(map.stats.byJudge).sort((a, b) => b[1] - a[1])) {
|
|
219
|
+
console.log(` ${judge.padEnd(25)} ${count} rules`);
|
|
220
|
+
}
|
|
221
|
+
console.log("");
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=coverage-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-map.js","sourceRoot":"","sources":["../../src/commands/coverage-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff-only evaluation — evaluate only changed lines in a PR or git diff.
|
|
3
|
+
*
|
|
4
|
+
* Parses unified diff output to identify changed line ranges,
|
|
5
|
+
* then filters evaluation findings to only those touching changed code.
|
|
6
|
+
* This drastically reduces noise in CI review comments.
|
|
7
|
+
*/
|
|
8
|
+
import type { Finding } from "../types.js";
|
|
9
|
+
export interface DiffHunk {
|
|
10
|
+
file: string;
|
|
11
|
+
startLine: number;
|
|
12
|
+
lineCount: number;
|
|
13
|
+
}
|
|
14
|
+
export interface DiffFilterResult {
|
|
15
|
+
original: number;
|
|
16
|
+
filtered: number;
|
|
17
|
+
removed: number;
|
|
18
|
+
findings: Finding[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse a unified diff to extract changed file/line ranges.
|
|
22
|
+
* Handles both `git diff` and `git diff --cached` output.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseDiff(diff: string): DiffHunk[];
|
|
25
|
+
/**
|
|
26
|
+
* Filter findings to only those touching changed lines.
|
|
27
|
+
*/
|
|
28
|
+
export declare function filterByDiff(findings: Finding[], diff: string): DiffFilterResult;
|
|
29
|
+
/**
|
|
30
|
+
* Get the list of changed files from a diff.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getChangedFiles(diff: string): string[];
|
|
33
|
+
export declare function runDiffOnly(argv: string[]): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=diff-only.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-only.d.ts","sourceRoot":"","sources":["../../src/commands/diff-only.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAwBlD;AAcD;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAUhF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOtD;AAID,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwF/D"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff-only evaluation — evaluate only changed lines in a PR or git diff.
|
|
3
|
+
*
|
|
4
|
+
* Parses unified diff output to identify changed line ranges,
|
|
5
|
+
* then filters evaluation findings to only those touching changed code.
|
|
6
|
+
* This drastically reduces noise in CI review comments.
|
|
7
|
+
*/
|
|
8
|
+
// ─── Diff Parsing ───────────────────────────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Parse a unified diff to extract changed file/line ranges.
|
|
11
|
+
* Handles both `git diff` and `git diff --cached` output.
|
|
12
|
+
*/
|
|
13
|
+
export function parseDiff(diff) {
|
|
14
|
+
const hunks = [];
|
|
15
|
+
let currentFile = "";
|
|
16
|
+
for (const line of diff.split("\n")) {
|
|
17
|
+
// Match +++ b/path/to/file
|
|
18
|
+
const fileMatch = line.match(/^\+\+\+ b\/(.+)$/);
|
|
19
|
+
if (fileMatch) {
|
|
20
|
+
currentFile = fileMatch[1];
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
// Match @@ -old,count +new,count @@
|
|
24
|
+
const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
|
|
25
|
+
if (hunkMatch && currentFile) {
|
|
26
|
+
hunks.push({
|
|
27
|
+
file: currentFile,
|
|
28
|
+
startLine: parseInt(hunkMatch[1], 10),
|
|
29
|
+
lineCount: parseInt(hunkMatch[2] || "1", 10),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return hunks;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check whether a finding overlaps with any changed hunk.
|
|
37
|
+
*/
|
|
38
|
+
function isInDiff(finding, hunks) {
|
|
39
|
+
const findingLine = finding.lineNumbers?.[0];
|
|
40
|
+
if (!findingLine)
|
|
41
|
+
return false;
|
|
42
|
+
return hunks.some((h) => {
|
|
43
|
+
return findingLine >= h.startLine && findingLine <= h.startLine + h.lineCount - 1;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Filter findings to only those touching changed lines.
|
|
48
|
+
*/
|
|
49
|
+
export function filterByDiff(findings, diff) {
|
|
50
|
+
const hunks = parseDiff(diff);
|
|
51
|
+
const filtered = findings.filter((f) => isInDiff(f, hunks));
|
|
52
|
+
return {
|
|
53
|
+
original: findings.length,
|
|
54
|
+
filtered: filtered.length,
|
|
55
|
+
removed: findings.length - filtered.length,
|
|
56
|
+
findings: filtered,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the list of changed files from a diff.
|
|
61
|
+
*/
|
|
62
|
+
export function getChangedFiles(diff) {
|
|
63
|
+
const files = new Set();
|
|
64
|
+
for (const line of diff.split("\n")) {
|
|
65
|
+
const match = line.match(/^\+\+\+ b\/(.+)$/);
|
|
66
|
+
if (match)
|
|
67
|
+
files.add(match[1]);
|
|
68
|
+
}
|
|
69
|
+
return [...files];
|
|
70
|
+
}
|
|
71
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
72
|
+
export async function runDiffOnly(argv) {
|
|
73
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
74
|
+
console.log(`
|
|
75
|
+
judges diff-only — Evaluate only changed lines in a PR or diff
|
|
76
|
+
|
|
77
|
+
Usage:
|
|
78
|
+
judges diff-only --base main Diff against main branch
|
|
79
|
+
judges diff-only --base HEAD~1 Diff against previous commit
|
|
80
|
+
judges diff-only --diff-file changes.patch Use a pre-generated diff
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
--base <ref> Git ref to diff against (default: main)
|
|
84
|
+
--diff-file <path> Pre-generated diff file
|
|
85
|
+
--input <path> JSON results to filter (default: run fresh eval)
|
|
86
|
+
--format json JSON output
|
|
87
|
+
--help, -h Show this help
|
|
88
|
+
|
|
89
|
+
The command diffs against the base ref, identifies changed lines,
|
|
90
|
+
and filters findings to only those touching changed code. This is
|
|
91
|
+
ideal for CI pipelines reviewing PRs.
|
|
92
|
+
`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const { readFileSync, existsSync } = await import("fs");
|
|
96
|
+
const { execSync } = await import("child_process");
|
|
97
|
+
let diff;
|
|
98
|
+
const diffFile = argv.find((_a, i) => argv[i - 1] === "--diff-file");
|
|
99
|
+
if (diffFile && existsSync(diffFile)) {
|
|
100
|
+
diff = readFileSync(diffFile, "utf-8");
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const base = argv.find((_a, i) => argv[i - 1] === "--base") || "main";
|
|
104
|
+
try {
|
|
105
|
+
diff = execSync(`git diff ${base}`, { encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 });
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
console.error(`Error: could not run git diff ${base}`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const changedFiles = getChangedFiles(diff);
|
|
113
|
+
const hunks = parseDiff(diff);
|
|
114
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
115
|
+
const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
|
|
116
|
+
if (inputPath && existsSync(inputPath)) {
|
|
117
|
+
const data = JSON.parse(readFileSync(inputPath, "utf-8"));
|
|
118
|
+
const findings = data.evaluations
|
|
119
|
+
? data.evaluations.flatMap((e) => e.findings || [])
|
|
120
|
+
: data.findings || data;
|
|
121
|
+
const result = filterByDiff(findings, diff);
|
|
122
|
+
if (format === "json") {
|
|
123
|
+
console.log(JSON.stringify(result, null, 2));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
console.log(`\n Diff-Only Filter Results\n`);
|
|
127
|
+
console.log(` Changed files: ${changedFiles.length}`);
|
|
128
|
+
console.log(` Changed hunks: ${hunks.length}`);
|
|
129
|
+
console.log(` Original findings: ${result.original}`);
|
|
130
|
+
console.log(` In diff: ${result.filtered}`);
|
|
131
|
+
console.log(` Filtered out: ${result.removed}\n`);
|
|
132
|
+
for (const f of result.findings) {
|
|
133
|
+
const loc = f.lineNumbers?.length ? `:${f.lineNumbers[0]}` : "";
|
|
134
|
+
console.log(` ${f.severity.padEnd(8)} ${f.ruleId}: ${f.title.slice(0, 80)}${loc}`);
|
|
135
|
+
}
|
|
136
|
+
console.log("");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Just show diff info without filtering
|
|
140
|
+
if (format === "json") {
|
|
141
|
+
console.log(JSON.stringify({ changedFiles, hunks, totalHunks: hunks.length }, null, 2));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
console.log(`\n Changed Files (${changedFiles.length}):\n`);
|
|
145
|
+
for (const f of changedFiles) {
|
|
146
|
+
const fileHunks = hunks.filter((h) => h.file === f);
|
|
147
|
+
const totalLines = fileHunks.reduce((s, h) => s + h.lineCount, 0);
|
|
148
|
+
console.log(` ${f} (${fileHunks.length} hunks, ${totalLines} lines)`);
|
|
149
|
+
}
|
|
150
|
+
console.log(`\n Run with --input <results.json> to filter findings.\n`);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=diff-only.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-only.js","sourceRoot":"","sources":["../../src/commands/diff-only.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* False-negative report — collect and analyze cases where Judges
|
|
3
|
+
* missed a real vulnerability or bug that was later found manually.
|
|
4
|
+
*
|
|
5
|
+
* Builds a local feedback database (.judges-false-negatives.json)
|
|
6
|
+
* that helps teams understand blind spots and request new rules.
|
|
7
|
+
*/
|
|
8
|
+
export interface FalseNegativeEntry {
|
|
9
|
+
id: string;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
file: string;
|
|
12
|
+
line?: number;
|
|
13
|
+
category: string;
|
|
14
|
+
description: string;
|
|
15
|
+
severity: string;
|
|
16
|
+
expectedRule?: string;
|
|
17
|
+
language: string;
|
|
18
|
+
codeSnippet?: string;
|
|
19
|
+
reportedBy?: string;
|
|
20
|
+
status: "open" | "rule-added" | "wont-fix" | "duplicate";
|
|
21
|
+
}
|
|
22
|
+
export interface FalseNegativeDb {
|
|
23
|
+
entries: FalseNegativeEntry[];
|
|
24
|
+
version: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function addFalseNegative(entry: Omit<FalseNegativeEntry, "id" | "timestamp" | "status">): FalseNegativeEntry;
|
|
27
|
+
export declare function getFalseNegativeStats(db: FalseNegativeDb): {
|
|
28
|
+
total: number;
|
|
29
|
+
open: number;
|
|
30
|
+
byCategory: Record<string, number>;
|
|
31
|
+
bySeverity: Record<string, number>;
|
|
32
|
+
byLanguage: Record<string, number>;
|
|
33
|
+
};
|
|
34
|
+
export declare function runFalseNegativeReport(argv: string[]): void;
|
|
35
|
+
//# sourceMappingURL=false-negatives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"false-negatives.d.ts","sourceRoot":"","sources":["../../src/commands/false-negatives.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAuBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,WAAW,GAAG,QAAQ,CAAC,GAAG,kBAAkB,CAcnH;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,eAAe,GAAG;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAaA;AAID,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2G3D"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* False-negative report — collect and analyze cases where Judges
|
|
3
|
+
* missed a real vulnerability or bug that was later found manually.
|
|
4
|
+
*
|
|
5
|
+
* Builds a local feedback database (.judges-false-negatives.json)
|
|
6
|
+
* that helps teams understand blind spots and request new rules.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "crypto";
|
|
9
|
+
// ─── Database ───────────────────────────────────────────────────────────────
|
|
10
|
+
const DB_FILE = ".judges-false-negatives.json";
|
|
11
|
+
function loadDb() {
|
|
12
|
+
const { readFileSync, existsSync } = require("fs");
|
|
13
|
+
if (existsSync(DB_FILE)) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(readFileSync(DB_FILE, "utf-8"));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
/* corrupt */
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { entries: [], version: "1.0" };
|
|
22
|
+
}
|
|
23
|
+
function saveDb(db) {
|
|
24
|
+
const { writeFileSync } = require("fs");
|
|
25
|
+
writeFileSync(DB_FILE, JSON.stringify(db, null, 2), "utf-8");
|
|
26
|
+
}
|
|
27
|
+
export function addFalseNegative(entry) {
|
|
28
|
+
const db = loadDb();
|
|
29
|
+
const fn = {
|
|
30
|
+
...entry,
|
|
31
|
+
id: createHash("sha256")
|
|
32
|
+
.update(Date.now().toString() + entry.file + entry.description)
|
|
33
|
+
.digest("hex")
|
|
34
|
+
.slice(0, 10),
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
|
+
status: "open",
|
|
37
|
+
};
|
|
38
|
+
db.entries.push(fn);
|
|
39
|
+
saveDb(db);
|
|
40
|
+
return fn;
|
|
41
|
+
}
|
|
42
|
+
export function getFalseNegativeStats(db) {
|
|
43
|
+
const open = db.entries.filter((e) => e.status === "open").length;
|
|
44
|
+
const byCategory = {};
|
|
45
|
+
const bySeverity = {};
|
|
46
|
+
const byLanguage = {};
|
|
47
|
+
for (const e of db.entries) {
|
|
48
|
+
byCategory[e.category] = (byCategory[e.category] || 0) + 1;
|
|
49
|
+
bySeverity[e.severity] = (bySeverity[e.severity] || 0) + 1;
|
|
50
|
+
byLanguage[e.language] = (byLanguage[e.language] || 0) + 1;
|
|
51
|
+
}
|
|
52
|
+
return { total: db.entries.length, open, byCategory, bySeverity, byLanguage };
|
|
53
|
+
}
|
|
54
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
55
|
+
export function runFalseNegativeReport(argv) {
|
|
56
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
57
|
+
console.log(`
|
|
58
|
+
judges false-negatives — Report and track missed vulnerabilities
|
|
59
|
+
|
|
60
|
+
Usage:
|
|
61
|
+
judges false-negatives Show report
|
|
62
|
+
judges false-negatives --add --file src/app.ts \\
|
|
63
|
+
--line 42 --category injection --severity high \\
|
|
64
|
+
--description "SQL injection via user input" Add a missed finding
|
|
65
|
+
judges false-negatives --resolve <id> Mark as resolved
|
|
66
|
+
|
|
67
|
+
Options:
|
|
68
|
+
--add Add a new false-negative report
|
|
69
|
+
--file <path> File where the issue was found
|
|
70
|
+
--line <n> Line number
|
|
71
|
+
--category <cat> Category (injection, auth, crypto, xss, etc.)
|
|
72
|
+
--severity <level> Severity (critical, high, medium, low)
|
|
73
|
+
--description <text> Description of what was missed
|
|
74
|
+
--language <lang> Language (auto-detected from file)
|
|
75
|
+
--resolve <id> Mark entry as resolved
|
|
76
|
+
--format json JSON output
|
|
77
|
+
--help, -h Show this help
|
|
78
|
+
|
|
79
|
+
This builds a local feedback database that helps identify blind spots
|
|
80
|
+
in the current rule set, informing future rule development.
|
|
81
|
+
`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
85
|
+
if (argv.includes("--add")) {
|
|
86
|
+
const file = argv.find((_a, i) => argv[i - 1] === "--file") || "";
|
|
87
|
+
const lineStr = argv.find((_a, i) => argv[i - 1] === "--line");
|
|
88
|
+
const category = argv.find((_a, i) => argv[i - 1] === "--category") || "unknown";
|
|
89
|
+
const severity = argv.find((_a, i) => argv[i - 1] === "--severity") || "medium";
|
|
90
|
+
const description = argv.find((_a, i) => argv[i - 1] === "--description") || "";
|
|
91
|
+
const language = argv.find((_a, i) => argv[i - 1] === "--language") || detectLanguage(file);
|
|
92
|
+
if (!file || !description) {
|
|
93
|
+
console.error("Error: --file and --description required");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const entry = addFalseNegative({
|
|
97
|
+
file,
|
|
98
|
+
line: lineStr ? parseInt(lineStr, 10) : undefined,
|
|
99
|
+
category,
|
|
100
|
+
severity,
|
|
101
|
+
description,
|
|
102
|
+
language,
|
|
103
|
+
});
|
|
104
|
+
console.log(` ✅ Added false-negative report: ${entry.id}`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const resolveId = argv.find((_a, i) => argv[i - 1] === "--resolve");
|
|
108
|
+
if (resolveId) {
|
|
109
|
+
const db = loadDb();
|
|
110
|
+
const entry = db.entries.find((e) => e.id === resolveId);
|
|
111
|
+
if (!entry) {
|
|
112
|
+
console.error(`Error: entry ${resolveId} not found`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
entry.status = "rule-added";
|
|
116
|
+
saveDb(db);
|
|
117
|
+
console.log(` ✅ Resolved: ${resolveId}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// Show report
|
|
121
|
+
const db = loadDb();
|
|
122
|
+
if (db.entries.length === 0) {
|
|
123
|
+
console.log("\n No false-negative reports. Use --add to report a missed finding.\n");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const stats = getFalseNegativeStats(db);
|
|
127
|
+
if (format === "json") {
|
|
128
|
+
console.log(JSON.stringify({ stats, entries: db.entries }, null, 2));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
console.log(`\n False-Negative Analysis\n`);
|
|
132
|
+
console.log(` Total: ${stats.total} | Open: ${stats.open}\n`);
|
|
133
|
+
console.log(" By Category:");
|
|
134
|
+
for (const [cat, count] of Object.entries(stats.byCategory).sort((a, b) => b[1] - a[1])) {
|
|
135
|
+
console.log(` ${cat.padEnd(20)} ${count}`);
|
|
136
|
+
}
|
|
137
|
+
console.log("\n By Severity:");
|
|
138
|
+
for (const [sev, count] of Object.entries(stats.bySeverity).sort((a, b) => b[1] - a[1])) {
|
|
139
|
+
console.log(` ${sev.padEnd(20)} ${count}`);
|
|
140
|
+
}
|
|
141
|
+
console.log("\n Recent entries:");
|
|
142
|
+
for (const e of db.entries.slice(-10)) {
|
|
143
|
+
const status = e.status === "open" ? "🔴" : "✅";
|
|
144
|
+
console.log(` ${status} ${e.id} ${e.severity.padEnd(8)} ${e.category.padEnd(15)} ${e.description.slice(0, 50)}`);
|
|
145
|
+
}
|
|
146
|
+
console.log("");
|
|
147
|
+
}
|
|
148
|
+
function detectLanguage(file) {
|
|
149
|
+
const { extname } = require("path");
|
|
150
|
+
const ext = extname(file).toLowerCase();
|
|
151
|
+
const map = {
|
|
152
|
+
".ts": "typescript",
|
|
153
|
+
".tsx": "typescript",
|
|
154
|
+
".js": "javascript",
|
|
155
|
+
".jsx": "javascript",
|
|
156
|
+
".py": "python",
|
|
157
|
+
".go": "go",
|
|
158
|
+
".rs": "rust",
|
|
159
|
+
".java": "java",
|
|
160
|
+
".cs": "csharp",
|
|
161
|
+
".rb": "ruby",
|
|
162
|
+
".php": "php",
|
|
163
|
+
};
|
|
164
|
+
return map[ext] || "unknown";
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=false-negatives.js.map
|