@kevinrabun/judges 3.57.0 → 3.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/api-misuse.d.ts +5 -0
- package/dist/commands/api-misuse.d.ts.map +1 -0
- package/dist/commands/api-misuse.js +261 -0
- package/dist/commands/api-misuse.js.map +1 -0
- package/dist/commands/assertion-density.d.ts +5 -0
- package/dist/commands/assertion-density.d.ts.map +1 -0
- package/dist/commands/assertion-density.js +264 -0
- package/dist/commands/assertion-density.js.map +1 -0
- package/dist/commands/async-safety.d.ts +5 -0
- package/dist/commands/async-safety.d.ts.map +1 -0
- package/dist/commands/async-safety.js +267 -0
- package/dist/commands/async-safety.js.map +1 -0
- package/dist/commands/clone-detect.d.ts +5 -0
- package/dist/commands/clone-detect.d.ts.map +1 -0
- package/dist/commands/clone-detect.js +233 -0
- package/dist/commands/clone-detect.js.map +1 -0
- package/dist/commands/completion-audit.d.ts +5 -0
- package/dist/commands/completion-audit.d.ts.map +1 -0
- package/dist/commands/completion-audit.js +297 -0
- package/dist/commands/completion-audit.js.map +1 -0
- package/dist/commands/contract-verify.d.ts +5 -0
- package/dist/commands/contract-verify.d.ts.map +1 -0
- package/dist/commands/contract-verify.js +317 -0
- package/dist/commands/contract-verify.js.map +1 -0
- package/dist/commands/cross-file-consistency.d.ts +5 -0
- package/dist/commands/cross-file-consistency.d.ts.map +1 -0
- package/dist/commands/cross-file-consistency.js +255 -0
- package/dist/commands/cross-file-consistency.js.map +1 -0
- package/dist/commands/dead-code-detect.d.ts +5 -0
- package/dist/commands/dead-code-detect.d.ts.map +1 -0
- package/dist/commands/dead-code-detect.js +256 -0
- package/dist/commands/dead-code-detect.js.map +1 -0
- package/dist/commands/encoding-safety.d.ts +5 -0
- package/dist/commands/encoding-safety.d.ts.map +1 -0
- package/dist/commands/encoding-safety.js +276 -0
- package/dist/commands/encoding-safety.js.map +1 -0
- package/dist/commands/example-leak.d.ts +5 -0
- package/dist/commands/example-leak.d.ts.map +1 -0
- package/dist/commands/example-leak.js +233 -0
- package/dist/commands/example-leak.js.map +1 -0
- package/dist/commands/input-guard.d.ts +5 -0
- package/dist/commands/input-guard.d.ts.map +1 -0
- package/dist/commands/input-guard.js +256 -0
- package/dist/commands/input-guard.js.map +1 -0
- package/dist/commands/logic-lint.d.ts +5 -0
- package/dist/commands/logic-lint.d.ts.map +1 -0
- package/dist/commands/logic-lint.js +256 -0
- package/dist/commands/logic-lint.js.map +1 -0
- package/dist/commands/phantom-import.d.ts +5 -0
- package/dist/commands/phantom-import.d.ts.map +1 -0
- package/dist/commands/phantom-import.js +261 -0
- package/dist/commands/phantom-import.js.map +1 -0
- package/dist/commands/review-focus.d.ts +5 -0
- package/dist/commands/review-focus.d.ts.map +1 -0
- package/dist/commands/review-focus.js +197 -0
- package/dist/commands/review-focus.js.map +1 -0
- package/dist/commands/spec-conform.d.ts +5 -0
- package/dist/commands/spec-conform.d.ts.map +1 -0
- package/dist/commands/spec-conform.js +305 -0
- package/dist/commands/spec-conform.js.map +1 -0
- package/dist/commands/state-integrity.d.ts +5 -0
- package/dist/commands/state-integrity.d.ts.map +1 -0
- package/dist/commands/state-integrity.js +284 -0
- package/dist/commands/state-integrity.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input guard — verify all system entry points have proper input validation.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
5
|
+
import { join, extname } from "path";
|
|
6
|
+
// ─── File Collection ────────────────────────────────────────────────────────
|
|
7
|
+
const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go"]);
|
|
8
|
+
function collectFiles(dir, max = 300) {
|
|
9
|
+
const files = [];
|
|
10
|
+
function walk(d) {
|
|
11
|
+
if (files.length >= max)
|
|
12
|
+
return;
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = readdirSync(d);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
for (const e of entries) {
|
|
21
|
+
if (files.length >= max)
|
|
22
|
+
return;
|
|
23
|
+
if (e.startsWith(".") || e === "node_modules" || e === "dist" || e === "build")
|
|
24
|
+
continue;
|
|
25
|
+
const full = join(d, e);
|
|
26
|
+
try {
|
|
27
|
+
if (statSync(full).isDirectory())
|
|
28
|
+
walk(full);
|
|
29
|
+
else if (CODE_EXTS.has(extname(full)))
|
|
30
|
+
files.push(full);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* skip */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
walk(dir);
|
|
38
|
+
return files;
|
|
39
|
+
}
|
|
40
|
+
// ─── Analysis ───────────────────────────────────────────────────────────────
|
|
41
|
+
function analyzeFile(filepath) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
let content;
|
|
44
|
+
try {
|
|
45
|
+
content = readFileSync(filepath, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return issues;
|
|
49
|
+
}
|
|
50
|
+
const lines = content.split("\n");
|
|
51
|
+
const fullText = content;
|
|
52
|
+
for (let i = 0; i < lines.length; i++) {
|
|
53
|
+
const line = lines[i];
|
|
54
|
+
// Route handler without validation
|
|
55
|
+
if (/(?:router|app)\.\s*(?:get|post|put|delete|patch)\s*\(\s*['"]/.test(line)) {
|
|
56
|
+
const handlerBlock = lines.slice(i, Math.min(i + 20, lines.length)).join("\n");
|
|
57
|
+
if (/req\.body|req\.params|req\.query/i.test(handlerBlock)) {
|
|
58
|
+
if (!/zod|joi|yup|ajv|class-validator|validate|schema|express-validator|celebrate|superstruct/i.test(handlerBlock)) {
|
|
59
|
+
issues.push({
|
|
60
|
+
file: filepath,
|
|
61
|
+
line: i + 1,
|
|
62
|
+
issue: "Route handler without input validation",
|
|
63
|
+
severity: "high",
|
|
64
|
+
detail: "Request body/params/query used without validation library — vulnerable to injection and type confusion",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Direct req.body property access without checking
|
|
70
|
+
if (/req\.body\.(\w+)/.test(line) || /request\.body\.(\w+)/.test(line)) {
|
|
71
|
+
const prop = line.match(/(?:req|request)\.body\.(\w+)/)?.[1];
|
|
72
|
+
const block = lines.slice(Math.max(0, i - 3), Math.min(i + 3, lines.length)).join("\n");
|
|
73
|
+
if (!/typeof|instanceof|validate|schema|zod|joi|if\s*\(|assert|guard|check/i.test(block)) {
|
|
74
|
+
issues.push({
|
|
75
|
+
file: filepath,
|
|
76
|
+
line: i + 1,
|
|
77
|
+
issue: "Direct request body access without type check",
|
|
78
|
+
severity: "medium",
|
|
79
|
+
detail: `\`req.body.${prop}\` accessed without type validation — may be undefined, wrong type, or malicious`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// SQL query with string interpolation
|
|
84
|
+
if (/`[^`]*\$\{.*req\.|`[^`]*\$\{.*params\.|`[^`]*\$\{.*query\./i.test(line)) {
|
|
85
|
+
if (/SELECT|INSERT|UPDATE|DELETE|FROM|WHERE/i.test(line)) {
|
|
86
|
+
issues.push({
|
|
87
|
+
file: filepath,
|
|
88
|
+
line: i + 1,
|
|
89
|
+
issue: "SQL query with string interpolation from user input",
|
|
90
|
+
severity: "high",
|
|
91
|
+
detail: "User input interpolated into SQL — use parameterized queries to prevent SQL injection",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Command injection risk
|
|
96
|
+
if (/exec\s*\(|execSync\s*\(|spawn\s*\(|child_process/i.test(line)) {
|
|
97
|
+
if (/req\.|params\.|query\.|body\.|user.*input|args\[/i.test(line)) {
|
|
98
|
+
issues.push({
|
|
99
|
+
file: filepath,
|
|
100
|
+
line: i + 1,
|
|
101
|
+
issue: "User input in shell command",
|
|
102
|
+
severity: "high",
|
|
103
|
+
detail: "User-supplied data passed to shell execution — command injection risk",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Missing Content-Type check on POST/PUT
|
|
108
|
+
if (/(?:app|router)\.\s*(?:post|put|patch)\s*\(/.test(line)) {
|
|
109
|
+
const handlerBlock = lines.slice(i, Math.min(i + 15, lines.length)).join("\n");
|
|
110
|
+
if (/req\.body/i.test(handlerBlock) &&
|
|
111
|
+
!/content-type|bodyParser|express\.json|express\.urlencoded|multer/i.test(fullText)) {
|
|
112
|
+
issues.push({
|
|
113
|
+
file: filepath,
|
|
114
|
+
line: i + 1,
|
|
115
|
+
issue: "POST handler without body parser",
|
|
116
|
+
severity: "medium",
|
|
117
|
+
detail: "Handler reads req.body but no body parser middleware detected — body may be undefined",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// GraphQL resolver without input validation
|
|
122
|
+
if (/(?:resolve|resolver)\s*[:(]/.test(line) && /graphql|gql|typeDefs|schema/i.test(fullText)) {
|
|
123
|
+
const block = lines.slice(i, Math.min(i + 15, lines.length)).join("\n");
|
|
124
|
+
if (/args\.\w+|input\.\w+/i.test(block) && !/validate|schema|zod|joi|check|guard|assert/i.test(block)) {
|
|
125
|
+
issues.push({
|
|
126
|
+
file: filepath,
|
|
127
|
+
line: i + 1,
|
|
128
|
+
issue: "GraphQL resolver without input validation",
|
|
129
|
+
severity: "medium",
|
|
130
|
+
detail: "Resolver uses args/input without validation — GraphQL types alone don't prevent malicious values",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// File upload without size/type check
|
|
135
|
+
if (/multer|upload|req\.file|req\.files/i.test(line)) {
|
|
136
|
+
const block = lines.slice(i, Math.min(i + 10, lines.length)).join("\n");
|
|
137
|
+
if (!/limits|fileSize|maxSize|fileFilter|mimetype|accept/i.test(block)) {
|
|
138
|
+
issues.push({
|
|
139
|
+
file: filepath,
|
|
140
|
+
line: i + 1,
|
|
141
|
+
issue: "File upload without size/type restrictions",
|
|
142
|
+
severity: "high",
|
|
143
|
+
detail: "File upload handler lacks size limits or type filtering — DoS and malicious upload risk",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// parseInt/Number without bounds check
|
|
148
|
+
if (/parseInt\s*\(\s*(?:req|params|query|body)\.|Number\s*\(\s*(?:req|params|query|body)\./i.test(line)) {
|
|
149
|
+
const block = lines.slice(i, Math.min(i + 5, lines.length)).join("\n");
|
|
150
|
+
if (!/isNaN|isFinite|Math\.min|Math\.max|clamp|>=|<=|>|</i.test(block)) {
|
|
151
|
+
issues.push({
|
|
152
|
+
file: filepath,
|
|
153
|
+
line: i + 1,
|
|
154
|
+
issue: "Numeric input without bounds check",
|
|
155
|
+
severity: "medium",
|
|
156
|
+
detail: "User input parsed to number without NaN or range check — can cause unexpected behavior",
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Regex from user input (ReDoS risk)
|
|
161
|
+
if (/new RegExp\s*\(\s*(?:req|params|query|body|input|user)/i.test(line)) {
|
|
162
|
+
issues.push({
|
|
163
|
+
file: filepath,
|
|
164
|
+
line: i + 1,
|
|
165
|
+
issue: "Regex from user input",
|
|
166
|
+
severity: "high",
|
|
167
|
+
detail: "User-supplied value used as regex pattern — ReDoS (Regular Expression Denial of Service) risk",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// URL/redirect without validation
|
|
171
|
+
if (/(?:redirect|location)\s*[:=]\s*(?:req|params|query|body)\./i.test(line) ||
|
|
172
|
+
/res\.redirect\s*\(\s*(?:req|params)/i.test(line)) {
|
|
173
|
+
const block = lines.slice(i, Math.min(i + 5, lines.length)).join("\n");
|
|
174
|
+
if (!/whitelist|allowedUrls|allowedDomains|startsWith|URL\(|validateUrl|safeRedirect/i.test(block)) {
|
|
175
|
+
issues.push({
|
|
176
|
+
file: filepath,
|
|
177
|
+
line: i + 1,
|
|
178
|
+
issue: "Open redirect from user input",
|
|
179
|
+
severity: "high",
|
|
180
|
+
detail: "Redirect URL from user input without domain validation — open redirect vulnerability",
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Array length from user input
|
|
185
|
+
if (/\.length\s*[<>=].*(?:req|params|query|limit|offset|page)/i.test(line) ||
|
|
186
|
+
/(?:limit|offset|page|size)\s*=.*(?:req|params|query)/i.test(line)) {
|
|
187
|
+
const block = lines.slice(i, Math.min(i + 5, lines.length)).join("\n");
|
|
188
|
+
if (!/Math\.min|clamp|MAX_|LIMIT|maxResults|<=\s*\d+/i.test(block)) {
|
|
189
|
+
issues.push({
|
|
190
|
+
file: filepath,
|
|
191
|
+
line: i + 1,
|
|
192
|
+
issue: "Unbounded pagination parameter",
|
|
193
|
+
severity: "medium",
|
|
194
|
+
detail: "Pagination parameter from user input without upper bound — can request excessive data",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return issues;
|
|
200
|
+
}
|
|
201
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
202
|
+
export function runInputGuard(argv) {
|
|
203
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
204
|
+
console.log(`
|
|
205
|
+
judges input-guard — Verify entry points have proper input validation
|
|
206
|
+
|
|
207
|
+
Usage:
|
|
208
|
+
judges input-guard [dir]
|
|
209
|
+
judges input-guard src/ --format json
|
|
210
|
+
|
|
211
|
+
Options:
|
|
212
|
+
[dir] Directory to scan (default: .)
|
|
213
|
+
--format json JSON output
|
|
214
|
+
--help, -h Show this help
|
|
215
|
+
|
|
216
|
+
Checks: route handlers without validation, SQL injection, command injection, missing body parsers,
|
|
217
|
+
file upload limits, numeric bounds, ReDoS from user regex, open redirects, unbounded pagination.
|
|
218
|
+
`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
222
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
223
|
+
const files = collectFiles(dir);
|
|
224
|
+
const allIssues = [];
|
|
225
|
+
for (const f of files)
|
|
226
|
+
allIssues.push(...analyzeFile(f));
|
|
227
|
+
const highCount = allIssues.filter((i) => i.severity === "high").length;
|
|
228
|
+
const medCount = allIssues.filter((i) => i.severity === "medium").length;
|
|
229
|
+
const score = Math.max(0, 100 - highCount * 10 - medCount * 4);
|
|
230
|
+
if (format === "json") {
|
|
231
|
+
console.log(JSON.stringify({
|
|
232
|
+
issues: allIssues,
|
|
233
|
+
score,
|
|
234
|
+
summary: { high: highCount, medium: medCount, total: allIssues.length },
|
|
235
|
+
timestamp: new Date().toISOString(),
|
|
236
|
+
}, null, 2));
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
const badge = score >= 80 ? "✅ GUARDED" : score >= 50 ? "⚠️ POROUS" : "❌ EXPOSED";
|
|
240
|
+
console.log(`\n Input Safety: ${badge} (${score}/100)\n ─────────────────────────────`);
|
|
241
|
+
if (allIssues.length === 0) {
|
|
242
|
+
console.log(" No input validation issues detected.\n");
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
for (const issue of allIssues.slice(0, 25)) {
|
|
246
|
+
const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
|
|
247
|
+
console.log(` ${icon} ${issue.issue}`);
|
|
248
|
+
console.log(` ${issue.file}:${issue.line}`);
|
|
249
|
+
console.log(` ${issue.detail}`);
|
|
250
|
+
}
|
|
251
|
+
if (allIssues.length > 25)
|
|
252
|
+
console.log(` ... and ${allIssues.length - 25} more`);
|
|
253
|
+
console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=input-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-guard.js","sourceRoot":"","sources":["../../src/commands/input-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logic-lint.d.ts","sourceRoot":"","sources":["../../src/commands/logic-lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmOH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6DjD"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logic lint — detect common logic errors that AI code generators produce.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
5
|
+
import { join, extname } from "path";
|
|
6
|
+
// ─── File Collection ────────────────────────────────────────────────────────
|
|
7
|
+
const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go", ".rs", ".cs"]);
|
|
8
|
+
function collectFiles(dir, max = 300) {
|
|
9
|
+
const files = [];
|
|
10
|
+
function walk(d) {
|
|
11
|
+
if (files.length >= max)
|
|
12
|
+
return;
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = readdirSync(d);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
for (const e of entries) {
|
|
21
|
+
if (files.length >= max)
|
|
22
|
+
return;
|
|
23
|
+
if (e.startsWith(".") || e === "node_modules" || e === "dist" || e === "build")
|
|
24
|
+
continue;
|
|
25
|
+
const full = join(d, e);
|
|
26
|
+
try {
|
|
27
|
+
if (statSync(full).isDirectory())
|
|
28
|
+
walk(full);
|
|
29
|
+
else if (CODE_EXTS.has(extname(full)))
|
|
30
|
+
files.push(full);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* skip */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
walk(dir);
|
|
38
|
+
return files;
|
|
39
|
+
}
|
|
40
|
+
// ─── Analysis ───────────────────────────────────────────────────────────────
|
|
41
|
+
function analyzeFile(filepath) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
let content;
|
|
44
|
+
try {
|
|
45
|
+
content = readFileSync(filepath, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return issues;
|
|
49
|
+
}
|
|
50
|
+
const lines = content.split("\n");
|
|
51
|
+
for (let i = 0; i < lines.length; i++) {
|
|
52
|
+
const line = lines[i];
|
|
53
|
+
const trimmed = line.trim();
|
|
54
|
+
// Tautological comparison: x === x, x !== x
|
|
55
|
+
if (/(\w+)\s*===\s*\1(?!\w)/.test(trimmed) || /(\w+)\s*!==\s*\1(?!\w)/.test(trimmed)) {
|
|
56
|
+
const match = trimmed.match(/(\w+)\s*[!=]==\s*\1(?!\w)/);
|
|
57
|
+
if (match && match[1] !== "NaN") {
|
|
58
|
+
issues.push({
|
|
59
|
+
file: filepath,
|
|
60
|
+
line: i + 1,
|
|
61
|
+
issue: "Tautological comparison",
|
|
62
|
+
severity: "high",
|
|
63
|
+
detail: `\`${match[1]}\` compared to itself — always true (===) or always false (!==)`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Assignment in condition (single = in if/while)
|
|
68
|
+
if (/(?:if|while)\s*\(\s*[^=!<>]*[^=!<>]=[^=]/.test(trimmed) &&
|
|
69
|
+
!/==|!=|<=|>=/.test(trimmed.replace(/=[^=]/, "XX"))) {
|
|
70
|
+
if (!/===|!==/.test(trimmed)) {
|
|
71
|
+
issues.push({
|
|
72
|
+
file: filepath,
|
|
73
|
+
line: i + 1,
|
|
74
|
+
issue: "Assignment in condition",
|
|
75
|
+
severity: "high",
|
|
76
|
+
detail: "Single `=` in if/while condition — likely meant `===` or `==`",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Unreachable code after return/throw/break/continue
|
|
81
|
+
if (/^\s*(?:return|throw|break|continue)\b/.test(trimmed) && !trimmed.endsWith("{")) {
|
|
82
|
+
const nextLine = (lines[i + 1] || "").trim();
|
|
83
|
+
if (nextLine &&
|
|
84
|
+
nextLine !== "}" &&
|
|
85
|
+
nextLine !== "}" &&
|
|
86
|
+
!/^\s*(?:case|default|\/\/|\/\*|\*|else|catch|finally)/.test(nextLine)) {
|
|
87
|
+
issues.push({
|
|
88
|
+
file: filepath,
|
|
89
|
+
line: i + 2,
|
|
90
|
+
issue: "Unreachable code after flow control",
|
|
91
|
+
severity: "medium",
|
|
92
|
+
detail: "Code after return/throw/break/continue is never executed",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Off-by-one: <= array.length in loop (should be <)
|
|
97
|
+
if (/for\s*\([^;]*;\s*\w+\s*<=\s*\w+\.length\s*;/.test(trimmed)) {
|
|
98
|
+
issues.push({
|
|
99
|
+
file: filepath,
|
|
100
|
+
line: i + 1,
|
|
101
|
+
issue: "Off-by-one in loop bound",
|
|
102
|
+
severity: "high",
|
|
103
|
+
detail: "`<= .length` iterates one past the end — use `< .length`",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Constant condition in if/while
|
|
107
|
+
if (/(?:if|while)\s*\(\s*(?:true|false|1|0|null|undefined)\s*\)/.test(trimmed)) {
|
|
108
|
+
if (!/while\s*\(\s*true\s*\)/.test(trimmed)) {
|
|
109
|
+
issues.push({
|
|
110
|
+
file: filepath,
|
|
111
|
+
line: i + 1,
|
|
112
|
+
issue: "Constant condition",
|
|
113
|
+
severity: "medium",
|
|
114
|
+
detail: "Condition is always true or always false — branch is never taken or always taken",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Inverted null check: if (x) { x = ... } vs if (!x) { x = ... }
|
|
119
|
+
if (/if\s*\(\s*(\w+)\s*\)\s*\{/.test(trimmed)) {
|
|
120
|
+
const varName = trimmed.match(/if\s*\(\s*(\w+)\s*\)/)?.[1];
|
|
121
|
+
const nextLines = lines.slice(i + 1, Math.min(i + 3, lines.length)).join("\n");
|
|
122
|
+
if (varName && new RegExp(`${varName}\\s*=\\s*(?:null|undefined|"")`).test(nextLines)) {
|
|
123
|
+
issues.push({
|
|
124
|
+
file: filepath,
|
|
125
|
+
line: i + 1,
|
|
126
|
+
issue: "Likely inverted null check",
|
|
127
|
+
severity: "medium",
|
|
128
|
+
detail: `Checking \`${varName}\` is truthy then setting it to null — did you mean \`!${varName}\`?`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Mismatched operator precedence: a && b || c (missing parentheses)
|
|
133
|
+
if (/\w+\s*&&\s*\w+\s*\|\|\s*\w+/.test(trimmed) && !trimmed.includes("(")) {
|
|
134
|
+
issues.push({
|
|
135
|
+
file: filepath,
|
|
136
|
+
line: i + 1,
|
|
137
|
+
issue: "Ambiguous operator precedence",
|
|
138
|
+
severity: "low",
|
|
139
|
+
detail: "`&&` and `||` mixed without parentheses — intention is unclear",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Empty catch block
|
|
143
|
+
if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(trimmed)) {
|
|
144
|
+
issues.push({
|
|
145
|
+
file: filepath,
|
|
146
|
+
line: i + 1,
|
|
147
|
+
issue: "Empty catch block",
|
|
148
|
+
severity: "medium",
|
|
149
|
+
detail: "Errors silently swallowed — at minimum log the error",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// typeof compared to wrong string
|
|
153
|
+
if (/typeof\s+\w+\s*===?\s*['"]/.test(trimmed)) {
|
|
154
|
+
const typeVal = trimmed.match(/typeof\s+\w+\s*===?\s*['"]([\w]+)['"]/)?.[1];
|
|
155
|
+
const validTypes = new Set([
|
|
156
|
+
"string",
|
|
157
|
+
"number",
|
|
158
|
+
"boolean",
|
|
159
|
+
"object",
|
|
160
|
+
"function",
|
|
161
|
+
"undefined",
|
|
162
|
+
"symbol",
|
|
163
|
+
"bigint",
|
|
164
|
+
]);
|
|
165
|
+
if (typeVal && !validTypes.has(typeVal)) {
|
|
166
|
+
issues.push({
|
|
167
|
+
file: filepath,
|
|
168
|
+
line: i + 1,
|
|
169
|
+
issue: "Invalid typeof comparison",
|
|
170
|
+
severity: "high",
|
|
171
|
+
detail: `typeof never returns "${typeVal}" — valid values: ${[...validTypes].join(", ")}`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Doubled negation logic: !!x === false or !(!x)
|
|
176
|
+
if (/!!\w+\s*===?\s*false/.test(trimmed) || /!\s*\(\s*!\s*\w+\s*\)/.test(trimmed)) {
|
|
177
|
+
issues.push({
|
|
178
|
+
file: filepath,
|
|
179
|
+
line: i + 1,
|
|
180
|
+
issue: "Redundant double negation",
|
|
181
|
+
severity: "low",
|
|
182
|
+
detail: "Double negation with false comparison — simplify the expression",
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Floating point equality
|
|
186
|
+
if (/(?:===?|!==?)\s*(?:\d+\.\d+|Math\.\w+)/.test(trimmed) && !/\.length|\.size|\.count|\.index/.test(trimmed)) {
|
|
187
|
+
if (/\d+\.\d+/.test(trimmed)) {
|
|
188
|
+
issues.push({
|
|
189
|
+
file: filepath,
|
|
190
|
+
line: i + 1,
|
|
191
|
+
issue: "Floating-point equality",
|
|
192
|
+
severity: "medium",
|
|
193
|
+
detail: "Exact equality with floating-point values is unreliable — use tolerance comparison (Math.abs(a-b) < epsilon)",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return issues;
|
|
199
|
+
}
|
|
200
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
201
|
+
export function runLogicLint(argv) {
|
|
202
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
203
|
+
console.log(`
|
|
204
|
+
judges logic-lint — Detect common logic errors in AI-generated code
|
|
205
|
+
|
|
206
|
+
Usage:
|
|
207
|
+
judges logic-lint [dir]
|
|
208
|
+
judges logic-lint src/ --format json
|
|
209
|
+
|
|
210
|
+
Options:
|
|
211
|
+
[dir] Directory to scan (default: .)
|
|
212
|
+
--format json JSON output
|
|
213
|
+
--help, -h Show this help
|
|
214
|
+
|
|
215
|
+
Checks: tautological comparisons, assignment in conditions, off-by-one loops,
|
|
216
|
+
unreachable code, constant conditions, inverted null checks, ambiguous precedence,
|
|
217
|
+
empty catch blocks, invalid typeof, floating-point equality.
|
|
218
|
+
`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
222
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
223
|
+
const files = collectFiles(dir);
|
|
224
|
+
const allIssues = [];
|
|
225
|
+
for (const f of files)
|
|
226
|
+
allIssues.push(...analyzeFile(f));
|
|
227
|
+
const highCount = allIssues.filter((i) => i.severity === "high").length;
|
|
228
|
+
const medCount = allIssues.filter((i) => i.severity === "medium").length;
|
|
229
|
+
const score = Math.max(0, 100 - highCount * 12 - medCount * 5);
|
|
230
|
+
if (format === "json") {
|
|
231
|
+
console.log(JSON.stringify({
|
|
232
|
+
issues: allIssues,
|
|
233
|
+
score,
|
|
234
|
+
summary: { high: highCount, medium: medCount, total: allIssues.length },
|
|
235
|
+
timestamp: new Date().toISOString(),
|
|
236
|
+
}, null, 2));
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
const badge = score >= 80 ? "✅ CLEAN" : score >= 50 ? "⚠️ SUSPECT" : "❌ BUGGY";
|
|
240
|
+
console.log(`\n Logic Lint: ${badge} (${score}/100)\n ─────────────────────────────`);
|
|
241
|
+
if (allIssues.length === 0) {
|
|
242
|
+
console.log(" No logic issues detected.\n");
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
for (const issue of allIssues.slice(0, 25)) {
|
|
246
|
+
const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
|
|
247
|
+
console.log(` ${icon} ${issue.issue}`);
|
|
248
|
+
console.log(` ${issue.file}:${issue.line}`);
|
|
249
|
+
console.log(` ${issue.detail}`);
|
|
250
|
+
}
|
|
251
|
+
if (allIssues.length > 25)
|
|
252
|
+
console.log(` ... and ${allIssues.length - 25} more`);
|
|
253
|
+
console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=logic-lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logic-lint.js","sourceRoot":"","sources":["../../src/commands/logic-lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phantom-import.d.ts","sourceRoot":"","sources":["../../src/commands/phantom-import.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8NH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8DrD"}
|