@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,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remediation guides — provide step-by-step fix guidance for common
|
|
3
|
+
* finding categories, linked from finding output.
|
|
4
|
+
*
|
|
5
|
+
* Each guide includes: description, risk level, fix steps,
|
|
6
|
+
* code examples (before/after), and references.
|
|
7
|
+
*/
|
|
8
|
+
// ─── Guides ─────────────────────────────────────────────────────────────────
|
|
9
|
+
const GUIDES = [
|
|
10
|
+
{
|
|
11
|
+
rulePrefix: "SEC-001",
|
|
12
|
+
title: "SQL Injection Prevention",
|
|
13
|
+
category: "Security",
|
|
14
|
+
risk: "Critical — allows attackers to read/modify/delete database data",
|
|
15
|
+
steps: [
|
|
16
|
+
"Replace string concatenation in SQL queries with parameterized queries",
|
|
17
|
+
"Use your ORM's built-in query builder instead of raw SQL",
|
|
18
|
+
"If raw SQL is required, use prepared statements with placeholders",
|
|
19
|
+
"Validate and sanitize all user input before using in queries",
|
|
20
|
+
"Apply principle of least privilege to database accounts",
|
|
21
|
+
],
|
|
22
|
+
beforeCode: `// VULNERABLE\nconst result = await db.query(\`SELECT * FROM users WHERE id = '\${userId}'\`);`,
|
|
23
|
+
afterCode: `// SECURE\nconst result = await db.query('SELECT * FROM users WHERE id = $1', [userId]);`,
|
|
24
|
+
references: [
|
|
25
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html",
|
|
26
|
+
"https://cwe.mitre.org/data/definitions/89.html",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
rulePrefix: "SEC-002",
|
|
31
|
+
title: "Cross-Site Scripting (XSS) Prevention",
|
|
32
|
+
category: "Security",
|
|
33
|
+
risk: "High — allows attackers to execute scripts in users' browsers",
|
|
34
|
+
steps: [
|
|
35
|
+
"Use context-aware output encoding (HTML, JavaScript, URL, CSS)",
|
|
36
|
+
"Use framework auto-escaping (React JSX, Angular templates, etc.)",
|
|
37
|
+
"Avoid dangerouslySetInnerHTML / v-html / innerHTML",
|
|
38
|
+
"Implement Content-Security-Policy headers",
|
|
39
|
+
"Validate and sanitize user input on the server side",
|
|
40
|
+
],
|
|
41
|
+
beforeCode: `// VULNERABLE\nelement.innerHTML = userInput;`,
|
|
42
|
+
afterCode: `// SECURE\nelement.textContent = userInput;`,
|
|
43
|
+
references: [
|
|
44
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html",
|
|
45
|
+
"https://cwe.mitre.org/data/definitions/79.html",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
rulePrefix: "SEC-003",
|
|
50
|
+
title: "Command Injection Prevention",
|
|
51
|
+
category: "Security",
|
|
52
|
+
risk: "Critical — allows attackers to execute arbitrary OS commands",
|
|
53
|
+
steps: [
|
|
54
|
+
"Avoid shell command execution with user-controlled input",
|
|
55
|
+
"Use language-native APIs instead of shell commands (e.g., fs.readdir instead of ls)",
|
|
56
|
+
"If shell execution is required, use allowlists for permitted commands",
|
|
57
|
+
"Use execFile/spawn with explicit argument arrays instead of exec with string concatenation",
|
|
58
|
+
"Never pass user input directly to child_process.exec()",
|
|
59
|
+
],
|
|
60
|
+
beforeCode: `// VULNERABLE\nexec(\`ls \${userDir}\`);`,
|
|
61
|
+
afterCode: `// SECURE\nexecFile('ls', [userDir]);`,
|
|
62
|
+
references: [
|
|
63
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html",
|
|
64
|
+
"https://cwe.mitre.org/data/definitions/78.html",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
rulePrefix: "AUTH-",
|
|
69
|
+
title: "Authentication Best Practices",
|
|
70
|
+
category: "Security",
|
|
71
|
+
risk: "High — weak authentication allows unauthorized access",
|
|
72
|
+
steps: [
|
|
73
|
+
"Use bcrypt, argon2, or scrypt for password hashing (never MD5/SHA1)",
|
|
74
|
+
"Implement rate limiting on login endpoints",
|
|
75
|
+
"Use secure session management with HttpOnly, Secure, SameSite cookies",
|
|
76
|
+
"Implement multi-factor authentication for sensitive operations",
|
|
77
|
+
"Validate JWT tokens on every request (check signature, expiry, issuer)",
|
|
78
|
+
],
|
|
79
|
+
references: [
|
|
80
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html",
|
|
81
|
+
"https://cwe.mitre.org/data/definitions/287.html",
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
rulePrefix: "CRYPTO-",
|
|
86
|
+
title: "Cryptographic Best Practices",
|
|
87
|
+
category: "Security",
|
|
88
|
+
risk: "High — weak cryptography exposes sensitive data",
|
|
89
|
+
steps: [
|
|
90
|
+
"Use AES-256-GCM for symmetric encryption (not DES, 3DES, or ECB mode)",
|
|
91
|
+
"Use RSA-2048+ or ECDSA P-256+ for asymmetric encryption",
|
|
92
|
+
"Use SHA-256+ for hashing (not MD5 or SHA-1)",
|
|
93
|
+
"Never hardcode encryption keys or secrets in source code",
|
|
94
|
+
"Use platform-provided key management (AWS KMS, Azure Key Vault, etc.)",
|
|
95
|
+
],
|
|
96
|
+
references: [
|
|
97
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html",
|
|
98
|
+
"https://cwe.mitre.org/data/definitions/327.html",
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
rulePrefix: "SSRF-",
|
|
103
|
+
title: "Server-Side Request Forgery Prevention",
|
|
104
|
+
category: "Security",
|
|
105
|
+
risk: "High — allows attackers to make requests from your server to internal resources",
|
|
106
|
+
steps: [
|
|
107
|
+
"Validate and sanitize all URLs before making server-side requests",
|
|
108
|
+
"Use an allowlist of permitted domains/IPs",
|
|
109
|
+
"Block requests to private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, ::1)",
|
|
110
|
+
"Disable HTTP redirects or validate redirect targets",
|
|
111
|
+
"Use a URL parser to validate the scheme (allow only https://)",
|
|
112
|
+
],
|
|
113
|
+
references: [
|
|
114
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html",
|
|
115
|
+
"https://cwe.mitre.org/data/definitions/918.html",
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
rulePrefix: "PERF-",
|
|
120
|
+
title: "Performance Optimization",
|
|
121
|
+
category: "Performance",
|
|
122
|
+
risk: "Medium — poor performance degrades user experience and increases costs",
|
|
123
|
+
steps: [
|
|
124
|
+
"Identify the bottleneck: CPU, memory, I/O, or network",
|
|
125
|
+
"Use profiling tools (Node.js --prof, py-spy, Go pprof)",
|
|
126
|
+
"Avoid N+1 queries — batch database operations",
|
|
127
|
+
"Use caching for expensive computations (Redis, in-memory LRU)",
|
|
128
|
+
"Implement pagination for large result sets",
|
|
129
|
+
],
|
|
130
|
+
references: ["https://web.dev/performance/"],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
rulePrefix: "ERR-",
|
|
134
|
+
title: "Error Handling Best Practices",
|
|
135
|
+
category: "Reliability",
|
|
136
|
+
risk: "Medium — poor error handling causes crashes and data corruption",
|
|
137
|
+
steps: [
|
|
138
|
+
"Catch and handle errors at appropriate boundaries",
|
|
139
|
+
"Never swallow exceptions silently — at minimum log them",
|
|
140
|
+
"Use structured error types with error codes",
|
|
141
|
+
"Implement graceful degradation for non-critical failures",
|
|
142
|
+
"Never expose stack traces or internal error details to users",
|
|
143
|
+
],
|
|
144
|
+
references: ["https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html"],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
rulePrefix: "CONCUR-",
|
|
148
|
+
title: "Concurrency Safety",
|
|
149
|
+
category: "Reliability",
|
|
150
|
+
risk: "High — race conditions cause data corruption and security vulnerabilities",
|
|
151
|
+
steps: [
|
|
152
|
+
"Identify shared mutable state and protect it with locks/mutexes",
|
|
153
|
+
"Prefer immutable data structures",
|
|
154
|
+
"Use atomic operations for simple shared counters",
|
|
155
|
+
"Avoid holding multiple locks simultaneously (prevents deadlocks)",
|
|
156
|
+
"Use channels/message-passing instead of shared memory where possible",
|
|
157
|
+
],
|
|
158
|
+
references: ["https://cwe.mitre.org/data/definitions/362.html"],
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
rulePrefix: "IAC-",
|
|
162
|
+
title: "Infrastructure as Code Security",
|
|
163
|
+
category: "Infrastructure",
|
|
164
|
+
risk: "High — IaC misconfigurations expose cloud resources to attack",
|
|
165
|
+
steps: [
|
|
166
|
+
"Enable encryption at rest and in transit for all storage resources",
|
|
167
|
+
"Apply principle of least privilege to IAM roles and policies",
|
|
168
|
+
"Enable logging and monitoring (CloudTrail, Azure Monitor, etc.)",
|
|
169
|
+
"Use private subnets for databases and internal services",
|
|
170
|
+
"Never hardcode secrets in Terraform/Bicep/CloudFormation templates",
|
|
171
|
+
],
|
|
172
|
+
references: ["https://cheatsheetseries.owasp.org/cheatsheets/Infrastructure_as_Code_Security_Cheat_Sheet.html"],
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
// ─── Lookup API ─────────────────────────────────────────────────────────────
|
|
176
|
+
export function findGuide(ruleId) {
|
|
177
|
+
// Exact match first, then prefix match
|
|
178
|
+
return GUIDES.find((g) => ruleId.startsWith(g.rulePrefix));
|
|
179
|
+
}
|
|
180
|
+
export function listGuides() {
|
|
181
|
+
return GUIDES;
|
|
182
|
+
}
|
|
183
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
184
|
+
export function runRemediationGuide(argv) {
|
|
185
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
186
|
+
console.log(`
|
|
187
|
+
judges remediation — Step-by-step fix guidance for findings
|
|
188
|
+
|
|
189
|
+
Usage:
|
|
190
|
+
judges remediation SEC-001 Show guide for a specific rule
|
|
191
|
+
judges remediation --list List all available guides
|
|
192
|
+
judges remediation --category Security Filter by category
|
|
193
|
+
|
|
194
|
+
Options:
|
|
195
|
+
--list List all guides
|
|
196
|
+
--category <cat> Filter by category
|
|
197
|
+
--format json JSON output
|
|
198
|
+
--help, -h Show this help
|
|
199
|
+
`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
203
|
+
const categoryFilter = argv.find((_a, i) => argv[i - 1] === "--category");
|
|
204
|
+
if (argv.includes("--list")) {
|
|
205
|
+
let guides = GUIDES;
|
|
206
|
+
if (categoryFilter)
|
|
207
|
+
guides = guides.filter((g) => g.category.toLowerCase() === categoryFilter.toLowerCase());
|
|
208
|
+
if (format === "json") {
|
|
209
|
+
console.log(JSON.stringify(guides, null, 2));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
console.log("\n Available Remediation Guides:\n");
|
|
213
|
+
for (const g of guides) {
|
|
214
|
+
console.log(` ${g.rulePrefix.padEnd(12)} ${g.title.padEnd(40)} [${g.category}]`);
|
|
215
|
+
}
|
|
216
|
+
console.log("");
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// Find guide by rule ID
|
|
220
|
+
const ruleId = argv.find((a, i) => i > 1 && !a.startsWith("-") && argv[i - 1] !== "--format" && argv[i - 1] !== "--category");
|
|
221
|
+
if (!ruleId) {
|
|
222
|
+
console.error("Error: provide a rule ID or use --list");
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
const guide = findGuide(ruleId);
|
|
226
|
+
if (!guide) {
|
|
227
|
+
console.log(` No guide found for "${ruleId}". Use --list to see available guides.`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (format === "json") {
|
|
231
|
+
console.log(JSON.stringify(guide, null, 2));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
console.log(`\n 📖 ${guide.title}\n`);
|
|
235
|
+
console.log(` Category: ${guide.category}`);
|
|
236
|
+
console.log(` Risk: ${guide.risk}\n`);
|
|
237
|
+
console.log(" Steps:");
|
|
238
|
+
for (let i = 0; i < guide.steps.length; i++) {
|
|
239
|
+
console.log(` ${i + 1}. ${guide.steps[i]}`);
|
|
240
|
+
}
|
|
241
|
+
if (guide.beforeCode) {
|
|
242
|
+
console.log("\n Before (vulnerable):");
|
|
243
|
+
console.log(` ${guide.beforeCode.split("\n").join("\n ")}`);
|
|
244
|
+
}
|
|
245
|
+
if (guide.afterCode) {
|
|
246
|
+
console.log("\n After (secure):");
|
|
247
|
+
console.log(` ${guide.afterCode.split("\n").join("\n ")}`);
|
|
248
|
+
}
|
|
249
|
+
if (guide.references.length > 0) {
|
|
250
|
+
console.log("\n References:");
|
|
251
|
+
for (const ref of guide.references) {
|
|
252
|
+
console.log(` • ${ref}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
console.log("");
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=remediation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remediation.js","sourceRoot":"","sources":["../../src/commands/remediation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLA tracking — define response-time SLAs per severity and track
|
|
3
|
+
* violation rates across runs.
|
|
4
|
+
*
|
|
5
|
+
* Data is stored locally in .judges-sla.json — no remote storage.
|
|
6
|
+
*/
|
|
7
|
+
import type { Finding } from "../types.js";
|
|
8
|
+
export interface SlaPolicy {
|
|
9
|
+
severity: string;
|
|
10
|
+
/** Max hours to first response/triage */
|
|
11
|
+
responseHours: number;
|
|
12
|
+
/** Max hours to remediation */
|
|
13
|
+
resolutionHours: number;
|
|
14
|
+
}
|
|
15
|
+
export interface SlaEntry {
|
|
16
|
+
findingId: string;
|
|
17
|
+
ruleId: string;
|
|
18
|
+
severity: string;
|
|
19
|
+
title: string;
|
|
20
|
+
firstSeenIso: string;
|
|
21
|
+
triagedIso?: string;
|
|
22
|
+
resolvedIso?: string;
|
|
23
|
+
status: "open" | "triaged" | "resolved";
|
|
24
|
+
}
|
|
25
|
+
interface SlaDb {
|
|
26
|
+
policies: SlaPolicy[];
|
|
27
|
+
entries: SlaEntry[];
|
|
28
|
+
}
|
|
29
|
+
export declare function trackFindings(findings: Finding[], dbPath?: string): SlaDb;
|
|
30
|
+
export declare function triageEntry(id: string, dbPath?: string): void;
|
|
31
|
+
export declare function resolveEntry(id: string, dbPath?: string): void;
|
|
32
|
+
export interface SlaViolation {
|
|
33
|
+
findingId: string;
|
|
34
|
+
ruleId: string;
|
|
35
|
+
severity: string;
|
|
36
|
+
type: "response" | "resolution";
|
|
37
|
+
elapsedHours: number;
|
|
38
|
+
allowedHours: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function checkViolations(dbPath?: string): SlaViolation[];
|
|
41
|
+
export declare function getSlaStats(dbPath?: string): {
|
|
42
|
+
total: number;
|
|
43
|
+
open: number;
|
|
44
|
+
triaged: number;
|
|
45
|
+
resolved: number;
|
|
46
|
+
violations: number;
|
|
47
|
+
bySeverity: Record<string, {
|
|
48
|
+
total: number;
|
|
49
|
+
open: number;
|
|
50
|
+
violations: number;
|
|
51
|
+
}>;
|
|
52
|
+
avgResponseHours: number;
|
|
53
|
+
avgResolutionHours: number;
|
|
54
|
+
};
|
|
55
|
+
export declare function runSlaTrack(argv: string[]): Promise<void>;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=sla-track.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sla-track.d.ts","sourceRoot":"","sources":["../../src/commands/sla-track.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;CACzC;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB;AA6BD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,SAAW,GAAG,KAAK,CAsB3E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,IAAI,CAO/D;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,IAAI,CAOhE;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,YAAY,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,MAAM,SAAW,GAAG,YAAY,EAAE,CAqCjE;AAED,wBAAgB,WAAW,CAAC,MAAM,SAAW,GAAG;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CA8CA;AAID,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgI/D"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLA tracking — define response-time SLAs per severity and track
|
|
3
|
+
* violation rates across runs.
|
|
4
|
+
*
|
|
5
|
+
* Data is stored locally in .judges-sla.json — no remote storage.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
8
|
+
// ─── Default SLA Policies ───────────────────────────────────────────────────
|
|
9
|
+
const DEFAULT_POLICIES = [
|
|
10
|
+
{ severity: "critical", responseHours: 4, resolutionHours: 24 },
|
|
11
|
+
{ severity: "high", responseHours: 24, resolutionHours: 72 },
|
|
12
|
+
{ severity: "medium", responseHours: 72, resolutionHours: 168 },
|
|
13
|
+
{ severity: "low", responseHours: 168, resolutionHours: 720 },
|
|
14
|
+
{ severity: "info", responseHours: 720, resolutionHours: 2160 },
|
|
15
|
+
];
|
|
16
|
+
const SLA_FILE = ".judges-sla.json";
|
|
17
|
+
// ─── Core Functions ─────────────────────────────────────────────────────────
|
|
18
|
+
function loadDb(file) {
|
|
19
|
+
if (!existsSync(file))
|
|
20
|
+
return { policies: DEFAULT_POLICIES, entries: [] };
|
|
21
|
+
return JSON.parse(readFileSync(file, "utf-8"));
|
|
22
|
+
}
|
|
23
|
+
function saveDb(file, db) {
|
|
24
|
+
writeFileSync(file, JSON.stringify(db, null, 2));
|
|
25
|
+
}
|
|
26
|
+
function findingId(f) {
|
|
27
|
+
return `${f.ruleId}:${f.title}`;
|
|
28
|
+
}
|
|
29
|
+
export function trackFindings(findings, dbPath = SLA_FILE) {
|
|
30
|
+
const db = loadDb(dbPath);
|
|
31
|
+
const now = new Date().toISOString();
|
|
32
|
+
const seen = new Set(db.entries.map((e) => e.findingId));
|
|
33
|
+
for (const f of findings) {
|
|
34
|
+
const id = findingId(f);
|
|
35
|
+
if (!seen.has(id)) {
|
|
36
|
+
db.entries.push({
|
|
37
|
+
findingId: id,
|
|
38
|
+
ruleId: f.ruleId,
|
|
39
|
+
severity: f.severity,
|
|
40
|
+
title: f.title,
|
|
41
|
+
firstSeenIso: now,
|
|
42
|
+
status: "open",
|
|
43
|
+
});
|
|
44
|
+
seen.add(id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
saveDb(dbPath, db);
|
|
48
|
+
return db;
|
|
49
|
+
}
|
|
50
|
+
export function triageEntry(id, dbPath = SLA_FILE) {
|
|
51
|
+
const db = loadDb(dbPath);
|
|
52
|
+
const entry = db.entries.find((e) => e.findingId === id);
|
|
53
|
+
if (!entry)
|
|
54
|
+
throw new Error(`Entry not found: ${id}`);
|
|
55
|
+
entry.triagedIso = new Date().toISOString();
|
|
56
|
+
entry.status = "triaged";
|
|
57
|
+
saveDb(dbPath, db);
|
|
58
|
+
}
|
|
59
|
+
export function resolveEntry(id, dbPath = SLA_FILE) {
|
|
60
|
+
const db = loadDb(dbPath);
|
|
61
|
+
const entry = db.entries.find((e) => e.findingId === id);
|
|
62
|
+
if (!entry)
|
|
63
|
+
throw new Error(`Entry not found: ${id}`);
|
|
64
|
+
entry.resolvedIso = new Date().toISOString();
|
|
65
|
+
entry.status = "resolved";
|
|
66
|
+
saveDb(dbPath, db);
|
|
67
|
+
}
|
|
68
|
+
export function checkViolations(dbPath = SLA_FILE) {
|
|
69
|
+
const db = loadDb(dbPath);
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const violations = [];
|
|
72
|
+
for (const entry of db.entries) {
|
|
73
|
+
const policy = db.policies.find((p) => p.severity === entry.severity);
|
|
74
|
+
if (!policy)
|
|
75
|
+
continue;
|
|
76
|
+
const firstSeen = new Date(entry.firstSeenIso).getTime();
|
|
77
|
+
const elapsedMs = now - firstSeen;
|
|
78
|
+
const elapsedHours = Math.round((elapsedMs / 3_600_000) * 10) / 10;
|
|
79
|
+
if (entry.status === "open" && elapsedHours > policy.responseHours) {
|
|
80
|
+
violations.push({
|
|
81
|
+
findingId: entry.findingId,
|
|
82
|
+
ruleId: entry.ruleId,
|
|
83
|
+
severity: entry.severity,
|
|
84
|
+
type: "response",
|
|
85
|
+
elapsedHours,
|
|
86
|
+
allowedHours: policy.responseHours,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (entry.status !== "resolved" && elapsedHours > policy.resolutionHours) {
|
|
90
|
+
violations.push({
|
|
91
|
+
findingId: entry.findingId,
|
|
92
|
+
ruleId: entry.ruleId,
|
|
93
|
+
severity: entry.severity,
|
|
94
|
+
type: "resolution",
|
|
95
|
+
elapsedHours,
|
|
96
|
+
allowedHours: policy.resolutionHours,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return violations;
|
|
101
|
+
}
|
|
102
|
+
export function getSlaStats(dbPath = SLA_FILE) {
|
|
103
|
+
const db = loadDb(dbPath);
|
|
104
|
+
const violations = checkViolations(dbPath);
|
|
105
|
+
const stats = {
|
|
106
|
+
total: db.entries.length,
|
|
107
|
+
open: db.entries.filter((e) => e.status === "open").length,
|
|
108
|
+
triaged: db.entries.filter((e) => e.status === "triaged").length,
|
|
109
|
+
resolved: db.entries.filter((e) => e.status === "resolved").length,
|
|
110
|
+
violations: violations.length,
|
|
111
|
+
bySeverity: {},
|
|
112
|
+
avgResponseHours: 0,
|
|
113
|
+
avgResolutionHours: 0,
|
|
114
|
+
};
|
|
115
|
+
for (const entry of db.entries) {
|
|
116
|
+
if (!stats.bySeverity[entry.severity]) {
|
|
117
|
+
stats.bySeverity[entry.severity] = { total: 0, open: 0, violations: 0 };
|
|
118
|
+
}
|
|
119
|
+
stats.bySeverity[entry.severity].total++;
|
|
120
|
+
if (entry.status === "open")
|
|
121
|
+
stats.bySeverity[entry.severity].open++;
|
|
122
|
+
}
|
|
123
|
+
for (const v of violations) {
|
|
124
|
+
if (stats.bySeverity[v.severity]) {
|
|
125
|
+
stats.bySeverity[v.severity].violations++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const triaged = db.entries.filter((e) => e.triagedIso);
|
|
129
|
+
if (triaged.length > 0) {
|
|
130
|
+
const totalResponseMs = triaged.reduce((sum, e) => {
|
|
131
|
+
return sum + (new Date(e.triagedIso).getTime() - new Date(e.firstSeenIso).getTime());
|
|
132
|
+
}, 0);
|
|
133
|
+
stats.avgResponseHours = Math.round((totalResponseMs / triaged.length / 3_600_000) * 10) / 10;
|
|
134
|
+
}
|
|
135
|
+
const resolved = db.entries.filter((e) => e.resolvedIso);
|
|
136
|
+
if (resolved.length > 0) {
|
|
137
|
+
const totalResMs = resolved.reduce((sum, e) => {
|
|
138
|
+
return sum + (new Date(e.resolvedIso).getTime() - new Date(e.firstSeenIso).getTime());
|
|
139
|
+
}, 0);
|
|
140
|
+
stats.avgResolutionHours = Math.round((totalResMs / resolved.length / 3_600_000) * 10) / 10;
|
|
141
|
+
}
|
|
142
|
+
return stats;
|
|
143
|
+
}
|
|
144
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
145
|
+
export async function runSlaTrack(argv) {
|
|
146
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
147
|
+
console.log(`
|
|
148
|
+
judges sla-track — SLA tracking for security findings
|
|
149
|
+
|
|
150
|
+
Usage:
|
|
151
|
+
judges sla-track --input results.json Track findings from a results file
|
|
152
|
+
judges sla-track --check Check for SLA violations
|
|
153
|
+
judges sla-track --triage <finding-id> Mark finding as triaged
|
|
154
|
+
judges sla-track --resolve <finding-id> Mark finding as resolved
|
|
155
|
+
judges sla-track --stats Show SLA statistics
|
|
156
|
+
judges sla-track --set-policy <severity> <resp-h> <res-h>
|
|
157
|
+
|
|
158
|
+
Options:
|
|
159
|
+
--input <path> Results JSON to track
|
|
160
|
+
--check Check for SLA violations
|
|
161
|
+
--triage <id> Mark a finding as triaged
|
|
162
|
+
--resolve <id> Resolve a finding
|
|
163
|
+
--stats Show statistics
|
|
164
|
+
--set-policy Set SLA for a severity level
|
|
165
|
+
--format json JSON output
|
|
166
|
+
--help, -h Show this help
|
|
167
|
+
`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
171
|
+
// Track findings from input file
|
|
172
|
+
const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
|
|
173
|
+
if (inputPath) {
|
|
174
|
+
if (!existsSync(inputPath)) {
|
|
175
|
+
console.error(`Error: file not found: ${inputPath}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
const data = JSON.parse(readFileSync(inputPath, "utf-8"));
|
|
179
|
+
const findings = data.evaluations
|
|
180
|
+
? data.evaluations.flatMap((e) => e.findings || [])
|
|
181
|
+
: data.findings || data;
|
|
182
|
+
const db = trackFindings(findings);
|
|
183
|
+
if (format === "json") {
|
|
184
|
+
console.log(JSON.stringify(db, null, 2));
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.log(`\n Tracked ${findings.length} findings (${db.entries.length} total in DB)\n`);
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// Triage
|
|
192
|
+
const triageTarget = argv.find((_a, i) => argv[i - 1] === "--triage");
|
|
193
|
+
if (triageTarget) {
|
|
194
|
+
triageEntry(triageTarget);
|
|
195
|
+
console.log(` Triaged: ${triageTarget}`);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Resolve
|
|
199
|
+
const resolveTarget = argv.find((_a, i) => argv[i - 1] === "--resolve");
|
|
200
|
+
if (resolveTarget) {
|
|
201
|
+
resolveEntry(resolveTarget);
|
|
202
|
+
console.log(` Resolved: ${resolveTarget}`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Set policy
|
|
206
|
+
if (argv.includes("--set-policy")) {
|
|
207
|
+
const idx = argv.indexOf("--set-policy");
|
|
208
|
+
const severity = argv[idx + 1];
|
|
209
|
+
const respH = parseFloat(argv[idx + 2]);
|
|
210
|
+
const resH = parseFloat(argv[idx + 3]);
|
|
211
|
+
if (!severity || isNaN(respH) || isNaN(resH)) {
|
|
212
|
+
console.error("Error: --set-policy <severity> <response-hours> <resolution-hours>");
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
const db = loadDb(SLA_FILE);
|
|
216
|
+
const existing = db.policies.find((p) => p.severity === severity);
|
|
217
|
+
if (existing) {
|
|
218
|
+
existing.responseHours = respH;
|
|
219
|
+
existing.resolutionHours = resH;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
db.policies.push({ severity, responseHours: respH, resolutionHours: resH });
|
|
223
|
+
}
|
|
224
|
+
saveDb(SLA_FILE, db);
|
|
225
|
+
console.log(` SLA policy set: ${severity} → response ${respH}h, resolution ${resH}h`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// Check violations
|
|
229
|
+
if (argv.includes("--check")) {
|
|
230
|
+
const violations = checkViolations();
|
|
231
|
+
if (format === "json") {
|
|
232
|
+
console.log(JSON.stringify(violations, null, 2));
|
|
233
|
+
}
|
|
234
|
+
else if (violations.length === 0) {
|
|
235
|
+
console.log("\n ✅ No SLA violations\n");
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
console.log(`\n ⚠️ ${violations.length} SLA violation(s)\n`);
|
|
239
|
+
for (const v of violations) {
|
|
240
|
+
console.log(` ${v.severity.padEnd(8)} ${v.type.padEnd(10)} ${v.ruleId} — ${v.elapsedHours}h / ${v.allowedHours}h allowed`);
|
|
241
|
+
}
|
|
242
|
+
console.log("");
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
// Stats (default if --stats or no other flag)
|
|
247
|
+
const s = getSlaStats();
|
|
248
|
+
if (format === "json") {
|
|
249
|
+
console.log(JSON.stringify(s, null, 2));
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
console.log(`
|
|
253
|
+
SLA Statistics
|
|
254
|
+
──────────────────
|
|
255
|
+
Total tracked: ${s.total}
|
|
256
|
+
Open: ${s.open}
|
|
257
|
+
Triaged: ${s.triaged}
|
|
258
|
+
Resolved: ${s.resolved}
|
|
259
|
+
Violations: ${s.violations}
|
|
260
|
+
Avg response time: ${s.avgResponseHours}h
|
|
261
|
+
Avg resolution time: ${s.avgResolutionHours}h
|
|
262
|
+
`);
|
|
263
|
+
for (const [sev, data] of Object.entries(s.bySeverity)) {
|
|
264
|
+
console.log(` ${sev.padEnd(10)} ${data.total} total, ${data.open} open, ${data.violations} violations`);
|
|
265
|
+
}
|
|
266
|
+
console.log("");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=sla-track.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sla-track.js","sourceRoot":"","sources":["../../src/commands/sla-track.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart judge selection — auto-select relevant judges based on file content.
|
|
3
|
+
*
|
|
4
|
+
* Avoids running irrelevant judges (e.g., SQL judge on .tsx files,
|
|
5
|
+
* IaC judge on .py files) to improve evaluation speed and reduce noise.
|
|
6
|
+
*
|
|
7
|
+
* Used internally by the evaluation pipeline when `smartSelect: true`.
|
|
8
|
+
*/
|
|
9
|
+
export interface JudgeRelevance {
|
|
10
|
+
judgeId: string;
|
|
11
|
+
relevant: boolean;
|
|
12
|
+
reason: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Select relevant judges for a given file based on its language and content.
|
|
16
|
+
* Returns the list of judge IDs that should be run.
|
|
17
|
+
*/
|
|
18
|
+
export declare function selectJudgesForFile(language: string, code: string, availableJudges?: string[]): JudgeRelevance[];
|
|
19
|
+
/**
|
|
20
|
+
* Get just the relevant judge IDs for a file.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getRelevantJudges(language: string, code: string, availableJudges?: string[]): string[];
|
|
23
|
+
/**
|
|
24
|
+
* CLI: Show judge selection for a file.
|
|
25
|
+
*/
|
|
26
|
+
export declare function runSmartSelect(argv: string[]): void;
|
|
27
|
+
//# sourceMappingURL=smart-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-select.d.ts","sourceRoot":"","sources":["../../src/commands/smart-select.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AA8ND;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAiChH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAItG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAkGnD"}
|