@kevinrabun/judges 1.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 +174 -0
- package/dist/evaluators/accessibility.d.ts +3 -0
- package/dist/evaluators/accessibility.d.ts.map +1 -0
- package/dist/evaluators/accessibility.js +306 -0
- package/dist/evaluators/accessibility.js.map +1 -0
- package/dist/evaluators/api-design.d.ts +3 -0
- package/dist/evaluators/api-design.d.ts.map +1 -0
- package/dist/evaluators/api-design.js +224 -0
- package/dist/evaluators/api-design.js.map +1 -0
- package/dist/evaluators/cloud-readiness.d.ts +3 -0
- package/dist/evaluators/cloud-readiness.d.ts.map +1 -0
- package/dist/evaluators/cloud-readiness.js +181 -0
- package/dist/evaluators/cloud-readiness.js.map +1 -0
- package/dist/evaluators/compliance.d.ts +3 -0
- package/dist/evaluators/compliance.d.ts.map +1 -0
- package/dist/evaluators/compliance.js +213 -0
- package/dist/evaluators/compliance.js.map +1 -0
- package/dist/evaluators/concurrency.d.ts +3 -0
- package/dist/evaluators/concurrency.d.ts.map +1 -0
- package/dist/evaluators/concurrency.js +220 -0
- package/dist/evaluators/concurrency.js.map +1 -0
- package/dist/evaluators/cost-effectiveness.d.ts +3 -0
- package/dist/evaluators/cost-effectiveness.d.ts.map +1 -0
- package/dist/evaluators/cost-effectiveness.js +206 -0
- package/dist/evaluators/cost-effectiveness.js.map +1 -0
- package/dist/evaluators/cybersecurity.d.ts +3 -0
- package/dist/evaluators/cybersecurity.d.ts.map +1 -0
- package/dist/evaluators/cybersecurity.js +282 -0
- package/dist/evaluators/cybersecurity.js.map +1 -0
- package/dist/evaluators/data-security.d.ts +3 -0
- package/dist/evaluators/data-security.d.ts.map +1 -0
- package/dist/evaluators/data-security.js +286 -0
- package/dist/evaluators/data-security.js.map +1 -0
- package/dist/evaluators/dependency-health.d.ts +3 -0
- package/dist/evaluators/dependency-health.d.ts.map +1 -0
- package/dist/evaluators/dependency-health.js +197 -0
- package/dist/evaluators/dependency-health.js.map +1 -0
- package/dist/evaluators/documentation.d.ts +3 -0
- package/dist/evaluators/documentation.d.ts.map +1 -0
- package/dist/evaluators/documentation.js +216 -0
- package/dist/evaluators/documentation.js.map +1 -0
- package/dist/evaluators/ethics-bias.d.ts +3 -0
- package/dist/evaluators/ethics-bias.d.ts.map +1 -0
- package/dist/evaluators/ethics-bias.js +205 -0
- package/dist/evaluators/ethics-bias.js.map +1 -0
- package/dist/evaluators/index.d.ts +12 -0
- package/dist/evaluators/index.d.ts.map +1 -0
- package/dist/evaluators/index.js +127 -0
- package/dist/evaluators/index.js.map +1 -0
- package/dist/evaluators/internationalization.d.ts +3 -0
- package/dist/evaluators/internationalization.d.ts.map +1 -0
- package/dist/evaluators/internationalization.js +176 -0
- package/dist/evaluators/internationalization.js.map +1 -0
- package/dist/evaluators/observability.d.ts +3 -0
- package/dist/evaluators/observability.d.ts.map +1 -0
- package/dist/evaluators/observability.js +171 -0
- package/dist/evaluators/observability.js.map +1 -0
- package/dist/evaluators/performance.d.ts +3 -0
- package/dist/evaluators/performance.d.ts.map +1 -0
- package/dist/evaluators/performance.js +306 -0
- package/dist/evaluators/performance.js.map +1 -0
- package/dist/evaluators/reliability.d.ts +3 -0
- package/dist/evaluators/reliability.d.ts.map +1 -0
- package/dist/evaluators/reliability.js +215 -0
- package/dist/evaluators/reliability.js.map +1 -0
- package/dist/evaluators/scalability.d.ts +3 -0
- package/dist/evaluators/scalability.d.ts.map +1 -0
- package/dist/evaluators/scalability.js +171 -0
- package/dist/evaluators/scalability.js.map +1 -0
- package/dist/evaluators/shared.d.ts +18 -0
- package/dist/evaluators/shared.d.ts.map +1 -0
- package/dist/evaluators/shared.js +147 -0
- package/dist/evaluators/shared.js.map +1 -0
- package/dist/evaluators/software-practices.d.ts +3 -0
- package/dist/evaluators/software-practices.d.ts.map +1 -0
- package/dist/evaluators/software-practices.js +272 -0
- package/dist/evaluators/software-practices.js.map +1 -0
- package/dist/evaluators/testing.d.ts +3 -0
- package/dist/evaluators/testing.d.ts.map +1 -0
- package/dist/evaluators/testing.js +185 -0
- package/dist/evaluators/testing.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +238 -0
- package/dist/index.js.map +1 -0
- package/dist/judges/accessibility.d.ts +3 -0
- package/dist/judges/accessibility.d.ts.map +1 -0
- package/dist/judges/accessibility.js +28 -0
- package/dist/judges/accessibility.js.map +1 -0
- package/dist/judges/api-design.d.ts +3 -0
- package/dist/judges/api-design.d.ts.map +1 -0
- package/dist/judges/api-design.js +30 -0
- package/dist/judges/api-design.js.map +1 -0
- package/dist/judges/cloud-readiness.d.ts +3 -0
- package/dist/judges/cloud-readiness.d.ts.map +1 -0
- package/dist/judges/cloud-readiness.js +28 -0
- package/dist/judges/cloud-readiness.js.map +1 -0
- package/dist/judges/compliance.d.ts +3 -0
- package/dist/judges/compliance.d.ts.map +1 -0
- package/dist/judges/compliance.js +28 -0
- package/dist/judges/compliance.js.map +1 -0
- package/dist/judges/concurrency.d.ts +3 -0
- package/dist/judges/concurrency.d.ts.map +1 -0
- package/dist/judges/concurrency.js +30 -0
- package/dist/judges/concurrency.js.map +1 -0
- package/dist/judges/cost-effectiveness.d.ts +3 -0
- package/dist/judges/cost-effectiveness.d.ts.map +1 -0
- package/dist/judges/cost-effectiveness.js +27 -0
- package/dist/judges/cost-effectiveness.js.map +1 -0
- package/dist/judges/cybersecurity.d.ts +3 -0
- package/dist/judges/cybersecurity.d.ts.map +1 -0
- package/dist/judges/cybersecurity.js +27 -0
- package/dist/judges/cybersecurity.js.map +1 -0
- package/dist/judges/data-security.d.ts +3 -0
- package/dist/judges/data-security.d.ts.map +1 -0
- package/dist/judges/data-security.js +25 -0
- package/dist/judges/data-security.js.map +1 -0
- package/dist/judges/dependency-health.d.ts +3 -0
- package/dist/judges/dependency-health.d.ts.map +1 -0
- package/dist/judges/dependency-health.js +30 -0
- package/dist/judges/dependency-health.js.map +1 -0
- package/dist/judges/documentation.d.ts +3 -0
- package/dist/judges/documentation.d.ts.map +1 -0
- package/dist/judges/documentation.js +30 -0
- package/dist/judges/documentation.js.map +1 -0
- package/dist/judges/ethics-bias.d.ts +3 -0
- package/dist/judges/ethics-bias.d.ts.map +1 -0
- package/dist/judges/ethics-bias.js +30 -0
- package/dist/judges/ethics-bias.js.map +1 -0
- package/dist/judges/index.d.ts +23 -0
- package/dist/judges/index.d.ts.map +1 -0
- package/dist/judges/index.js +63 -0
- package/dist/judges/index.js.map +1 -0
- package/dist/judges/internationalization.d.ts +3 -0
- package/dist/judges/internationalization.d.ts.map +1 -0
- package/dist/judges/internationalization.js +28 -0
- package/dist/judges/internationalization.js.map +1 -0
- package/dist/judges/observability.d.ts +3 -0
- package/dist/judges/observability.d.ts.map +1 -0
- package/dist/judges/observability.js +28 -0
- package/dist/judges/observability.js.map +1 -0
- package/dist/judges/performance.d.ts +3 -0
- package/dist/judges/performance.d.ts.map +1 -0
- package/dist/judges/performance.js +30 -0
- package/dist/judges/performance.js.map +1 -0
- package/dist/judges/reliability.d.ts +3 -0
- package/dist/judges/reliability.d.ts.map +1 -0
- package/dist/judges/reliability.js +30 -0
- package/dist/judges/reliability.js.map +1 -0
- package/dist/judges/scalability.d.ts +3 -0
- package/dist/judges/scalability.d.ts.map +1 -0
- package/dist/judges/scalability.js +28 -0
- package/dist/judges/scalability.js.map +1 -0
- package/dist/judges/software-practices.d.ts +3 -0
- package/dist/judges/software-practices.d.ts.map +1 -0
- package/dist/judges/software-practices.js +30 -0
- package/dist/judges/software-practices.js.map +1 -0
- package/dist/judges/testing.d.ts +3 -0
- package/dist/judges/testing.d.ts.map +1 -0
- package/dist/judges/testing.js +30 -0
- package/dist/judges/testing.js.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
- package/server.json +21 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
export function analyzeCompliance(code, language) {
|
|
2
|
+
const findings = [];
|
|
3
|
+
const lines = code.split("\n");
|
|
4
|
+
const prefix = "COMP";
|
|
5
|
+
let ruleNum = 1;
|
|
6
|
+
// Detect PII handling without encryption
|
|
7
|
+
const piiFieldLines = [];
|
|
8
|
+
lines.forEach((line, i) => {
|
|
9
|
+
if (/(?:ssn|social_security|tax_id|passport|national_id|driver_license)/i.test(line) && !/encrypt|hash|mask|redact/i.test(line)) {
|
|
10
|
+
piiFieldLines.push(i + 1);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
if (piiFieldLines.length > 0) {
|
|
14
|
+
findings.push({
|
|
15
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
16
|
+
severity: "critical",
|
|
17
|
+
title: "PII field handled without protection",
|
|
18
|
+
description: "Personally Identifiable Information (SSN, passport, tax ID) must be encrypted at rest and in transit, and masked in logs.",
|
|
19
|
+
lineNumbers: piiFieldLines,
|
|
20
|
+
recommendation: "Encrypt PII fields, mask them in logs and UI displays, and ensure they are stored with column-level encryption.",
|
|
21
|
+
reference: "GDPR Article 32 / CCPA / HIPAA",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// Detect missing consent/opt-in checks
|
|
25
|
+
const trackingLines = [];
|
|
26
|
+
lines.forEach((line, i) => {
|
|
27
|
+
if (/analytics|tracking|telemetry|gtag|fbq|pixel|ga\s*\(/i.test(line)) {
|
|
28
|
+
trackingLines.push(i + 1);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const hasConsent = /consent|opt.?in|cookie.?banner|gdpr|accept.*cookie/i.test(code);
|
|
32
|
+
if (trackingLines.length > 0 && !hasConsent) {
|
|
33
|
+
findings.push({
|
|
34
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
35
|
+
severity: "high",
|
|
36
|
+
title: "Tracking/analytics without consent check",
|
|
37
|
+
description: "Analytics and tracking scripts are loaded without checking for user consent, potentially violating GDPR and ePrivacy regulations.",
|
|
38
|
+
lineNumbers: trackingLines,
|
|
39
|
+
recommendation: "Implement a consent management system. Only load tracking scripts after obtaining explicit user consent.",
|
|
40
|
+
reference: "GDPR Article 6 / ePrivacy Directive",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Detect data retention issues
|
|
44
|
+
const storeForeverLines = [];
|
|
45
|
+
lines.forEach((line, i) => {
|
|
46
|
+
if (/(?:save|store|insert|persist|write)\s*\(/i.test(line) && /(?:user|personal|customer|patient|email|phone)/i.test(line)) {
|
|
47
|
+
const context = lines.slice(Math.max(0, i - 5), Math.min(lines.length, i + 5)).join("\n");
|
|
48
|
+
if (!/ttl|expir|retention|purge|delete.*after|archive/i.test(context)) {
|
|
49
|
+
storeForeverLines.push(i + 1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
if (storeForeverLines.length > 0) {
|
|
54
|
+
findings.push({
|
|
55
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
56
|
+
severity: "medium",
|
|
57
|
+
title: "Personal data stored without retention policy",
|
|
58
|
+
description: "Personal data appears to be stored indefinitely without a defined retention period or cleanup mechanism.",
|
|
59
|
+
lineNumbers: storeForeverLines,
|
|
60
|
+
recommendation: "Define and implement data retention policies. Set TTLs, schedule purge jobs, or implement right-to-deletion workflows.",
|
|
61
|
+
reference: "GDPR Article 5(1)(e) Storage Limitation",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Detect logging of sensitive information
|
|
65
|
+
const logSensitiveLines = [];
|
|
66
|
+
lines.forEach((line, i) => {
|
|
67
|
+
if (/(?:console|logger|log)\.\w+\s*\(/.test(line) && /(?:password|token|secret|ssn|credit.?card|api.?key|auth)/i.test(line)) {
|
|
68
|
+
logSensitiveLines.push(i + 1);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
if (logSensitiveLines.length > 0) {
|
|
72
|
+
findings.push({
|
|
73
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
74
|
+
severity: "critical",
|
|
75
|
+
title: "Sensitive data in log statements",
|
|
76
|
+
description: "Logging sensitive information (passwords, tokens, SSNs, credit cards) creates compliance violations and security risks.",
|
|
77
|
+
lineNumbers: logSensitiveLines,
|
|
78
|
+
recommendation: "Never log sensitive data. Use redaction/masking utilities to sanitize log output. Audit all log statements.",
|
|
79
|
+
reference: "OWASP Logging Cheat Sheet / PCI DSS Requirement 3",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Detect missing data classification markers
|
|
83
|
+
const dataModelLines = [];
|
|
84
|
+
lines.forEach((line, i) => {
|
|
85
|
+
if (/(?:interface|class|type|schema|model)\s+\w*(?:User|Customer|Patient|Employee|Person)/i.test(line)) {
|
|
86
|
+
const context = lines.slice(i, Math.min(lines.length, i + 15)).join("\n");
|
|
87
|
+
if (!/classification|sensitivity|pii|confidential|restricted|public/i.test(context)) {
|
|
88
|
+
dataModelLines.push(i + 1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (dataModelLines.length > 0) {
|
|
93
|
+
findings.push({
|
|
94
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
95
|
+
severity: "low",
|
|
96
|
+
title: "Data model lacks classification markers",
|
|
97
|
+
description: "Data models containing personal information should include data classification metadata to guide handling policies.",
|
|
98
|
+
lineNumbers: dataModelLines,
|
|
99
|
+
recommendation: "Add data classification comments or decorators (e.g., @PII, @Confidential) to help enforce appropriate handling.",
|
|
100
|
+
reference: "Data Classification Best Practices",
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Detect credit card number patterns (PCI DSS)
|
|
104
|
+
const cardNumberLines = [];
|
|
105
|
+
lines.forEach((line, i) => {
|
|
106
|
+
if (/\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})\b/.test(line)) {
|
|
107
|
+
cardNumberLines.push(i + 1);
|
|
108
|
+
}
|
|
109
|
+
if (/credit.?card|card.?number|ccn|pan\b|cardNumber/i.test(line) && !/mask|redact|encrypt|hash|tokenize|\*{4}/i.test(line)) {
|
|
110
|
+
cardNumberLines.push(i + 1);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
if (cardNumberLines.length > 0) {
|
|
114
|
+
findings.push({
|
|
115
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
116
|
+
severity: "critical",
|
|
117
|
+
title: "Credit card data handling detected",
|
|
118
|
+
description: "Credit card numbers must never be stored in plain text. PCI DSS requires tokenization, encryption, or use of a payment processor.",
|
|
119
|
+
lineNumbers: [...new Set(cardNumberLines)],
|
|
120
|
+
recommendation: "Use a PCI-compliant payment processor (Stripe, Braintree). Never store, log, or transmit raw card numbers. Tokenize immediately.",
|
|
121
|
+
reference: "PCI DSS Requirement 3: Protect Stored Cardholder Data",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// Detect HIPAA-relevant health data
|
|
125
|
+
const healthDataLines = [];
|
|
126
|
+
lines.forEach((line, i) => {
|
|
127
|
+
if (/(?:diagnosis|medical_record|health_condition|prescription|treatment|patient_id|medical_history|lab_result)/i.test(line) && !/encrypt|hipaa|protected|phi\b/i.test(line)) {
|
|
128
|
+
healthDataLines.push(i + 1);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
if (healthDataLines.length > 0) {
|
|
132
|
+
findings.push({
|
|
133
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
134
|
+
severity: "critical",
|
|
135
|
+
title: "Protected Health Information without HIPAA safeguards",
|
|
136
|
+
description: "Health-related data fields detected without encryption or HIPAA compliance markers. PHI requires special handling under HIPAA.",
|
|
137
|
+
lineNumbers: healthDataLines,
|
|
138
|
+
recommendation: "Encrypt PHI at rest and in transit. Implement access controls, audit logging, and ensure BAA with cloud providers.",
|
|
139
|
+
reference: "HIPAA Security Rule / 45 CFR Part 164",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Detect right-to-delete / data erasure gaps
|
|
143
|
+
const deleteEndpointExists = /delete.*user|erase.*data|remove.*account|right.?to.?delete|gdpr.*delete|data.?erasure/i.test(code);
|
|
144
|
+
const storesUserData = /(?:save|create|insert)\s*\(.*(?:user|customer|profile|account)/i.test(code);
|
|
145
|
+
if (storesUserData && !deleteEndpointExists) {
|
|
146
|
+
findings.push({
|
|
147
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
148
|
+
severity: "medium",
|
|
149
|
+
title: "No data deletion/erasure capability detected",
|
|
150
|
+
description: "User data is stored but no deletion mechanism exists. GDPR and CCPA require the ability to delete personal data on request.",
|
|
151
|
+
recommendation: "Implement a user data deletion endpoint that cascades across all storage systems (DB, cache, backups, third parties).",
|
|
152
|
+
reference: "GDPR Article 17: Right to Erasure / CCPA Right to Delete",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// Detect cookie handling without SameSite/Secure flags
|
|
156
|
+
const cookieLines = [];
|
|
157
|
+
lines.forEach((line, i) => {
|
|
158
|
+
if (/set-cookie|setCookie|cookie\s*\(/i.test(line) && !/sameSite|secure|httpOnly/i.test(line)) {
|
|
159
|
+
cookieLines.push(i + 1);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
if (cookieLines.length > 0) {
|
|
163
|
+
findings.push({
|
|
164
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
165
|
+
severity: "medium",
|
|
166
|
+
title: "Cookies set without security flags",
|
|
167
|
+
description: "Cookies are set without SameSite, Secure, or HttpOnly flags, which may violate security compliance standards.",
|
|
168
|
+
lineNumbers: cookieLines,
|
|
169
|
+
recommendation: "Set Secure, HttpOnly, and SameSite=Strict on sensitive cookies. Review cookie consent requirements per jurisdiction.",
|
|
170
|
+
reference: "OWASP Cookie Security / ePrivacy Directive",
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Detect age verification gaps
|
|
174
|
+
const ageRelatedLines = [];
|
|
175
|
+
lines.forEach((line, i) => {
|
|
176
|
+
if (/(?:age|date.?of.?birth|dob|birthdate|birth_date|minor|child|under.?13|under.?16|coppa)/i.test(line)) {
|
|
177
|
+
ageRelatedLines.push(i + 1);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
const hasAgeVerification = /age.?verif|age.?check|age.?gate|is.?minor|is.?adult|minimum.?age/i.test(code);
|
|
181
|
+
if (ageRelatedLines.length > 0 && !hasAgeVerification) {
|
|
182
|
+
findings.push({
|
|
183
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
184
|
+
severity: "medium",
|
|
185
|
+
title: "Age-related data without verification mechanism",
|
|
186
|
+
description: "Code references age or date of birth but has no age verification mechanism. COPPA, GDPR (under 16), and other laws require special handling for minors.",
|
|
187
|
+
lineNumbers: ageRelatedLines.slice(0, 5),
|
|
188
|
+
recommendation: "Implement age verification and parental consent flows for users under the applicable age threshold.",
|
|
189
|
+
reference: "COPPA / GDPR Article 8 / Age Appropriate Design Code",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// Detect audit trail gaps for regulated operations
|
|
193
|
+
const regulatedOpLines = [];
|
|
194
|
+
lines.forEach((line, i) => {
|
|
195
|
+
if (/(?:transfer|payment|withdrawal|approve|sign|certify|authorize|attest)\s*[=(]/i.test(line)) {
|
|
196
|
+
regulatedOpLines.push(i + 1);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
const hasAuditTrail = /audit|auditLog|audit_log|audit_trail|compliance_log/i.test(code);
|
|
200
|
+
if (regulatedOpLines.length > 0 && !hasAuditTrail) {
|
|
201
|
+
findings.push({
|
|
202
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
203
|
+
severity: "high",
|
|
204
|
+
title: "Regulated operations without audit trail",
|
|
205
|
+
description: "Financial or approval operations detected without audit logging. SOX, SOC2, and financial regulations require complete audit trails.",
|
|
206
|
+
lineNumbers: regulatedOpLines.slice(0, 5),
|
|
207
|
+
recommendation: "Implement immutable audit logging for all regulated operations. Log who, what, when, and the outcome.",
|
|
208
|
+
reference: "SOX Compliance / SOC2 Trust Criteria",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return findings;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=compliance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/evaluators/compliance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../src/evaluators/concurrency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAqO5E"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
export function analyzeConcurrency(code, language) {
|
|
2
|
+
const findings = [];
|
|
3
|
+
const lines = code.split("\n");
|
|
4
|
+
const prefix = "CONC";
|
|
5
|
+
let ruleNum = 1;
|
|
6
|
+
// Detect unbounded Promise.all
|
|
7
|
+
const promiseAllLines = [];
|
|
8
|
+
lines.forEach((line, i) => {
|
|
9
|
+
if (/Promise\.all\s*\(\s*\w+\.map/i.test(line)) {
|
|
10
|
+
const context = lines.slice(Math.max(0, i - 3), Math.min(lines.length, i + 5)).join("\n");
|
|
11
|
+
if (!/chunk|batch|limit|throttle|pLimit|p-limit|concurrency|pool/i.test(context)) {
|
|
12
|
+
promiseAllLines.push(i + 1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
if (promiseAllLines.length > 0) {
|
|
17
|
+
findings.push({
|
|
18
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
19
|
+
severity: "high",
|
|
20
|
+
title: "Unbounded Promise.all with dynamic array",
|
|
21
|
+
description: "Using Promise.all with a mapped array without concurrency limits can overwhelm resources (database connections, API rate limits, memory).",
|
|
22
|
+
lineNumbers: promiseAllLines,
|
|
23
|
+
recommendation: "Use a concurrency limiter (p-limit, p-map with concurrency option) or batch the operations. Consider Promise.allSettled for fault tolerance.",
|
|
24
|
+
reference: "Node.js Concurrency Patterns",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// Detect shared mutable state
|
|
28
|
+
const globalMutableLines = [];
|
|
29
|
+
const globalVarPattern = /^(?:let|var)\s+\w+\s*=\s*(?:\[|\{|0|""|\d)/i;
|
|
30
|
+
lines.forEach((line, i) => {
|
|
31
|
+
if (globalVarPattern.test(line.trim())) {
|
|
32
|
+
// Check if used in async context
|
|
33
|
+
const restOfFile = lines.slice(i + 1).join("\n");
|
|
34
|
+
const varName = line.trim().match(/(?:let|var)\s+(\w+)/)?.[1];
|
|
35
|
+
if (varName && /async\s|\.then\s*\(/i.test(restOfFile) && new RegExp(`\\b${varName}\\b`).test(restOfFile)) {
|
|
36
|
+
globalMutableLines.push(i + 1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
if (globalMutableLines.length > 0) {
|
|
41
|
+
findings.push({
|
|
42
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
43
|
+
severity: "high",
|
|
44
|
+
title: "Shared mutable state in async context",
|
|
45
|
+
description: "Module-level mutable variables accessed from async functions can cause race conditions and data corruption.",
|
|
46
|
+
lineNumbers: globalMutableLines,
|
|
47
|
+
recommendation: "Use request-scoped/context-scoped state, atomic operations, or proper synchronization mechanisms instead of shared mutable variables.",
|
|
48
|
+
reference: "Concurrency: Shared State Hazards",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Detect missing await
|
|
52
|
+
const missingAwaitLines = [];
|
|
53
|
+
lines.forEach((line, i) => {
|
|
54
|
+
// Detect promise-returning calls without await in async context
|
|
55
|
+
if (/^\s*\w+\.(save|update|delete|insert|remove|send|post|put|fetch)\s*\(/i.test(line) && !/await|return|\.then|\.catch/i.test(line)) {
|
|
56
|
+
// Check if we're in an async function
|
|
57
|
+
const prevCode = lines.slice(Math.max(0, i - 20), i).join("\n");
|
|
58
|
+
if (/async\s+(?:function|\(|=>)/i.test(prevCode)) {
|
|
59
|
+
missingAwaitLines.push(i + 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
if (missingAwaitLines.length > 0) {
|
|
64
|
+
findings.push({
|
|
65
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
66
|
+
severity: "high",
|
|
67
|
+
title: "Potentially missing await on async operation",
|
|
68
|
+
description: "Async operations without await fire-and-forget, meaning errors are silently lost and operations may not complete before the response is sent.",
|
|
69
|
+
lineNumbers: missingAwaitLines,
|
|
70
|
+
recommendation: "Add await to async operations, or explicitly handle the returned promise with .catch(). Use ESLint's no-floating-promises rule.",
|
|
71
|
+
reference: "Async/Await Error Handling",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Detect async operations in loops without understanding of ordering
|
|
75
|
+
const awaitInLoopLines = [];
|
|
76
|
+
lines.forEach((line, i) => {
|
|
77
|
+
if (/for\s*\(|for\s+await|while\s*\(/.test(line)) {
|
|
78
|
+
const loopBody = lines.slice(i + 1, Math.min(lines.length, i + 15)).join("\n");
|
|
79
|
+
const awaitCount = (loopBody.match(/await\s/g) || []).length;
|
|
80
|
+
if (awaitCount > 0) {
|
|
81
|
+
awaitInLoopLines.push(i + 1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
if (awaitInLoopLines.length > 0) {
|
|
86
|
+
findings.push({
|
|
87
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
88
|
+
severity: "medium",
|
|
89
|
+
title: "Sequential await in loop",
|
|
90
|
+
description: "Using await inside a loop processes items sequentially. If operations are independent, this unnecessarily serializes them.",
|
|
91
|
+
lineNumbers: awaitInLoopLines,
|
|
92
|
+
recommendation: "For independent operations, collect promises and use Promise.all() (with concurrency limits). Keep sequential only if order matters.",
|
|
93
|
+
reference: "Async Patterns: Parallel vs Sequential",
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Detect setInterval without cleanup
|
|
97
|
+
const setIntervalLines = [];
|
|
98
|
+
lines.forEach((line, i) => {
|
|
99
|
+
if (/setInterval\s*\(/i.test(line)) {
|
|
100
|
+
setIntervalLines.push(i + 1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const hasClearInterval = /clearInterval/i.test(code);
|
|
104
|
+
if (setIntervalLines.length > 0 && !hasClearInterval) {
|
|
105
|
+
findings.push({
|
|
106
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
107
|
+
severity: "medium",
|
|
108
|
+
title: "setInterval without clearInterval",
|
|
109
|
+
description: "Intervals without cleanup continue running after the component/module is no longer needed, causing memory leaks and unexpected behavior.",
|
|
110
|
+
lineNumbers: setIntervalLines,
|
|
111
|
+
recommendation: "Store the interval ID and call clearInterval in cleanup/unmount/dispose handlers.",
|
|
112
|
+
reference: "Resource Cleanup Patterns",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// Detect race condition patterns with read-modify-write
|
|
116
|
+
const readModifyWriteLines = [];
|
|
117
|
+
lines.forEach((line, i) => {
|
|
118
|
+
if (/await\s+\w+\.(get|find|read|load)\s*\(/i.test(line)) {
|
|
119
|
+
const nextLines = lines.slice(i + 1, Math.min(lines.length, i + 10)).join("\n");
|
|
120
|
+
if (/await\s+\w+\.(save|update|set|write|put)\s*\(/i.test(nextLines)) {
|
|
121
|
+
readModifyWriteLines.push(i + 1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
if (readModifyWriteLines.length > 0) {
|
|
126
|
+
findings.push({
|
|
127
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
128
|
+
severity: "high",
|
|
129
|
+
title: "Potential read-modify-write race condition",
|
|
130
|
+
description: "Reading a value, modifying it, and writing it back without atomicity can cause lost updates when concurrent operations overlap.",
|
|
131
|
+
lineNumbers: readModifyWriteLines,
|
|
132
|
+
recommendation: "Use atomic operations (findOneAndUpdate, INCR), optimistic locking (version field), or database transactions.",
|
|
133
|
+
reference: "Race Conditions / Optimistic Concurrency Control",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Detect worker/thread creation without pool
|
|
137
|
+
const workerLines = [];
|
|
138
|
+
lines.forEach((line, i) => {
|
|
139
|
+
if (/new\s+Worker\s*\(|new\s+Thread\s*\(|threading\.Thread\s*\(|Thread\.start/i.test(line)) {
|
|
140
|
+
workerLines.push(i + 1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
const hasPool = /pool|WorkerPool|ThreadPool|threadpool|ExecutorService/i.test(code);
|
|
144
|
+
if (workerLines.length > 0 && !hasPool) {
|
|
145
|
+
findings.push({
|
|
146
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
147
|
+
severity: "medium",
|
|
148
|
+
title: "Worker/thread creation without pooling",
|
|
149
|
+
description: "Creating new workers or threads per request is expensive and can exhaust system resources under load.",
|
|
150
|
+
lineNumbers: workerLines,
|
|
151
|
+
recommendation: "Use a worker/thread pool with a bounded size. Reuse workers for subsequent tasks.",
|
|
152
|
+
reference: "Thread Pool Pattern / Worker Pools",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// Detect callback-based async mixed with promises
|
|
156
|
+
const mixedAsyncLines = [];
|
|
157
|
+
lines.forEach((line, i) => {
|
|
158
|
+
if (/function\s*\(\s*(?:err|error)\s*,\s*(?:data|result|res)\s*\)/i.test(line)) {
|
|
159
|
+
const context = lines.slice(Math.max(0, i - 10), i).join("\n");
|
|
160
|
+
if (/async\s|Promise|\.then\s*\(/i.test(context)) {
|
|
161
|
+
mixedAsyncLines.push(i + 1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
if (mixedAsyncLines.length > 0) {
|
|
166
|
+
findings.push({
|
|
167
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
168
|
+
severity: "medium",
|
|
169
|
+
title: "Mixed callback and promise async patterns",
|
|
170
|
+
description: "Mixing callbacks with promises/async-await in the same code path is error-prone and makes error handling inconsistent.",
|
|
171
|
+
lineNumbers: mixedAsyncLines,
|
|
172
|
+
recommendation: "Standardize on async/await. Wrap callback-based APIs with util.promisify() or manual Promise wrappers.",
|
|
173
|
+
reference: "Node.js util.promisify / Async Patterns",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// Detect mutex/lock-free concurrent data access
|
|
177
|
+
const concurrentDataLines = [];
|
|
178
|
+
lines.forEach((line, i) => {
|
|
179
|
+
if (/(?:Map|Set|Array|Object)\s*\(\s*\)/i.test(line) && /shared|global|cache|store|registry/i.test(line)) {
|
|
180
|
+
const restOfFile = lines.slice(i + 1).join("\n");
|
|
181
|
+
if (/async\s|Promise|\.then\s*\(/i.test(restOfFile) && !/mutex|lock|semaphore|synchronized|atomic/i.test(restOfFile)) {
|
|
182
|
+
concurrentDataLines.push(i + 1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
if (concurrentDataLines.length > 0) {
|
|
187
|
+
findings.push({
|
|
188
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
189
|
+
severity: "medium",
|
|
190
|
+
title: "Shared data structure without synchronization",
|
|
191
|
+
description: "Data structures labeled as shared/global/cache are used in async contexts without any synchronization mechanism.",
|
|
192
|
+
lineNumbers: concurrentDataLines,
|
|
193
|
+
recommendation: "Use ConcurrentHashMap (Java), Mutex/RWLock (Go/Rust), or atomic operations. In Node.js, consider request-scoped state.",
|
|
194
|
+
reference: "Concurrent Data Access Patterns",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// Detect deadlock-prone patterns (nested locks/awaits)
|
|
198
|
+
const nestedAwaitLines = [];
|
|
199
|
+
lines.forEach((line, i) => {
|
|
200
|
+
if (/await\s+.*lock|acquire\s*\(/i.test(line)) {
|
|
201
|
+
const innerBlock = lines.slice(i + 1, Math.min(lines.length, i + 20)).join("\n");
|
|
202
|
+
if (/await\s+.*lock|acquire\s*\(/i.test(innerBlock)) {
|
|
203
|
+
nestedAwaitLines.push(i + 1);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
if (nestedAwaitLines.length > 0) {
|
|
208
|
+
findings.push({
|
|
209
|
+
ruleId: `${prefix}-${String(ruleNum++).padStart(3, "0")}`,
|
|
210
|
+
severity: "critical",
|
|
211
|
+
title: "Potential deadlock: nested lock acquisition",
|
|
212
|
+
description: "Acquiring locks inside other lock scopes can cause deadlocks when two operations acquire locks in different orders.",
|
|
213
|
+
lineNumbers: nestedAwaitLines,
|
|
214
|
+
recommendation: "Acquire locks in a consistent order, use lock-free algorithms, or use a single coarser lock. Add deadlock detection/timeouts.",
|
|
215
|
+
reference: "Deadlock Prevention / Lock Ordering",
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
return findings;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=concurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/evaluators/concurrency.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-effectiveness.d.ts","sourceRoot":"","sources":["../../src/evaluators/cost-effectiveness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAyNlF"}
|