@kevinrabun/judges 3.43.0 → 3.44.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 +12 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/burndown.d.ts +27 -0
- package/dist/commands/burndown.d.ts.map +1 -0
- package/dist/commands/burndown.js +180 -0
- package/dist/commands/burndown.js.map +1 -0
- package/dist/commands/kb.d.ts +41 -0
- package/dist/commands/kb.d.ts.map +1 -0
- package/dist/commands/kb.js +231 -0
- package/dist/commands/kb.js.map +1 -0
- package/dist/commands/noise-advisor.d.ts +30 -0
- package/dist/commands/noise-advisor.d.ts.map +1 -0
- package/dist/commands/noise-advisor.js +171 -0
- package/dist/commands/noise-advisor.js.map +1 -0
- package/dist/commands/recommend.d.ts +21 -0
- package/dist/commands/recommend.d.ts.map +1 -0
- package/dist/commands/recommend.js +283 -0
- package/dist/commands/recommend.js.map +1 -0
- package/dist/commands/report-template.d.ts +17 -0
- package/dist/commands/report-template.d.ts.map +1 -0
- package/dist/commands/report-template.js +291 -0
- package/dist/commands/report-template.js.map +1 -0
- package/dist/commands/review-queue.d.ts +34 -0
- package/dist/commands/review-queue.d.ts.map +1 -0
- package/dist/commands/review-queue.js +226 -0
- package/dist/commands/review-queue.js.map +1 -0
- package/dist/commands/rule-owner.d.ts +31 -0
- package/dist/commands/rule-owner.d.ts.map +1 -0
- package/dist/commands/rule-owner.js +182 -0
- package/dist/commands/rule-owner.js.map +1 -0
- package/dist/commands/suppress.d.ts +40 -0
- package/dist/commands/suppress.d.ts.map +1 -0
- package/dist/commands/suppress.js +209 -0
- package/dist/commands/suppress.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review queue — surface findings needing human judgment and route
|
|
3
|
+
* them to appropriate experts based on rule ownership.
|
|
4
|
+
*
|
|
5
|
+
* Uses local data from findings, rule-owners, and feedback.
|
|
6
|
+
*/
|
|
7
|
+
import type { Finding } from "../types.js";
|
|
8
|
+
export interface ReviewItem {
|
|
9
|
+
id: string;
|
|
10
|
+
ruleId: string;
|
|
11
|
+
severity: string;
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
confidence: number;
|
|
15
|
+
recommendedReviewer?: string;
|
|
16
|
+
status: "pending" | "approved" | "dismissed" | "escalated";
|
|
17
|
+
verdict?: string;
|
|
18
|
+
reviewedBy?: string;
|
|
19
|
+
reviewedIso?: string;
|
|
20
|
+
addedIso: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function addToReviewQueue(findings: Finding[], confidenceThreshold?: number): ReviewItem[];
|
|
23
|
+
export declare function reviewItem(id: string, verdict: "approved" | "dismissed" | "escalated", reviewer: string): void;
|
|
24
|
+
export declare function getQueueStats(): {
|
|
25
|
+
total: number;
|
|
26
|
+
pending: number;
|
|
27
|
+
approved: number;
|
|
28
|
+
dismissed: number;
|
|
29
|
+
escalated: number;
|
|
30
|
+
byReviewer: Record<string, number>;
|
|
31
|
+
avgConfidence: number;
|
|
32
|
+
};
|
|
33
|
+
export declare function runReviewQueue(argv: string[]): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=review-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-queue.d.ts","sourceRoot":"","sources":["../../src/commands/review-queue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CAAC;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6CD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,mBAAmB,SAAM,GAAG,UAAU,EAAE,CA+B7F;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAS9G;AAED,wBAAgB,aAAa,IAAI;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,CAuBA;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HlE"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review queue — surface findings needing human judgment and route
|
|
3
|
+
* them to appropriate experts based on rule ownership.
|
|
4
|
+
*
|
|
5
|
+
* Uses local data from findings, rule-owners, and feedback.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
8
|
+
const REVIEW_FILE = ".judges-review-queue.json";
|
|
9
|
+
// ─── Core ───────────────────────────────────────────────────────────────────
|
|
10
|
+
function loadDb(file = REVIEW_FILE) {
|
|
11
|
+
if (!existsSync(file))
|
|
12
|
+
return { items: [] };
|
|
13
|
+
return JSON.parse(readFileSync(file, "utf-8"));
|
|
14
|
+
}
|
|
15
|
+
function saveDb(db, file = REVIEW_FILE) {
|
|
16
|
+
writeFileSync(file, JSON.stringify(db, null, 2));
|
|
17
|
+
}
|
|
18
|
+
function itemId(f) {
|
|
19
|
+
return `${f.ruleId}:${f.title}`.slice(0, 80);
|
|
20
|
+
}
|
|
21
|
+
function resolveReviewer(ruleId) {
|
|
22
|
+
try {
|
|
23
|
+
const ownerFile = ".judges-owners.json";
|
|
24
|
+
if (!existsSync(ownerFile))
|
|
25
|
+
return undefined;
|
|
26
|
+
const db = JSON.parse(readFileSync(ownerFile, "utf-8"));
|
|
27
|
+
if (!db.owners)
|
|
28
|
+
return undefined;
|
|
29
|
+
// Exact match first
|
|
30
|
+
const exact = db.owners.find((o) => o.pattern === ruleId);
|
|
31
|
+
if (exact)
|
|
32
|
+
return exact.owner;
|
|
33
|
+
// Prefix match
|
|
34
|
+
let best;
|
|
35
|
+
for (const o of db.owners) {
|
|
36
|
+
if (ruleId.startsWith(o.pattern) && (!best || o.pattern.length > best.pattern.length)) {
|
|
37
|
+
best = o;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return best?.owner;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function addToReviewQueue(findings, confidenceThreshold = 0.6) {
|
|
47
|
+
const db = loadDb();
|
|
48
|
+
const existing = new Set(db.items.map((i) => i.id));
|
|
49
|
+
const added = [];
|
|
50
|
+
const now = new Date().toISOString();
|
|
51
|
+
for (const f of findings) {
|
|
52
|
+
const conf = f.confidence ?? 0.5;
|
|
53
|
+
if (conf >= confidenceThreshold)
|
|
54
|
+
continue; // High-confidence: auto-approved
|
|
55
|
+
const id = itemId(f);
|
|
56
|
+
if (existing.has(id))
|
|
57
|
+
continue;
|
|
58
|
+
const item = {
|
|
59
|
+
id,
|
|
60
|
+
ruleId: f.ruleId,
|
|
61
|
+
severity: f.severity,
|
|
62
|
+
title: f.title,
|
|
63
|
+
description: f.description,
|
|
64
|
+
confidence: conf,
|
|
65
|
+
recommendedReviewer: resolveReviewer(f.ruleId),
|
|
66
|
+
status: "pending",
|
|
67
|
+
addedIso: now,
|
|
68
|
+
};
|
|
69
|
+
db.items.push(item);
|
|
70
|
+
added.push(item);
|
|
71
|
+
existing.add(id);
|
|
72
|
+
}
|
|
73
|
+
saveDb(db);
|
|
74
|
+
return added;
|
|
75
|
+
}
|
|
76
|
+
export function reviewItem(id, verdict, reviewer) {
|
|
77
|
+
const db = loadDb();
|
|
78
|
+
const item = db.items.find((i) => i.id === id);
|
|
79
|
+
if (!item)
|
|
80
|
+
throw new Error(`Review item not found: ${id}`);
|
|
81
|
+
item.status = verdict;
|
|
82
|
+
item.verdict = verdict;
|
|
83
|
+
item.reviewedBy = reviewer;
|
|
84
|
+
item.reviewedIso = new Date().toISOString();
|
|
85
|
+
saveDb(db);
|
|
86
|
+
}
|
|
87
|
+
export function getQueueStats() {
|
|
88
|
+
const db = loadDb();
|
|
89
|
+
const stats = {
|
|
90
|
+
total: db.items.length,
|
|
91
|
+
pending: db.items.filter((i) => i.status === "pending").length,
|
|
92
|
+
approved: db.items.filter((i) => i.status === "approved").length,
|
|
93
|
+
dismissed: db.items.filter((i) => i.status === "dismissed").length,
|
|
94
|
+
escalated: db.items.filter((i) => i.status === "escalated").length,
|
|
95
|
+
byReviewer: {},
|
|
96
|
+
avgConfidence: 0,
|
|
97
|
+
};
|
|
98
|
+
for (const i of db.items) {
|
|
99
|
+
const reviewer = i.recommendedReviewer || "unassigned";
|
|
100
|
+
stats.byReviewer[reviewer] = (stats.byReviewer[reviewer] || 0) + 1;
|
|
101
|
+
}
|
|
102
|
+
const pending = db.items.filter((i) => i.status === "pending");
|
|
103
|
+
if (pending.length > 0) {
|
|
104
|
+
stats.avgConfidence = Math.round((pending.reduce((s, i) => s + i.confidence, 0) / pending.length) * 100) / 100;
|
|
105
|
+
}
|
|
106
|
+
return stats;
|
|
107
|
+
}
|
|
108
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
109
|
+
export async function runReviewQueue(argv) {
|
|
110
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
111
|
+
console.log(`
|
|
112
|
+
judges review-queue — Human review queue for low-confidence findings
|
|
113
|
+
|
|
114
|
+
Usage:
|
|
115
|
+
judges review-queue --input results.json Add low-confidence findings to queue
|
|
116
|
+
judges review-queue --list Show pending review items
|
|
117
|
+
judges review-queue --approve <id> --reviewer "Alice"
|
|
118
|
+
judges review-queue --dismiss <id> --reviewer "Bob"
|
|
119
|
+
judges review-queue --escalate <id> --reviewer "Carol"
|
|
120
|
+
judges review-queue --stats Show queue statistics
|
|
121
|
+
|
|
122
|
+
Options:
|
|
123
|
+
--input <path> Results JSON with findings
|
|
124
|
+
--threshold <n> Confidence threshold (default: 0.6, below → queue)
|
|
125
|
+
--list Show pending items
|
|
126
|
+
--approve <id> Approve a finding as valid
|
|
127
|
+
--dismiss <id> Dismiss a finding as FP
|
|
128
|
+
--escalate <id> Escalate for deeper review
|
|
129
|
+
--reviewer <name> Reviewer name (required for verdicts)
|
|
130
|
+
--stats Queue statistics
|
|
131
|
+
--format json JSON output
|
|
132
|
+
--help, -h Show this help
|
|
133
|
+
`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
137
|
+
// Add findings from input
|
|
138
|
+
const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
|
|
139
|
+
if (inputPath) {
|
|
140
|
+
if (!existsSync(inputPath)) {
|
|
141
|
+
console.error(`Error: file not found: ${inputPath}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
const data = JSON.parse(readFileSync(inputPath, "utf-8"));
|
|
145
|
+
const findings = data.evaluations
|
|
146
|
+
? data.evaluations.flatMap((e) => e.findings || [])
|
|
147
|
+
: data.findings || data;
|
|
148
|
+
const thresholdStr = argv.find((_a, i) => argv[i - 1] === "--threshold");
|
|
149
|
+
const threshold = thresholdStr ? parseFloat(thresholdStr) : 0.6;
|
|
150
|
+
const added = addToReviewQueue(findings, threshold);
|
|
151
|
+
if (format === "json") {
|
|
152
|
+
console.log(JSON.stringify(added, null, 2));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log(`\n Added ${added.length} finding(s) to review queue (threshold: ${threshold})\n`);
|
|
156
|
+
for (const item of added.slice(0, 10)) {
|
|
157
|
+
console.log(` ${item.severity.padEnd(8)} ${item.ruleId.padEnd(12)} conf: ${item.confidence} → ${item.recommendedReviewer || "unassigned"}`);
|
|
158
|
+
}
|
|
159
|
+
if (added.length > 10)
|
|
160
|
+
console.log(` ... and ${added.length - 10} more`);
|
|
161
|
+
console.log("");
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Verdicts
|
|
166
|
+
const reviewer = argv.find((_a, i) => argv[i - 1] === "--reviewer");
|
|
167
|
+
for (const action of ["approve", "dismiss", "escalate"]) {
|
|
168
|
+
const target = argv.find((_a, i) => argv[i - 1] === `--${action}`);
|
|
169
|
+
if (target) {
|
|
170
|
+
if (!reviewer) {
|
|
171
|
+
console.error("Error: --reviewer required");
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
const verdict = action === "approve" ? "approved" : action === "dismiss" ? "dismissed" : "escalated";
|
|
175
|
+
reviewItem(target, verdict, reviewer);
|
|
176
|
+
console.log(` ${verdict}: ${target} by ${reviewer}`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// List pending
|
|
181
|
+
if (argv.includes("--list")) {
|
|
182
|
+
const db = loadDb();
|
|
183
|
+
const pending = db.items.filter((i) => i.status === "pending");
|
|
184
|
+
if (format === "json") {
|
|
185
|
+
console.log(JSON.stringify(pending, null, 2));
|
|
186
|
+
}
|
|
187
|
+
else if (pending.length === 0) {
|
|
188
|
+
console.log("\n Review queue is empty.\n");
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.log(`\n Pending Reviews (${pending.length})\n ──────────────────`);
|
|
192
|
+
for (const item of pending) {
|
|
193
|
+
console.log(` ${item.severity.padEnd(8)} ${item.ruleId.padEnd(12)} conf: ${item.confidence} → ${item.recommendedReviewer || "unassigned"}`);
|
|
194
|
+
console.log(` ${item.title}`);
|
|
195
|
+
console.log(` ID: ${item.id}`);
|
|
196
|
+
}
|
|
197
|
+
console.log("");
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Stats (default)
|
|
202
|
+
const s = getQueueStats();
|
|
203
|
+
if (format === "json") {
|
|
204
|
+
console.log(JSON.stringify(s, null, 2));
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
console.log(`
|
|
208
|
+
Review Queue
|
|
209
|
+
────────────
|
|
210
|
+
Total: ${s.total}
|
|
211
|
+
Pending: ${s.pending}
|
|
212
|
+
Approved: ${s.approved}
|
|
213
|
+
Dismissed: ${s.dismissed}
|
|
214
|
+
Escalated: ${s.escalated}
|
|
215
|
+
Avg conf: ${s.avgConfidence}
|
|
216
|
+
`);
|
|
217
|
+
if (Object.keys(s.byReviewer).length > 0) {
|
|
218
|
+
console.log(" By reviewer:");
|
|
219
|
+
for (const [name, count] of Object.entries(s.byReviewer)) {
|
|
220
|
+
console.log(` ${name.padEnd(20)} ${count}`);
|
|
221
|
+
}
|
|
222
|
+
console.log("");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=review-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-queue.js","sourceRoot":"","sources":["../../src/commands/review-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule ownership — map rules/categories to team owners for
|
|
3
|
+
* accountability, escalation, and expertise routing.
|
|
4
|
+
*
|
|
5
|
+
* Stored locally in .judges-owners.json.
|
|
6
|
+
*/
|
|
7
|
+
export interface RuleOwner {
|
|
8
|
+
/** Rule ID or prefix (e.g., "SEC-001" or "SEC") */
|
|
9
|
+
pattern: string;
|
|
10
|
+
/** Owner name or team */
|
|
11
|
+
owner: string;
|
|
12
|
+
/** Contact (email/Slack handle) */
|
|
13
|
+
contact?: string;
|
|
14
|
+
/** Expertise level */
|
|
15
|
+
expertise: "expert" | "familiar" | "learning";
|
|
16
|
+
/** When assigned */
|
|
17
|
+
assignedIso: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function assignOwner(pattern: string, owner: string, opts?: {
|
|
20
|
+
contact?: string;
|
|
21
|
+
expertise?: RuleOwner["expertise"];
|
|
22
|
+
}): RuleOwner;
|
|
23
|
+
export declare function removeOwner(pattern: string): boolean;
|
|
24
|
+
export declare function findOwner(ruleId: string): RuleOwner | undefined;
|
|
25
|
+
export declare function getOwnerStats(): {
|
|
26
|
+
totalPatterns: number;
|
|
27
|
+
byOwner: Record<string, number>;
|
|
28
|
+
byExpertise: Record<string, number>;
|
|
29
|
+
};
|
|
30
|
+
export declare function runRuleOwner(argv: string[]): void;
|
|
31
|
+
//# sourceMappingURL=rule-owner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-owner.d.ts","sourceRoot":"","sources":["../../src/commands/rule-owner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,SAAS;IACxB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,SAAS,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9C,oBAAoB;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAmBD,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;CAAE,GAC9D,SAAS,CAiBX;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAa/D;AAED,wBAAgB,aAAa,IAAI;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CASA;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAgHjD"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule ownership — map rules/categories to team owners for
|
|
3
|
+
* accountability, escalation, and expertise routing.
|
|
4
|
+
*
|
|
5
|
+
* Stored locally in .judges-owners.json.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
8
|
+
const OWNER_FILE = ".judges-owners.json";
|
|
9
|
+
// ─── Core ───────────────────────────────────────────────────────────────────
|
|
10
|
+
function loadDb(file = OWNER_FILE) {
|
|
11
|
+
if (!existsSync(file))
|
|
12
|
+
return { owners: [] };
|
|
13
|
+
return JSON.parse(readFileSync(file, "utf-8"));
|
|
14
|
+
}
|
|
15
|
+
function saveDb(db, file = OWNER_FILE) {
|
|
16
|
+
writeFileSync(file, JSON.stringify(db, null, 2));
|
|
17
|
+
}
|
|
18
|
+
export function assignOwner(pattern, owner, opts) {
|
|
19
|
+
const db = loadDb();
|
|
20
|
+
const existing = db.owners.find((o) => o.pattern === pattern);
|
|
21
|
+
const entry = {
|
|
22
|
+
pattern,
|
|
23
|
+
owner,
|
|
24
|
+
contact: opts?.contact,
|
|
25
|
+
expertise: opts?.expertise || "familiar",
|
|
26
|
+
assignedIso: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
if (existing) {
|
|
29
|
+
Object.assign(existing, entry);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
db.owners.push(entry);
|
|
33
|
+
}
|
|
34
|
+
saveDb(db);
|
|
35
|
+
return entry;
|
|
36
|
+
}
|
|
37
|
+
export function removeOwner(pattern) {
|
|
38
|
+
const db = loadDb();
|
|
39
|
+
const idx = db.owners.findIndex((o) => o.pattern === pattern);
|
|
40
|
+
if (idx < 0)
|
|
41
|
+
return false;
|
|
42
|
+
db.owners.splice(idx, 1);
|
|
43
|
+
saveDb(db);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
export function findOwner(ruleId) {
|
|
47
|
+
const db = loadDb();
|
|
48
|
+
// Exact match first, then prefix match (longest prefix wins)
|
|
49
|
+
const exact = db.owners.find((o) => o.pattern === ruleId);
|
|
50
|
+
if (exact)
|
|
51
|
+
return exact;
|
|
52
|
+
let best;
|
|
53
|
+
for (const o of db.owners) {
|
|
54
|
+
if (ruleId.startsWith(o.pattern) && (!best || o.pattern.length > best.pattern.length)) {
|
|
55
|
+
best = o;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return best;
|
|
59
|
+
}
|
|
60
|
+
export function getOwnerStats() {
|
|
61
|
+
const db = loadDb();
|
|
62
|
+
const byOwner = {};
|
|
63
|
+
const byExpertise = {};
|
|
64
|
+
for (const o of db.owners) {
|
|
65
|
+
byOwner[o.owner] = (byOwner[o.owner] || 0) + 1;
|
|
66
|
+
byExpertise[o.expertise] = (byExpertise[o.expertise] || 0) + 1;
|
|
67
|
+
}
|
|
68
|
+
return { totalPatterns: db.owners.length, byOwner, byExpertise };
|
|
69
|
+
}
|
|
70
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
71
|
+
export function runRuleOwner(argv) {
|
|
72
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
73
|
+
console.log(`
|
|
74
|
+
judges rule-owner — Map rules to team owners for accountability
|
|
75
|
+
|
|
76
|
+
Usage:
|
|
77
|
+
judges rule-owner --set SEC --owner "Security Team" --contact "#sec-channel"
|
|
78
|
+
judges rule-owner --set AUTH-003 --owner "Alice" --expertise expert
|
|
79
|
+
judges rule-owner --find SEC-001 Find who owns a rule
|
|
80
|
+
judges rule-owner --list List all ownership mappings
|
|
81
|
+
judges rule-owner --remove SEC Remove ownership
|
|
82
|
+
judges rule-owner --stats Show ownership statistics
|
|
83
|
+
|
|
84
|
+
Options:
|
|
85
|
+
--set <pattern> Rule ID or prefix to assign
|
|
86
|
+
--owner <name> Owner name or team (required with --set)
|
|
87
|
+
--contact <info> Contact info (email/Slack)
|
|
88
|
+
--expertise <level> expert | familiar | learning
|
|
89
|
+
--find <rule-id> Find owner for a rule
|
|
90
|
+
--remove <pattern> Remove ownership mapping
|
|
91
|
+
--list List all mappings
|
|
92
|
+
--stats Show statistics
|
|
93
|
+
--format json JSON output
|
|
94
|
+
--help, -h Show this help
|
|
95
|
+
`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
99
|
+
// Set ownership
|
|
100
|
+
const setPattern = argv.find((_a, i) => argv[i - 1] === "--set");
|
|
101
|
+
if (setPattern) {
|
|
102
|
+
const owner = argv.find((_a, i) => argv[i - 1] === "--owner");
|
|
103
|
+
if (!owner) {
|
|
104
|
+
console.error("Error: --owner required with --set");
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
const contact = argv.find((_a, i) => argv[i - 1] === "--contact");
|
|
108
|
+
const expertise = argv.find((_a, i) => argv[i - 1] === "--expertise");
|
|
109
|
+
const entry = assignOwner(setPattern, owner, { contact, expertise });
|
|
110
|
+
if (format === "json") {
|
|
111
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(` ✅ ${entry.pattern} → ${entry.owner} (${entry.expertise})`);
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Find owner
|
|
119
|
+
const findRule = argv.find((_a, i) => argv[i - 1] === "--find");
|
|
120
|
+
if (findRule) {
|
|
121
|
+
const owner = findOwner(findRule);
|
|
122
|
+
if (!owner) {
|
|
123
|
+
console.log(` No owner found for ${findRule}`);
|
|
124
|
+
}
|
|
125
|
+
else if (format === "json") {
|
|
126
|
+
console.log(JSON.stringify(owner, null, 2));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(` ${findRule} → ${owner.owner} (${owner.expertise})${owner.contact ? ` — ${owner.contact}` : ""}`);
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Remove
|
|
134
|
+
const removePattern = argv.find((_a, i) => argv[i - 1] === "--remove");
|
|
135
|
+
if (removePattern) {
|
|
136
|
+
if (removeOwner(removePattern)) {
|
|
137
|
+
console.log(` Removed: ${removePattern}`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.error(` Not found: ${removePattern}`);
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// Stats
|
|
145
|
+
if (argv.includes("--stats")) {
|
|
146
|
+
const s = getOwnerStats();
|
|
147
|
+
if (format === "json") {
|
|
148
|
+
console.log(JSON.stringify(s, null, 2));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(`\n Rule Ownership\n ──────────────`);
|
|
152
|
+
console.log(` Total mappings: ${s.totalPatterns}\n`);
|
|
153
|
+
console.log(" By owner:");
|
|
154
|
+
for (const [name, count] of Object.entries(s.byOwner)) {
|
|
155
|
+
console.log(` ${name.padEnd(20)} ${count} rule(s)`);
|
|
156
|
+
}
|
|
157
|
+
console.log("\n By expertise:");
|
|
158
|
+
for (const [level, count] of Object.entries(s.byExpertise)) {
|
|
159
|
+
console.log(` ${level.padEnd(12)} ${count}`);
|
|
160
|
+
}
|
|
161
|
+
console.log("");
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Default: list all
|
|
166
|
+
const db = loadDb();
|
|
167
|
+
if (db.owners.length === 0) {
|
|
168
|
+
console.log("\n No ownership mappings. Use --set to add one.\n");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (format === "json") {
|
|
172
|
+
console.log(JSON.stringify(db.owners, null, 2));
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
console.log("\n Rule Ownership Mappings\n ──────────────────────");
|
|
176
|
+
for (const o of db.owners) {
|
|
177
|
+
console.log(` ${o.pattern.padEnd(15)} → ${o.owner} (${o.expertise})${o.contact ? ` — ${o.contact}` : ""}`);
|
|
178
|
+
}
|
|
179
|
+
console.log("");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=rule-owner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-owner.js","sourceRoot":"","sources":["../../src/commands/rule-owner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch false-positive suppression — suppress findings by glob, rule
|
|
3
|
+
* prefix, severity, or pattern with a full audit trail.
|
|
4
|
+
*
|
|
5
|
+
* Suppressions stored locally in .judges-suppressions.json.
|
|
6
|
+
*/
|
|
7
|
+
export interface SuppressionRule {
|
|
8
|
+
id: string;
|
|
9
|
+
/** Glob pattern for file paths (e.g., **\/*.test.ts) */
|
|
10
|
+
fileGlob?: string;
|
|
11
|
+
/** Rule ID prefix to suppress (e.g., AUTH) */
|
|
12
|
+
rulePrefix?: string;
|
|
13
|
+
/** Exact rule IDs to suppress */
|
|
14
|
+
ruleIds?: string[];
|
|
15
|
+
/** Minimum severity to suppress (suppress this level and below) */
|
|
16
|
+
maxSeverity?: string;
|
|
17
|
+
/** Reason for suppression */
|
|
18
|
+
reason: string;
|
|
19
|
+
/** Who created this suppression */
|
|
20
|
+
author: string;
|
|
21
|
+
/** When this suppression was created */
|
|
22
|
+
createdIso: string;
|
|
23
|
+
/** Optional expiry date */
|
|
24
|
+
expiresIso?: string;
|
|
25
|
+
/** Whether this suppression is active */
|
|
26
|
+
active: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function addSuppression(opts: {
|
|
29
|
+
fileGlob?: string;
|
|
30
|
+
rulePrefix?: string;
|
|
31
|
+
ruleIds?: string[];
|
|
32
|
+
maxSeverity?: string;
|
|
33
|
+
reason: string;
|
|
34
|
+
author?: string;
|
|
35
|
+
expiresIn?: number;
|
|
36
|
+
}): SuppressionRule;
|
|
37
|
+
export declare function removeSuppression(id: string): boolean;
|
|
38
|
+
export declare function isFindiingSuppressed(ruleId: string, severity: string, filePath?: string): boolean;
|
|
39
|
+
export declare function runSuppress(argv: string[]): void;
|
|
40
|
+
//# sourceMappingURL=suppress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppress.d.ts","sourceRoot":"","sources":["../../src/commands/suppress.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,MAAM,EAAE,OAAO,CAAC;CACjB;AAkCD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,eAAe,CAqBlB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAOrD;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAiCjG;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+GhD"}
|