@kevinrabun/judges 2.2.0 → 3.0.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/README.md +203 -20
- package/dist/api.d.ts +40 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +56 -0
- package/dist/api.js.map +1 -0
- package/dist/ast/cross-file-taint.d.ts +43 -0
- package/dist/ast/cross-file-taint.d.ts.map +1 -0
- package/dist/ast/cross-file-taint.js +713 -0
- package/dist/ast/cross-file-taint.js.map +1 -0
- package/dist/ast/index.d.ts +4 -0
- package/dist/ast/index.d.ts.map +1 -1
- package/dist/ast/index.js +5 -0
- package/dist/ast/index.js.map +1 -1
- package/dist/ast/structural-parser.d.ts.map +1 -1
- package/dist/ast/structural-parser.js +66 -11
- package/dist/ast/structural-parser.js.map +1 -1
- package/dist/ast/taint-tracker.d.ts +35 -0
- package/dist/ast/taint-tracker.d.ts.map +1 -0
- package/dist/ast/taint-tracker.js +518 -0
- package/dist/ast/taint-tracker.js.map +1 -0
- package/dist/ast/types.d.ts +2 -0
- package/dist/ast/types.d.ts.map +1 -1
- package/dist/ast/typescript-ast.d.ts.map +1 -1
- package/dist/ast/typescript-ast.js +25 -5
- package/dist/ast/typescript-ast.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -9
- package/dist/config.js.map +1 -1
- package/dist/dedup.d.ts +19 -0
- package/dist/dedup.d.ts.map +1 -0
- package/dist/dedup.js +222 -0
- package/dist/dedup.js.map +1 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/evaluators/accessibility.d.ts +1 -1
- package/dist/evaluators/accessibility.d.ts.map +1 -1
- package/dist/evaluators/accessibility.js +45 -7
- package/dist/evaluators/accessibility.js.map +1 -1
- package/dist/evaluators/agent-instructions.d.ts +1 -1
- package/dist/evaluators/agent-instructions.d.ts.map +1 -1
- package/dist/evaluators/agent-instructions.js +60 -2
- package/dist/evaluators/agent-instructions.js.map +1 -1
- package/dist/evaluators/ai-code-safety.d.ts +9 -0
- package/dist/evaluators/ai-code-safety.d.ts.map +1 -0
- package/dist/evaluators/ai-code-safety.js +507 -0
- package/dist/evaluators/ai-code-safety.js.map +1 -0
- package/dist/evaluators/api-design.d.ts +1 -1
- package/dist/evaluators/api-design.d.ts.map +1 -1
- package/dist/evaluators/api-design.js +33 -17
- package/dist/evaluators/api-design.js.map +1 -1
- package/dist/evaluators/app-builder.d.ts +34 -0
- package/dist/evaluators/app-builder.d.ts.map +1 -0
- package/dist/evaluators/app-builder.js +156 -0
- package/dist/evaluators/app-builder.js.map +1 -0
- package/dist/evaluators/authentication.d.ts +1 -1
- package/dist/evaluators/authentication.d.ts.map +1 -1
- package/dist/evaluators/authentication.js +69 -75
- package/dist/evaluators/authentication.js.map +1 -1
- package/dist/evaluators/backwards-compatibility.d.ts +1 -1
- package/dist/evaluators/backwards-compatibility.d.ts.map +1 -1
- package/dist/evaluators/backwards-compatibility.js +25 -3
- package/dist/evaluators/backwards-compatibility.js.map +1 -1
- package/dist/evaluators/caching.d.ts +1 -1
- package/dist/evaluators/caching.d.ts.map +1 -1
- package/dist/evaluators/caching.js +25 -4
- package/dist/evaluators/caching.js.map +1 -1
- package/dist/evaluators/ci-cd.d.ts +1 -1
- package/dist/evaluators/ci-cd.d.ts.map +1 -1
- package/dist/evaluators/ci-cd.js +34 -12
- package/dist/evaluators/ci-cd.js.map +1 -1
- package/dist/evaluators/cloud-readiness.d.ts +1 -1
- package/dist/evaluators/cloud-readiness.d.ts.map +1 -1
- package/dist/evaluators/cloud-readiness.js +26 -0
- package/dist/evaluators/cloud-readiness.js.map +1 -1
- package/dist/evaluators/code-structure.d.ts +1 -1
- package/dist/evaluators/code-structure.d.ts.map +1 -1
- package/dist/evaluators/code-structure.js +19 -6
- package/dist/evaluators/code-structure.js.map +1 -1
- package/dist/evaluators/compliance.d.ts +1 -1
- package/dist/evaluators/compliance.d.ts.map +1 -1
- package/dist/evaluators/compliance.js +48 -10
- package/dist/evaluators/compliance.js.map +1 -1
- package/dist/evaluators/concurrency.d.ts +1 -1
- package/dist/evaluators/concurrency.d.ts.map +1 -1
- package/dist/evaluators/concurrency.js +29 -4
- package/dist/evaluators/concurrency.js.map +1 -1
- package/dist/evaluators/configuration-management.d.ts +1 -1
- package/dist/evaluators/configuration-management.d.ts.map +1 -1
- package/dist/evaluators/configuration-management.js +57 -13
- package/dist/evaluators/configuration-management.js.map +1 -1
- package/dist/evaluators/cost-effectiveness.d.ts +1 -1
- package/dist/evaluators/cost-effectiveness.d.ts.map +1 -1
- package/dist/evaluators/cost-effectiveness.js +27 -3
- package/dist/evaluators/cost-effectiveness.js.map +1 -1
- package/dist/evaluators/cybersecurity.d.ts +1 -1
- package/dist/evaluators/cybersecurity.d.ts.map +1 -1
- package/dist/evaluators/cybersecurity.js +190 -1
- package/dist/evaluators/cybersecurity.js.map +1 -1
- package/dist/evaluators/data-security.d.ts +1 -1
- package/dist/evaluators/data-security.d.ts.map +1 -1
- package/dist/evaluators/data-security.js +114 -66
- package/dist/evaluators/data-security.js.map +1 -1
- package/dist/evaluators/data-sovereignty.d.ts +1 -1
- package/dist/evaluators/data-sovereignty.d.ts.map +1 -1
- package/dist/evaluators/data-sovereignty.js +89 -2
- package/dist/evaluators/data-sovereignty.js.map +1 -1
- package/dist/evaluators/database.d.ts +1 -1
- package/dist/evaluators/database.d.ts.map +1 -1
- package/dist/evaluators/database.js +35 -9
- package/dist/evaluators/database.js.map +1 -1
- package/dist/evaluators/dependencies.d.ts +6 -0
- package/dist/evaluators/dependencies.d.ts.map +1 -0
- package/dist/evaluators/dependencies.js +204 -0
- package/dist/evaluators/dependencies.js.map +1 -0
- package/dist/evaluators/dependency-health.d.ts +1 -1
- package/dist/evaluators/dependency-health.d.ts.map +1 -1
- package/dist/evaluators/dependency-health.js +265 -11
- package/dist/evaluators/dependency-health.js.map +1 -1
- package/dist/evaluators/documentation.d.ts +1 -1
- package/dist/evaluators/documentation.d.ts.map +1 -1
- package/dist/evaluators/documentation.js +25 -2
- package/dist/evaluators/documentation.js.map +1 -1
- package/dist/evaluators/error-handling.d.ts +1 -1
- package/dist/evaluators/error-handling.d.ts.map +1 -1
- package/dist/evaluators/error-handling.js +89 -24
- package/dist/evaluators/error-handling.js.map +1 -1
- package/dist/evaluators/ethics-bias.d.ts +1 -1
- package/dist/evaluators/ethics-bias.d.ts.map +1 -1
- package/dist/evaluators/ethics-bias.js +30 -5
- package/dist/evaluators/ethics-bias.js.map +1 -1
- package/dist/evaluators/framework-safety.d.ts +13 -0
- package/dist/evaluators/framework-safety.d.ts.map +1 -0
- package/dist/evaluators/framework-safety.js +424 -0
- package/dist/evaluators/framework-safety.js.map +1 -0
- package/dist/evaluators/index.d.ts +21 -24
- package/dist/evaluators/index.d.ts.map +1 -1
- package/dist/evaluators/index.js +297 -677
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/internationalization.d.ts +1 -1
- package/dist/evaluators/internationalization.d.ts.map +1 -1
- package/dist/evaluators/internationalization.js +55 -4
- package/dist/evaluators/internationalization.js.map +1 -1
- package/dist/evaluators/logging-privacy.d.ts +1 -1
- package/dist/evaluators/logging-privacy.d.ts.map +1 -1
- package/dist/evaluators/logging-privacy.js +68 -30
- package/dist/evaluators/logging-privacy.js.map +1 -1
- package/dist/evaluators/maintainability.d.ts +1 -1
- package/dist/evaluators/maintainability.d.ts.map +1 -1
- package/dist/evaluators/maintainability.js +53 -26
- package/dist/evaluators/maintainability.js.map +1 -1
- package/dist/evaluators/observability.d.ts +1 -1
- package/dist/evaluators/observability.d.ts.map +1 -1
- package/dist/evaluators/observability.js +22 -1
- package/dist/evaluators/observability.js.map +1 -1
- package/dist/evaluators/performance.d.ts +1 -1
- package/dist/evaluators/performance.d.ts.map +1 -1
- package/dist/evaluators/performance.js +209 -2
- package/dist/evaluators/performance.js.map +1 -1
- package/dist/evaluators/portability.d.ts +1 -1
- package/dist/evaluators/portability.d.ts.map +1 -1
- package/dist/evaluators/portability.js +24 -1
- package/dist/evaluators/portability.js.map +1 -1
- package/dist/evaluators/project.d.ts +16 -0
- package/dist/evaluators/project.d.ts.map +1 -0
- package/dist/evaluators/project.js +353 -0
- package/dist/evaluators/project.js.map +1 -0
- package/dist/evaluators/rate-limiting.d.ts +1 -1
- package/dist/evaluators/rate-limiting.d.ts.map +1 -1
- package/dist/evaluators/rate-limiting.js +33 -10
- package/dist/evaluators/rate-limiting.js.map +1 -1
- package/dist/evaluators/reliability.d.ts +1 -1
- package/dist/evaluators/reliability.d.ts.map +1 -1
- package/dist/evaluators/reliability.js +20 -0
- package/dist/evaluators/reliability.js.map +1 -1
- package/dist/evaluators/scalability.d.ts +1 -1
- package/dist/evaluators/scalability.d.ts.map +1 -1
- package/dist/evaluators/scalability.js +27 -1
- package/dist/evaluators/scalability.js.map +1 -1
- package/dist/evaluators/shared.d.ts +24 -2
- package/dist/evaluators/shared.d.ts.map +1 -1
- package/dist/evaluators/shared.js +194 -26
- package/dist/evaluators/shared.js.map +1 -1
- package/dist/evaluators/software-practices.d.ts +1 -1
- package/dist/evaluators/software-practices.d.ts.map +1 -1
- package/dist/evaluators/software-practices.js +50 -3
- package/dist/evaluators/software-practices.js.map +1 -1
- package/dist/evaluators/testing.d.ts +1 -1
- package/dist/evaluators/testing.d.ts.map +1 -1
- package/dist/evaluators/testing.js +32 -4
- package/dist/evaluators/testing.js.map +1 -1
- package/dist/evaluators/ux.d.ts +1 -1
- package/dist/evaluators/ux.d.ts.map +1 -1
- package/dist/evaluators/ux.js +24 -0
- package/dist/evaluators/ux.js.map +1 -1
- package/dist/evaluators/v2.d.ts +1 -1
- package/dist/evaluators/v2.d.ts.map +1 -1
- package/dist/evaluators/v2.js +15 -35
- package/dist/evaluators/v2.js.map +1 -1
- package/dist/formatters/sarif.d.ts +75 -0
- package/dist/formatters/sarif.d.ts.map +1 -0
- package/dist/formatters/sarif.js +93 -0
- package/dist/formatters/sarif.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -782
- package/dist/index.js.map +1 -1
- package/dist/judges/accessibility.d.ts +1 -1
- package/dist/judges/accessibility.d.ts.map +1 -1
- package/dist/judges/agent-instructions.d.ts +1 -1
- package/dist/judges/agent-instructions.d.ts.map +1 -1
- package/dist/judges/ai-code-safety.d.ts +3 -0
- package/dist/judges/ai-code-safety.d.ts.map +1 -0
- package/dist/judges/ai-code-safety.js +45 -0
- package/dist/judges/ai-code-safety.js.map +1 -0
- package/dist/judges/api-design.d.ts +1 -1
- package/dist/judges/api-design.d.ts.map +1 -1
- package/dist/judges/authentication.d.ts +1 -1
- package/dist/judges/authentication.d.ts.map +1 -1
- package/dist/judges/backwards-compatibility.d.ts +1 -1
- package/dist/judges/backwards-compatibility.d.ts.map +1 -1
- package/dist/judges/caching.d.ts +1 -1
- package/dist/judges/caching.d.ts.map +1 -1
- package/dist/judges/ci-cd.d.ts +1 -1
- package/dist/judges/ci-cd.d.ts.map +1 -1
- package/dist/judges/cloud-readiness.d.ts +1 -1
- package/dist/judges/cloud-readiness.d.ts.map +1 -1
- package/dist/judges/code-structure.d.ts +1 -1
- package/dist/judges/code-structure.d.ts.map +1 -1
- package/dist/judges/compliance.d.ts +1 -1
- package/dist/judges/compliance.d.ts.map +1 -1
- package/dist/judges/concurrency.d.ts +1 -1
- package/dist/judges/concurrency.d.ts.map +1 -1
- package/dist/judges/configuration-management.d.ts +1 -1
- package/dist/judges/configuration-management.d.ts.map +1 -1
- package/dist/judges/cost-effectiveness.d.ts +1 -1
- package/dist/judges/cost-effectiveness.d.ts.map +1 -1
- package/dist/judges/cybersecurity.d.ts +1 -1
- package/dist/judges/cybersecurity.d.ts.map +1 -1
- package/dist/judges/data-security.d.ts +1 -1
- package/dist/judges/data-security.d.ts.map +1 -1
- package/dist/judges/data-sovereignty.d.ts +1 -1
- package/dist/judges/data-sovereignty.d.ts.map +1 -1
- package/dist/judges/database.d.ts +1 -1
- package/dist/judges/database.d.ts.map +1 -1
- package/dist/judges/dependency-health.d.ts +1 -1
- package/dist/judges/dependency-health.d.ts.map +1 -1
- package/dist/judges/documentation.d.ts +1 -1
- package/dist/judges/documentation.d.ts.map +1 -1
- package/dist/judges/error-handling.d.ts +1 -1
- package/dist/judges/error-handling.d.ts.map +1 -1
- package/dist/judges/ethics-bias.d.ts +1 -1
- package/dist/judges/ethics-bias.d.ts.map +1 -1
- package/dist/judges/framework-safety.d.ts +3 -0
- package/dist/judges/framework-safety.d.ts.map +1 -0
- package/dist/judges/framework-safety.js +25 -0
- package/dist/judges/framework-safety.js.map +1 -0
- package/dist/judges/index.d.ts +1 -1
- package/dist/judges/index.d.ts.map +1 -1
- package/dist/judges/index.js +76 -0
- package/dist/judges/index.js.map +1 -1
- package/dist/judges/internationalization.d.ts +1 -1
- package/dist/judges/internationalization.d.ts.map +1 -1
- package/dist/judges/logging-privacy.d.ts +1 -1
- package/dist/judges/logging-privacy.d.ts.map +1 -1
- package/dist/judges/maintainability.d.ts +1 -1
- package/dist/judges/maintainability.d.ts.map +1 -1
- package/dist/judges/observability.d.ts +1 -1
- package/dist/judges/observability.d.ts.map +1 -1
- package/dist/judges/performance.d.ts +1 -1
- package/dist/judges/performance.d.ts.map +1 -1
- package/dist/judges/portability.d.ts +1 -1
- package/dist/judges/portability.d.ts.map +1 -1
- package/dist/judges/rate-limiting.d.ts +1 -1
- package/dist/judges/rate-limiting.d.ts.map +1 -1
- package/dist/judges/reliability.d.ts +1 -1
- package/dist/judges/reliability.d.ts.map +1 -1
- package/dist/judges/scalability.d.ts +1 -1
- package/dist/judges/scalability.d.ts.map +1 -1
- package/dist/judges/software-practices.d.ts +1 -1
- package/dist/judges/software-practices.d.ts.map +1 -1
- package/dist/judges/testing.d.ts +1 -1
- package/dist/judges/testing.d.ts.map +1 -1
- package/dist/judges/ux.d.ts +1 -1
- package/dist/judges/ux.d.ts.map +1 -1
- package/dist/language-patterns.d.ts +37 -0
- package/dist/language-patterns.d.ts.map +1 -1
- package/dist/language-patterns.js +59 -4
- package/dist/language-patterns.js.map +1 -1
- package/dist/patches/index.d.ts +10 -0
- package/dist/patches/index.d.ts.map +1 -0
- package/dist/patches/index.js +533 -0
- package/dist/patches/index.js.map +1 -0
- package/dist/reports/public-repo-report.d.ts +3 -1
- package/dist/reports/public-repo-report.d.ts.map +1 -1
- package/dist/reports/public-repo-report.js +41 -0
- package/dist/reports/public-repo-report.js.map +1 -1
- package/dist/scoring.d.ts +18 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +178 -0
- package/dist/scoring.js.map +1 -0
- package/dist/tools/deep-review.d.ts +4 -0
- package/dist/tools/deep-review.d.ts.map +1 -0
- package/dist/tools/deep-review.js +56 -0
- package/dist/tools/deep-review.js.map +1 -0
- package/dist/tools/prompts.d.ts +8 -0
- package/dist/tools/prompts.d.ts.map +1 -0
- package/dist/tools/prompts.js +66 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/register-evaluation.d.ts +7 -0
- package/dist/tools/register-evaluation.d.ts.map +1 -0
- package/dist/tools/register-evaluation.js +303 -0
- package/dist/tools/register-evaluation.js.map +1 -0
- package/dist/tools/register-workflow.d.ts +7 -0
- package/dist/tools/register-workflow.d.ts.map +1 -0
- package/dist/tools/register-workflow.js +395 -0
- package/dist/tools/register-workflow.js.map +1 -0
- package/dist/tools/register.d.ts +7 -0
- package/dist/tools/register.d.ts.map +1 -0
- package/dist/tools/register.js +14 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/tools/schemas.d.ts +26 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +42 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/types.d.ts +53 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +42 -3
- package/server.json +51 -3
|
@@ -17,6 +17,8 @@ export function analyzeReliability(code, language) {
|
|
|
17
17
|
lineNumbers: emptyCatchLines,
|
|
18
18
|
recommendation: "At minimum, log the error. Ideally, handle it appropriately, rethrow, or propagate to a global error handler.",
|
|
19
19
|
reference: "Error Handling Best Practices",
|
|
20
|
+
suggestedFix: "Log in catch blocks: catch (err) { logger.error({ err }, 'Operation failed'); throw err; } — never leave catch blocks empty.",
|
|
21
|
+
confidence: 0.9,
|
|
20
22
|
});
|
|
21
23
|
}
|
|
22
24
|
// Detect missing timeout on network calls (multi-language)
|
|
@@ -38,6 +40,8 @@ export function analyzeReliability(code, language) {
|
|
|
38
40
|
lineNumbers: noTimeoutLines,
|
|
39
41
|
recommendation: "Set explicit timeouts on all network calls. Use AbortController with setTimeout for fetch, or timeout options for HTTP clients.",
|
|
40
42
|
reference: "Resilience Patterns: Timeout",
|
|
43
|
+
suggestedFix: "Add timeout: const controller = new AbortController(); setTimeout(() => controller.abort(), 5000); fetch(url, { signal: controller.signal });",
|
|
44
|
+
confidence: 0.8,
|
|
41
45
|
});
|
|
42
46
|
}
|
|
43
47
|
// Detect missing retry logic for transient failures (multi-language)
|
|
@@ -52,6 +56,8 @@ export function analyzeReliability(code, language) {
|
|
|
52
56
|
lineNumbers: externalCallLines.slice(0, 5),
|
|
53
57
|
recommendation: "Implement retry with exponential backoff for transient failures. Use libraries like p-retry, tenacity, Polly, Resilience4j, or backoff crate.",
|
|
54
58
|
reference: "Resilience Patterns: Retry with Backoff",
|
|
59
|
+
suggestedFix: "Add retry: import pRetry from 'p-retry'; const result = await pRetry(() => fetchData(), { retries: 3, minTimeout: 1000 });",
|
|
60
|
+
confidence: 0.7,
|
|
55
61
|
});
|
|
56
62
|
}
|
|
57
63
|
// Detect single point of failure patterns
|
|
@@ -70,6 +76,8 @@ export function analyzeReliability(code, language) {
|
|
|
70
76
|
lineNumbers: singleConnLines,
|
|
71
77
|
recommendation: "Use connection pooling to improve resilience and throughput. Most database drivers support connection pools.",
|
|
72
78
|
reference: "Database Connection Management",
|
|
79
|
+
suggestedFix: "Replace single connection with pool: const pool = new Pool({ max: 10, idleTimeoutMillis: 30000 }); const client = await pool.connect(); try { ... } finally { client.release(); }",
|
|
80
|
+
confidence: 0.8,
|
|
73
81
|
});
|
|
74
82
|
}
|
|
75
83
|
// Detect unchecked null/undefined access
|
|
@@ -88,6 +96,8 @@ export function analyzeReliability(code, language) {
|
|
|
88
96
|
lineNumbers: unsafeAccessLines.slice(0, 5),
|
|
89
97
|
recommendation: "Use optional chaining (?.) or explicit null checks for deeply nested property access.",
|
|
90
98
|
reference: "Defensive Programming Practices",
|
|
99
|
+
suggestedFix: "Use optional chaining: const value = obj?.nested?.deep?.prop ?? defaultValue; — prevents TypeError on null/undefined intermediaries.",
|
|
100
|
+
confidence: 0.75,
|
|
91
101
|
});
|
|
92
102
|
}
|
|
93
103
|
// Detect process.exit / panic / System.exit (multi-language)
|
|
@@ -101,6 +111,8 @@ export function analyzeReliability(code, language) {
|
|
|
101
111
|
lineNumbers: processExitLines,
|
|
102
112
|
recommendation: "Throw errors or use graceful shutdown patterns instead. Let the process exit naturally after cleanup. Reserve panics for truly unrecoverable situations.",
|
|
103
113
|
reference: "Graceful Shutdown Patterns",
|
|
114
|
+
suggestedFix: "Replace process.exit() with graceful shutdown: process.on('SIGTERM', async () => { await server.close(); await db.disconnect(); });",
|
|
115
|
+
confidence: 0.9,
|
|
104
116
|
});
|
|
105
117
|
}
|
|
106
118
|
// Circuit breaker pattern missing
|
|
@@ -114,6 +126,8 @@ export function analyzeReliability(code, language) {
|
|
|
114
126
|
description: "Multiple external calls without circuit breaker protection. A failing dependency can cause cascading failure across your system.",
|
|
115
127
|
recommendation: "Implement the circuit breaker pattern (opossum, cockatiel, Polly) to fail fast when external dependencies are unhealthy.",
|
|
116
128
|
reference: "Resilience Patterns: Circuit Breaker (Martin Fowler)",
|
|
129
|
+
suggestedFix: "Add circuit breaker: import CircuitBreaker from 'opossum'; const breaker = new CircuitBreaker(fetchData, { timeout: 3000, errorThresholdPercentage: 50 }); await breaker.fire();",
|
|
130
|
+
confidence: 0.7,
|
|
117
131
|
});
|
|
118
132
|
}
|
|
119
133
|
// Missing fallback / degraded mode
|
|
@@ -135,6 +149,8 @@ export function analyzeReliability(code, language) {
|
|
|
135
149
|
lineNumbers: criticalCallLines,
|
|
136
150
|
recommendation: "Provide fallback behavior: cached responses, default values, or gracefully degraded features when dependencies fail.",
|
|
137
151
|
reference: "Resilience Patterns: Fallback / Graceful Degradation",
|
|
152
|
+
suggestedFix: "Add fallback: try { data = await fetchFromApi(); } catch { data = await cache.get(key) ?? DEFAULT_VALUE; logger.warn('Using fallback data'); }",
|
|
153
|
+
confidence: 0.8,
|
|
138
154
|
});
|
|
139
155
|
}
|
|
140
156
|
// Missing idempotency for write operations
|
|
@@ -154,6 +170,8 @@ export function analyzeReliability(code, language) {
|
|
|
154
170
|
lineNumbers: writeEndpointLines.slice(0, 3),
|
|
155
171
|
recommendation: "Accept an idempotency key header (Idempotency-Key) and use it to deduplicate write operations.",
|
|
156
172
|
reference: "API Idempotency / Stripe Idempotency Pattern",
|
|
173
|
+
suggestedFix: "Add idempotency: const key = req.headers['idempotency-key']; if (key && await cache.has(key)) return res.json(await cache.get(key)); // process then cache result.",
|
|
174
|
+
confidence: 0.7,
|
|
157
175
|
});
|
|
158
176
|
}
|
|
159
177
|
// Panic/fatal in Go or System.exit in Java (already covered above, remove duplicate)
|
|
@@ -178,6 +196,8 @@ export function analyzeReliability(code, language) {
|
|
|
178
196
|
lineNumbers: unhandledPromiseLines,
|
|
179
197
|
recommendation: "Always handle promise rejections with .catch() or try/catch around await. Set up global unhandledRejection handler as safety net.",
|
|
180
198
|
reference: "Node.js Unhandled Rejections",
|
|
199
|
+
suggestedFix: "Add rejection handling: new Promise((resolve, reject) => { ... }).catch(err => logger.error(err)); or use try/catch with await.",
|
|
200
|
+
confidence: 0.8,
|
|
181
201
|
});
|
|
182
202
|
}
|
|
183
203
|
return findings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reliability.js","sourceRoot":"","sources":["../../src/evaluators/reliability.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"reliability.js","sourceRoot":"","sources":["../../src/evaluators/reliability.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scalability.d.ts","sourceRoot":"","sources":["../../src/evaluators/scalability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"scalability.d.ts","sourceRoot":"","sources":["../../src/evaluators/scalability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CA2P5E"}
|
|
@@ -16,6 +16,8 @@ export function analyzeScalability(code, language) {
|
|
|
16
16
|
lineNumbers: globalStateLines,
|
|
17
17
|
recommendation: "Externalize state to a database, cache (Redis), or message queue. Use const/final/immutable for configuration. Each instance should be stateless.",
|
|
18
18
|
reference: "12-Factor App: Processes (Factor VI)",
|
|
19
|
+
suggestedFix: "Replace the top-level mutable variable with a call to an external store (e.g., `await redis.get(key)`) so each instance remains stateless.",
|
|
20
|
+
confidence: 0.9,
|
|
19
21
|
});
|
|
20
22
|
}
|
|
21
23
|
// In-memory session/store
|
|
@@ -30,10 +32,14 @@ export function analyzeScalability(code, language) {
|
|
|
30
32
|
lineNumbers: inMemLines,
|
|
31
33
|
recommendation: "Use a distributed store (Redis, Memcached, database) for session data, caches, and shared state.",
|
|
32
34
|
reference: "Distributed Systems Best Practices",
|
|
35
|
+
suggestedFix: "Swap the in-memory `Map`/object store for a Redis-backed store (e.g., `new RedisStore(...)`) so data is shared across instances.",
|
|
36
|
+
confidence: 0.85,
|
|
33
37
|
});
|
|
34
38
|
}
|
|
35
39
|
// Synchronous blocking in hot paths (multi-language)
|
|
36
|
-
|
|
40
|
+
// Require a word-char before "Sync(" so we match readFileSync(), writeSync(),
|
|
41
|
+
// etc., but not unrelated identifiers that happen to contain "Sync".
|
|
42
|
+
const blockingPattern = /\wSync\s*\(|\.sleep\s*\(|Thread\.sleep|time\.sleep|threading\.Event\(\)\.wait|Task\.Delay.*\.Wait\(\)|\.Result\b|std::thread::sleep|tokio::task::block_in_place/gi;
|
|
37
43
|
const blockingLines = getLineNumbers(code, blockingPattern);
|
|
38
44
|
if (blockingLines.length > 0) {
|
|
39
45
|
findings.push({
|
|
@@ -44,6 +50,8 @@ export function analyzeScalability(code, language) {
|
|
|
44
50
|
lineNumbers: blockingLines,
|
|
45
51
|
recommendation: "Use asynchronous alternatives (async/await, promises, non-blocking I/O). Move long-running work to background queues.",
|
|
46
52
|
reference: "Reactive & Non-Blocking Architecture Patterns",
|
|
53
|
+
suggestedFix: "Replace the synchronous call with its async counterpart (e.g., `fs.readFileSync` → `await fs.promises.readFile`) to avoid blocking the event loop.",
|
|
54
|
+
confidence: 0.9,
|
|
47
55
|
});
|
|
48
56
|
}
|
|
49
57
|
// No timeout on external calls (multi-language)
|
|
@@ -58,6 +66,8 @@ export function analyzeScalability(code, language) {
|
|
|
58
66
|
lineNumbers: fetchLines,
|
|
59
67
|
recommendation: "Set explicit timeouts on all external calls (e.g., 5-30 seconds). Implement circuit breakers (e.g., using libraries like cockatiel or opossum) for critical dependencies.",
|
|
60
68
|
reference: "Release It! — Stability Patterns",
|
|
69
|
+
suggestedFix: "Add a timeout option to the HTTP call (e.g., `fetch(url, { signal: AbortSignal.timeout(5000) })`) to prevent indefinite hangs.",
|
|
70
|
+
confidence: 0.7,
|
|
61
71
|
});
|
|
62
72
|
}
|
|
63
73
|
// Single-threaded heavy computation
|
|
@@ -75,6 +85,8 @@ export function analyzeScalability(code, language) {
|
|
|
75
85
|
lineNumbers: cpuOpsLines.length > 0 ? cpuOpsLines : undefined,
|
|
76
86
|
recommendation: "Offload CPU-intensive work to worker threads, a job queue (Bull, Celery), or a dedicated compute service. Use async variants of crypto operations (pbkdf2, scrypt). Consider WebAssembly for hot-path computation.",
|
|
77
87
|
reference: "Node.js Worker Threads / Job Queue Patterns",
|
|
88
|
+
suggestedFix: "Move the heavy computation into a worker thread or use the async variant (e.g., `crypto.pbkdf2` instead of `crypto.pbkdf2Sync`) to keep the main thread free.",
|
|
89
|
+
confidence: 0.8,
|
|
78
90
|
});
|
|
79
91
|
}
|
|
80
92
|
// No rate limiting detected
|
|
@@ -87,6 +99,8 @@ export function analyzeScalability(code, language) {
|
|
|
87
99
|
description: "No rate limiting or throttling mechanism is visible. Without rate limiting, the system is vulnerable to being overwhelmed by traffic spikes or abuse.",
|
|
88
100
|
recommendation: "Implement rate limiting at the API gateway or application level. Consider token bucket or sliding window algorithms. Use libraries like express-rate-limit or a cloud-native solution.",
|
|
89
101
|
reference: "API Security & Scalability Best Practices",
|
|
102
|
+
suggestedFix: "Add a rate-limiting middleware (e.g., `app.use(rateLimit({ windowMs: 60000, max: 100 }))`) to protect endpoints from traffic spikes.",
|
|
103
|
+
confidence: 0.7,
|
|
90
104
|
});
|
|
91
105
|
}
|
|
92
106
|
// File-based locking / local mutex
|
|
@@ -101,6 +115,8 @@ export function analyzeScalability(code, language) {
|
|
|
101
115
|
lineNumbers: fileLockLines,
|
|
102
116
|
recommendation: "Use distributed locks (Redis SETNX/Redlock, ZooKeeper, etcd) or database-level locking for cross-instance coordination.",
|
|
103
117
|
reference: "Distributed Locking Patterns",
|
|
118
|
+
suggestedFix: "Replace the local file/mutex lock with a distributed lock (e.g., Redlock via `await redlock.acquire([resource], ttl)`) for cross-instance safety.",
|
|
119
|
+
confidence: 0.9,
|
|
104
120
|
});
|
|
105
121
|
}
|
|
106
122
|
// Sticky session / session affinity assumptions
|
|
@@ -116,6 +132,8 @@ export function analyzeScalability(code, language) {
|
|
|
116
132
|
lineNumbers: stickySessionLines,
|
|
117
133
|
recommendation: "Use an external session store (Redis, DynamoDB, database) so any instance can serve any request. This enables zero-downtime deployments.",
|
|
118
134
|
reference: "Scalable Session Management",
|
|
135
|
+
suggestedFix: "Configure the session middleware to use an external store (e.g., `session({ store: new RedisStore({ client }) })`) instead of the default in-memory store.",
|
|
136
|
+
confidence: 0.75,
|
|
119
137
|
});
|
|
120
138
|
}
|
|
121
139
|
// Hardcoded thread/worker pool sizes
|
|
@@ -130,6 +148,8 @@ export function analyzeScalability(code, language) {
|
|
|
130
148
|
lineNumbers: hardcodedPoolLines,
|
|
131
149
|
recommendation: "Configure pool sizes via environment variables or derive from available resources (os.cpus().length). Allow runtime tuning.",
|
|
132
150
|
reference: "Resource Configuration Best Practices",
|
|
151
|
+
suggestedFix: "Replace the hardcoded pool size with a configurable value (e.g., `parseInt(process.env.POOL_SIZE) || os.cpus().length`) to adapt to each environment.",
|
|
152
|
+
confidence: 0.85,
|
|
133
153
|
});
|
|
134
154
|
}
|
|
135
155
|
// No circuit breaker pattern
|
|
@@ -143,6 +163,8 @@ export function analyzeScalability(code, language) {
|
|
|
143
163
|
description: "Multiple external service calls detected without circuit breaker protection. A failing dependency can cascade and bring down the entire system.",
|
|
144
164
|
recommendation: "Implement circuit breakers (opossum, cockatiel, Resilience4j, Polly) to fail fast when dependencies are down. Configure fallbacks.",
|
|
145
165
|
reference: "Release It! — Circuit Breaker Pattern",
|
|
166
|
+
suggestedFix: "Wrap external service calls with a circuit breaker (e.g., `const breaker = new CircuitBreaker(callFn, { timeout: 3000 }); await breaker.fire()`).",
|
|
167
|
+
confidence: 0.7,
|
|
146
168
|
});
|
|
147
169
|
}
|
|
148
170
|
// Monolithic query / large payload assembly
|
|
@@ -155,6 +177,8 @@ export function analyzeScalability(code, language) {
|
|
|
155
177
|
description: "Large response payloads increase serialization time, network transfer, and client memory usage. This limits throughput at scale.",
|
|
156
178
|
recommendation: "Implement pagination, field filtering (sparse fieldsets), or streaming for large responses. Consider GraphQL for client-driven field selection.",
|
|
157
179
|
reference: "API Scalability Patterns",
|
|
180
|
+
suggestedFix: "Add pagination parameters (e.g., `?page=1&limit=50`) and return only the requested slice instead of the full dataset.",
|
|
181
|
+
confidence: 0.8,
|
|
158
182
|
});
|
|
159
183
|
}
|
|
160
184
|
// WebSocket without connection limits
|
|
@@ -170,6 +194,8 @@ export function analyzeScalability(code, language) {
|
|
|
170
194
|
lineNumbers: wsLines,
|
|
171
195
|
recommendation: "Set maxPayload size, maximum connection limits, and implement connection throttling. Use a WebSocket gateway for production scale.",
|
|
172
196
|
reference: "WebSocket Security & Scalability",
|
|
197
|
+
suggestedFix: "Pass connection limits when creating the WebSocket server (e.g., `new WebSocketServer({ maxPayload: 1048576, maxConnections: 1000 })`).",
|
|
198
|
+
confidence: 0.75,
|
|
173
199
|
});
|
|
174
200
|
}
|
|
175
201
|
return findings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scalability.js","sourceRoot":"","sources":["../../src/evaluators/scalability.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAE9C,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,QAAgB;IAC/D,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,MAAM,GAAG,OAAO,CAAC;IACvB,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAErC,wCAAwC;IACxC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC;IAC/E,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,+BAA+B;YACtC,WAAW,
|
|
1
|
+
{"version":3,"file":"scalability.js","sourceRoot":"","sources":["../../src/evaluators/scalability.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAE9C,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,QAAgB;IAC/D,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,MAAM,GAAG,OAAO,CAAC;IACvB,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAErC,wCAAwC;IACxC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC;IAC/E,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,+BAA+B;YACtC,WAAW,EACT,6JAA6J;YAC/J,WAAW,EAAE,gBAAgB;YAC7B,cAAc,EACZ,mJAAmJ;YACrJ,SAAS,EAAE,sCAAsC;YACjD,YAAY,EACV,4IAA4I;YAC9I,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,0BAA0B;IAC1B,MAAM,YAAY,GAChB,kKAAkK,CAAC;IACrK,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACtD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,oCAAoC;YAC3C,WAAW,EACT,8JAA8J;YAChK,WAAW,EAAE,UAAU;YACvB,cAAc,EACZ,kGAAkG;YACpG,SAAS,EAAE,oCAAoC;YAC/C,YAAY,EACV,kIAAkI;YACpI,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,qDAAqD;IACrD,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,eAAe,GACnB,mKAAmK,CAAC;IACtK,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC5D,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,gCAAgC;YACvC,WAAW,EACT,oJAAoJ;YACtJ,WAAW,EAAE,aAAa;YAC1B,cAAc,EACZ,uHAAuH;YACzH,SAAS,EAAE,+CAA+C;YAC1D,YAAY,EACV,oJAAoJ;YACtJ,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,gDAAgD;IAChD,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,0EAA0E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,gCAAgC;YACvC,WAAW,EACT,yJAAyJ;YAC3J,WAAW,EAAE,UAAU;YACvB,cAAc,EACZ,2KAA2K;YAC7K,SAAS,EAAE,kCAAkC;YAC7C,YAAY,EACV,gIAAgI;YAClI,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,oCAAoC;IACpC,6EAA6E;IAC7E,MAAM,gBAAgB,GAAG,gFAAgF,CAAC;IAC1G,MAAM,eAAe,GACnB,mMAAmM,CAAC;IACtM,MAAM,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC1D,IAAI,cAAc,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,6CAA6C;YACpD,WAAW,EAAE,YAAY,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,cAAc,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,iCAAiC,CAAC,CAAC,CAAC,EAAE,0GAA0G;YACxT,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;YAC7D,cAAc,EACZ,oNAAoN;YACtN,SAAS,EAAE,6CAA6C;YACxD,YAAY,EACV,+JAA+J;YACjK,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,4BAA4B;IAC5B,MAAM,YAAY,GAAG,0CAA0C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3E,IAAI,CAAC,YAAY,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,2BAA2B;YAClC,WAAW,EACT,uJAAuJ;YACzJ,cAAc,EACZ,wLAAwL;YAC1L,SAAS,EAAE,2CAA2C;YACtD,YAAY,EACV,sIAAsI;YACxI,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,mCAAmC;IACnC,MAAM,eAAe,GAAG,yFAAyF,CAAC;IAClH,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC5D,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,gDAAgD;YACvD,WAAW,EACT,oJAAoJ;YACtJ,WAAW,EAAE,aAAa;YAC1B,cAAc,EACZ,yHAAyH;YAC3H,SAAS,EAAE,8BAA8B;YACzC,YAAY,EACV,mJAAmJ;YACrJ,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,gDAAgD;IAChD,MAAM,oBAAoB,GAAG,kEAAkE,CAAC;IAChG,MAAM,kBAAkB,GAAG,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;IACtE,MAAM,kBAAkB,GAAG,mEAAmE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1G,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACzD,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,6CAA6C;YACpD,WAAW,EACT,qJAAqJ;YACvJ,WAAW,EAAE,kBAAkB;YAC/B,cAAc,EACZ,0IAA0I;YAC5I,SAAS,EAAE,6BAA6B;YACxC,YAAY,EACV,4JAA4J;YAC9J,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,qCAAqC;IACrC,MAAM,oBAAoB,GAAG,yEAAyE,CAAC;IACvG,MAAM,kBAAkB,GAAG,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;IACtE,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,mCAAmC;YAC1C,WAAW,EACT,oJAAoJ;YACtJ,WAAW,EAAE,kBAAkB;YAC/B,cAAc,EACZ,6HAA6H;YAC/H,SAAS,EAAE,uCAAuC;YAClD,YAAY,EACV,uJAAuJ;YACzJ,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,6BAA6B;IAC7B,MAAM,iBAAiB,GAAG,gFAAgF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtH,MAAM,wBAAwB,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IACvD,IAAI,wBAAwB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACnD,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,8CAA8C;YACrD,WAAW,EACT,iJAAiJ;YACnJ,cAAc,EACZ,oIAAoI;YACtI,SAAS,EAAE,uCAAuC;YAClD,YAAY,EACV,mJAAmJ;YACrJ,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,4CAA4C;IAC5C,MAAM,mBAAmB,GACvB,6GAA6G,CAAC;IAChH,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,oCAAoC;YAC3C,WAAW,EACT,kIAAkI;YACpI,cAAc,EACZ,iJAAiJ;YACnJ,SAAS,EAAE,0BAA0B;YACrC,YAAY,EACV,uHAAuH;YACzH,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAED,sCAAsC;IACtC,MAAM,SAAS,GAAG,yDAAyD,CAAC;IAC5E,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,6DAA6D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5F,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACtC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzD,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,qCAAqC;YAC5C,WAAW,EACT,4IAA4I;YAC9I,WAAW,EAAE,OAAO;YACpB,cAAc,EACZ,oIAAoI;YACtI,SAAS,EAAE,kCAAkC;YAC7C,YAAY,EACV,yIAAyI;YAC3I,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import { JudgeDefinition, JudgeEvaluation, TribunalVerdict, Finding, Verdict, JudgesConfig, LangFamily } from "../types.js";
|
|
1
|
+
import type { JudgeDefinition, JudgeEvaluation, TribunalVerdict, Finding, Verdict, JudgesConfig, LangFamily } from "../types.js";
|
|
2
2
|
import { normalizeLanguage, langPattern } from "../language-patterns.js";
|
|
3
3
|
export { normalizeLanguage, langPattern };
|
|
4
|
+
export type FileCategory = "test" | "config" | "types" | "utility" | "server" | "unknown";
|
|
5
|
+
/**
|
|
6
|
+
* Heuristically classify a source file based on its content (and optionally its
|
|
7
|
+
* file path). The classification drives file-type gating: absence-based
|
|
8
|
+
* rules (e.g. "no rate limiting", "no config schema") are suppressed on
|
|
9
|
+
* non-server files where they would only produce noise.
|
|
10
|
+
*/
|
|
11
|
+
export declare function classifyFile(code: string, language: string, filePath?: string): FileCategory;
|
|
12
|
+
/**
|
|
13
|
+
* Whether absence-based rules should fire for a file of this category.
|
|
14
|
+
* Absence-based rules (e.g. "no rate limiting", "no input validation") are
|
|
15
|
+
* only meaningful on server / entry-point code.
|
|
16
|
+
*/
|
|
17
|
+
export declare function shouldRunAbsenceRules(category: FileCategory): boolean;
|
|
4
18
|
/**
|
|
5
19
|
* Find line numbers in source code that match a given regex pattern.
|
|
6
20
|
*/
|
|
@@ -20,7 +34,12 @@ export declare function getLangFamily(language: string): LangFamily;
|
|
|
20
34
|
* override severities, and filter by minimum severity.
|
|
21
35
|
*/
|
|
22
36
|
export declare function applyConfig(findings: Finding[], config?: JudgesConfig): Finding[];
|
|
23
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Detect positive engineering signals in source code. Returns a bonus score.
|
|
39
|
+
* Called during scoring to reward good practices, not just penalize problems.
|
|
40
|
+
*/
|
|
41
|
+
export declare function detectPositiveSignals(code: string): number;
|
|
42
|
+
export declare function calculateScore(findings: Finding[], code?: string): number;
|
|
24
43
|
export declare function deriveVerdict(findings: Finding[], score: number): Verdict;
|
|
25
44
|
export declare function buildSummary(judge: JudgeDefinition, findings: Finding[], score: number, verdict: Verdict): string;
|
|
26
45
|
export declare function buildTribunalSummary(evaluations: JudgeEvaluation[], verdict: Verdict, score: number, criticalCount: number, highCount: number): string;
|
|
@@ -28,6 +47,9 @@ export declare function buildTribunalSummary(evaluations: JudgeEvaluation[], ver
|
|
|
28
47
|
* Format a full tribunal verdict as a readable Markdown string.
|
|
29
48
|
*/
|
|
30
49
|
export declare function formatVerdictAsMarkdown(verdict: TribunalVerdict): string;
|
|
50
|
+
export declare function isLikelyPlaceholderCredentialValue(value: string): boolean;
|
|
51
|
+
export declare function isStrictCredentialDetectionEnabled(): boolean;
|
|
52
|
+
export declare function looksLikeRealCredentialValue(value: string): boolean;
|
|
31
53
|
/**
|
|
32
54
|
* Format a single judge evaluation as a readable Markdown string.
|
|
33
55
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/evaluators/shared.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/evaluators/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,OAAO,EAEP,OAAO,EACP,YAAY,EACZ,UAAU,EACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGzE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;AAO1C,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,SAAS,GACT,QAAQ,GACR,SAAS,CAAC;AAEd;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAqG5F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAErE;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAUtE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,KAAK,EAAE,MAAM,CAAC,CAAC,GAC7D,MAAM,EAAE,CAKV;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAE1D;AAID;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,EAAE,CAsDjF;AAID;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0B1D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA4BzE;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAMzE;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAqBjH;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,eAAe,EAAE,EAC9B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,MAAM,CAmBR;AAID;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAmCxE;AA+BD,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQzE;AAED,wBAAgB,kCAAkC,IAAI,OAAO,CAE5D;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAuBnE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAiC9E"}
|
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
import { normalizeLanguage, langPattern } from "../language-patterns.js";
|
|
2
2
|
// ─── Re-export language utilities for convenience ────────────────────────────
|
|
3
3
|
export { normalizeLanguage, langPattern };
|
|
4
|
+
/**
|
|
5
|
+
* Heuristically classify a source file based on its content (and optionally its
|
|
6
|
+
* file path). The classification drives file-type gating: absence-based
|
|
7
|
+
* rules (e.g. "no rate limiting", "no config schema") are suppressed on
|
|
8
|
+
* non-server files where they would only produce noise.
|
|
9
|
+
*/
|
|
10
|
+
export function classifyFile(code, language, filePath) {
|
|
11
|
+
const lines = code.split("\n");
|
|
12
|
+
const lineCount = lines.length;
|
|
13
|
+
// ── Path-based fast checks ───────────────────────────────────────────────
|
|
14
|
+
if (filePath) {
|
|
15
|
+
const lowerPath = filePath.toLowerCase().replace(/\\/g, "/");
|
|
16
|
+
if (/[/\\]?(?:__tests__|test|tests|spec|__mocks__|__fixtures__)[/\\]/i.test(lowerPath) ||
|
|
17
|
+
/\.(test|spec|e2e)\.\w+$/i.test(lowerPath)) {
|
|
18
|
+
return "test";
|
|
19
|
+
}
|
|
20
|
+
if (/(?:^|[/\\])(?:tsconfig|jest\.config|webpack\.config|vite\.config|eslint|\.eslintrc|babel\.config|rollup\.config|\.prettierrc|Makefile|Dockerfile|docker-compose|package\.json|Cargo\.toml|go\.mod|pom\.xml|build\.gradle|\.csproj|\.sln|\.editorconfig)[^/\\]*$/i.test(lowerPath)) {
|
|
21
|
+
return "config";
|
|
22
|
+
}
|
|
23
|
+
if (/\.d\.ts$/i.test(lowerPath)) {
|
|
24
|
+
return "types";
|
|
25
|
+
}
|
|
26
|
+
// Health check / readiness probe endpoints (should not trigger absence rules)
|
|
27
|
+
if (/(?:^|[/\\])(?:health|healthcheck|health-check|readiness|liveness|ready|live|ping|status)\.\w+$/i.test(lowerPath)) {
|
|
28
|
+
return "utility";
|
|
29
|
+
}
|
|
30
|
+
// Migration / seed files
|
|
31
|
+
if (/(?:^|[/\\])(?:migrations?|seeds?|fixtures)[/\\]/i.test(lowerPath)) {
|
|
32
|
+
return "config";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// ── Content-based classification ─────────────────────────────────────────
|
|
36
|
+
// Test files: heavy test framework usage
|
|
37
|
+
const testFrameworkLines = lines.filter((l) => /\b(?:describe|it|test|beforeEach|afterEach|beforeAll|afterAll|expect|assert)\s*\(/i.test(l)).length;
|
|
38
|
+
if (testFrameworkLines >= 3) {
|
|
39
|
+
return "test";
|
|
40
|
+
}
|
|
41
|
+
// Pure type-definition files: mostly interfaces, types, enums, no runtime
|
|
42
|
+
const typeOnlyPattern = /^\s*(?:export\s+)?(?:interface|type|enum|declare|namespace)\b/;
|
|
43
|
+
const importPattern = /^\s*(?:import|export)\s/;
|
|
44
|
+
const commentOrBlank = /^\s*(?:\/\/|\/\*|\*|$)/;
|
|
45
|
+
const runtimeStatements = lines.filter((l) => {
|
|
46
|
+
const trimmed = l.trim();
|
|
47
|
+
return (trimmed.length > 0 &&
|
|
48
|
+
!commentOrBlank.test(trimmed) &&
|
|
49
|
+
!typeOnlyPattern.test(trimmed) &&
|
|
50
|
+
!importPattern.test(trimmed) &&
|
|
51
|
+
!/^\s*\}/.test(trimmed) && // closing braces
|
|
52
|
+
!/^\s*\*\//.test(trimmed)); // end of block comment
|
|
53
|
+
}).length;
|
|
54
|
+
if (lineCount > 5 && runtimeStatements / lineCount < 0.15) {
|
|
55
|
+
return "types";
|
|
56
|
+
}
|
|
57
|
+
// Config-like files: mostly key-value, constants, no functions
|
|
58
|
+
const constExportLines = lines.filter((l) => /^\s*(?:export\s+)?(?:const|let|var)\s+\w+\s*=\s*(?:\{|"|'|\d|true|false|null|\[)/i.test(l)).length;
|
|
59
|
+
const functionDeclLines = lines.filter((l) => /(?:function\s+\w+|=>\s*\{|class\s+\w+|def\s+\w+|fn\s+\w+|func\s+\w+)/i.test(l)).length;
|
|
60
|
+
if (lineCount > 5 && constExportLines / lineCount > 0.3 && functionDeclLines === 0) {
|
|
61
|
+
return "config";
|
|
62
|
+
}
|
|
63
|
+
// Health-check endpoints detected by content (lightweight route returning 200/ok)
|
|
64
|
+
if (/(?:\/health|\/ready|\/live|\/ping|\/status)\b/i.test(code) &&
|
|
65
|
+
lineCount < 50 &&
|
|
66
|
+
/(?:res\.(?:send|json|status)|return.*(?:ok|healthy|200))/i.test(code)) {
|
|
67
|
+
return "utility";
|
|
68
|
+
}
|
|
69
|
+
// Server / entry point: has HTTP handlers, route definitions, or listen
|
|
70
|
+
const serverSignals = /\b(?:app\.(?:get|post|put|delete|patch|use|listen)|router\.|express\(|createServer|fastify|Koa|hono|http\.(?:Server|createServer)|new\s+Hono|Flask|Django|Spring|@(?:Get|Post|Put|Delete|Controller|RequestMapping)|func\s+\w+Handler|gin\.\w+|http\.Handle)/i;
|
|
71
|
+
if (serverSignals.test(code)) {
|
|
72
|
+
return "server";
|
|
73
|
+
}
|
|
74
|
+
// Small utility with no I/O
|
|
75
|
+
const hasIO = /\b(?:fetch|axios|http|https|net|fs\.|readFile|writeFile|database|query|exec|spawn|child_process|socket)\b/i.test(code);
|
|
76
|
+
if (!hasIO && lineCount < 200) {
|
|
77
|
+
return "utility";
|
|
78
|
+
}
|
|
79
|
+
return "unknown";
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether absence-based rules should fire for a file of this category.
|
|
83
|
+
* Absence-based rules (e.g. "no rate limiting", "no input validation") are
|
|
84
|
+
* only meaningful on server / entry-point code.
|
|
85
|
+
*/
|
|
86
|
+
export function shouldRunAbsenceRules(category) {
|
|
87
|
+
return category === "server" || category === "unknown";
|
|
88
|
+
}
|
|
4
89
|
// ─── Shared Utilities ────────────────────────────────────────────────────────
|
|
5
90
|
// Helper functions used by all analyzer modules and the evaluation engine.
|
|
6
91
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -11,6 +96,7 @@ export function getLineNumbers(code, pattern) {
|
|
|
11
96
|
const lines = code.split("\n");
|
|
12
97
|
const matches = [];
|
|
13
98
|
for (let i = 0; i < lines.length; i++) {
|
|
99
|
+
pattern.lastIndex = 0;
|
|
14
100
|
if (pattern.test(lines[i])) {
|
|
15
101
|
matches.push(i + 1);
|
|
16
102
|
}
|
|
@@ -91,7 +177,46 @@ export function applyConfig(findings, config) {
|
|
|
91
177
|
return result;
|
|
92
178
|
}
|
|
93
179
|
// ─── Scoring ─────────────────────────────────────────────────────────────────
|
|
94
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Detect positive engineering signals in source code. Returns a bonus score.
|
|
182
|
+
* Called during scoring to reward good practices, not just penalize problems.
|
|
183
|
+
*/
|
|
184
|
+
export function detectPositiveSignals(code) {
|
|
185
|
+
let bonus = 0;
|
|
186
|
+
// Parameterized queries (prepared statements, $1 placeholders)
|
|
187
|
+
if (/\$\d+|PreparedStatement|\?\s*(?:,|\))|\.prepare\s*\(/i.test(code))
|
|
188
|
+
bonus += 3;
|
|
189
|
+
// Security headers imported (helmet, csp, hsts)
|
|
190
|
+
if (/\bhelmet\b|content-security-policy|strict-transport-security/i.test(code))
|
|
191
|
+
bonus += 3;
|
|
192
|
+
// Proper error handling (try/catch with actual handling, not empty catch)
|
|
193
|
+
if (/catch\s*\([^)]+\)\s*\{[^}]*(?:log|throw|return|next|reject|emit)/i.test(code))
|
|
194
|
+
bonus += 2;
|
|
195
|
+
// Input validation present (joi, zod, yup, express-validator, class-validator)
|
|
196
|
+
if (/\b(?:joi|zod|yup|ajv|class-validator|express-validator)\b/i.test(code))
|
|
197
|
+
bonus += 2;
|
|
198
|
+
// Authentication middleware
|
|
199
|
+
if (/\b(?:passport|requireAuth|isAuthenticated|authMiddleware|verifyToken|authorize)\b/i.test(code))
|
|
200
|
+
bonus += 3;
|
|
201
|
+
// Rate limiting
|
|
202
|
+
if (/\b(?:rateLimit|rateLimiter|express-rate-limit|throttle|bottleneck)\b/i.test(code))
|
|
203
|
+
bonus += 2;
|
|
204
|
+
// CORS properly configured
|
|
205
|
+
if (/\bcors\b.*\b(?:origin|methods|credentials)\b/i.test(code))
|
|
206
|
+
bonus += 1;
|
|
207
|
+
// TypeScript strict mode or runtime type checking
|
|
208
|
+
if (/\bstrict(?:NullChecks|Mode)?\s*:\s*true\b/i.test(code))
|
|
209
|
+
bonus += 1;
|
|
210
|
+
// Structured logging (winston, pino, bunyan)
|
|
211
|
+
if (/\b(?:winston|pino|bunyan|createLogger|getLogger)\b/i.test(code))
|
|
212
|
+
bonus += 2;
|
|
213
|
+
// Tests present (basic signal for quality)
|
|
214
|
+
if (/\b(?:describe|it|test|expect|assert)\s*\(/i.test(code))
|
|
215
|
+
bonus += 1;
|
|
216
|
+
// Cap total bonus at +15
|
|
217
|
+
return Math.min(bonus, 15);
|
|
218
|
+
}
|
|
219
|
+
export function calculateScore(findings, code) {
|
|
95
220
|
let score = 100;
|
|
96
221
|
for (const f of findings) {
|
|
97
222
|
switch (f.severity) {
|
|
@@ -112,29 +237,12 @@ export function calculateScore(findings) {
|
|
|
112
237
|
break;
|
|
113
238
|
}
|
|
114
239
|
}
|
|
240
|
+
// Add positive signals bonus if code is provided
|
|
241
|
+
if (code) {
|
|
242
|
+
score += detectPositiveSignals(code);
|
|
243
|
+
}
|
|
115
244
|
return Math.max(0, Math.min(100, score));
|
|
116
245
|
}
|
|
117
|
-
function findingPriorityValue(finding) {
|
|
118
|
-
const severityWeight = {
|
|
119
|
-
critical: 100,
|
|
120
|
-
high: 70,
|
|
121
|
-
medium: 40,
|
|
122
|
-
low: 15,
|
|
123
|
-
info: 5,
|
|
124
|
-
};
|
|
125
|
-
const confidence = typeof finding.confidence === "number"
|
|
126
|
-
? Math.max(0, Math.min(1, finding.confidence))
|
|
127
|
-
: 0.75;
|
|
128
|
-
return severityWeight[finding.severity] * (0.6 + confidence * 0.4);
|
|
129
|
-
}
|
|
130
|
-
function sortFindingsByPriority(findings) {
|
|
131
|
-
return [...findings].sort((a, b) => {
|
|
132
|
-
const priorityDiff = findingPriorityValue(b) - findingPriorityValue(a);
|
|
133
|
-
if (priorityDiff !== 0)
|
|
134
|
-
return priorityDiff;
|
|
135
|
-
return a.ruleId.localeCompare(b.ruleId);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
246
|
export function deriveVerdict(findings, score) {
|
|
139
247
|
if (findings.some((f) => f.severity === "critical"))
|
|
140
248
|
return "fail";
|
|
@@ -154,11 +262,12 @@ export function buildSummary(judge, findings, score, verdict) {
|
|
|
154
262
|
summary += `Verdict: **${verdict.toUpperCase()}** | Score: **${score}/100**\n`;
|
|
155
263
|
summary += `Findings: ${critical} critical, ${high} high, ${medium} medium, ${low} low\n\n`;
|
|
156
264
|
if (findings.length === 0) {
|
|
157
|
-
summary +=
|
|
265
|
+
summary +=
|
|
266
|
+
"No pattern-based issues detected. Heuristic analysis has inherent limits — absence of findings does not guarantee the code is free of defects. Manual expert review is strongly recommended.";
|
|
158
267
|
}
|
|
159
268
|
else {
|
|
160
269
|
summary += "Key issues:\n";
|
|
161
|
-
for (const f of
|
|
270
|
+
for (const f of findings.filter((f) => ["critical", "high"].includes(f.severity))) {
|
|
162
271
|
summary += `- [${f.ruleId}] (${f.severity}) ${f.title}: ${f.description}\n`;
|
|
163
272
|
}
|
|
164
273
|
}
|
|
@@ -188,7 +297,7 @@ export function formatVerdictAsMarkdown(verdict) {
|
|
|
188
297
|
let md = verdict.summary;
|
|
189
298
|
md += `\n## Detailed Findings\n\n`;
|
|
190
299
|
for (const evaluation of verdict.evaluations) {
|
|
191
|
-
for (const finding of
|
|
300
|
+
for (const finding of evaluation.findings) {
|
|
192
301
|
const severityBadge = finding.severity === "critical"
|
|
193
302
|
? "🔴 CRITICAL"
|
|
194
303
|
: finding.severity === "high"
|
|
@@ -215,13 +324,72 @@ export function formatVerdictAsMarkdown(verdict) {
|
|
|
215
324
|
}
|
|
216
325
|
return md;
|
|
217
326
|
}
|
|
327
|
+
// ─── Shared Credential / Placeholder Detection ──────────────────────────────
|
|
328
|
+
// Centralised so authentication.ts, data-security.ts, and cybersecurity.ts
|
|
329
|
+
// all use the same logic instead of maintaining identical copies.
|
|
330
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
331
|
+
const EXACT_PLACEHOLDERS = new Set([
|
|
332
|
+
"test",
|
|
333
|
+
"testing",
|
|
334
|
+
"mock",
|
|
335
|
+
"dummy",
|
|
336
|
+
"example",
|
|
337
|
+
"sample",
|
|
338
|
+
"fake",
|
|
339
|
+
"na",
|
|
340
|
+
"n/a",
|
|
341
|
+
"none",
|
|
342
|
+
"null",
|
|
343
|
+
"undefined",
|
|
344
|
+
"changeme",
|
|
345
|
+
"change_me",
|
|
346
|
+
"replace_me",
|
|
347
|
+
"replace-me",
|
|
348
|
+
"your_token_here",
|
|
349
|
+
"your_api_key",
|
|
350
|
+
"unused",
|
|
351
|
+
"not_used",
|
|
352
|
+
"placeholder",
|
|
353
|
+
]);
|
|
354
|
+
export function isLikelyPlaceholderCredentialValue(value) {
|
|
355
|
+
const normalized = value.trim().toLowerCase();
|
|
356
|
+
if (EXACT_PLACEHOLDERS.has(normalized))
|
|
357
|
+
return true;
|
|
358
|
+
if (/^(?:test|mock|dummy|sample|example|fake|placeholder|na|n\/a|unused|changeme|replace)[-_a-z0-9]*$/i.test(normalized))
|
|
359
|
+
return true;
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
export function isStrictCredentialDetectionEnabled() {
|
|
363
|
+
return process.env.JUDGES_CREDENTIAL_MODE?.toLowerCase() === "strict";
|
|
364
|
+
}
|
|
365
|
+
export function looksLikeRealCredentialValue(value) {
|
|
366
|
+
if (isLikelyPlaceholderCredentialValue(value))
|
|
367
|
+
return false;
|
|
368
|
+
if (!isStrictCredentialDetectionEnabled())
|
|
369
|
+
return true;
|
|
370
|
+
const normalized = value.trim();
|
|
371
|
+
if (normalized.length < 12)
|
|
372
|
+
return false;
|
|
373
|
+
if (/(?:test|mock|dummy|sample|example|fake|placeholder|changeme|replace[_-]?me|unused|not[_-]?used|password|secret)/i.test(normalized))
|
|
374
|
+
return false;
|
|
375
|
+
const hasLower = /[a-z]/.test(normalized);
|
|
376
|
+
const hasUpper = /[A-Z]/.test(normalized);
|
|
377
|
+
const hasDigit = /\d/.test(normalized);
|
|
378
|
+
const hasSymbol = /[^A-Za-z0-9]/.test(normalized);
|
|
379
|
+
const classCount = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;
|
|
380
|
+
if (normalized.length >= 20 && classCount >= 2)
|
|
381
|
+
return true;
|
|
382
|
+
if (normalized.length >= 16 && classCount >= 3)
|
|
383
|
+
return true;
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
218
386
|
/**
|
|
219
387
|
* Format a single judge evaluation as a readable Markdown string.
|
|
220
388
|
*/
|
|
221
389
|
export function formatEvaluationAsMarkdown(evaluation) {
|
|
222
390
|
let md = evaluation.summary + "\n\n";
|
|
223
391
|
md += `## Detailed Findings\n\n`;
|
|
224
|
-
for (const finding of
|
|
392
|
+
for (const finding of evaluation.findings) {
|
|
225
393
|
const severityBadge = finding.severity === "critical"
|
|
226
394
|
? "🔴 CRITICAL"
|
|
227
395
|
: finding.severity === "high"
|