@vibecheckai/cli 3.5.0 → 3.5.2
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/bin/registry.js +214 -237
- package/bin/runners/cli-utils.js +33 -2
- package/bin/runners/context/analyzer.js +52 -1
- package/bin/runners/context/generators/cursor.js +2 -49
- package/bin/runners/context/git-context.js +3 -1
- package/bin/runners/context/team-conventions.js +33 -7
- package/bin/runners/lib/analysis-core.js +25 -5
- package/bin/runners/lib/analyzers.js +431 -481
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/doctor/modules/security.js +3 -1
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +18 -218
- package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
- package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
- package/bin/runners/lib/engines/mock-data-engine.js +10 -53
- package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
- package/bin/runners/lib/engines/type-aware-engine.js +39 -263
- package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +73 -373
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/entitlements-v2.js +73 -97
- package/bin/runners/lib/error-handler.js +44 -3
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +7 -1
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/html-proof-report.js +700 -350
- package/bin/runners/lib/missions/plan.js +6 -46
- package/bin/runners/lib/missions/templates.js +0 -232
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/route-detection.js +137 -68
- package/bin/runners/lib/scan-output.js +91 -76
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/validator.js +27 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -0
- package/bin/runners/lib/ship-output-enterprise.js +23 -23
- package/bin/runners/lib/ship-output.js +75 -31
- package/bin/runners/lib/terminal-ui.js +6 -113
- package/bin/runners/lib/truth.js +351 -10
- package/bin/runners/lib/unified-cli-output.js +430 -603
- package/bin/runners/lib/unified-output.js +13 -9
- package/bin/runners/runAIAgent.js +10 -5
- package/bin/runners/runAgent.js +0 -3
- package/bin/runners/runAllowlist.js +389 -0
- package/bin/runners/runApprove.js +0 -33
- package/bin/runners/runAuth.js +73 -45
- package/bin/runners/runCheckpoint.js +51 -11
- package/bin/runners/runClassify.js +85 -21
- package/bin/runners/runContext.js +0 -3
- package/bin/runners/runDoctor.js +41 -28
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.js +0 -3
- package/bin/runners/runFirewallHook.js +0 -3
- package/bin/runners/runFix.js +66 -76
- package/bin/runners/runGuard.js +18 -411
- package/bin/runners/runInit.js +113 -30
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runMcp.js +19 -25
- package/bin/runners/runPolish.js +64 -240
- package/bin/runners/runPromptFirewall.js +12 -5
- package/bin/runners/runProve.js +57 -22
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +59 -68
- package/bin/runners/runReport.js +38 -33
- package/bin/runners/runRuntime.js +8 -5
- package/bin/runners/runScan.js +1413 -190
- package/bin/runners/runShip.js +113 -719
- package/bin/runners/runTruth.js +0 -3
- package/bin/runners/runValidate.js +13 -9
- package/bin/runners/runWatch.js +23 -14
- package/bin/scan.js +6 -1
- package/bin/vibecheck.js +204 -185
- package/mcp-server/deprecation-middleware.js +282 -0
- package/mcp-server/handlers/index.ts +15 -0
- package/mcp-server/handlers/tool-handler.ts +554 -0
- package/mcp-server/index-v1.js +698 -0
- package/mcp-server/index.js +210 -238
- package/mcp-server/lib/cache-wrapper.cjs +383 -0
- package/mcp-server/lib/error-envelope.js +138 -0
- package/mcp-server/lib/executor.ts +499 -0
- package/mcp-server/lib/index.ts +19 -0
- package/mcp-server/lib/rate-limiter.js +166 -0
- package/mcp-server/lib/sandbox.test.ts +519 -0
- package/mcp-server/lib/sandbox.ts +395 -0
- package/mcp-server/lib/types.ts +267 -0
- package/mcp-server/package.json +12 -3
- package/mcp-server/registry/tool-registry.js +794 -0
- package/mcp-server/registry/tools.json +605 -0
- package/mcp-server/registry.test.ts +334 -0
- package/mcp-server/tests/tier-gating.test.js +297 -0
- package/mcp-server/tier-auth.js +378 -45
- package/mcp-server/tools-v3.js +353 -442
- package/mcp-server/tsconfig.json +37 -0
- package/mcp-server/vibecheck-2.0-tools.js +14 -1
- package/package.json +1 -1
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
- package/bin/runners/lib/audit-logger.js +0 -532
- package/bin/runners/lib/authority/authorities/architecture.js +0 -364
- package/bin/runners/lib/authority/authorities/compliance.js +0 -341
- package/bin/runners/lib/authority/authorities/human.js +0 -343
- package/bin/runners/lib/authority/authorities/quality.js +0 -420
- package/bin/runners/lib/authority/authorities/security.js +0 -228
- package/bin/runners/lib/authority/index.js +0 -293
- package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
- package/bin/runners/lib/cli-charts.js +0 -368
- package/bin/runners/lib/cli-config-display.js +0 -405
- package/bin/runners/lib/cli-demo.js +0 -275
- package/bin/runners/lib/cli-errors.js +0 -438
- package/bin/runners/lib/cli-help-formatter.js +0 -439
- package/bin/runners/lib/cli-interactive-menu.js +0 -509
- package/bin/runners/lib/cli-prompts.js +0 -441
- package/bin/runners/lib/cli-scan-cards.js +0 -362
- package/bin/runners/lib/compliance-reporter.js +0 -710
- package/bin/runners/lib/conductor/index.js +0 -671
- package/bin/runners/lib/easy/README.md +0 -123
- package/bin/runners/lib/easy/index.js +0 -140
- package/bin/runners/lib/easy/interactive-wizard.js +0 -788
- package/bin/runners/lib/easy/one-click-firewall.js +0 -564
- package/bin/runners/lib/easy/zero-config-reality.js +0 -714
- package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
- package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
- package/bin/runners/lib/engines/confidence-scoring.js +0 -276
- package/bin/runners/lib/engines/context-detection.js +0 -264
- package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
- package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
- package/bin/runners/lib/engines/env-variables-engine.js +0 -458
- package/bin/runners/lib/engines/error-handling-engine.js +0 -437
- package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
- package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
- package/bin/runners/lib/engines/framework-detection.js +0 -508
- package/bin/runners/lib/engines/import-order-engine.js +0 -429
- package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
- package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
- package/bin/runners/lib/engines/orchestrator.js +0 -334
- package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
- package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
- package/bin/runners/lib/enhanced-features/index.js +0 -305
- package/bin/runners/lib/enhanced-output.js +0 -631
- package/bin/runners/lib/enterprise.js +0 -300
- package/bin/runners/lib/firewall/command-validator.js +0 -351
- package/bin/runners/lib/firewall/config.js +0 -341
- package/bin/runners/lib/firewall/content-validator.js +0 -519
- package/bin/runners/lib/firewall/index.js +0 -101
- package/bin/runners/lib/firewall/path-validator.js +0 -256
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
- package/bin/runners/lib/mcp-utils.js +0 -425
- package/bin/runners/lib/output/index.js +0 -1022
- package/bin/runners/lib/policy-engine.js +0 -652
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
- package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
- package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
- package/bin/runners/lib/polish/autofix/index.js +0 -200
- package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
- package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
- package/bin/runners/lib/polish/backend-checks.js +0 -148
- package/bin/runners/lib/polish/documentation-checks.js +0 -111
- package/bin/runners/lib/polish/frontend-checks.js +0 -168
- package/bin/runners/lib/polish/index.js +0 -71
- package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
- package/bin/runners/lib/polish/library-detection.js +0 -175
- package/bin/runners/lib/polish/performance-checks.js +0 -100
- package/bin/runners/lib/polish/security-checks.js +0 -148
- package/bin/runners/lib/polish/utils.js +0 -203
- package/bin/runners/lib/prompt-builder.js +0 -540
- package/bin/runners/lib/proof-certificate.js +0 -634
- package/bin/runners/lib/reality/accessibility-audit.js +0 -946
- package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
- package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
- package/bin/runners/lib/reality/performance-tracker.js +0 -1077
- package/bin/runners/lib/reality/scenario-generator.js +0 -1404
- package/bin/runners/lib/reality/visual-regression.js +0 -852
- package/bin/runners/lib/reality-profiler.js +0 -717
- package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
- package/bin/runners/lib/review/ai-code-review.js +0 -832
- package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
- package/bin/runners/lib/sbom-generator.js +0 -641
- package/bin/runners/lib/scan-output-enhanced.js +0 -512
- package/bin/runners/lib/security/owasp-scanner.js +0 -939
- package/bin/runners/lib/validators/contract-validator.js +0 -283
- package/bin/runners/lib/validators/dead-export-detector.js +0 -279
- package/bin/runners/lib/validators/dep-audit.js +0 -245
- package/bin/runners/lib/validators/env-validator.js +0 -319
- package/bin/runners/lib/validators/index.js +0 -120
- package/bin/runners/lib/validators/license-checker.js +0 -252
- package/bin/runners/lib/validators/route-validator.js +0 -290
- package/bin/runners/runAuthority.js +0 -528
- package/bin/runners/runConductor.js +0 -772
- package/bin/runners/runContainer.js +0 -366
- package/bin/runners/runEasy.js +0 -410
- package/bin/runners/runIaC.js +0 -372
- package/bin/runners/runVibe.js +0 -791
- package/mcp-server/tools.js +0 -495
|
@@ -1,161 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* API Consistency Engine
|
|
3
|
-
*
|
|
4
|
-
* - REST convention checking (HTTP methods, response codes)
|
|
5
|
-
* - Response shape consistency
|
|
6
|
-
* - Input validation detection
|
|
7
|
-
* - Error response format standardization
|
|
8
|
-
* - CORS and security header detection
|
|
9
|
-
* - Rate limiting indicators
|
|
10
|
-
* - API versioning patterns
|
|
3
|
+
* Checks API route consistency, response formats, error handling patterns
|
|
11
4
|
*/
|
|
12
5
|
|
|
13
6
|
const { getAST } = require("./ast-cache");
|
|
14
7
|
const traverse = require("@babel/traverse").default;
|
|
15
8
|
const t = require("@babel/types");
|
|
16
9
|
|
|
17
|
-
/**
|
|
18
|
-
* HTTP method best practices
|
|
19
|
-
*/
|
|
20
|
-
const HTTP_METHOD_EXPECTATIONS = {
|
|
21
|
-
GET: {
|
|
22
|
-
shouldHaveBody: false,
|
|
23
|
-
typicalStatusCodes: [200, 404],
|
|
24
|
-
description: "Retrieve data",
|
|
25
|
-
},
|
|
26
|
-
POST: {
|
|
27
|
-
shouldHaveBody: true,
|
|
28
|
-
typicalStatusCodes: [201, 400, 409],
|
|
29
|
-
description: "Create resource",
|
|
30
|
-
},
|
|
31
|
-
PUT: {
|
|
32
|
-
shouldHaveBody: true,
|
|
33
|
-
typicalStatusCodes: [200, 204, 404],
|
|
34
|
-
description: "Replace resource",
|
|
35
|
-
},
|
|
36
|
-
PATCH: {
|
|
37
|
-
shouldHaveBody: true,
|
|
38
|
-
typicalStatusCodes: [200, 204, 404],
|
|
39
|
-
description: "Update resource partially",
|
|
40
|
-
},
|
|
41
|
-
DELETE: {
|
|
42
|
-
shouldHaveBody: false,
|
|
43
|
-
typicalStatusCodes: [204, 404],
|
|
44
|
-
description: "Remove resource",
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Common response wrapper patterns
|
|
50
|
-
*/
|
|
51
|
-
const RESPONSE_WRAPPER_PATTERNS = [
|
|
52
|
-
{ pattern: /\{\s*data\s*:/, name: "data" },
|
|
53
|
-
{ pattern: /\{\s*result\s*:/, name: "result" },
|
|
54
|
-
{ pattern: /\{\s*payload\s*:/, name: "payload" },
|
|
55
|
-
{ pattern: /\{\s*response\s*:/, name: "response" },
|
|
56
|
-
{ pattern: /\{\s*body\s*:/, name: "body" },
|
|
57
|
-
{ pattern: /\{\s*message\s*:/, name: "message" },
|
|
58
|
-
{ pattern: /\{\s*error\s*:/, name: "error" },
|
|
59
|
-
{ pattern: /\{\s*success\s*:/, name: "success" },
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Detect HTTP method from file or code
|
|
64
|
-
*/
|
|
65
|
-
function detectHTTPMethod(code, filePath) {
|
|
66
|
-
const methods = new Set();
|
|
67
|
-
|
|
68
|
-
// Next.js App Router pattern: export function GET/POST/etc
|
|
69
|
-
const appRouterMatch = code.match(/export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g);
|
|
70
|
-
if (appRouterMatch) {
|
|
71
|
-
appRouterMatch.forEach(m => {
|
|
72
|
-
const method = m.match(/(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/)[1];
|
|
73
|
-
methods.add(method);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Express pattern: app.get/post/etc or router.get/post/etc
|
|
78
|
-
const expressMatch = code.match(/\.(get|post|put|patch|delete|head|options)\s*\(/gi);
|
|
79
|
-
if (expressMatch) {
|
|
80
|
-
expressMatch.forEach(m => {
|
|
81
|
-
const method = m.match(/\.(get|post|put|patch|delete|head|options)/i)[1].toUpperCase();
|
|
82
|
-
methods.add(method);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Next.js Pages Router pattern
|
|
87
|
-
if (/req\.method\s*===?\s*['"](\w+)['"]/g.test(code)) {
|
|
88
|
-
const methodMatch = code.match(/req\.method\s*===?\s*['"](\w+)['"]/g);
|
|
89
|
-
methodMatch?.forEach(m => {
|
|
90
|
-
const method = m.match(/['"](\w+)['"]/)[1].toUpperCase();
|
|
91
|
-
methods.add(method);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return methods;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Check for input validation
|
|
100
|
-
*/
|
|
101
|
-
function hasInputValidation(code) {
|
|
102
|
-
const validationPatterns = [
|
|
103
|
-
/\bzod\b/,
|
|
104
|
-
/\byup\b/,
|
|
105
|
-
/\bjoi\b/,
|
|
106
|
-
/\bvalidate\s*\(/i,
|
|
107
|
-
/\bschema\s*\.\s*parse/,
|
|
108
|
-
/\bschema\s*\.\s*safeParse/,
|
|
109
|
-
/\.input\s*\(/, // tRPC input
|
|
110
|
-
/\bz\s*\.\s*object/,
|
|
111
|
-
/\bz\s*\.\s*string/,
|
|
112
|
-
/\bvalidateBody/i,
|
|
113
|
-
/\brequestSchema/i,
|
|
114
|
-
/\bbodySchema/i,
|
|
115
|
-
];
|
|
116
|
-
|
|
117
|
-
return validationPatterns.some(p => p.test(code));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check for authentication
|
|
122
|
-
*/
|
|
123
|
-
function hasAuthentication(code) {
|
|
124
|
-
const authPatterns = [
|
|
125
|
-
/getServerSession/,
|
|
126
|
-
/getSession/,
|
|
127
|
-
/auth\s*\(\)/,
|
|
128
|
-
/verifyToken/,
|
|
129
|
-
/authenticate/i,
|
|
130
|
-
/authorization/i,
|
|
131
|
-
/protectedProcedure/,
|
|
132
|
-
/withAuth/i,
|
|
133
|
-
/requireAuth/i,
|
|
134
|
-
/isAuthenticated/i,
|
|
135
|
-
/bearer/i,
|
|
136
|
-
/jwt/i,
|
|
137
|
-
];
|
|
138
|
-
|
|
139
|
-
return authPatterns.some(p => p.test(code));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Check for rate limiting
|
|
144
|
-
*/
|
|
145
|
-
function hasRateLimiting(code) {
|
|
146
|
-
const rateLimitPatterns = [
|
|
147
|
-
/rateLimit/i,
|
|
148
|
-
/rateLimiter/i,
|
|
149
|
-
/throttle/i,
|
|
150
|
-
/X-RateLimit/i,
|
|
151
|
-
/upstash.*ratelimit/i,
|
|
152
|
-
/@upstash\/ratelimit/,
|
|
153
|
-
/limiter\./i,
|
|
154
|
-
];
|
|
155
|
-
|
|
156
|
-
return rateLimitPatterns.some(p => p.test(code));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
10
|
/**
|
|
160
11
|
* Analyze API consistency issues
|
|
161
12
|
*/
|
|
@@ -165,23 +16,13 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
165
16
|
if (!ast) return findings;
|
|
166
17
|
|
|
167
18
|
const lines = code.split("\n");
|
|
168
|
-
const
|
|
169
|
-
const isAPIRoute = normalizedPath.includes("/api/") ||
|
|
170
|
-
normalizedPath.includes("/routes/") ||
|
|
171
|
-
normalizedPath.match(/\/route\.(ts|js)$/);
|
|
19
|
+
const isAPIRoute = filePath.includes("/api/") || filePath.includes("/routes/");
|
|
172
20
|
|
|
173
21
|
if (!isAPIRoute) return findings;
|
|
174
22
|
|
|
175
23
|
const responseFormats = new Set();
|
|
176
24
|
const errorHandlingPatterns = new Set();
|
|
177
|
-
const statusCodesUsed = new Set();
|
|
178
|
-
const responseWrappers = new Set();
|
|
179
25
|
let hasErrorHandler = false;
|
|
180
|
-
let readsRequestBody = false;
|
|
181
|
-
let hasContentTypeCheck = false;
|
|
182
|
-
|
|
183
|
-
// Detect HTTP methods
|
|
184
|
-
const httpMethods = detectHTTPMethod(code, filePath);
|
|
185
26
|
|
|
186
27
|
traverse(ast, {
|
|
187
28
|
// Check response formats
|
|
@@ -191,39 +32,18 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
191
32
|
// Next.js API routes
|
|
192
33
|
if (t.isMemberExpression(node.callee) &&
|
|
193
34
|
t.isIdentifier(node.callee.object, { name: "NextResponse" })) {
|
|
194
|
-
const method = node.callee.property
|
|
35
|
+
const method = node.callee.property.name;
|
|
195
36
|
if (["json", "redirect", "next"].includes(method)) {
|
|
196
37
|
responseFormats.add(`NextResponse.${method}`);
|
|
197
38
|
}
|
|
198
|
-
|
|
199
|
-
// Check response wrapper in NextResponse.json()
|
|
200
|
-
if (method === "json" && node.arguments[0]) {
|
|
201
|
-
const arg = node.arguments[0];
|
|
202
|
-
if (t.isObjectExpression(arg)) {
|
|
203
|
-
arg.properties.forEach(prop => {
|
|
204
|
-
if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {
|
|
205
|
-
responseWrappers.add(prop.key.name);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
39
|
}
|
|
211
40
|
|
|
212
41
|
// Express-style responses
|
|
213
42
|
if (t.isMemberExpression(node.callee)) {
|
|
214
43
|
const prop = node.callee.property;
|
|
215
|
-
if (t.isIdentifier(prop)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Track status codes
|
|
221
|
-
if (prop.name === "status" && node.arguments[0]) {
|
|
222
|
-
const statusArg = node.arguments[0];
|
|
223
|
-
if (t.isNumericLiteral(statusArg)) {
|
|
224
|
-
statusCodesUsed.add(statusArg.value);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
44
|
+
if (t.isIdentifier(prop) &&
|
|
45
|
+
["json", "send", "status", "redirect"].includes(prop.name)) {
|
|
46
|
+
responseFormats.add(`res.${prop.name}`);
|
|
227
47
|
}
|
|
228
48
|
}
|
|
229
49
|
|
|
@@ -233,43 +53,6 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
233
53
|
hasErrorHandler = true;
|
|
234
54
|
errorHandlingPatterns.add("promise.catch");
|
|
235
55
|
}
|
|
236
|
-
|
|
237
|
-
// Request body access
|
|
238
|
-
if (t.isMemberExpression(node.callee)) {
|
|
239
|
-
const obj = node.callee.object;
|
|
240
|
-
const prop = node.callee.property;
|
|
241
|
-
|
|
242
|
-
// req.body, request.json(), etc.
|
|
243
|
-
if ((t.isIdentifier(obj, { name: "req" }) || t.isIdentifier(obj, { name: "request" })) &&
|
|
244
|
-
t.isIdentifier(prop) && ["body", "json"].includes(prop.name)) {
|
|
245
|
-
readsRequestBody = true;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Content-Type check
|
|
250
|
-
if (t.isMemberExpression(node.callee)) {
|
|
251
|
-
const callee = node.callee;
|
|
252
|
-
if (t.isIdentifier(callee.property, { name: "get" }) &&
|
|
253
|
-
node.arguments[0] &&
|
|
254
|
-
t.isStringLiteral(node.arguments[0]) &&
|
|
255
|
-
node.arguments[0].value.toLowerCase() === "content-type") {
|
|
256
|
-
hasContentTypeCheck = true;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
|
|
261
|
-
// Await request.json() also indicates body reading
|
|
262
|
-
AwaitExpression(path) {
|
|
263
|
-
const arg = path.node.argument;
|
|
264
|
-
if (t.isCallExpression(arg) && t.isMemberExpression(arg.callee)) {
|
|
265
|
-
const obj = arg.callee.object;
|
|
266
|
-
const prop = arg.callee.property;
|
|
267
|
-
if (t.isIdentifier(prop, { name: "json" }) ||
|
|
268
|
-
t.isIdentifier(prop, { name: "formData" }) ||
|
|
269
|
-
t.isIdentifier(prop, { name: "text" })) {
|
|
270
|
-
readsRequestBody = true;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
56
|
},
|
|
274
57
|
|
|
275
58
|
// Try-catch blocks
|
|
@@ -284,6 +67,7 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
284
67
|
if (t.isBinaryExpression(test) &&
|
|
285
68
|
(test.operator === "===" || test.operator === "==")) {
|
|
286
69
|
const left = test.left;
|
|
70
|
+
const right = test.right;
|
|
287
71
|
|
|
288
72
|
// Check for error status checks
|
|
289
73
|
if ((t.isMemberExpression(left) &&
|
|
@@ -314,59 +98,18 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
314
98
|
},
|
|
315
99
|
});
|
|
316
100
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
const expectations = HTTP_METHOD_EXPECTATIONS[method];
|
|
320
|
-
if (!expectations) continue;
|
|
321
|
-
|
|
322
|
-
// Check GET/DELETE with body
|
|
323
|
-
if (!expectations.shouldHaveBody && readsRequestBody) {
|
|
324
|
-
findings.push({
|
|
325
|
-
type: "rest_convention_violation",
|
|
326
|
-
severity: "WARN",
|
|
327
|
-
category: "APIConsistency",
|
|
328
|
-
file: filePath,
|
|
329
|
-
line: 1,
|
|
330
|
-
column: 0,
|
|
331
|
-
title: `${method} request should not have body`,
|
|
332
|
-
message: `REST convention: ${method} requests typically don't have a request body. Consider using query parameters instead.`,
|
|
333
|
-
confidence: "med",
|
|
334
|
-
fixHint: "Use query parameters (searchParams) instead of request body for GET requests",
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Check POST/PUT/PATCH without body
|
|
339
|
-
if (expectations.shouldHaveBody && !readsRequestBody && method !== "DELETE") {
|
|
340
|
-
findings.push({
|
|
341
|
-
type: "rest_convention_violation",
|
|
342
|
-
severity: "INFO",
|
|
343
|
-
category: "APIConsistency",
|
|
344
|
-
file: filePath,
|
|
345
|
-
line: 1,
|
|
346
|
-
column: 0,
|
|
347
|
-
title: `${method} request without body`,
|
|
348
|
-
message: `${method} requests typically include a request body. This might be intentional for some endpoints.`,
|
|
349
|
-
confidence: "low",
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Check for inconsistent response wrappers
|
|
355
|
-
const dataWrappers = Array.from(responseWrappers).filter(w =>
|
|
356
|
-
["data", "result", "payload", "response", "body"].includes(w)
|
|
357
|
-
);
|
|
358
|
-
if (dataWrappers.length > 1) {
|
|
101
|
+
// Check for inconsistent response formats
|
|
102
|
+
if (responseFormats.size > 1) {
|
|
359
103
|
findings.push({
|
|
360
|
-
type: "
|
|
104
|
+
type: "inconsistent_response_format",
|
|
361
105
|
severity: "WARN",
|
|
362
106
|
category: "APIConsistency",
|
|
363
107
|
file: filePath,
|
|
364
108
|
line: 1,
|
|
365
109
|
column: 0,
|
|
366
|
-
title: "Inconsistent response
|
|
367
|
-
message: `Multiple response
|
|
368
|
-
confidence: "
|
|
369
|
-
fixHint: "Use a consistent wrapper like { data: ... } or { result: ... } across all endpoints",
|
|
110
|
+
title: "Inconsistent API response formats",
|
|
111
|
+
message: `Multiple response formats used: ${Array.from(responseFormats).join(", ")}`,
|
|
112
|
+
confidence: "low",
|
|
370
113
|
});
|
|
371
114
|
}
|
|
372
115
|
|
|
@@ -380,78 +123,34 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
380
123
|
line: 1,
|
|
381
124
|
column: 0,
|
|
382
125
|
title: "API route missing error handling",
|
|
383
|
-
message: "API route should have try-catch or promise error handling
|
|
126
|
+
message: "API route should have try-catch or promise error handling",
|
|
384
127
|
confidence: "med",
|
|
385
|
-
fixHint: "Wrap async logic in try-catch and return appropriate error responses",
|
|
386
128
|
});
|
|
387
129
|
}
|
|
388
130
|
|
|
389
|
-
// Check for missing
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
column: 0,
|
|
401
|
-
title: "API endpoint missing input validation",
|
|
402
|
-
message: "Mutation endpoints should validate request body. Consider using Zod, Yup, or similar.",
|
|
403
|
-
confidence: "med",
|
|
404
|
-
fixHint: "Add schema validation: const body = schema.parse(await request.json())",
|
|
405
|
-
});
|
|
406
|
-
}
|
|
131
|
+
// Check for missing status codes
|
|
132
|
+
let hasStatusCode = false;
|
|
133
|
+
traverse(ast, {
|
|
134
|
+
CallExpression(path) {
|
|
135
|
+
const node = path.node;
|
|
136
|
+
if (t.isMemberExpression(node.callee) &&
|
|
137
|
+
t.isIdentifier(node.callee.property, { name: "status" })) {
|
|
138
|
+
hasStatusCode = true;
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
});
|
|
407
142
|
|
|
408
|
-
|
|
409
|
-
const isSensitiveEndpoint = /\/(admin|user|account|settings|billing|payment)/i.test(normalizedPath);
|
|
410
|
-
if (isSensitiveEndpoint && !hasAuthentication(code)) {
|
|
143
|
+
if (!hasStatusCode && responseFormats.size > 0) {
|
|
411
144
|
findings.push({
|
|
412
|
-
type: "
|
|
145
|
+
type: "missing_status_code",
|
|
413
146
|
severity: "WARN",
|
|
414
147
|
category: "APIConsistency",
|
|
415
148
|
file: filePath,
|
|
416
149
|
line: 1,
|
|
417
150
|
column: 0,
|
|
418
|
-
title: "
|
|
419
|
-
message:
|
|
420
|
-
confidence: "
|
|
421
|
-
fixHint: "Add authentication check: const session = await getServerSession()",
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Check for missing rate limiting on public endpoints
|
|
426
|
-
const isPublicEndpoint = /(public|webhook|auth\/.*login|auth\/.*register)/i.test(normalizedPath);
|
|
427
|
-
if (isPublicEndpoint && !hasRateLimiting(code)) {
|
|
428
|
-
findings.push({
|
|
429
|
-
type: "missing_rate_limiting",
|
|
430
|
-
severity: "INFO",
|
|
431
|
-
category: "APIConsistency",
|
|
432
|
-
file: filePath,
|
|
433
|
-
line: 1,
|
|
434
|
-
column: 0,
|
|
435
|
-
title: "Public endpoint without rate limiting",
|
|
436
|
-
message: "Public endpoints should consider rate limiting to prevent abuse",
|
|
437
|
-
confidence: "low",
|
|
438
|
-
fixHint: "Consider using @upstash/ratelimit or similar rate limiting solution",
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Check Content-Type validation for POST/PUT/PATCH
|
|
443
|
-
if (hasMutationMethod && readsRequestBody && !hasContentTypeCheck) {
|
|
444
|
-
// This is a low-priority check - most frameworks handle this
|
|
445
|
-
findings.push({
|
|
446
|
-
type: "missing_content_type_check",
|
|
447
|
-
severity: "INFO",
|
|
448
|
-
category: "APIConsistency",
|
|
449
|
-
file: filePath,
|
|
450
|
-
line: 1,
|
|
451
|
-
column: 0,
|
|
452
|
-
title: "No explicit Content-Type validation",
|
|
453
|
-
message: "Consider validating Content-Type header for request body endpoints",
|
|
454
|
-
confidence: "low",
|
|
151
|
+
title: "API response missing explicit status code",
|
|
152
|
+
message: "API responses should explicitly set HTTP status codes",
|
|
153
|
+
confidence: "med",
|
|
455
154
|
});
|
|
456
155
|
}
|
|
457
156
|
|
|
@@ -460,8 +159,4 @@ function analyzeAPIConsistency(code, filePath) {
|
|
|
460
159
|
|
|
461
160
|
module.exports = {
|
|
462
161
|
analyzeAPIConsistency,
|
|
463
|
-
detectHTTPMethod,
|
|
464
|
-
hasInputValidation,
|
|
465
|
-
hasAuthentication,
|
|
466
|
-
hasRateLimiting,
|
|
467
162
|
};
|