@kevinrabun/judges 3.14.0 → 3.15.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 +22 -9
- package/dist/api.d.ts +2 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +2 -2
- package/dist/api.js.map +1 -1
- package/dist/evaluators/false-positive-review.d.ts +22 -0
- package/dist/evaluators/false-positive-review.d.ts.map +1 -0
- package/dist/evaluators/false-positive-review.js +229 -0
- package/dist/evaluators/false-positive-review.js.map +1 -0
- package/dist/evaluators/index.d.ts.map +1 -1
- package/dist/evaluators/index.js +3 -1
- package/dist/evaluators/index.js.map +1 -1
- package/dist/judges/false-positive-review.d.ts +3 -0
- package/dist/judges/false-positive-review.d.ts.map +1 -0
- package/dist/judges/false-positive-review.js +70 -0
- package/dist/judges/false-positive-review.js.map +1 -0
- package/dist/judges/index.d.ts.map +1 -1
- package/dist/judges/index.js +2 -0
- package/dist/judges/index.js.map +1 -1
- package/dist/tools/deep-review.d.ts +2 -2
- package/dist/tools/deep-review.d.ts.map +1 -1
- package/dist/tools/deep-review.js +2 -12
- package/dist/tools/deep-review.js.map +1 -1
- package/dist/tools/register-evaluation.d.ts.map +1 -1
- package/dist/tools/register-evaluation.js +7 -27
- package/dist/tools/register-evaluation.js.map +1 -1
- package/dist/tools/register-workflow.d.ts.map +1 -1
- package/dist/tools/register-workflow.js +3 -9
- package/dist/tools/register-workflow.js.map +1 -1
- package/package.json +1 -1
- package/dist/llm-fp-filter.d.ts +0 -74
- package/dist/llm-fp-filter.d.ts.map +0 -1
- package/dist/llm-fp-filter.js +0 -321
- package/dist/llm-fp-filter.js.map +0 -1
package/dist/llm-fp-filter.js
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
// ─── LLM-Based False Positive Filter ─────────────────────────────────────────
|
|
2
|
-
// Post-processes static analysis findings through an LLM to identify and
|
|
3
|
-
// remove false positives. Gated on LLM availability — when no API key is
|
|
4
|
-
// configured the filter is a no-op and all findings pass through unchanged.
|
|
5
|
-
//
|
|
6
|
-
// Supports any OpenAI-compatible chat completion API (OpenAI, Azure OpenAI,
|
|
7
|
-
// Ollama, LM Studio, vLLM, etc.)
|
|
8
|
-
//
|
|
9
|
-
// Environment variables:
|
|
10
|
-
// JUDGES_LLM_API_KEY — API key (falls back to OPENAI_API_KEY)
|
|
11
|
-
// JUDGES_LLM_BASE_URL — API base URL (default: https://api.openai.com/v1)
|
|
12
|
-
// JUDGES_LLM_MODEL — Model name (default: gpt-4o-mini)
|
|
13
|
-
// JUDGES_LLM_FP_FILTER — Set to "false" or "0" to disable even when key exists
|
|
14
|
-
// JUDGES_LLM_MAX_FINDINGS — Max findings to send for review (default: 50)
|
|
15
|
-
// JUDGES_LLM_TIMEOUT_MS — Request timeout in ms (default: 30000)
|
|
16
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
17
|
-
import { calculateScore, deriveVerdict } from "./evaluators/shared.js";
|
|
18
|
-
// ─── LLM Availability Detection ─────────────────────────────────────────────
|
|
19
|
-
/**
|
|
20
|
-
* Detect LLM configuration from environment variables.
|
|
21
|
-
* Returns null if no API key is available or the filter is disabled.
|
|
22
|
-
*/
|
|
23
|
-
export function detectLlmConfig() {
|
|
24
|
-
const apiKey = process.env.JUDGES_LLM_API_KEY || process.env.OPENAI_API_KEY;
|
|
25
|
-
if (!apiKey)
|
|
26
|
-
return null;
|
|
27
|
-
// Allow explicit disable via env var
|
|
28
|
-
const filterFlag = process.env.JUDGES_LLM_FP_FILTER;
|
|
29
|
-
if (filterFlag === "false" || filterFlag === "0")
|
|
30
|
-
return null;
|
|
31
|
-
return {
|
|
32
|
-
apiKey,
|
|
33
|
-
baseUrl: process.env.JUDGES_LLM_BASE_URL || "https://api.openai.com/v1",
|
|
34
|
-
model: process.env.JUDGES_LLM_MODEL || "gpt-4o-mini",
|
|
35
|
-
maxFindings: safeParseInt(process.env.JUDGES_LLM_MAX_FINDINGS, 50),
|
|
36
|
-
maxCodeLength: safeParseInt(process.env.JUDGES_LLM_MAX_CODE_LENGTH, 15000),
|
|
37
|
-
timeoutMs: safeParseInt(process.env.JUDGES_LLM_TIMEOUT_MS, 30000),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Quick check: is an LLM available for FP filtering?
|
|
42
|
-
*/
|
|
43
|
-
export function isLlmAvailable() {
|
|
44
|
-
return detectLlmConfig() !== null;
|
|
45
|
-
}
|
|
46
|
-
function safeParseInt(value, fallback) {
|
|
47
|
-
if (!value)
|
|
48
|
-
return fallback;
|
|
49
|
-
const parsed = parseInt(value, 10);
|
|
50
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
51
|
-
}
|
|
52
|
-
function buildFpReviewPrompt(findings, code, language) {
|
|
53
|
-
const summaries = findings.map((f, i) => ({
|
|
54
|
-
index: i,
|
|
55
|
-
ruleId: f.ruleId,
|
|
56
|
-
severity: f.severity,
|
|
57
|
-
title: f.title,
|
|
58
|
-
description: f.description,
|
|
59
|
-
lineNumbers: f.lineNumbers,
|
|
60
|
-
confidence: f.confidence,
|
|
61
|
-
}));
|
|
62
|
-
return `You are a code review expert specializing in false positive detection for static analysis tools.
|
|
63
|
-
|
|
64
|
-
Below is source code and a list of static analysis findings. Review each finding against the actual code and identify FALSE POSITIVES — findings that are incorrect, misleading, or do not represent real issues.
|
|
65
|
-
|
|
66
|
-
A finding is a FALSE POSITIVE if:
|
|
67
|
-
- The flagged pattern appears only in a string literal, comment, or documentation
|
|
68
|
-
- The code has adequate mitigation or handling nearby that the static analyzer missed
|
|
69
|
-
- The finding is based on a keyword match that doesn't apply in this context (e.g., "age" in cache TTL context flagged as age discrimination)
|
|
70
|
-
- The code is in a test file and the pattern is intentionally used for testing
|
|
71
|
-
- The variable/function name matches a keyword but has no actual security/quality implications
|
|
72
|
-
- The finding flags something that is standard practice for the framework being used
|
|
73
|
-
- The flagged code is dead code, unreachable, or in an exception handler that appropriately handles the concern
|
|
74
|
-
|
|
75
|
-
A finding is NOT a false positive if:
|
|
76
|
-
- There is a genuine security, quality, or compliance concern
|
|
77
|
-
- The code could be improved even if not currently exploitable
|
|
78
|
-
- The finding identifies a real missing best practice
|
|
79
|
-
|
|
80
|
-
SOURCE CODE (${language}):
|
|
81
|
-
\`\`\`${language}
|
|
82
|
-
${code}
|
|
83
|
-
\`\`\`
|
|
84
|
-
|
|
85
|
-
FINDINGS TO REVIEW:
|
|
86
|
-
${JSON.stringify(summaries, null, 2)}
|
|
87
|
-
|
|
88
|
-
Respond with ONLY a JSON object in this exact format:
|
|
89
|
-
{
|
|
90
|
-
"false_positives": [
|
|
91
|
-
{
|
|
92
|
-
"index": 0,
|
|
93
|
-
"reason": "Brief explanation of why this is a false positive"
|
|
94
|
-
}
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
Rules:
|
|
99
|
-
- Only include findings you are CONFIDENT are false positives
|
|
100
|
-
- When in doubt, do NOT mark a finding as a false positive (err on the side of caution)
|
|
101
|
-
- The "index" field must match the 0-based index in the FINDINGS array above
|
|
102
|
-
- Keep reasons concise (1-2 sentences)
|
|
103
|
-
- If no findings are false positives, return {"false_positives": []}`;
|
|
104
|
-
}
|
|
105
|
-
// ─── LLM API Call ────────────────────────────────────────────────────────────
|
|
106
|
-
async function callLlm(config, prompt) {
|
|
107
|
-
const url = `${config.baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
108
|
-
const controller = new AbortController();
|
|
109
|
-
const timeout = setTimeout(() => controller.abort(), config.timeoutMs);
|
|
110
|
-
try {
|
|
111
|
-
const response = await fetch(url, {
|
|
112
|
-
method: "POST",
|
|
113
|
-
headers: {
|
|
114
|
-
"Content-Type": "application/json",
|
|
115
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify({
|
|
118
|
-
model: config.model,
|
|
119
|
-
messages: [
|
|
120
|
-
{
|
|
121
|
-
role: "system",
|
|
122
|
-
content: "You are a precise code review expert. Respond only with valid JSON.",
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
role: "user",
|
|
126
|
-
content: prompt,
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
temperature: 0,
|
|
130
|
-
max_tokens: 2000,
|
|
131
|
-
}),
|
|
132
|
-
signal: controller.signal,
|
|
133
|
-
});
|
|
134
|
-
if (!response.ok) {
|
|
135
|
-
const errorText = await response.text().catch(() => "unknown error");
|
|
136
|
-
throw new Error(`LLM API returned ${response.status}: ${errorText}`);
|
|
137
|
-
}
|
|
138
|
-
const data = (await response.json());
|
|
139
|
-
return data.choices?.[0]?.message?.content ?? "";
|
|
140
|
-
}
|
|
141
|
-
finally {
|
|
142
|
-
clearTimeout(timeout);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
function parseFpResponse(responseText) {
|
|
146
|
-
const fpMap = new Map();
|
|
147
|
-
try {
|
|
148
|
-
// Extract JSON from markdown code blocks if the LLM wrapped it
|
|
149
|
-
const jsonMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
150
|
-
const jsonText = jsonMatch ? jsonMatch[1].trim() : responseText.trim();
|
|
151
|
-
const parsed = JSON.parse(jsonText);
|
|
152
|
-
if (Array.isArray(parsed.false_positives)) {
|
|
153
|
-
for (const fp of parsed.false_positives) {
|
|
154
|
-
if (typeof fp.index === "number" && typeof fp.reason === "string") {
|
|
155
|
-
fpMap.set(fp.index, fp.reason);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
// If parsing fails, return empty map — no findings are removed
|
|
162
|
-
}
|
|
163
|
-
return fpMap;
|
|
164
|
-
}
|
|
165
|
-
// ─── Core Filter Function ────────────────────────────────────────────────────
|
|
166
|
-
/**
|
|
167
|
-
* Filter false positives from findings using an LLM.
|
|
168
|
-
*
|
|
169
|
-
* If no LLM configuration is provided or detected, returns findings unchanged.
|
|
170
|
-
* On any error (network, parsing, timeout), gracefully degrades and returns
|
|
171
|
-
* all findings unmodified.
|
|
172
|
-
*
|
|
173
|
-
* @param findings - Static analysis findings to review
|
|
174
|
-
* @param code - The source code that was analyzed
|
|
175
|
-
* @param language - Programming language of the code
|
|
176
|
-
* @param config - Explicit LLM config, or null/undefined to auto-detect from env
|
|
177
|
-
*/
|
|
178
|
-
export async function filterFalsePositivesWithLlm(findings, code, language, config) {
|
|
179
|
-
const resolvedConfig = config === undefined ? detectLlmConfig() : config;
|
|
180
|
-
// No LLM available or no findings to review
|
|
181
|
-
if (!resolvedConfig || findings.length === 0) {
|
|
182
|
-
return {
|
|
183
|
-
filteredFindings: findings,
|
|
184
|
-
removedFindings: [],
|
|
185
|
-
llmUsed: false,
|
|
186
|
-
reviewedCount: 0,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
// Truncate code if too long
|
|
190
|
-
const truncatedCode = code.length > resolvedConfig.maxCodeLength
|
|
191
|
-
? code.slice(0, resolvedConfig.maxCodeLength) + "\n// ... [truncated for review] ..."
|
|
192
|
-
: code;
|
|
193
|
-
// Limit findings count for cost/latency control
|
|
194
|
-
const findingsToReview = findings.slice(0, resolvedConfig.maxFindings);
|
|
195
|
-
const findingsPassthrough = findings.slice(resolvedConfig.maxFindings);
|
|
196
|
-
try {
|
|
197
|
-
const prompt = buildFpReviewPrompt(findingsToReview, truncatedCode, language);
|
|
198
|
-
const responseText = await callLlm(resolvedConfig, prompt);
|
|
199
|
-
const fpMap = parseFpResponse(responseText);
|
|
200
|
-
const removed = [];
|
|
201
|
-
const kept = [];
|
|
202
|
-
for (let i = 0; i < findingsToReview.length; i++) {
|
|
203
|
-
const reason = fpMap.get(i);
|
|
204
|
-
if (reason) {
|
|
205
|
-
removed.push({ ...findingsToReview[i], fpReason: reason });
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
kept.push(findingsToReview[i]);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
// Append any findings that exceeded the review limit (kept as-is)
|
|
212
|
-
kept.push(...findingsPassthrough);
|
|
213
|
-
return {
|
|
214
|
-
filteredFindings: kept,
|
|
215
|
-
removedFindings: removed,
|
|
216
|
-
llmUsed: true,
|
|
217
|
-
model: resolvedConfig.model,
|
|
218
|
-
reviewedCount: findingsToReview.length,
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
catch (error) {
|
|
222
|
-
// Graceful degradation — log and return all findings unchanged
|
|
223
|
-
console.error(`[judges] LLM FP filter error: ${error instanceof Error ? error.message : String(error)}`);
|
|
224
|
-
return {
|
|
225
|
-
filteredFindings: findings,
|
|
226
|
-
removedFindings: [],
|
|
227
|
-
llmUsed: false,
|
|
228
|
-
reviewedCount: 0,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
// ─── Verdict-Level Integration ───────────────────────────────────────────────
|
|
233
|
-
/**
|
|
234
|
-
* Apply LLM-based false positive filtering to a complete TribunalVerdict.
|
|
235
|
-
*
|
|
236
|
-
* Filters both the top-level findings and the per-judge evaluation findings,
|
|
237
|
-
* then recalculates scores and verdicts for consistency.
|
|
238
|
-
*
|
|
239
|
-
* If no LLM is available or no FPs are found, returns the verdict unchanged.
|
|
240
|
-
*
|
|
241
|
-
* @param verdict - The tribunal verdict from static analysis
|
|
242
|
-
* @param code - The source code that was analyzed
|
|
243
|
-
* @param language - Programming language
|
|
244
|
-
* @param config - Explicit LLM config, or undefined to auto-detect
|
|
245
|
-
*/
|
|
246
|
-
export async function applyLlmFpFilterToVerdict(verdict, code, language, config) {
|
|
247
|
-
const result = await filterFalsePositivesWithLlm(verdict.findings, code, language, config);
|
|
248
|
-
if (!result.llmUsed || result.removedFindings.length === 0) {
|
|
249
|
-
return { verdict, filterResult: result };
|
|
250
|
-
}
|
|
251
|
-
// Build a set of removed finding identifiers for fast lookup
|
|
252
|
-
const removedKeys = new Set(result.removedFindings.map((f) => findingKey(f)));
|
|
253
|
-
// Update per-judge evaluations: remove filtered findings, recalculate scores
|
|
254
|
-
const updatedEvaluations = verdict.evaluations.map((evaluation) => {
|
|
255
|
-
const filtered = evaluation.findings.filter((f) => !removedKeys.has(findingKey(f)));
|
|
256
|
-
const score = calculateScore(filtered, code);
|
|
257
|
-
const evalVerdict = deriveVerdict(filtered, score);
|
|
258
|
-
return {
|
|
259
|
-
...evaluation,
|
|
260
|
-
findings: filtered,
|
|
261
|
-
score,
|
|
262
|
-
verdict: evalVerdict,
|
|
263
|
-
};
|
|
264
|
-
});
|
|
265
|
-
// Recalculate overall metrics
|
|
266
|
-
const criticalCount = result.filteredFindings.filter((f) => f.severity === "critical").length;
|
|
267
|
-
const highCount = result.filteredFindings.filter((f) => f.severity === "high").length;
|
|
268
|
-
const overallScore = Math.round(updatedEvaluations.reduce((sum, e) => sum + e.score, 0) / updatedEvaluations.length);
|
|
269
|
-
const overallVerdict = updatedEvaluations.some((e) => e.verdict === "fail")
|
|
270
|
-
? "fail"
|
|
271
|
-
: updatedEvaluations.some((e) => e.verdict === "warning")
|
|
272
|
-
? "warning"
|
|
273
|
-
: "pass";
|
|
274
|
-
// Build filter summary section
|
|
275
|
-
const filterSummary = buildFilterSummary(result);
|
|
276
|
-
const updatedVerdict = {
|
|
277
|
-
...verdict,
|
|
278
|
-
findings: result.filteredFindings,
|
|
279
|
-
evaluations: updatedEvaluations,
|
|
280
|
-
overallScore,
|
|
281
|
-
overallVerdict,
|
|
282
|
-
criticalCount,
|
|
283
|
-
highCount,
|
|
284
|
-
summary: verdict.summary + filterSummary,
|
|
285
|
-
};
|
|
286
|
-
return { verdict: updatedVerdict, filterResult: result };
|
|
287
|
-
}
|
|
288
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
289
|
-
/**
|
|
290
|
-
* Generate a stable key for a finding to enable set-based lookup.
|
|
291
|
-
*/
|
|
292
|
-
function findingKey(f) {
|
|
293
|
-
return `${f.ruleId}|${f.title}|${(f.lineNumbers ?? []).join(",")}`;
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Build a Markdown section summarizing the LLM FP filter results.
|
|
297
|
-
*/
|
|
298
|
-
function buildFilterSummary(result) {
|
|
299
|
-
if (!result.llmUsed || result.removedFindings.length === 0)
|
|
300
|
-
return "";
|
|
301
|
-
let md = `\n\n## LLM False Positive Filter\n\n`;
|
|
302
|
-
md += `- **Model:** ${result.model}\n`;
|
|
303
|
-
md += `- **Findings Reviewed:** ${result.reviewedCount}\n`;
|
|
304
|
-
md += `- **False Positives Removed:** ${result.removedFindings.length}\n\n`;
|
|
305
|
-
if (result.removedFindings.length > 0) {
|
|
306
|
-
md += `### Dismissed Findings\n\n`;
|
|
307
|
-
for (const f of result.removedFindings) {
|
|
308
|
-
md += `- **[${f.ruleId}] ${f.title}**: ${f.fpReason}\n`;
|
|
309
|
-
}
|
|
310
|
-
md += "\n";
|
|
311
|
-
}
|
|
312
|
-
return md;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Format an LLM filter result section for appending to tool output.
|
|
316
|
-
* Used by MCP tool handlers to add filter information to the response.
|
|
317
|
-
*/
|
|
318
|
-
export function formatFilterResultAsMarkdown(result) {
|
|
319
|
-
return buildFilterSummary(result);
|
|
320
|
-
}
|
|
321
|
-
//# sourceMappingURL=llm-fp-filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"llm-fp-filter.js","sourceRoot":"","sources":["../src/llm-fp-filter.ts"],"names":[],"mappings":"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"}
|