@vibecheckai/cli 3.2.2 → 3.2.4

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.
Files changed (170) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/runners/ENHANCEMENT_GUIDE.md +121 -121
  4. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  5. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
  6. package/bin/runners/lib/agent-firewall/claims/extractor.js +117 -28
  7. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +23 -14
  8. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +72 -1
  9. package/bin/runners/lib/agent-firewall/interceptor/base.js +2 -2
  10. package/bin/runners/lib/agent-firewall/policy/default-policy.json +6 -0
  11. package/bin/runners/lib/agent-firewall/policy/engine.js +34 -3
  12. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +29 -4
  13. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +12 -0
  14. package/bin/runners/lib/agent-firewall/truthpack/loader.js +21 -0
  15. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
  16. package/bin/runners/lib/analyzers.js +606 -325
  17. package/bin/runners/lib/auth-truth.js +193 -193
  18. package/bin/runners/lib/backup.js +62 -62
  19. package/bin/runners/lib/billing.js +107 -107
  20. package/bin/runners/lib/claims.js +118 -118
  21. package/bin/runners/lib/cli-ui.js +540 -540
  22. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  23. package/bin/runners/lib/contracts/env-contract.js +181 -181
  24. package/bin/runners/lib/contracts/external-contract.js +206 -206
  25. package/bin/runners/lib/contracts/guard.js +168 -168
  26. package/bin/runners/lib/contracts/index.js +89 -89
  27. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  28. package/bin/runners/lib/contracts/route-contract.js +199 -199
  29. package/bin/runners/lib/contracts.js +804 -804
  30. package/bin/runners/lib/detect.js +89 -89
  31. package/bin/runners/lib/doctor/autofix.js +254 -254
  32. package/bin/runners/lib/doctor/index.js +37 -37
  33. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  34. package/bin/runners/lib/doctor/modules/index.js +46 -46
  35. package/bin/runners/lib/doctor/modules/network.js +250 -250
  36. package/bin/runners/lib/doctor/modules/project.js +312 -312
  37. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  38. package/bin/runners/lib/doctor/modules/security.js +348 -348
  39. package/bin/runners/lib/doctor/modules/system.js +213 -213
  40. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  41. package/bin/runners/lib/doctor/reporter.js +262 -262
  42. package/bin/runners/lib/doctor/service.js +262 -262
  43. package/bin/runners/lib/doctor/types.js +113 -113
  44. package/bin/runners/lib/doctor/ui.js +263 -263
  45. package/bin/runners/lib/doctor-v2.js +608 -608
  46. package/bin/runners/lib/drift.js +425 -425
  47. package/bin/runners/lib/enforcement.js +72 -72
  48. package/bin/runners/lib/engines/accessibility-engine.js +190 -0
  49. package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
  50. package/bin/runners/lib/engines/ast-cache.js +99 -0
  51. package/bin/runners/lib/engines/code-quality-engine.js +255 -0
  52. package/bin/runners/lib/engines/console-logs-engine.js +115 -0
  53. package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
  54. package/bin/runners/lib/engines/dead-code-engine.js +198 -0
  55. package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
  56. package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
  57. package/bin/runners/lib/engines/file-filter.js +131 -0
  58. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
  59. package/bin/runners/lib/engines/mock-data-engine.js +272 -0
  60. package/bin/runners/lib/engines/parallel-processor.js +71 -0
  61. package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
  62. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
  63. package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
  64. package/bin/runners/lib/engines/type-aware-engine.js +152 -0
  65. package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
  66. package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
  67. package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
  68. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  69. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  70. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  71. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  72. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  73. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  74. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  75. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
  76. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  77. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  78. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  79. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  80. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  81. package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
  82. package/bin/runners/lib/enterprise-detect.js +603 -603
  83. package/bin/runners/lib/enterprise-init.js +942 -942
  84. package/bin/runners/lib/env-resolver.js +417 -417
  85. package/bin/runners/lib/env-template.js +66 -66
  86. package/bin/runners/lib/env.js +189 -189
  87. package/bin/runners/lib/extractors/client-calls.js +990 -990
  88. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  89. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  90. package/bin/runners/lib/extractors/index.js +363 -363
  91. package/bin/runners/lib/extractors/next-routes.js +524 -524
  92. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  93. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  94. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  95. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  96. package/bin/runners/lib/findings-schema.js +281 -281
  97. package/bin/runners/lib/firewall-prompt.js +50 -50
  98. package/bin/runners/lib/global-flags.js +213 -213
  99. package/bin/runners/lib/graph/graph-builder.js +265 -265
  100. package/bin/runners/lib/graph/html-renderer.js +413 -413
  101. package/bin/runners/lib/graph/index.js +32 -32
  102. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  103. package/bin/runners/lib/graph/static-extractor.js +518 -518
  104. package/bin/runners/lib/html-report.js +650 -650
  105. package/bin/runners/lib/interactive-menu.js +1496 -1496
  106. package/bin/runners/lib/llm.js +75 -75
  107. package/bin/runners/lib/meter.js +61 -61
  108. package/bin/runners/lib/missions/evidence.js +126 -126
  109. package/bin/runners/lib/patch.js +40 -40
  110. package/bin/runners/lib/permissions/auth-model.js +213 -213
  111. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  112. package/bin/runners/lib/permissions/index.js +45 -45
  113. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  114. package/bin/runners/lib/pkgjson.js +28 -28
  115. package/bin/runners/lib/policy.js +295 -295
  116. package/bin/runners/lib/preflight.js +142 -142
  117. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  118. package/bin/runners/lib/reality/index.js +318 -318
  119. package/bin/runners/lib/reality/request-hashing.js +416 -416
  120. package/bin/runners/lib/reality/request-mapper.js +453 -453
  121. package/bin/runners/lib/reality/safety-rails.js +463 -463
  122. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  123. package/bin/runners/lib/reality/toast-detector.js +393 -393
  124. package/bin/runners/lib/reality-findings.js +84 -84
  125. package/bin/runners/lib/receipts.js +179 -179
  126. package/bin/runners/lib/redact.js +29 -29
  127. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  128. package/bin/runners/lib/replay/index.js +263 -263
  129. package/bin/runners/lib/replay/player.js +348 -348
  130. package/bin/runners/lib/replay/recorder.js +331 -331
  131. package/bin/runners/lib/report-output.js +187 -187
  132. package/bin/runners/lib/report.js +135 -135
  133. package/bin/runners/lib/route-detection.js +1140 -1140
  134. package/bin/runners/lib/sandbox/index.js +59 -59
  135. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  136. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  137. package/bin/runners/lib/sandbox/worktree.js +174 -174
  138. package/bin/runners/lib/scan-output.js +525 -190
  139. package/bin/runners/lib/schema-validator.js +350 -350
  140. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  141. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  142. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  143. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  144. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  145. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  146. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  147. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  148. package/bin/runners/lib/schemas/validator.js +438 -438
  149. package/bin/runners/lib/score-history.js +282 -282
  150. package/bin/runners/lib/share-pack.js +239 -239
  151. package/bin/runners/lib/snippets.js +67 -67
  152. package/bin/runners/lib/status-output.js +253 -253
  153. package/bin/runners/lib/terminal-ui.js +351 -271
  154. package/bin/runners/lib/upsell.js +510 -510
  155. package/bin/runners/lib/usage.js +153 -153
  156. package/bin/runners/lib/validate-patch.js +156 -156
  157. package/bin/runners/lib/verdict-engine.js +628 -628
  158. package/bin/runners/reality/engine.js +917 -917
  159. package/bin/runners/reality/flows.js +122 -122
  160. package/bin/runners/reality/report.js +378 -378
  161. package/bin/runners/reality/session.js +193 -193
  162. package/bin/runners/runGuard.js +168 -168
  163. package/bin/runners/runProof.zip +0 -0
  164. package/bin/runners/runProve.js +8 -0
  165. package/bin/runners/runReality.js +14 -0
  166. package/bin/runners/runScan.js +17 -1
  167. package/bin/runners/runTruth.js +15 -3
  168. package/mcp-server/tier-auth.js +4 -4
  169. package/mcp-server/tools/index.js +72 -72
  170. package/package.json +1 -1
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Hardcoded Secrets Detection Engine
3
+ * Uses AST analysis + entropy to detect hardcoded secrets
4
+ */
5
+
6
+ const { getAST, parseCode } = require("./ast-cache");
7
+ const traverse = require("@babel/traverse").default;
8
+ const t = require("@babel/types");
9
+ const crypto = require("crypto");
10
+ const { shouldExcludeFile } = require("./file-filter");
11
+
12
+ /**
13
+ * Calculate Shannon entropy for a string
14
+ */
15
+ function getShannonEntropy(str) {
16
+ if (!str || str.length === 0) return 0;
17
+ const len = str.length;
18
+ const frequencies = {};
19
+ for (let i = 0; i < len; i++) {
20
+ const char = str[i];
21
+ frequencies[char] = (frequencies[char] || 0) + 1;
22
+ }
23
+
24
+ let entropy = 0;
25
+ for (const char in frequencies) {
26
+ const p = frequencies[char] / len;
27
+ entropy -= p * Math.log2(p);
28
+ }
29
+ return entropy;
30
+ }
31
+
32
+ /**
33
+ * Specific secret patterns (high confidence, no entropy needed)
34
+ */
35
+ const SPECIFIC_PATTERNS = [
36
+ {
37
+ pattern: /^sk_live_[a-zA-Z0-9]{20,}$/,
38
+ label: "Stripe live secret key",
39
+ severity: "BLOCK",
40
+ },
41
+ {
42
+ pattern: /^sk_test_[a-zA-Z0-9]{20,}$/,
43
+ label: "Stripe test secret key",
44
+ severity: "WARN",
45
+ },
46
+ {
47
+ pattern: /^pk_live_[a-zA-Z0-9]{20,}$/,
48
+ label: "Stripe live publishable key",
49
+ severity: "BLOCK",
50
+ },
51
+ {
52
+ pattern: /^AKIA[0-9A-Z]{16}$/,
53
+ label: "AWS Access Key ID",
54
+ severity: "BLOCK",
55
+ },
56
+ {
57
+ pattern: /^ghp_[a-zA-Z0-9]{36}$/,
58
+ label: "GitHub Personal Access Token",
59
+ severity: "BLOCK",
60
+ },
61
+ {
62
+ pattern: /^gho_[a-zA-Z0-9]{36}$/,
63
+ label: "GitHub OAuth Token",
64
+ severity: "BLOCK",
65
+ },
66
+ {
67
+ pattern: /^xox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24}$/,
68
+ label: "Slack Token",
69
+ severity: "BLOCK",
70
+ },
71
+ {
72
+ pattern: /^eyJ[a-zA-Z0-9_-]{100,}\.[a-zA-Z0-9_-]{100,}\.[a-zA-Z0-9_-]{43,}$/,
73
+ label: "JWT Token (hardcoded)",
74
+ severity: "WARN",
75
+ },
76
+ ];
77
+
78
+ /**
79
+ * Check if string matches a specific secret pattern
80
+ */
81
+ function matchesSpecificPattern(value) {
82
+ for (const { pattern, label, severity } of SPECIFIC_PATTERNS) {
83
+ if (pattern.test(value)) {
84
+ return { label, severity, confidence: "high" };
85
+ }
86
+ }
87
+ return null;
88
+ }
89
+
90
+ /**
91
+ * Check if string looks like a secret based on context and entropy
92
+ */
93
+ function looksLikeSecret(value, context = {}) {
94
+ // Skip common false positives
95
+ if (/^(undefined|null|true|false|localhost|example|placeholder|test|demo|development|production)$/i.test(value)) {
96
+ return null;
97
+ }
98
+
99
+ // Skip hex-only strings (likely Git SHAs, image IDs, hashes)
100
+ if (/^[a-f0-9]{32,}$/i.test(value)) {
101
+ return null;
102
+ }
103
+
104
+ // Skip UUIDs (they have high entropy but are not secrets)
105
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) {
106
+ return null;
107
+ }
108
+
109
+ // Skip common test/example values
110
+ if (/^(test|example|sample|demo|placeholder|foo|bar|baz|qux)/i.test(value)) {
111
+ return null;
112
+ }
113
+
114
+ // Check entropy
115
+ const entropy = getShannonEntropy(value);
116
+
117
+ // Context-based checks - require explicit secret context
118
+ const hasSecretContext =
119
+ context.variableName && /(password|secret|key|token|credential|api[_-]?key|private[_-]?key|access[_-]?token)/i.test(context.variableName);
120
+
121
+ // Only flag if we have explicit secret context AND high entropy
122
+ if (hasSecretContext && value.length >= 12 && entropy >= 4.0) {
123
+ return {
124
+ label: `Hardcoded ${context.variableName.match(/(password|secret|key|token|credential|api[_-]?key|private[_-]?key|access[_-]?token)/i)?.[0] || "secret"}`,
125
+ severity: "WARN",
126
+ confidence: "med",
127
+ entropy,
128
+ };
129
+ }
130
+
131
+ // Generic high entropy check - be more conservative (require longer strings and higher entropy)
132
+ if (entropy >= 5.0 && value.length >= 32) {
133
+ return {
134
+ label: "Possible hardcoded secret (high entropy)",
135
+ severity: "WARN",
136
+ confidence: "low",
137
+ entropy,
138
+ };
139
+ }
140
+
141
+ return null;
142
+ }
143
+
144
+ /**
145
+ * Analyze a file for hardcoded secrets
146
+ */
147
+ function analyzeHardcodedSecrets(code, filePath) {
148
+ const findings = [];
149
+
150
+ // Skip excluded files (includes .env files)
151
+ if (shouldExcludeFile(filePath)) return findings;
152
+
153
+ const ast = getAST(code, filePath);
154
+ if (!ast) return findings;
155
+
156
+ const lines = code.split("\n");
157
+
158
+ traverse(ast, {
159
+ // Check string literals
160
+ StringLiteral(path) {
161
+ const value = path.node.value;
162
+ if (!value || value.length < 8) return;
163
+
164
+ // Check specific patterns first
165
+ const specificMatch = matchesSpecificPattern(value);
166
+ if (specificMatch) {
167
+ const line = path.node.loc.start.line;
168
+ findings.push({
169
+ type: "specific_secret",
170
+ severity: specificMatch.severity,
171
+ category: "HardcodedSecret",
172
+ file: filePath,
173
+ line,
174
+ column: path.node.loc.start.column,
175
+ title: `${specificMatch.label} detected`,
176
+ message: `${specificMatch.label} found in code`,
177
+ codeSnippet: lines[line - 1]?.trim(),
178
+ confidence: specificMatch.confidence,
179
+ });
180
+ return;
181
+ }
182
+
183
+ // Check generic patterns with context
184
+ const parent = path.parent;
185
+ let variableName = null;
186
+
187
+ if (t.isVariableDeclarator(parent)) {
188
+ variableName = parent.id.name;
189
+ } else if (t.isObjectProperty(parent)) {
190
+ variableName = t.isIdentifier(parent.key) ? parent.key.name : null;
191
+ } else if (t.isAssignmentExpression(parent)) {
192
+ if (t.isIdentifier(parent.left)) {
193
+ variableName = parent.left.name;
194
+ }
195
+ }
196
+
197
+ const secretMatch = looksLikeSecret(value, { variableName });
198
+ if (secretMatch) {
199
+ const line = path.node.loc.start.line;
200
+ findings.push({
201
+ type: "generic_secret",
202
+ severity: secretMatch.severity,
203
+ category: "HardcodedSecret",
204
+ file: filePath,
205
+ line,
206
+ column: path.node.loc.start.column,
207
+ title: secretMatch.label,
208
+ message: `High entropy string (${secretMatch.entropy.toFixed(2)}) detected${variableName ? ` in variable "${variableName}"` : ""}`,
209
+ codeSnippet: lines[line - 1]?.trim(),
210
+ confidence: secretMatch.confidence,
211
+ });
212
+ }
213
+ },
214
+
215
+ // Check template literals
216
+ TemplateLiteral(path) {
217
+ const quasis = path.node.quasis;
218
+ for (const quasi of quasis) {
219
+ if (quasi.value && quasi.value.raw) {
220
+ const value = quasi.value.raw;
221
+ if (value.length >= 8) {
222
+ const specificMatch = matchesSpecificPattern(value);
223
+ if (specificMatch) {
224
+ const line = path.node.loc.start.line;
225
+ findings.push({
226
+ type: "specific_secret",
227
+ severity: specificMatch.severity,
228
+ category: "HardcodedSecret",
229
+ file: filePath,
230
+ line,
231
+ column: path.node.loc.start.column,
232
+ title: `${specificMatch.label} detected`,
233
+ message: `${specificMatch.label} found in template literal`,
234
+ codeSnippet: lines[line - 1]?.trim(),
235
+ confidence: specificMatch.confidence,
236
+ });
237
+ }
238
+ }
239
+ }
240
+ }
241
+ },
242
+ });
243
+
244
+ return findings;
245
+ }
246
+
247
+ module.exports = {
248
+ analyzeHardcodedSecrets,
249
+ parseCode,
250
+ getShannonEntropy,
251
+ };
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Mock Data Detection Engine
3
+ * Uses AST analysis to detect mock/test data patterns in production code
4
+ */
5
+
6
+ const { getAST, parseCode } = require("./ast-cache");
7
+ const traverse = require("@babel/traverse").default;
8
+ const t = require("@babel/types");
9
+ const { shouldExcludeFile } = require("./file-filter");
10
+
11
+ /**
12
+ * Check if a string literal looks like mock/test data
13
+ */
14
+ function isMockString(value) {
15
+ if (typeof value !== "string") return false;
16
+
17
+ const lower = value.toLowerCase();
18
+
19
+ // Mock data patterns
20
+ const mockPatterns = [
21
+ /^(fake|mock|dummy|test|sample|placeholder)[_-]?/i,
22
+ /@(test|example|fake|demo)\.com$/i,
23
+ /^(password|admin|test|secret)123$/i,
24
+ /^test@/i,
25
+ /^(MOCK|FAKE|DUMMY)_API/i,
26
+ ];
27
+
28
+ return mockPatterns.some(pattern => pattern.test(value));
29
+ }
30
+
31
+ /**
32
+ * Check if a variable name suggests mock data
33
+ * Be more conservative - only flag explicit mock/test data variables
34
+ */
35
+ function isMockVariableName(name) {
36
+ if (!name || typeof name !== "string") return false;
37
+
38
+ const lower = name.toLowerCase();
39
+
40
+ // Only flag explicit mock/test data variable names (exact matches or explicit prefixes)
41
+ const mockNamePatterns = [
42
+ /^(fake|mock|dummy)[_-]?(data|user|api|response|value|input)$/i, // Explicit mock prefixes
43
+ /^mockData$/i,
44
+ /^fakeData$/i,
45
+ ];
46
+
47
+ // Exclude common legitimate patterns
48
+ const legitimatePatterns = [
49
+ /sample/i, // "sample" is often legitimate
50
+ /example/i, // "example" is often legitimate
51
+ /demo/i, // "demo" is often legitimate
52
+ /test/i, // "test" alone is often legitimate
53
+ ];
54
+
55
+ // Don't flag if it matches legitimate patterns
56
+ if (legitimatePatterns.some(pattern => pattern.test(name))) {
57
+ return false;
58
+ }
59
+
60
+ return mockNamePatterns.some(pattern => pattern.test(name));
61
+ }
62
+
63
+ /**
64
+ * Check if a call expression is generating random/mock data
65
+ */
66
+ function isRandomDataGeneration(node) {
67
+ if (!t.isCallExpression(node)) return false;
68
+
69
+ const callee = node.callee;
70
+
71
+ // Math.random() with multiplication
72
+ if (t.isMemberExpression(callee) &&
73
+ t.isIdentifier(callee.object) && callee.object.name === "Math" &&
74
+ t.isIdentifier(callee.property) && callee.property.name === "random") {
75
+
76
+ // Check parent for multiplication or comparison
77
+ const parent = node.parent;
78
+ if (t.isBinaryExpression(parent) &&
79
+ (parent.operator === "*" || parent.operator === "<" || parent.operator === ">")) {
80
+ return true;
81
+ }
82
+ }
83
+
84
+ return false;
85
+ }
86
+
87
+ /**
88
+ * Check if setTimeout has suspiciously long delays (simulated delays)
89
+ */
90
+ function isSuspiciousSetTimeout(node) {
91
+ if (!t.isCallExpression(node)) return false;
92
+
93
+ const callee = node.callee;
94
+ if (!t.isIdentifier(callee) || callee.name !== "setTimeout") return false;
95
+
96
+ const args = node.arguments;
97
+ if (args.length < 2) return false;
98
+
99
+ // Check delay argument
100
+ const delay = args[1];
101
+ if (t.isNumericLiteral(delay)) {
102
+ // Suspicious if > 5000ms (5 seconds)
103
+ return delay.value > 5000;
104
+ }
105
+
106
+ return false;
107
+ }
108
+
109
+ /**
110
+ * Analyze a file for mock data patterns
111
+ */
112
+ function analyzeMockData(code, filePath) {
113
+ const findings = [];
114
+
115
+ // Skip excluded files (test files, examples, etc.)
116
+ if (shouldExcludeFile(filePath)) return findings;
117
+
118
+ const ast = getAST(code, filePath);
119
+ if (!ast) return findings;
120
+
121
+ const lines = code.split("\n");
122
+
123
+ traverse(ast, {
124
+ // Check variable declarations
125
+ VariableDeclarator(path) {
126
+ const id = path.node.id;
127
+ const init = path.node.init;
128
+
129
+ // Check variable name
130
+ if (t.isIdentifier(id) && isMockVariableName(id.name)) {
131
+ const line = getLineNumber(path.node, code);
132
+ findings.push({
133
+ type: "mock_variable",
134
+ severity: "WARN",
135
+ category: "MockData",
136
+ file: filePath,
137
+ line,
138
+ column: path.node.loc.start.column,
139
+ title: `Mock data variable: ${id.name}`,
140
+ message: `Variable name suggests mock/test data: ${id.name}`,
141
+ codeSnippet: lines[line - 1]?.trim(),
142
+ confidence: "high",
143
+ });
144
+ }
145
+
146
+ // Check initializer value
147
+ if (init && t.isStringLiteral(init) && isMockString(init.value)) {
148
+ const line = getLineNumber(path.node, code);
149
+ findings.push({
150
+ type: "mock_string_literal",
151
+ severity: "WARN",
152
+ category: "MockData",
153
+ file: filePath,
154
+ line,
155
+ column: path.node.loc.start.column,
156
+ title: "Mock/test string literal detected",
157
+ message: `String value appears to be mock data: "${init.value.substring(0, 50)}"`,
158
+ codeSnippet: lines[line - 1]?.trim(),
159
+ confidence: "med",
160
+ });
161
+ }
162
+ },
163
+
164
+ // Check object properties
165
+ ObjectProperty(path) {
166
+ const key = path.node.key;
167
+ const value = path.node.value;
168
+
169
+ if (t.isIdentifier(key) && isMockVariableName(key.name)) {
170
+ const line = getLineNumber(path.node, code);
171
+ findings.push({
172
+ type: "mock_object_property",
173
+ severity: "WARN",
174
+ category: "MockData",
175
+ file: filePath,
176
+ line,
177
+ column: path.node.loc.start.column,
178
+ title: `Mock data property: ${key.name}`,
179
+ message: `Object property name suggests mock data: ${key.name}`,
180
+ codeSnippet: lines[line - 1]?.trim(),
181
+ confidence: "med",
182
+ });
183
+ }
184
+
185
+ if (t.isStringLiteral(value) && isMockString(value.value)) {
186
+ const line = getLineNumber(path.node, code);
187
+ findings.push({
188
+ type: "mock_property_value",
189
+ severity: "WARN",
190
+ category: "MockData",
191
+ file: filePath,
192
+ line,
193
+ column: path.node.loc.start.column,
194
+ title: "Mock string in object property",
195
+ message: `Property value appears to be mock data: "${value.value.substring(0, 50)}"`,
196
+ codeSnippet: lines[line - 1]?.trim(),
197
+ confidence: "med",
198
+ });
199
+ }
200
+ },
201
+
202
+ // Check call expressions for random data generation
203
+ CallExpression(path) {
204
+ if (isRandomDataGeneration(path.node)) {
205
+ const line = getLineNumber(path.node, code);
206
+ findings.push({
207
+ type: "random_data_generation",
208
+ severity: "WARN",
209
+ category: "MockData",
210
+ file: filePath,
211
+ line,
212
+ column: path.node.loc.start.column,
213
+ title: "Random data generation detected",
214
+ message: "Math.random() used for data generation (may be mock data)",
215
+ codeSnippet: lines[line - 1]?.trim(),
216
+ confidence: "low",
217
+ });
218
+ }
219
+
220
+ if (isSuspiciousSetTimeout(path.node)) {
221
+ const line = getLineNumber(path.node, code);
222
+ findings.push({
223
+ type: "suspicious_settimeout",
224
+ severity: "WARN",
225
+ category: "MockData",
226
+ file: filePath,
227
+ line,
228
+ column: path.node.loc.start.column,
229
+ title: "Long setTimeout delay (possible simulated delay)",
230
+ message: "setTimeout with delay > 5000ms may indicate simulated/mock behavior",
231
+ codeSnippet: lines[line - 1]?.trim(),
232
+ confidence: "low",
233
+ });
234
+ }
235
+ },
236
+
237
+ // Check template literals
238
+ TemplateLiteral(path) {
239
+ const quasis = path.node.quasis;
240
+ for (const quasi of quasis) {
241
+ if (quasi.value && isMockString(quasi.value.raw)) {
242
+ const line = getLineNumber(path.node, code);
243
+ findings.push({
244
+ type: "mock_template_literal",
245
+ severity: "WARN",
246
+ category: "MockData",
247
+ file: filePath,
248
+ line,
249
+ column: path.node.loc.start.column,
250
+ title: "Mock data in template literal",
251
+ message: `Template literal contains mock/test data pattern`,
252
+ codeSnippet: lines[line - 1]?.trim(),
253
+ confidence: "med",
254
+ });
255
+ break;
256
+ }
257
+ }
258
+ },
259
+ });
260
+
261
+ return findings;
262
+ }
263
+
264
+ function getLineNumber(node, code) {
265
+ if (!node || !node.loc) return 1;
266
+ return node.loc.start.line;
267
+ }
268
+
269
+ module.exports = {
270
+ analyzeMockData,
271
+ parseCode,
272
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Parallel File Processor
3
+ * Processes files in parallel with configurable concurrency
4
+ */
5
+
6
+ const os = require("os");
7
+
8
+ /**
9
+ * Process files in parallel batches
10
+ */
11
+ async function processFilesInParallel(files, processor, options = {}) {
12
+ const {
13
+ concurrency = Math.min(os.cpus().length, 8), // Default to CPU count, max 8
14
+ onProgress = null,
15
+ } = options;
16
+
17
+ const results = [];
18
+ const errors = [];
19
+
20
+ // Process in batches
21
+ for (let i = 0; i < files.length; i += concurrency) {
22
+ const batch = files.slice(i, i + concurrency);
23
+
24
+ const batchPromises = batch.map(async (file, index) => {
25
+ try {
26
+ const result = await processor(file);
27
+ if (onProgress) {
28
+ onProgress(i + index + 1, files.length);
29
+ }
30
+ return { file, result, error: null };
31
+ } catch (error) {
32
+ errors.push({ file, error });
33
+ return { file, result: null, error };
34
+ }
35
+ });
36
+
37
+ const batchResults = await Promise.all(batchPromises);
38
+ results.push(...batchResults);
39
+ }
40
+
41
+ return { results, errors };
42
+ }
43
+
44
+ /**
45
+ * Process files sequentially (fallback)
46
+ */
47
+ async function processFilesSequentially(files, processor, onProgress = null) {
48
+ const results = [];
49
+ const errors = [];
50
+
51
+ for (let i = 0; i < files.length; i++) {
52
+ const file = files[i];
53
+ try {
54
+ const result = await processor(file);
55
+ if (onProgress) {
56
+ onProgress(i + 1, files.length);
57
+ }
58
+ results.push({ file, result, error: null });
59
+ } catch (error) {
60
+ errors.push({ file, error });
61
+ results.push({ file, result: null, error });
62
+ }
63
+ }
64
+
65
+ return { results, errors };
66
+ }
67
+
68
+ module.exports = {
69
+ processFilesInParallel,
70
+ processFilesSequentially,
71
+ };