@kevinrabun/judges 3.49.0 → 3.51.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/ai-gate.d.ts +8 -0
- package/dist/commands/ai-gate.d.ts.map +1 -0
- package/dist/commands/ai-gate.js +213 -0
- package/dist/commands/ai-gate.js.map +1 -0
- package/dist/commands/ai-output-compare.d.ts +9 -0
- package/dist/commands/ai-output-compare.d.ts.map +1 -0
- package/dist/commands/ai-output-compare.js +203 -0
- package/dist/commands/ai-output-compare.js.map +1 -0
- package/dist/commands/ai-pattern-trend.d.ts +9 -0
- package/dist/commands/ai-pattern-trend.d.ts.map +1 -0
- package/dist/commands/ai-pattern-trend.js +224 -0
- package/dist/commands/ai-pattern-trend.js.map +1 -0
- package/dist/commands/api-audit.d.ts +9 -0
- package/dist/commands/api-audit.d.ts.map +1 -0
- package/dist/commands/api-audit.js +360 -0
- package/dist/commands/api-audit.js.map +1 -0
- package/dist/commands/arch-audit.d.ts +9 -0
- package/dist/commands/arch-audit.d.ts.map +1 -0
- package/dist/commands/arch-audit.js +284 -0
- package/dist/commands/arch-audit.js.map +1 -0
- package/dist/commands/clarity-score.d.ts +9 -0
- package/dist/commands/clarity-score.d.ts.map +1 -0
- package/dist/commands/clarity-score.js +261 -0
- package/dist/commands/clarity-score.js.map +1 -0
- package/dist/commands/compliance-map.d.ts +9 -0
- package/dist/commands/compliance-map.d.ts.map +1 -0
- package/dist/commands/compliance-map.js +375 -0
- package/dist/commands/compliance-map.js.map +1 -0
- package/dist/commands/exec-report.d.ts +9 -0
- package/dist/commands/exec-report.d.ts.map +1 -0
- package/dist/commands/exec-report.js +272 -0
- package/dist/commands/exec-report.js.map +1 -0
- package/dist/commands/guided-tour.d.ts +9 -0
- package/dist/commands/guided-tour.d.ts.map +1 -0
- package/dist/commands/guided-tour.js +288 -0
- package/dist/commands/guided-tour.js.map +1 -0
- package/dist/commands/hallucination-score.d.ts +9 -0
- package/dist/commands/hallucination-score.d.ts.map +1 -0
- package/dist/commands/hallucination-score.js +317 -0
- package/dist/commands/hallucination-score.js.map +1 -0
- package/dist/commands/iac-lint.d.ts +8 -0
- package/dist/commands/iac-lint.d.ts.map +1 -0
- package/dist/commands/iac-lint.js +313 -0
- package/dist/commands/iac-lint.js.map +1 -0
- package/dist/commands/perf-compare.d.ts +9 -0
- package/dist/commands/perf-compare.d.ts.map +1 -0
- package/dist/commands/perf-compare.js +246 -0
- package/dist/commands/perf-compare.js.map +1 -0
- package/dist/commands/pii-scan.d.ts +8 -0
- package/dist/commands/pii-scan.d.ts.map +1 -0
- package/dist/commands/pii-scan.js +300 -0
- package/dist/commands/pii-scan.js.map +1 -0
- package/dist/commands/secret-scan.d.ts +8 -0
- package/dist/commands/secret-scan.d.ts.map +1 -0
- package/dist/commands/secret-scan.js +245 -0
- package/dist/commands/secret-scan.js.map +1 -0
- package/dist/commands/test-suggest.d.ts +9 -0
- package/dist/commands/test-suggest.d.ts.map +1 -0
- package/dist/commands/test-suggest.js +248 -0
- package/dist/commands/test-suggest.js.map +1 -0
- package/dist/commands/vendor-lock-detect.d.ts +8 -0
- package/dist/commands/vendor-lock-detect.d.ts.map +1 -0
- package/dist/commands/vendor-lock-detect.js +289 -0
- package/dist/commands/vendor-lock-detect.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret scan — entropy-based and regex-based secret detection
|
|
3
|
+
* in source files. Optimized for CI gates and pre-commit hooks.
|
|
4
|
+
*
|
|
5
|
+
* All analysis local — no external services.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } from "fs";
|
|
8
|
+
import { join, extname } from "path";
|
|
9
|
+
// ─── Patterns ───────────────────────────────────────────────────────────────
|
|
10
|
+
const SECRET_PATTERNS = [
|
|
11
|
+
{ id: "aws-access-key", name: "AWS Access Key", regex: /AKIA[0-9A-Z]{16}/, severity: "critical" },
|
|
12
|
+
{
|
|
13
|
+
id: "aws-secret-key",
|
|
14
|
+
name: "AWS Secret Key",
|
|
15
|
+
regex: /(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\s*[=:]\s*['"]?([A-Za-z0-9/+=]{40})/,
|
|
16
|
+
severity: "critical",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "github-token",
|
|
20
|
+
name: "GitHub Token",
|
|
21
|
+
regex: /ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{82}/,
|
|
22
|
+
severity: "critical",
|
|
23
|
+
},
|
|
24
|
+
{ id: "github-oauth", name: "GitHub OAuth", regex: /gho_[A-Za-z0-9]{36}/, severity: "critical" },
|
|
25
|
+
{
|
|
26
|
+
id: "generic-api-key",
|
|
27
|
+
name: "Generic API Key",
|
|
28
|
+
regex: /(?:api[_-]?key|apikey)\s*[=:]\s*['"]([A-Za-z0-9_-]{20,})['"]/,
|
|
29
|
+
severity: "high",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "generic-secret",
|
|
33
|
+
name: "Generic Secret",
|
|
34
|
+
regex: /(?:secret|password|passwd|pwd)\s*[=:]\s*['"]([^'"]{8,})['"]/,
|
|
35
|
+
severity: "high",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "private-key",
|
|
39
|
+
name: "Private Key",
|
|
40
|
+
regex: /-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/,
|
|
41
|
+
severity: "critical",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "gcp-service-account",
|
|
45
|
+
name: "GCP Service Account",
|
|
46
|
+
regex: /"type"\s*:\s*"service_account"/,
|
|
47
|
+
severity: "critical",
|
|
48
|
+
},
|
|
49
|
+
{ id: "stripe-key", name: "Stripe API Key", regex: /sk_live_[A-Za-z0-9]{24,}/, severity: "critical" },
|
|
50
|
+
{ id: "stripe-test", name: "Stripe Test Key", regex: /sk_test_[A-Za-z0-9]{24,}/, severity: "medium" },
|
|
51
|
+
{
|
|
52
|
+
id: "slack-webhook",
|
|
53
|
+
name: "Slack Webhook",
|
|
54
|
+
regex: /hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/,
|
|
55
|
+
severity: "high",
|
|
56
|
+
},
|
|
57
|
+
{ id: "slack-token", name: "Slack Token", regex: /xox[bprs]-[A-Za-z0-9-]+/, severity: "high" },
|
|
58
|
+
{ id: "npm-token", name: "NPM Token", regex: /npm_[A-Za-z0-9]{36}/, severity: "critical" },
|
|
59
|
+
{
|
|
60
|
+
id: "sendgrid-key",
|
|
61
|
+
name: "SendGrid API Key",
|
|
62
|
+
regex: /SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/,
|
|
63
|
+
severity: "critical",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "jwt-token",
|
|
67
|
+
name: "JWT Token",
|
|
68
|
+
regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/,
|
|
69
|
+
severity: "high",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "connection-string",
|
|
73
|
+
name: "Database Connection String",
|
|
74
|
+
regex: /(?:mongodb|postgres|mysql|redis):\/\/[^:]+:[^@]+@[^\s'"]+/,
|
|
75
|
+
severity: "critical",
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
// ─── Scanner ────────────────────────────────────────────────────────────────
|
|
79
|
+
const SKIP_EXTENSIONS = new Set([
|
|
80
|
+
".png",
|
|
81
|
+
".jpg",
|
|
82
|
+
".jpeg",
|
|
83
|
+
".gif",
|
|
84
|
+
".ico",
|
|
85
|
+
".svg",
|
|
86
|
+
".woff",
|
|
87
|
+
".woff2",
|
|
88
|
+
".ttf",
|
|
89
|
+
".eot",
|
|
90
|
+
".zip",
|
|
91
|
+
".tar",
|
|
92
|
+
".gz",
|
|
93
|
+
]);
|
|
94
|
+
const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build", "coverage", ".next"]);
|
|
95
|
+
function collectFiles(dir, maxFiles) {
|
|
96
|
+
const result = [];
|
|
97
|
+
function walk(d) {
|
|
98
|
+
if (result.length >= maxFiles)
|
|
99
|
+
return;
|
|
100
|
+
let entries;
|
|
101
|
+
try {
|
|
102
|
+
entries = readdirSync(d);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
for (const name of entries) {
|
|
108
|
+
if (result.length >= maxFiles)
|
|
109
|
+
return;
|
|
110
|
+
if (SKIP_DIRS.has(name))
|
|
111
|
+
continue;
|
|
112
|
+
const full = join(d, name);
|
|
113
|
+
if (SKIP_EXTENSIONS.has(extname(name)))
|
|
114
|
+
continue;
|
|
115
|
+
try {
|
|
116
|
+
const sub = readdirSync(full);
|
|
117
|
+
void sub;
|
|
118
|
+
walk(full);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
result.push(full);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
walk(dir);
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
function maskSecret(value) {
|
|
129
|
+
if (value.length <= 8)
|
|
130
|
+
return "****";
|
|
131
|
+
return value.substring(0, 4) + "****" + value.substring(value.length - 4);
|
|
132
|
+
}
|
|
133
|
+
function scanFile(filePath) {
|
|
134
|
+
let content;
|
|
135
|
+
try {
|
|
136
|
+
content = readFileSync(filePath, "utf-8");
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
// Skip binary-looking files
|
|
142
|
+
if (content.includes("\0"))
|
|
143
|
+
return [];
|
|
144
|
+
const lines = content.split("\n");
|
|
145
|
+
const findings = [];
|
|
146
|
+
for (let i = 0; i < lines.length; i++) {
|
|
147
|
+
const line = lines[i];
|
|
148
|
+
// Skip comments that are likely documentation
|
|
149
|
+
if (/^\s*(?:\/\/|#|\/\*|\*)\s*(?:example|sample|placeholder|todo|fixme)/i.test(line))
|
|
150
|
+
continue;
|
|
151
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
152
|
+
const match = pattern.regex.exec(line);
|
|
153
|
+
if (match) {
|
|
154
|
+
findings.push({
|
|
155
|
+
file: filePath,
|
|
156
|
+
line: i + 1,
|
|
157
|
+
patternId: pattern.id,
|
|
158
|
+
patternName: pattern.name,
|
|
159
|
+
severity: pattern.severity,
|
|
160
|
+
snippet: line.trim().substring(0, 80),
|
|
161
|
+
masked: maskSecret(match[0]),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return findings;
|
|
167
|
+
}
|
|
168
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
169
|
+
const STORE = ".judges-secret-scan";
|
|
170
|
+
export function runSecretScan(argv) {
|
|
171
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
172
|
+
console.log(`
|
|
173
|
+
judges secret-scan — Detect secrets and credentials in source code
|
|
174
|
+
|
|
175
|
+
Usage:
|
|
176
|
+
judges secret-scan [dir]
|
|
177
|
+
judges secret-scan src/ --severity critical
|
|
178
|
+
judges secret-scan --patterns
|
|
179
|
+
judges secret-scan --save
|
|
180
|
+
|
|
181
|
+
Options:
|
|
182
|
+
--severity <level> Filter by severity (critical, high, medium)
|
|
183
|
+
--patterns List all secret detection patterns
|
|
184
|
+
--save Save report to ${STORE}/
|
|
185
|
+
--format json JSON output
|
|
186
|
+
--help, -h Show this help
|
|
187
|
+
`);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
191
|
+
// List patterns
|
|
192
|
+
if (argv.includes("--patterns")) {
|
|
193
|
+
if (format === "json") {
|
|
194
|
+
console.log(JSON.stringify(SECRET_PATTERNS.map(({ regex: _r, ...rest }) => rest), null, 2));
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
console.log(`\n Secret Patterns (${SECRET_PATTERNS.length})\n ──────────────────────────`);
|
|
198
|
+
for (const p of SECRET_PATTERNS) {
|
|
199
|
+
console.log(` [${p.severity.toUpperCase().padEnd(8)}] ${p.id.padEnd(25)} ${p.name}`);
|
|
200
|
+
}
|
|
201
|
+
console.log("");
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const scanDir = argv.find((a) => !a.startsWith("--") && !argv[argv.indexOf(a) - 1]?.startsWith("--")) || ".";
|
|
206
|
+
const sevFilter = argv.find((_a, i) => argv[i - 1] === "--severity");
|
|
207
|
+
const files = collectFiles(scanDir, 1000);
|
|
208
|
+
let findings = [];
|
|
209
|
+
for (const file of files)
|
|
210
|
+
findings.push(...scanFile(file));
|
|
211
|
+
if (sevFilter)
|
|
212
|
+
findings = findings.filter((f) => f.severity === sevFilter);
|
|
213
|
+
const report = { findings, scannedFiles: files.length, timestamp: new Date().toISOString() };
|
|
214
|
+
if (argv.includes("--save")) {
|
|
215
|
+
if (!existsSync(STORE))
|
|
216
|
+
mkdirSync(STORE, { recursive: true });
|
|
217
|
+
writeFileSync(join(STORE, "secret-report.json"), JSON.stringify(report, null, 2));
|
|
218
|
+
console.log(` Report saved to ${STORE}/secret-report.json`);
|
|
219
|
+
}
|
|
220
|
+
if (format === "json") {
|
|
221
|
+
console.log(JSON.stringify(report, null, 2));
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
console.log(`\n Secret Scan — ${report.scannedFiles} files scanned`);
|
|
225
|
+
console.log(` Found: ${findings.length} potential secrets\n ──────────────────────────`);
|
|
226
|
+
if (findings.length === 0) {
|
|
227
|
+
console.log(` ✅ No secrets detected\n`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
for (const sev of ["critical", "high", "medium"]) {
|
|
231
|
+
const items = findings.filter((f) => f.severity === sev);
|
|
232
|
+
if (items.length === 0)
|
|
233
|
+
continue;
|
|
234
|
+
console.log(`\n ${sev.toUpperCase()} (${items.length})`);
|
|
235
|
+
for (const f of items.slice(0, 10)) {
|
|
236
|
+
console.log(` ${f.file}:${f.line} — ${f.patternName}`);
|
|
237
|
+
console.log(` ${f.masked}`);
|
|
238
|
+
}
|
|
239
|
+
if (items.length > 10)
|
|
240
|
+
console.log(` ... and ${items.length - 10} more`);
|
|
241
|
+
}
|
|
242
|
+
console.log("");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=secret-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scan.js","sourceRoot":"","sources":["../../src/commands/secret-scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test suggest — analyze AI-generated code and suggest specific
|
|
3
|
+
* test scenarios (edge cases, error paths, boundary conditions)
|
|
4
|
+
* that the code likely missed.
|
|
5
|
+
*
|
|
6
|
+
* All analysis local.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runTestSuggest(argv: string[]): void;
|
|
9
|
+
//# sourceMappingURL=test-suggest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-suggest.d.ts","sourceRoot":"","sources":["../../src/commands/test-suggest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA0MH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8FnD"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test suggest — analyze AI-generated code and suggest specific
|
|
3
|
+
* test scenarios (edge cases, error paths, boundary conditions)
|
|
4
|
+
* that the code likely missed.
|
|
5
|
+
*
|
|
6
|
+
* All analysis local.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from "fs";
|
|
9
|
+
// ─── Function extraction ────────────────────────────────────────────────────
|
|
10
|
+
function extractFunctions(content, lines) {
|
|
11
|
+
const functions = [];
|
|
12
|
+
const fnPatterns = [
|
|
13
|
+
/(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g,
|
|
14
|
+
/(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\(([^)]*)\)|(\w+))\s*=>/g,
|
|
15
|
+
/(\w+)\s*\(([^)]*)\)\s*(?::\s*\w+)?\s*{/g,
|
|
16
|
+
];
|
|
17
|
+
for (const pattern of fnPatterns) {
|
|
18
|
+
pattern.lastIndex = 0;
|
|
19
|
+
let m;
|
|
20
|
+
while ((m = pattern.exec(content)) !== null) {
|
|
21
|
+
const lineIdx = content.substring(0, m.index).split("\n").length;
|
|
22
|
+
const name = m[1];
|
|
23
|
+
const params = (m[2] || m[3] || "")
|
|
24
|
+
.split(",")
|
|
25
|
+
.map((p) => p.trim())
|
|
26
|
+
.filter(Boolean);
|
|
27
|
+
// Extract rough function body
|
|
28
|
+
let braceCount = 0;
|
|
29
|
+
let bodyStart = -1;
|
|
30
|
+
let bodyEnd = -1;
|
|
31
|
+
for (let i = lineIdx - 1; i < lines.length; i++) {
|
|
32
|
+
if (lines[i].includes("{") && bodyStart === -1)
|
|
33
|
+
bodyStart = i;
|
|
34
|
+
braceCount += (lines[i].match(/{/g) || []).length;
|
|
35
|
+
braceCount -= (lines[i].match(/}/g) || []).length;
|
|
36
|
+
if (bodyStart !== -1 && braceCount <= 0) {
|
|
37
|
+
bodyEnd = i;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const body = bodyStart >= 0 && bodyEnd >= 0 ? lines.slice(bodyStart, bodyEnd + 1).join("\n") : "";
|
|
42
|
+
const hasReturn = /\breturn\b/.test(body);
|
|
43
|
+
const isAsync = /\basync\b/.test(m[0]);
|
|
44
|
+
functions.push({ name, line: lineIdx, params, hasReturn, isAsync, body });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Deduplicate by name and line
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
return functions.filter((f) => {
|
|
50
|
+
const key = `${f.name}:${f.line}`;
|
|
51
|
+
if (seen.has(key))
|
|
52
|
+
return false;
|
|
53
|
+
seen.add(key);
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// ─── Test suggestion generators ─────────────────────────────────────────────
|
|
58
|
+
function suggestTests(fn, _content) {
|
|
59
|
+
const suggestions = [];
|
|
60
|
+
// 1. Null/undefined parameter tests
|
|
61
|
+
for (const param of fn.params) {
|
|
62
|
+
const paramName = param.split(/[:=]/)[0].trim().replace(/[?!]/g, "");
|
|
63
|
+
if (paramName) {
|
|
64
|
+
suggestions.push({
|
|
65
|
+
category: "Null Input",
|
|
66
|
+
description: `Test ${fn.name}() with ${paramName} = null/undefined`,
|
|
67
|
+
priority: "high",
|
|
68
|
+
targetLine: fn.line,
|
|
69
|
+
testCode: `it("should handle null ${paramName}", () => { expect(() => ${fn.name}(${fn.params.map((p) => (p.split(/[:=]/)[0].trim() === paramName ? "null" : "'valid'")).join(", ")})).not.toThrow(); });`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 2. Empty input tests
|
|
74
|
+
if (fn.params.length > 0) {
|
|
75
|
+
suggestions.push({
|
|
76
|
+
category: "Empty Input",
|
|
77
|
+
description: `Test ${fn.name}() with empty string/array/object inputs`,
|
|
78
|
+
priority: "high",
|
|
79
|
+
targetLine: fn.line,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// 3. Error path tests
|
|
83
|
+
if (/\bthrow\b/.test(fn.body)) {
|
|
84
|
+
suggestions.push({
|
|
85
|
+
category: "Error Path",
|
|
86
|
+
description: `Test error throwing conditions in ${fn.name}()`,
|
|
87
|
+
priority: "high",
|
|
88
|
+
targetLine: fn.line,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// 4. Async error handling
|
|
92
|
+
if (fn.isAsync) {
|
|
93
|
+
suggestions.push({
|
|
94
|
+
category: "Async Error",
|
|
95
|
+
description: `Test ${fn.name}() with rejected promises and timeout scenarios`,
|
|
96
|
+
priority: "high",
|
|
97
|
+
targetLine: fn.line,
|
|
98
|
+
});
|
|
99
|
+
if (/\bawait\b/.test(fn.body) && !/\btry\s*{/.test(fn.body)) {
|
|
100
|
+
suggestions.push({
|
|
101
|
+
category: "Unhandled Rejection",
|
|
102
|
+
description: `${fn.name}() has await without try/catch — test rejection behavior`,
|
|
103
|
+
priority: "high",
|
|
104
|
+
targetLine: fn.line,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// 5. Boundary conditions
|
|
109
|
+
if (/\b(?:length|size|count|index|i|j)\b/.test(fn.body)) {
|
|
110
|
+
suggestions.push({
|
|
111
|
+
category: "Boundary",
|
|
112
|
+
description: `Test ${fn.name}() with boundary values (0, -1, MAX_SAFE_INTEGER, empty collection)`,
|
|
113
|
+
priority: "medium",
|
|
114
|
+
targetLine: fn.line,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// 6. Type coercion
|
|
118
|
+
if (/\b(?:parseInt|parseFloat|Number\(|String\(|\.toString\()/.test(fn.body)) {
|
|
119
|
+
suggestions.push({
|
|
120
|
+
category: "Type Coercion",
|
|
121
|
+
description: `Test ${fn.name}() with unexpected types (NaN, Infinity, "not a number")`,
|
|
122
|
+
priority: "medium",
|
|
123
|
+
targetLine: fn.line,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// 7. Regular expression edge cases
|
|
127
|
+
if (/new\s+RegExp|\/[^/]+\/[gimsuy]*/.test(fn.body)) {
|
|
128
|
+
suggestions.push({
|
|
129
|
+
category: "Regex Edge Case",
|
|
130
|
+
description: `Test ${fn.name}() with regex edge cases (empty string, special characters, very long input)`,
|
|
131
|
+
priority: "medium",
|
|
132
|
+
targetLine: fn.line,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// 8. File/IO operations
|
|
136
|
+
if (/\bread(?:File|dir)|write(?:File)|open|close|exists/.test(fn.body)) {
|
|
137
|
+
suggestions.push({
|
|
138
|
+
category: "File IO",
|
|
139
|
+
description: `Test ${fn.name}() with missing files, permission errors, and empty files`,
|
|
140
|
+
priority: "high",
|
|
141
|
+
targetLine: fn.line,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// 9. State mutation
|
|
145
|
+
if (/\.push\(|\.splice\(|\.pop\(|\.shift\(|delete\s/.test(fn.body)) {
|
|
146
|
+
suggestions.push({
|
|
147
|
+
category: "State Mutation",
|
|
148
|
+
description: `Test ${fn.name}() for unintended side effects on input data`,
|
|
149
|
+
priority: "medium",
|
|
150
|
+
targetLine: fn.line,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// 10. Return value consistency
|
|
154
|
+
if (fn.hasReturn) {
|
|
155
|
+
const returnCount = (fn.body.match(/\breturn\b/g) || []).length;
|
|
156
|
+
if (returnCount > 2) {
|
|
157
|
+
suggestions.push({
|
|
158
|
+
category: "Return Consistency",
|
|
159
|
+
description: `${fn.name}() has ${returnCount} return paths — test each returns consistent type`,
|
|
160
|
+
priority: "medium",
|
|
161
|
+
targetLine: fn.line,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return suggestions;
|
|
166
|
+
}
|
|
167
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
168
|
+
export function runTestSuggest(argv) {
|
|
169
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
170
|
+
console.log(`
|
|
171
|
+
judges test-suggest — Suggest test scenarios for AI-generated code
|
|
172
|
+
|
|
173
|
+
Usage:
|
|
174
|
+
judges test-suggest <file>
|
|
175
|
+
judges test-suggest src/service.ts --priority high
|
|
176
|
+
judges test-suggest handler.js --format json
|
|
177
|
+
|
|
178
|
+
Options:
|
|
179
|
+
--priority <level> Filter by priority (high, medium, low)
|
|
180
|
+
--function <name> Focus on a specific function
|
|
181
|
+
--format json JSON output
|
|
182
|
+
--help, -h Show this help
|
|
183
|
+
|
|
184
|
+
Categories: Null Input, Empty Input, Error Path, Async Error,
|
|
185
|
+
Boundary, Type Coercion, Regex Edge Case, File IO,
|
|
186
|
+
State Mutation, Return Consistency
|
|
187
|
+
`);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
191
|
+
const priorityFilter = argv.find((_a, i) => argv[i - 1] === "--priority");
|
|
192
|
+
const fnFilter = argv.find((_a, i) => argv[i - 1] === "--function");
|
|
193
|
+
const target = argv.find((a) => !a.startsWith("--") && !argv[argv.indexOf(a) - 1]?.startsWith("--"));
|
|
194
|
+
if (!target || !existsSync(target)) {
|
|
195
|
+
console.error(" Please provide a valid source file");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
let content;
|
|
199
|
+
try {
|
|
200
|
+
content = readFileSync(target, "utf-8");
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
console.error(` Cannot read: ${target}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const lines = content.split("\n");
|
|
207
|
+
let functions = extractFunctions(content, lines);
|
|
208
|
+
if (fnFilter) {
|
|
209
|
+
functions = functions.filter((f) => f.name === fnFilter);
|
|
210
|
+
if (functions.length === 0) {
|
|
211
|
+
console.error(` Function not found: ${fnFilter}`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
let allSuggestions = [];
|
|
216
|
+
for (const fn of functions) {
|
|
217
|
+
const suggestions = suggestTests(fn, content);
|
|
218
|
+
allSuggestions.push(...suggestions.map((s) => ({ ...s, functionName: fn.name })));
|
|
219
|
+
}
|
|
220
|
+
if (priorityFilter) {
|
|
221
|
+
allSuggestions = allSuggestions.filter((s) => s.priority === priorityFilter);
|
|
222
|
+
}
|
|
223
|
+
if (format === "json") {
|
|
224
|
+
console.log(JSON.stringify({ file: target, functions: functions.length, suggestions: allSuggestions, timestamp: new Date().toISOString() }, null, 2));
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.log(`\n Test Suggestions for ${target}`);
|
|
228
|
+
console.log(` Functions: ${functions.length} | Suggestions: ${allSuggestions.length}\n ──────────────────────────`);
|
|
229
|
+
if (allSuggestions.length === 0) {
|
|
230
|
+
console.log(` No test suggestions generated.\n`);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
for (const priority of ["high", "medium", "low"]) {
|
|
234
|
+
const items = allSuggestions.filter((s) => s.priority === priority);
|
|
235
|
+
if (items.length === 0)
|
|
236
|
+
continue;
|
|
237
|
+
console.log(`\n ${priority.toUpperCase()} PRIORITY (${items.length})`);
|
|
238
|
+
for (const s of items) {
|
|
239
|
+
console.log(` [${s.category}] ${s.functionName}() — ${s.description}`);
|
|
240
|
+
if (s.testCode) {
|
|
241
|
+
console.log(` Code: ${s.testCode.substring(0, 100)}${s.testCode.length > 100 ? "..." : ""}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
console.log("");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=test-suggest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-suggest.js","sourceRoot":"","sources":["../../src/commands/test-suggest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendor lock detect — scan code for vendor-specific APIs and SDKs
|
|
3
|
+
* commonly embedded by AI models. Flag portability risks.
|
|
4
|
+
*
|
|
5
|
+
* All analysis local.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runVendorLockDetect(argv: string[]): void;
|
|
8
|
+
//# sourceMappingURL=vendor-lock-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor-lock-detect.d.ts","sourceRoot":"","sources":["../../src/commands/vendor-lock-detect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8MH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAwHxD"}
|