@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.
Files changed (34) hide show
  1. package/CHANGELOG.md +22 -9
  2. package/dist/api.d.ts +2 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +2 -2
  5. package/dist/api.js.map +1 -1
  6. package/dist/evaluators/false-positive-review.d.ts +22 -0
  7. package/dist/evaluators/false-positive-review.d.ts.map +1 -0
  8. package/dist/evaluators/false-positive-review.js +229 -0
  9. package/dist/evaluators/false-positive-review.js.map +1 -0
  10. package/dist/evaluators/index.d.ts.map +1 -1
  11. package/dist/evaluators/index.js +3 -1
  12. package/dist/evaluators/index.js.map +1 -1
  13. package/dist/judges/false-positive-review.d.ts +3 -0
  14. package/dist/judges/false-positive-review.d.ts.map +1 -0
  15. package/dist/judges/false-positive-review.js +70 -0
  16. package/dist/judges/false-positive-review.js.map +1 -0
  17. package/dist/judges/index.d.ts.map +1 -1
  18. package/dist/judges/index.js +2 -0
  19. package/dist/judges/index.js.map +1 -1
  20. package/dist/tools/deep-review.d.ts +2 -2
  21. package/dist/tools/deep-review.d.ts.map +1 -1
  22. package/dist/tools/deep-review.js +2 -12
  23. package/dist/tools/deep-review.js.map +1 -1
  24. package/dist/tools/register-evaluation.d.ts.map +1 -1
  25. package/dist/tools/register-evaluation.js +7 -27
  26. package/dist/tools/register-evaluation.js.map +1 -1
  27. package/dist/tools/register-workflow.d.ts.map +1 -1
  28. package/dist/tools/register-workflow.js +3 -9
  29. package/dist/tools/register-workflow.js.map +1 -1
  30. package/package.json +1 -1
  31. package/dist/llm-fp-filter.d.ts +0 -74
  32. package/dist/llm-fp-filter.d.ts.map +0 -1
  33. package/dist/llm-fp-filter.js +0 -321
  34. package/dist/llm-fp-filter.js.map +0 -1
@@ -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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"}