@kevinrabun/judges 3.38.0 → 3.40.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 +46 -0
- package/README.md +5 -4
- package/dist/api.d.ts +5 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +5 -1
- package/dist/api.js.map +1 -1
- package/dist/ast/structural-parser.js +3 -3
- package/dist/ast/structural-parser.js.map +1 -1
- package/dist/calibration.d.ts +35 -0
- package/dist/calibration.d.ts.map +1 -1
- package/dist/calibration.js +52 -0
- package/dist/calibration.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +307 -16
- package/dist/cli.js.map +1 -1
- package/dist/commands/benchmark-languages.js +4 -4
- package/dist/commands/benchmark.d.ts +2 -1
- package/dist/commands/benchmark.d.ts.map +1 -1
- package/dist/commands/benchmark.js +67 -2
- package/dist/commands/benchmark.js.map +1 -1
- package/dist/commands/calibration-dashboard.d.ts.map +1 -1
- package/dist/commands/calibration-dashboard.js +198 -0
- package/dist/commands/calibration-dashboard.js.map +1 -1
- package/dist/commands/calibration-share.d.ts +31 -0
- package/dist/commands/calibration-share.d.ts.map +1 -0
- package/dist/commands/calibration-share.js +183 -0
- package/dist/commands/calibration-share.js.map +1 -0
- package/dist/commands/compliance-report.d.ts +35 -0
- package/dist/commands/compliance-report.d.ts.map +1 -0
- package/dist/commands/compliance-report.js +162 -0
- package/dist/commands/compliance-report.js.map +1 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +8 -3
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/feedback-rules.d.ts +29 -0
- package/dist/commands/feedback-rules.d.ts.map +1 -0
- package/dist/commands/feedback-rules.js +174 -0
- package/dist/commands/feedback-rules.js.map +1 -0
- package/dist/commands/feedback.d.ts +12 -0
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +16 -0
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +33 -1
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/governance.d.ts +32 -0
- package/dist/commands/governance.d.ts.map +1 -0
- package/dist/commands/governance.js +203 -0
- package/dist/commands/governance.js.map +1 -0
- package/dist/commands/help.d.ts +8 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +303 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +17 -20
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/llm-benchmark.d.ts +119 -0
- package/dist/commands/llm-benchmark.d.ts.map +1 -0
- package/dist/commands/llm-benchmark.js +396 -0
- package/dist/commands/llm-benchmark.js.map +1 -0
- package/dist/commands/metrics-dashboard.d.ts +22 -0
- package/dist/commands/metrics-dashboard.d.ts.map +1 -0
- package/dist/commands/metrics-dashboard.js +335 -0
- package/dist/commands/metrics-dashboard.js.map +1 -0
- package/dist/commands/metrics.d.ts +58 -0
- package/dist/commands/metrics.d.ts.map +1 -0
- package/dist/commands/metrics.js +242 -0
- package/dist/commands/metrics.js.map +1 -0
- package/dist/commands/onboard.d.ts +13 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +179 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/org-metrics.d.ts +24 -0
- package/dist/commands/org-metrics.d.ts.map +1 -0
- package/dist/commands/org-metrics.js +238 -0
- package/dist/commands/org-metrics.js.map +1 -0
- package/dist/commands/override.d.ts +62 -0
- package/dist/commands/override.d.ts.map +1 -0
- package/dist/commands/override.js +264 -0
- package/dist/commands/override.js.map +1 -0
- package/dist/commands/parity.d.ts +31 -0
- package/dist/commands/parity.d.ts.map +1 -0
- package/dist/commands/parity.js +213 -0
- package/dist/commands/parity.js.map +1 -0
- package/dist/commands/plugin-search.d.ts +40 -0
- package/dist/commands/plugin-search.d.ts.map +1 -0
- package/dist/commands/plugin-search.js +328 -0
- package/dist/commands/plugin-search.js.map +1 -0
- package/dist/commands/plugins.d.ts +13 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +105 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/review.js +1 -1
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/snapshot.d.ts +27 -0
- package/dist/commands/snapshot.d.ts.map +1 -1
- package/dist/commands/snapshot.js +99 -0
- package/dist/commands/snapshot.js.map +1 -1
- package/dist/commands/trace.d.ts +65 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +246 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/trust-ramp.d.ts +30 -0
- package/dist/commands/trust-ramp.d.ts.map +1 -0
- package/dist/commands/trust-ramp.js +190 -0
- package/dist/commands/trust-ramp.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -1
- package/dist/data-adapter.d.ts +124 -0
- package/dist/data-adapter.d.ts.map +1 -0
- package/dist/data-adapter.js +213 -0
- package/dist/data-adapter.js.map +1 -0
- package/dist/evaluators/accessibility.js +1 -1
- package/dist/evaluators/accessibility.js.map +1 -1
- package/dist/evaluators/ai-code-safety.d.ts.map +1 -1
- package/dist/evaluators/ai-code-safety.js +1 -4
- package/dist/evaluators/ai-code-safety.js.map +1 -1
- package/dist/evaluators/cost-effectiveness.js +1 -1
- package/dist/evaluators/cost-effectiveness.js.map +1 -1
- package/dist/evaluators/false-positive-review.js +4 -4
- package/dist/evaluators/false-positive-review.js.map +1 -1
- package/dist/evaluators/iac-security.js +1 -1
- package/dist/evaluators/iac-security.js.map +1 -1
- package/dist/evaluators/index.d.ts.map +1 -1
- package/dist/evaluators/index.js +59 -10
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/intent-alignment.d.ts +4 -0
- package/dist/evaluators/intent-alignment.d.ts.map +1 -1
- package/dist/evaluators/intent-alignment.js +163 -0
- package/dist/evaluators/intent-alignment.js.map +1 -1
- package/dist/evaluators/logic-review.js +1 -1
- package/dist/evaluators/logic-review.js.map +1 -1
- package/dist/evaluators/maintainability.js +1 -1
- package/dist/evaluators/maintainability.js.map +1 -1
- package/dist/evaluators/over-engineering.js +3 -3
- package/dist/evaluators/over-engineering.js.map +1 -1
- package/dist/evaluators/project.d.ts +12 -0
- package/dist/evaluators/project.d.ts.map +1 -1
- package/dist/evaluators/project.js +86 -0
- package/dist/evaluators/project.js.map +1 -1
- package/dist/evaluators/security.js +2 -2
- package/dist/evaluators/security.js.map +1 -1
- package/dist/evaluators/ux.js +1 -1
- package/dist/evaluators/ux.js.map +1 -1
- package/dist/finding-lifecycle.d.ts +9 -0
- package/dist/finding-lifecycle.d.ts.map +1 -1
- package/dist/finding-lifecycle.js +15 -0
- package/dist/finding-lifecycle.js.map +1 -1
- package/dist/fix-history.d.ts +9 -0
- package/dist/fix-history.d.ts.map +1 -1
- package/dist/fix-history.js +15 -0
- package/dist/fix-history.js.map +1 -1
- package/dist/formatters/sarif.d.ts +3 -0
- package/dist/formatters/sarif.d.ts.map +1 -1
- package/dist/formatters/sarif.js +36 -12
- package/dist/formatters/sarif.js.map +1 -1
- package/dist/github-app.d.ts +16 -1
- package/dist/github-app.d.ts.map +1 -1
- package/dist/github-app.js +85 -2
- package/dist/github-app.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/judge-registry.d.ts +157 -0
- package/dist/judge-registry.d.ts.map +1 -0
- package/dist/judge-registry.js +273 -0
- package/dist/judge-registry.js.map +1 -0
- package/dist/judges/accessibility.d.ts.map +1 -1
- package/dist/judges/accessibility.js +4 -0
- package/dist/judges/accessibility.js.map +1 -1
- package/dist/judges/agent-instructions.d.ts.map +1 -1
- package/dist/judges/agent-instructions.js +4 -0
- package/dist/judges/agent-instructions.js.map +1 -1
- package/dist/judges/ai-code-safety.d.ts.map +1 -1
- package/dist/judges/ai-code-safety.js +4 -0
- package/dist/judges/ai-code-safety.js.map +1 -1
- package/dist/judges/api-contract.d.ts.map +1 -1
- package/dist/judges/api-contract.js +4 -0
- package/dist/judges/api-contract.js.map +1 -1
- package/dist/judges/api-design.d.ts.map +1 -1
- package/dist/judges/api-design.js +4 -0
- package/dist/judges/api-design.js.map +1 -1
- package/dist/judges/authentication.d.ts.map +1 -1
- package/dist/judges/authentication.js +4 -0
- package/dist/judges/authentication.js.map +1 -1
- package/dist/judges/backwards-compatibility.d.ts.map +1 -1
- package/dist/judges/backwards-compatibility.js +4 -0
- package/dist/judges/backwards-compatibility.js.map +1 -1
- package/dist/judges/caching.d.ts.map +1 -1
- package/dist/judges/caching.js +4 -0
- package/dist/judges/caching.js.map +1 -1
- package/dist/judges/ci-cd.d.ts.map +1 -1
- package/dist/judges/ci-cd.js +4 -0
- package/dist/judges/ci-cd.js.map +1 -1
- package/dist/judges/cloud-readiness.d.ts.map +1 -1
- package/dist/judges/cloud-readiness.js +4 -0
- package/dist/judges/cloud-readiness.js.map +1 -1
- package/dist/judges/code-structure.d.ts.map +1 -1
- package/dist/judges/code-structure.js +4 -0
- package/dist/judges/code-structure.js.map +1 -1
- package/dist/judges/compliance.d.ts.map +1 -1
- package/dist/judges/compliance.js +4 -0
- package/dist/judges/compliance.js.map +1 -1
- package/dist/judges/concurrency.d.ts.map +1 -1
- package/dist/judges/concurrency.js +4 -0
- package/dist/judges/concurrency.js.map +1 -1
- package/dist/judges/configuration-management.d.ts.map +1 -1
- package/dist/judges/configuration-management.js +4 -0
- package/dist/judges/configuration-management.js.map +1 -1
- package/dist/judges/cost-effectiveness.d.ts.map +1 -1
- package/dist/judges/cost-effectiveness.js +4 -0
- package/dist/judges/cost-effectiveness.js.map +1 -1
- package/dist/judges/cybersecurity.d.ts.map +1 -1
- package/dist/judges/cybersecurity.js +4 -0
- package/dist/judges/cybersecurity.js.map +1 -1
- package/dist/judges/data-security.d.ts.map +1 -1
- package/dist/judges/data-security.js +4 -0
- package/dist/judges/data-security.js.map +1 -1
- package/dist/judges/data-sovereignty.d.ts.map +1 -1
- package/dist/judges/data-sovereignty.js +4 -0
- package/dist/judges/data-sovereignty.js.map +1 -1
- package/dist/judges/database.d.ts.map +1 -1
- package/dist/judges/database.js +4 -0
- package/dist/judges/database.js.map +1 -1
- package/dist/judges/dependency-health.d.ts.map +1 -1
- package/dist/judges/dependency-health.js +4 -0
- package/dist/judges/dependency-health.js.map +1 -1
- package/dist/judges/documentation.d.ts.map +1 -1
- package/dist/judges/documentation.js +4 -0
- package/dist/judges/documentation.js.map +1 -1
- package/dist/judges/error-handling.d.ts.map +1 -1
- package/dist/judges/error-handling.js +4 -0
- package/dist/judges/error-handling.js.map +1 -1
- package/dist/judges/ethics-bias.d.ts.map +1 -1
- package/dist/judges/ethics-bias.js +4 -0
- package/dist/judges/ethics-bias.js.map +1 -1
- package/dist/judges/false-positive-review.d.ts.map +1 -1
- package/dist/judges/false-positive-review.js +2 -0
- package/dist/judges/false-positive-review.js.map +1 -1
- package/dist/judges/framework-safety.d.ts.map +1 -1
- package/dist/judges/framework-safety.js +4 -0
- package/dist/judges/framework-safety.js.map +1 -1
- package/dist/judges/hallucination-detection.d.ts.map +1 -1
- package/dist/judges/hallucination-detection.js +4 -0
- package/dist/judges/hallucination-detection.js.map +1 -1
- package/dist/judges/iac-security.d.ts.map +1 -1
- package/dist/judges/iac-security.js +4 -0
- package/dist/judges/iac-security.js.map +1 -1
- package/dist/judges/index.d.ts +59 -0
- package/dist/judges/index.d.ts.map +1 -1
- package/dist/judges/index.js +65 -189
- package/dist/judges/index.js.map +1 -1
- package/dist/judges/intent-alignment.d.ts.map +1 -1
- package/dist/judges/intent-alignment.js +4 -0
- package/dist/judges/intent-alignment.js.map +1 -1
- package/dist/judges/internationalization.d.ts.map +1 -1
- package/dist/judges/internationalization.js +4 -0
- package/dist/judges/internationalization.js.map +1 -1
- package/dist/judges/logging-privacy.d.ts.map +1 -1
- package/dist/judges/logging-privacy.js +4 -0
- package/dist/judges/logging-privacy.js.map +1 -1
- package/dist/judges/logic-review.d.ts.map +1 -1
- package/dist/judges/logic-review.js +4 -0
- package/dist/judges/logic-review.js.map +1 -1
- package/dist/judges/maintainability.d.ts.map +1 -1
- package/dist/judges/maintainability.js +4 -0
- package/dist/judges/maintainability.js.map +1 -1
- package/dist/judges/model-fingerprint.d.ts.map +1 -1
- package/dist/judges/model-fingerprint.js +4 -0
- package/dist/judges/model-fingerprint.js.map +1 -1
- package/dist/judges/multi-turn-coherence.d.ts.map +1 -1
- package/dist/judges/multi-turn-coherence.js +4 -0
- package/dist/judges/multi-turn-coherence.js.map +1 -1
- package/dist/judges/observability.d.ts.map +1 -1
- package/dist/judges/observability.js +4 -0
- package/dist/judges/observability.js.map +1 -1
- package/dist/judges/over-engineering.d.ts.map +1 -1
- package/dist/judges/over-engineering.js +4 -0
- package/dist/judges/over-engineering.js.map +1 -1
- package/dist/judges/performance.d.ts.map +1 -1
- package/dist/judges/performance.js +4 -0
- package/dist/judges/performance.js.map +1 -1
- package/dist/judges/portability.d.ts.map +1 -1
- package/dist/judges/portability.js +4 -0
- package/dist/judges/portability.js.map +1 -1
- package/dist/judges/rate-limiting.d.ts.map +1 -1
- package/dist/judges/rate-limiting.js +4 -0
- package/dist/judges/rate-limiting.js.map +1 -1
- package/dist/judges/reliability.d.ts.map +1 -1
- package/dist/judges/reliability.js +4 -0
- package/dist/judges/reliability.js.map +1 -1
- package/dist/judges/scalability.d.ts.map +1 -1
- package/dist/judges/scalability.js +4 -0
- package/dist/judges/scalability.js.map +1 -1
- package/dist/judges/security.d.ts.map +1 -1
- package/dist/judges/security.js +4 -0
- package/dist/judges/security.js.map +1 -1
- package/dist/judges/software-practices.d.ts.map +1 -1
- package/dist/judges/software-practices.js +4 -0
- package/dist/judges/software-practices.js.map +1 -1
- package/dist/judges/testing.d.ts.map +1 -1
- package/dist/judges/testing.js +4 -0
- package/dist/judges/testing.js.map +1 -1
- package/dist/judges/ux.d.ts.map +1 -1
- package/dist/judges/ux.js +4 -0
- package/dist/judges/ux.js.map +1 -1
- package/dist/plugins.d.ts +8 -51
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +16 -125
- package/dist/plugins.js.map +1 -1
- package/dist/security-ids.d.ts +24 -0
- package/dist/security-ids.d.ts.map +1 -0
- package/dist/security-ids.js +240 -0
- package/dist/security-ids.js.map +1 -0
- package/dist/tools/prompts.d.ts +4 -0
- package/dist/tools/prompts.d.ts.map +1 -1
- package/dist/tools/prompts.js +6 -4
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/register-scaffold.d.ts +3 -0
- package/dist/tools/register-scaffold.d.ts.map +1 -0
- package/dist/tools/register-scaffold.js +399 -0
- package/dist/tools/register-scaffold.js.map +1 -0
- package/dist/tools/register.d.ts +1 -1
- package/dist/tools/register.d.ts.map +1 -1
- package/dist/tools/register.js +3 -1
- package/dist/tools/register.js.map +1 -1
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/server.json +2 -2
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// ─── Trace Mode — Show Your Work ─────────────────────────────────────────────
|
|
2
|
+
// Renders a detailed, human-readable trace of exactly how the evaluation
|
|
3
|
+
// pipeline reached its decision for every finding. Each finding's journey
|
|
4
|
+
// through the pipeline is shown: detection → FP filters → dedup → calibration
|
|
5
|
+
// → confidence scoring → final disposition.
|
|
6
|
+
//
|
|
7
|
+
// All data is computed locally from the evaluation result — no external
|
|
8
|
+
// services or data storage involved.
|
|
9
|
+
//
|
|
10
|
+
// Usage:
|
|
11
|
+
// judges eval src/app.ts --trace # text trace to stdout
|
|
12
|
+
// judges eval src/app.ts --trace --format json # structured trace
|
|
13
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
// ─── Trace Builder ──────────────────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Build an evaluation trace from a tribunal verdict.
|
|
17
|
+
*
|
|
18
|
+
* This reconstructs the pipeline journey from the data available on the
|
|
19
|
+
* verdict — it does not require runtime hooks in the evaluator. The trace
|
|
20
|
+
* is approximate but highly informative for understanding why findings
|
|
21
|
+
* were kept or dropped.
|
|
22
|
+
*/
|
|
23
|
+
export function buildEvaluationTrace(verdict, filePath, language) {
|
|
24
|
+
const judgeSummaries = verdict.evaluations.map((e) => ({
|
|
25
|
+
judgeId: e.judgeId,
|
|
26
|
+
judgeName: e.judgeName,
|
|
27
|
+
findingsProduced: e.findings.length,
|
|
28
|
+
durationMs: e.durationMs ?? 0,
|
|
29
|
+
}));
|
|
30
|
+
const rawFindingCount = verdict.evaluations.reduce((sum, e) => sum + e.findings.length, 0);
|
|
31
|
+
// Build per-finding traces from what we can infer
|
|
32
|
+
const findingTraces = [];
|
|
33
|
+
// Track what the final set contains
|
|
34
|
+
const finalRuleIds = new Set(verdict.findings.map((f) => `${f.ruleId}:${f.lineNumbers?.[0] ?? 0}`));
|
|
35
|
+
// Process each judge's findings
|
|
36
|
+
for (const evaluation of verdict.evaluations) {
|
|
37
|
+
for (const finding of evaluation.findings) {
|
|
38
|
+
const key = `${finding.ruleId}:${finding.lineNumbers?.[0] ?? 0}`;
|
|
39
|
+
const steps = [];
|
|
40
|
+
// Step 1: Detection
|
|
41
|
+
steps.push({
|
|
42
|
+
stage: "detection",
|
|
43
|
+
action: "kept",
|
|
44
|
+
reason: `Detected by ${evaluation.judgeName} (${evaluation.judgeId}) via ${finding.provenance ?? "pattern-match"}`,
|
|
45
|
+
});
|
|
46
|
+
// Step 2: Evidence basis
|
|
47
|
+
if (finding.evidenceBasis) {
|
|
48
|
+
steps.push({
|
|
49
|
+
stage: "confidence-scoring",
|
|
50
|
+
action: finding.confidence && finding.confidence >= 0.7 ? "boosted" : "kept",
|
|
51
|
+
reason: `Evidence: ${finding.evidenceBasis}`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Step 3: Evidence chain
|
|
55
|
+
if (finding.evidenceChain) {
|
|
56
|
+
const chainDesc = finding.evidenceChain.steps
|
|
57
|
+
.map((s) => `${s.source}${s.line ? ` L${s.line}` : ""}: ${s.observation}`)
|
|
58
|
+
.join(" → ");
|
|
59
|
+
steps.push({
|
|
60
|
+
stage: "evidence-chain",
|
|
61
|
+
action: "kept",
|
|
62
|
+
reason: chainDesc,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// Step 4: Absence gating
|
|
66
|
+
if (finding.isAbsenceBased) {
|
|
67
|
+
steps.push({
|
|
68
|
+
stage: "absence-gating",
|
|
69
|
+
action: "demoted",
|
|
70
|
+
reason: "Absence-based finding — severity capped at medium, confidence capped at 0.6",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Step 5: Confidence tier
|
|
74
|
+
if (finding.confidenceTier) {
|
|
75
|
+
steps.push({
|
|
76
|
+
stage: "confidence-tiering",
|
|
77
|
+
action: "kept",
|
|
78
|
+
reason: `Classified as "${finding.confidenceTier}" (confidence: ${((finding.confidence ?? 0.5) * 100).toFixed(0)}%)`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Step 6: Check if it survived to final output
|
|
82
|
+
const inFinal = finalRuleIds.has(key);
|
|
83
|
+
if (!inFinal) {
|
|
84
|
+
// Determine likely suppression reason
|
|
85
|
+
if (finding.isAbsenceBased) {
|
|
86
|
+
steps.push({
|
|
87
|
+
stage: "pipeline-filter",
|
|
88
|
+
action: "suppressed",
|
|
89
|
+
reason: "Suppressed: absence-based finding in single-file mode",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
steps.push({
|
|
94
|
+
stage: "pipeline-filter",
|
|
95
|
+
action: "suppressed",
|
|
96
|
+
reason: "Suppressed: likely removed by FP heuristics, dedup, or config filter",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Step 7: OWASP LLM mapping
|
|
101
|
+
if (finding.owaspLlmTop10) {
|
|
102
|
+
steps.push({
|
|
103
|
+
stage: "ai-risk-mapping",
|
|
104
|
+
action: "kept",
|
|
105
|
+
reason: `Mapped to ${finding.owaspLlmTop10}`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Step 8: Patch availability
|
|
109
|
+
if (finding.patch) {
|
|
110
|
+
steps.push({
|
|
111
|
+
stage: "auto-fix",
|
|
112
|
+
action: "added",
|
|
113
|
+
reason: `Auto-fix available: L${finding.patch.startLine}-${finding.patch.endLine}`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const confidenceJourney = finding.evidenceBasis
|
|
117
|
+
? {
|
|
118
|
+
initial: 0.5,
|
|
119
|
+
final: finding.confidence ?? 0.5,
|
|
120
|
+
adjustments: finding.evidenceBasis.split(", "),
|
|
121
|
+
}
|
|
122
|
+
: undefined;
|
|
123
|
+
findingTraces.push({
|
|
124
|
+
ruleId: finding.ruleId,
|
|
125
|
+
title: finding.title,
|
|
126
|
+
severity: finding.severity,
|
|
127
|
+
disposition: inFinal ? "reported" : "suppressed",
|
|
128
|
+
steps,
|
|
129
|
+
confidenceJourney,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Add traces for suppressed findings (from inline suppression audit trail)
|
|
134
|
+
if (verdict.suppressions) {
|
|
135
|
+
for (const s of verdict.suppressions) {
|
|
136
|
+
findingTraces.push({
|
|
137
|
+
ruleId: s.ruleId,
|
|
138
|
+
title: s.title,
|
|
139
|
+
severity: s.severity,
|
|
140
|
+
disposition: "suppressed",
|
|
141
|
+
steps: [
|
|
142
|
+
{ stage: "detection", action: "kept", reason: "Detected by pattern match" },
|
|
143
|
+
{
|
|
144
|
+
stage: "inline-suppression",
|
|
145
|
+
action: "suppressed",
|
|
146
|
+
reason: `Suppressed by ${s.kind} comment at L${s.commentLine}${s.reason ? `: ${s.reason}` : ""}`,
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Compute suppression summary by stage
|
|
153
|
+
const suppressionMap = new Map();
|
|
154
|
+
for (const trace of findingTraces) {
|
|
155
|
+
if (trace.disposition === "suppressed") {
|
|
156
|
+
const lastStep = trace.steps[trace.steps.length - 1];
|
|
157
|
+
const stage = lastStep?.stage ?? "unknown";
|
|
158
|
+
suppressionMap.set(stage, (suppressionMap.get(stage) ?? 0) + 1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const suppressionSummary = [...suppressionMap.entries()]
|
|
162
|
+
.map(([stage, count]) => ({ stage, count }))
|
|
163
|
+
.sort((a, b) => b.count - a.count);
|
|
164
|
+
return {
|
|
165
|
+
filePath,
|
|
166
|
+
language: language ?? "unknown",
|
|
167
|
+
judgesRun: verdict.evaluations.length,
|
|
168
|
+
rawFindingCount,
|
|
169
|
+
finalFindingCount: verdict.findings.length,
|
|
170
|
+
suppressionSummary,
|
|
171
|
+
findings: findingTraces,
|
|
172
|
+
judgeSummaries,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// ─── Text Formatter ─────────────────────────────────────────────────────────
|
|
176
|
+
/**
|
|
177
|
+
* Format an evaluation trace as human-readable text output.
|
|
178
|
+
*/
|
|
179
|
+
export function formatTraceText(trace) {
|
|
180
|
+
const lines = [];
|
|
181
|
+
lines.push("");
|
|
182
|
+
lines.push("╔══════════════════════════════════════════════════════════════╗");
|
|
183
|
+
lines.push("║ Judges Panel — Evaluation Trace ║");
|
|
184
|
+
lines.push("╚══════════════════════════════════════════════════════════════╝");
|
|
185
|
+
lines.push("");
|
|
186
|
+
if (trace.filePath)
|
|
187
|
+
lines.push(` File : ${trace.filePath}`);
|
|
188
|
+
lines.push(` Language : ${trace.language}`);
|
|
189
|
+
lines.push(` Judges : ${trace.judgesRun}`);
|
|
190
|
+
lines.push(` Raw : ${trace.rawFindingCount} findings detected`);
|
|
191
|
+
lines.push(` Final : ${trace.finalFindingCount} findings reported`);
|
|
192
|
+
lines.push(` Filtered : ${trace.rawFindingCount - trace.finalFindingCount} findings suppressed`);
|
|
193
|
+
lines.push("");
|
|
194
|
+
// Judge timing breakdown
|
|
195
|
+
lines.push(" ─── Judge Execution ────────────────────────────────────────");
|
|
196
|
+
lines.push("");
|
|
197
|
+
for (const j of trace.judgeSummaries) {
|
|
198
|
+
const icon = j.findingsProduced > 0 ? "🔍" : "✅";
|
|
199
|
+
lines.push(` ${icon} ${j.judgeName.padEnd(35)} ${j.findingsProduced} finding(s) ${j.durationMs}ms`);
|
|
200
|
+
}
|
|
201
|
+
lines.push("");
|
|
202
|
+
// Suppression summary
|
|
203
|
+
if (trace.suppressionSummary.length > 0) {
|
|
204
|
+
lines.push(" ─── Suppression Summary ────────────────────────────────────");
|
|
205
|
+
lines.push("");
|
|
206
|
+
for (const s of trace.suppressionSummary) {
|
|
207
|
+
lines.push(` ⊘ ${s.stage.padEnd(30)} ${s.count} finding(s) removed`);
|
|
208
|
+
}
|
|
209
|
+
lines.push("");
|
|
210
|
+
}
|
|
211
|
+
// Per-finding traces
|
|
212
|
+
lines.push(" ─── Finding Decision Traces ────────────────────────────────");
|
|
213
|
+
lines.push("");
|
|
214
|
+
for (const f of trace.findings) {
|
|
215
|
+
const icon = f.disposition === "reported" ? "📋" : f.disposition === "merged" ? "🔀" : "⊘";
|
|
216
|
+
lines.push(` ${icon} [${f.severity.toUpperCase().padEnd(8)}] ${f.ruleId}: ${f.title}`);
|
|
217
|
+
lines.push(` Disposition: ${f.disposition.toUpperCase()}`);
|
|
218
|
+
for (const step of f.steps) {
|
|
219
|
+
const actionIcon = step.action === "kept"
|
|
220
|
+
? " →"
|
|
221
|
+
: step.action === "suppressed"
|
|
222
|
+
? " ✗"
|
|
223
|
+
: step.action === "demoted"
|
|
224
|
+
? " ↓"
|
|
225
|
+
: step.action === "boosted"
|
|
226
|
+
? " ↑"
|
|
227
|
+
: step.action === "merged"
|
|
228
|
+
? " ⊕"
|
|
229
|
+
: step.action === "added"
|
|
230
|
+
? " +"
|
|
231
|
+
: step.action === "capped"
|
|
232
|
+
? " ⌐"
|
|
233
|
+
: " ?";
|
|
234
|
+
lines.push(` ${actionIcon} [${step.stage}] ${step.reason}`);
|
|
235
|
+
}
|
|
236
|
+
if (f.confidenceJourney) {
|
|
237
|
+
lines.push(` Confidence: ${(f.confidenceJourney.initial * 100).toFixed(0)}% → ${(f.confidenceJourney.final * 100).toFixed(0)}%`);
|
|
238
|
+
for (const adj of f.confidenceJourney.adjustments) {
|
|
239
|
+
lines.push(` ${adj.trim()}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
lines.push("");
|
|
243
|
+
}
|
|
244
|
+
return lines.join("\n");
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../src/commands/trace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `judges trust-ramp` — Generate a graduated trust configuration.
|
|
3
|
+
*
|
|
4
|
+
* Produces a phased .judgesrc progression that starts with advisory-only
|
|
5
|
+
* (no CI gating) and ramps up to full enforcement over 30/60/90 days.
|
|
6
|
+
* All data stays local — phases are encoded as config files you commit.
|
|
7
|
+
*
|
|
8
|
+
* Phases:
|
|
9
|
+
* 1. Advisory (days 0-30) — high+critical only, no fail, baseline created
|
|
10
|
+
* 2. Selective (days 30-60) — medium+, fail on critical, auto-fix enabled
|
|
11
|
+
* 3. Enforcing (days 60-90) — all severities, fail on findings, score gate
|
|
12
|
+
* 4. Full trust (day 90+) — strict preset, full gating, baseline removed
|
|
13
|
+
*/
|
|
14
|
+
import type { JudgesConfig } from "../types.js";
|
|
15
|
+
export interface TrustPhase {
|
|
16
|
+
/** Phase number (1-4) */
|
|
17
|
+
phase: number;
|
|
18
|
+
/** Human-readable name */
|
|
19
|
+
name: string;
|
|
20
|
+
/** Day range description */
|
|
21
|
+
days: string;
|
|
22
|
+
/** What this phase enables */
|
|
23
|
+
description: string;
|
|
24
|
+
/** The generated .judgesrc config */
|
|
25
|
+
config: JudgesConfig;
|
|
26
|
+
/** CI workflow snippet (optional) */
|
|
27
|
+
ciTip: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function runTrustRamp(argv: string[]): void;
|
|
30
|
+
//# sourceMappingURL=trust-ramp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-ramp.d.ts","sourceRoot":"","sources":["../../src/commands/trust-ramp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,aAAa,CAAC;AAI1D,MAAM,WAAW,UAAU;IACzB,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,MAAM,EAAE,YAAY,CAAC;IACrB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AA2HD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+BjD"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `judges trust-ramp` — Generate a graduated trust configuration.
|
|
3
|
+
*
|
|
4
|
+
* Produces a phased .judgesrc progression that starts with advisory-only
|
|
5
|
+
* (no CI gating) and ramps up to full enforcement over 30/60/90 days.
|
|
6
|
+
* All data stays local — phases are encoded as config files you commit.
|
|
7
|
+
*
|
|
8
|
+
* Phases:
|
|
9
|
+
* 1. Advisory (days 0-30) — high+critical only, no fail, baseline created
|
|
10
|
+
* 2. Selective (days 30-60) — medium+, fail on critical, auto-fix enabled
|
|
11
|
+
* 3. Enforcing (days 60-90) — all severities, fail on findings, score gate
|
|
12
|
+
* 4. Full trust (day 90+) — strict preset, full gating, baseline removed
|
|
13
|
+
*/
|
|
14
|
+
import { writeFileSync } from "fs";
|
|
15
|
+
import { join, resolve } from "path";
|
|
16
|
+
function buildPhases(basePreset) {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
phase: 1,
|
|
20
|
+
name: "Advisory",
|
|
21
|
+
days: "Days 0–30",
|
|
22
|
+
description: "Report only critical and high severity findings. No CI gating. " +
|
|
23
|
+
"Creates a baseline of existing issues so new introductions are visible.",
|
|
24
|
+
config: {
|
|
25
|
+
...(basePreset ? { preset: basePreset } : {}),
|
|
26
|
+
minSeverity: "high",
|
|
27
|
+
failOnFindings: false,
|
|
28
|
+
},
|
|
29
|
+
ciTip: "# Phase 1: advisory only — do NOT add --fail-on-findings to CI",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
phase: 2,
|
|
33
|
+
name: "Selective Enforcement",
|
|
34
|
+
days: "Days 30–60",
|
|
35
|
+
description: "Lower threshold to medium severity. Gate CI on critical findings only " +
|
|
36
|
+
"via failOnScoreBelow. Auto-fix suggestions become available.",
|
|
37
|
+
config: {
|
|
38
|
+
...(basePreset ? { preset: basePreset } : {}),
|
|
39
|
+
minSeverity: "medium",
|
|
40
|
+
failOnFindings: false,
|
|
41
|
+
failOnScoreBelow: 3,
|
|
42
|
+
},
|
|
43
|
+
ciTip: "# Phase 2: gate on score — blocks PRs scoring below 3/10",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
phase: 3,
|
|
47
|
+
name: "Enforcing",
|
|
48
|
+
days: "Days 60–90",
|
|
49
|
+
description: "Report all severities. Fail on any findings. Score gate raised to 6. " +
|
|
50
|
+
"Team should be comfortable with judges output by now.",
|
|
51
|
+
config: {
|
|
52
|
+
...(basePreset ? { preset: basePreset } : {}),
|
|
53
|
+
minSeverity: "low",
|
|
54
|
+
failOnFindings: true,
|
|
55
|
+
failOnScoreBelow: 6,
|
|
56
|
+
},
|
|
57
|
+
ciTip: "# Phase 3: enforcing — PR merges blocked on findings or low score",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
phase: 4,
|
|
61
|
+
name: "Full Trust",
|
|
62
|
+
days: "Day 90+",
|
|
63
|
+
description: "Strict mode with all judges and all severities. Full gating enabled. " +
|
|
64
|
+
"Remove the baseline file — all findings are real.",
|
|
65
|
+
config: {
|
|
66
|
+
preset: "strict",
|
|
67
|
+
failOnFindings: true,
|
|
68
|
+
failOnScoreBelow: 7,
|
|
69
|
+
},
|
|
70
|
+
ciTip: "# Phase 4: full trust — judges is your primary reviewer",
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
// ─── Output Formats ─────────────────────────────────────────────────────────
|
|
75
|
+
function formatPhasesText(phases) {
|
|
76
|
+
const lines = [
|
|
77
|
+
"╔══════════════════════════════════════════════════════════════╗",
|
|
78
|
+
"║ Judges — Graduated Trust Ramp Plan ║",
|
|
79
|
+
"╚══════════════════════════════════════════════════════════════╝",
|
|
80
|
+
"",
|
|
81
|
+
];
|
|
82
|
+
for (const p of phases) {
|
|
83
|
+
lines.push(`── Phase ${p.phase}: ${p.name} (${p.days}) ${"─".repeat(Math.max(0, 40 - p.name.length - p.days.length))}`);
|
|
84
|
+
lines.push(` ${p.description}`);
|
|
85
|
+
lines.push("");
|
|
86
|
+
lines.push(" .judgesrc:");
|
|
87
|
+
lines.push(` ${JSON.stringify(p.config, null, 2).replace(/\n/g, "\n ")}`);
|
|
88
|
+
lines.push("");
|
|
89
|
+
lines.push(` ${p.ciTip}`);
|
|
90
|
+
lines.push("");
|
|
91
|
+
}
|
|
92
|
+
lines.push("── Getting Started ──────────────────────────────────────────");
|
|
93
|
+
lines.push(" 1. Run: judges trust-ramp --emit phase-1");
|
|
94
|
+
lines.push(" 2. Commit the generated .judgesrc to your repo");
|
|
95
|
+
lines.push(" 3. When ready to advance, run: judges trust-ramp --emit phase-2");
|
|
96
|
+
lines.push(" 4. Repeat until full trust is achieved");
|
|
97
|
+
lines.push("");
|
|
98
|
+
return lines.join("\n");
|
|
99
|
+
}
|
|
100
|
+
function formatPhasesJson(phases) {
|
|
101
|
+
return JSON.stringify(phases.map((p) => ({
|
|
102
|
+
phase: p.phase,
|
|
103
|
+
name: p.name,
|
|
104
|
+
days: p.days,
|
|
105
|
+
description: p.description,
|
|
106
|
+
config: p.config,
|
|
107
|
+
})), null, 2);
|
|
108
|
+
}
|
|
109
|
+
// ─── Emit a Phase Config ─────────────────────────────────────────────────
|
|
110
|
+
function emitPhaseConfig(phase, targetDir) {
|
|
111
|
+
const configPath = join(targetDir, ".judgesrc");
|
|
112
|
+
const content = JSON.stringify(phase.config, null, 2);
|
|
113
|
+
writeFileSync(configPath, content + "\n", "utf-8");
|
|
114
|
+
return configPath;
|
|
115
|
+
}
|
|
116
|
+
// ─── CLI Entry ──────────────────────────────────────────────────────────────
|
|
117
|
+
export function runTrustRamp(argv) {
|
|
118
|
+
const args = parseArgs(argv);
|
|
119
|
+
const phases = buildPhases(args.preset);
|
|
120
|
+
if (args.emit) {
|
|
121
|
+
const match = /^phase-?(\d)$/i.exec(args.emit);
|
|
122
|
+
if (!match) {
|
|
123
|
+
console.error(`Error: --emit expects "phase-1" through "phase-4", got "${args.emit}"`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
const num = parseInt(match[1], 10);
|
|
127
|
+
const phase = phases.find((p) => p.phase === num);
|
|
128
|
+
if (!phase) {
|
|
129
|
+
console.error(`Error: no phase ${num}. Valid: 1-4`);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
const dir = resolve(args.dir || ".");
|
|
133
|
+
const path = emitPhaseConfig(phase, dir);
|
|
134
|
+
console.log(`✔ Phase ${num} (${phase.name}) config written to ${path}`);
|
|
135
|
+
console.log(` ${phase.ciTip}`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Default: show the plan
|
|
139
|
+
if (args.format === "json") {
|
|
140
|
+
console.log(formatPhasesJson(phases));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log(formatPhasesText(phases));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function parseArgs(argv) {
|
|
147
|
+
const result = { format: "text" };
|
|
148
|
+
for (let i = 0; i < argv.length; i++) {
|
|
149
|
+
const arg = argv[i];
|
|
150
|
+
if (arg === "--emit" && argv[i + 1]) {
|
|
151
|
+
result.emit = argv[++i];
|
|
152
|
+
}
|
|
153
|
+
else if (arg === "--preset" && argv[i + 1]) {
|
|
154
|
+
result.preset = argv[++i];
|
|
155
|
+
}
|
|
156
|
+
else if (arg === "--format" && argv[i + 1]) {
|
|
157
|
+
const fmt = argv[++i];
|
|
158
|
+
if (fmt === "json" || fmt === "text")
|
|
159
|
+
result.format = fmt;
|
|
160
|
+
}
|
|
161
|
+
else if (arg === "--dir" && argv[i + 1]) {
|
|
162
|
+
result.dir = argv[++i];
|
|
163
|
+
}
|
|
164
|
+
else if (arg === "--help" || arg === "-h") {
|
|
165
|
+
printHelp();
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
function printHelp() {
|
|
172
|
+
console.log(`
|
|
173
|
+
judges trust-ramp — Generate a graduated trust configuration
|
|
174
|
+
|
|
175
|
+
Usage:
|
|
176
|
+
judges trust-ramp Show the 4-phase ramp plan
|
|
177
|
+
judges trust-ramp --format json Output plan as JSON
|
|
178
|
+
judges trust-ramp --emit phase-1 Write Phase 1 .judgesrc to cwd
|
|
179
|
+
judges trust-ramp --emit phase-2 --dir . Write Phase 2 .judgesrc to dir
|
|
180
|
+
judges trust-ramp --preset security-only Base phases on a preset
|
|
181
|
+
|
|
182
|
+
Options:
|
|
183
|
+
--emit <phase> Emit a phase config: phase-1, phase-2, phase-3, phase-4
|
|
184
|
+
--preset <name> Base the ramp on a named preset (e.g. security-only)
|
|
185
|
+
--format <fmt> Output format: text (default), json
|
|
186
|
+
--dir <path> Target directory for --emit (default: cwd)
|
|
187
|
+
-h, --help Show this help
|
|
188
|
+
`);
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=trust-ramp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-ramp.js","sourceRoot":"","sources":["../../src/commands/trust-ramp.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ export declare function discoverCascadingConfigs(startDir: string, rootDir?: str
|
|
|
18
18
|
* concatenated (union). Scalars (minSeverity, maxFiles, preset, failOnFindings,
|
|
19
19
|
* baseline, format) use the leaf value.
|
|
20
20
|
* ruleOverrides are deep-merged.
|
|
21
|
+
*
|
|
22
|
+
* Org-level policy enforcement:
|
|
23
|
+
* - `lockedRules`: locked rules cannot be added to `disabledRules`
|
|
24
|
+
* - `lockedJudges`: locked judges cannot be added to `disabledJudges`
|
|
25
|
+
* - `lockedMinSeverity`: child configs cannot set a more lenient minSeverity
|
|
21
26
|
*/
|
|
22
27
|
export declare function mergeConfigs(...configs: JudgesConfig[]): JudgesConfig;
|
|
23
28
|
/**
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAY,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAY,eAAe,EAAE,MAAM,YAAY,CAAC;AAe1E;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CA0RzD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,YAAY,CAE5C;AAOD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAkC3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,GAAG,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,CAoFrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAC5B,YAAY,CAiCd;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAIpF;AAID;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,eAAe,CAY3E;AAWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,gBAAgB,CACpC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAoB,GAC9C,OAAO,CAAC,eAAe,EAAE,CAAC,CAyD5B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAgBvE;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAwB1F;AAsCD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CASzF"}
|
package/dist/config.js
CHANGED
|
@@ -9,6 +9,11 @@ import { ConfigError } from "./errors.js";
|
|
|
9
9
|
import { normalizeLanguage } from "./language-patterns.js";
|
|
10
10
|
const VALID_SEVERITIES = new Set(["critical", "high", "medium", "low", "info"]);
|
|
11
11
|
const VALID_FORMATS = new Set(["text", "json", "sarif", "markdown", "html", "junit", "codeclimate"]);
|
|
12
|
+
/** Numeric rank for severity comparison (lower = stricter). */
|
|
13
|
+
const SEVERITY_RANK = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
14
|
+
function severityRank(s) {
|
|
15
|
+
return SEVERITY_RANK[s] ?? 4;
|
|
16
|
+
}
|
|
12
17
|
/**
|
|
13
18
|
* Parse a JSON string into a JudgesConfig, with validation.
|
|
14
19
|
*/
|
|
@@ -243,6 +248,27 @@ export function parseConfig(jsonStr) {
|
|
|
243
248
|
}
|
|
244
249
|
config.customRules = obj.customRules;
|
|
245
250
|
}
|
|
251
|
+
// lockedRules
|
|
252
|
+
if (obj.lockedRules !== undefined) {
|
|
253
|
+
if (!Array.isArray(obj.lockedRules) || !obj.lockedRules.every((r) => typeof r === "string")) {
|
|
254
|
+
throw new ConfigError('Invalid .judgesrc: "lockedRules" must be an array of strings');
|
|
255
|
+
}
|
|
256
|
+
config.lockedRules = obj.lockedRules;
|
|
257
|
+
}
|
|
258
|
+
// lockedJudges
|
|
259
|
+
if (obj.lockedJudges !== undefined) {
|
|
260
|
+
if (!Array.isArray(obj.lockedJudges) || !obj.lockedJudges.every((r) => typeof r === "string")) {
|
|
261
|
+
throw new ConfigError('Invalid .judgesrc: "lockedJudges" must be an array of strings');
|
|
262
|
+
}
|
|
263
|
+
config.lockedJudges = obj.lockedJudges;
|
|
264
|
+
}
|
|
265
|
+
// lockedMinSeverity
|
|
266
|
+
if (obj.lockedMinSeverity !== undefined) {
|
|
267
|
+
if (typeof obj.lockedMinSeverity !== "string" || !VALID_SEVERITIES.has(obj.lockedMinSeverity)) {
|
|
268
|
+
throw new ConfigError('Invalid .judgesrc: "lockedMinSeverity" must be one of critical, high, medium, low, info');
|
|
269
|
+
}
|
|
270
|
+
config.lockedMinSeverity = obj.lockedMinSeverity;
|
|
271
|
+
}
|
|
246
272
|
return config;
|
|
247
273
|
}
|
|
248
274
|
/**
|
|
@@ -298,10 +324,28 @@ export function discoverCascadingConfigs(startDir, rootDir) {
|
|
|
298
324
|
* concatenated (union). Scalars (minSeverity, maxFiles, preset, failOnFindings,
|
|
299
325
|
* baseline, format) use the leaf value.
|
|
300
326
|
* ruleOverrides are deep-merged.
|
|
327
|
+
*
|
|
328
|
+
* Org-level policy enforcement:
|
|
329
|
+
* - `lockedRules`: locked rules cannot be added to `disabledRules`
|
|
330
|
+
* - `lockedJudges`: locked judges cannot be added to `disabledJudges`
|
|
331
|
+
* - `lockedMinSeverity`: child configs cannot set a more lenient minSeverity
|
|
301
332
|
*/
|
|
302
333
|
export function mergeConfigs(...configs) {
|
|
303
334
|
const merged = {};
|
|
304
335
|
for (const cfg of configs) {
|
|
336
|
+
// Accumulate locked fields (union across all configs — once locked, always locked)
|
|
337
|
+
if (cfg.lockedRules) {
|
|
338
|
+
merged.lockedRules = [...new Set([...(merged.lockedRules ?? []), ...cfg.lockedRules])];
|
|
339
|
+
}
|
|
340
|
+
if (cfg.lockedJudges) {
|
|
341
|
+
merged.lockedJudges = [...new Set([...(merged.lockedJudges ?? []), ...cfg.lockedJudges])];
|
|
342
|
+
}
|
|
343
|
+
if (cfg.lockedMinSeverity !== undefined) {
|
|
344
|
+
// Keep the strictest lock (lowest severity index = strictest)
|
|
345
|
+
if (!merged.lockedMinSeverity || severityRank(cfg.lockedMinSeverity) < severityRank(merged.lockedMinSeverity)) {
|
|
346
|
+
merged.lockedMinSeverity = cfg.lockedMinSeverity;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
305
349
|
// Concatenate arrays (deduplicated)
|
|
306
350
|
if (cfg.disabledRules) {
|
|
307
351
|
merged.disabledRules = [...new Set([...(merged.disabledRules ?? []), ...cfg.disabledRules])];
|
|
@@ -349,6 +393,27 @@ export function mergeConfigs(...configs) {
|
|
|
349
393
|
merged.overrides = [...(merged.overrides ?? []), ...cfg.overrides];
|
|
350
394
|
}
|
|
351
395
|
}
|
|
396
|
+
// ── Enforce org-level locked policies ──────────────────────────────
|
|
397
|
+
// Remove locked rules from disabledRules (they must stay enabled)
|
|
398
|
+
if (merged.lockedRules?.length && merged.disabledRules?.length) {
|
|
399
|
+
const locked = new Set(merged.lockedRules);
|
|
400
|
+
merged.disabledRules = merged.disabledRules.filter((r) => !locked.has(r));
|
|
401
|
+
if (merged.disabledRules.length === 0)
|
|
402
|
+
delete merged.disabledRules;
|
|
403
|
+
}
|
|
404
|
+
// Remove locked judges from disabledJudges (they must stay enabled)
|
|
405
|
+
if (merged.lockedJudges?.length && merged.disabledJudges?.length) {
|
|
406
|
+
const locked = new Set(merged.lockedJudges);
|
|
407
|
+
merged.disabledJudges = merged.disabledJudges.filter((j) => !locked.has(j));
|
|
408
|
+
if (merged.disabledJudges.length === 0)
|
|
409
|
+
delete merged.disabledJudges;
|
|
410
|
+
}
|
|
411
|
+
// Enforce minSeverity floor — child cannot be more lenient than the lock
|
|
412
|
+
if (merged.lockedMinSeverity && merged.minSeverity) {
|
|
413
|
+
if (severityRank(merged.minSeverity) > severityRank(merged.lockedMinSeverity)) {
|
|
414
|
+
merged.minSeverity = merged.lockedMinSeverity;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
352
417
|
return merged;
|
|
353
418
|
}
|
|
354
419
|
/**
|