@vibecheckai/cli 3.5.1 → 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.
Files changed (272) hide show
  1. package/bin/registry.js +406 -154
  2. package/bin/runners/context/analyzer.js +52 -1
  3. package/bin/runners/context/generators/mcp.js +15 -13
  4. package/bin/runners/context/git-context.js +3 -1
  5. package/bin/runners/context/proof-context.js +248 -1
  6. package/bin/runners/context/team-conventions.js +33 -7
  7. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
  8. package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
  9. package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
  10. package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
  11. package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
  12. package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
  13. package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
  14. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  15. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  16. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  17. package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
  18. package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
  19. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
  20. package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
  21. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
  22. package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
  23. package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
  24. package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
  25. package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
  26. package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
  27. package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
  28. package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
  29. package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
  30. package/bin/runners/lib/agent-firewall/interceptor/base.js +304 -0
  31. package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
  32. package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
  33. package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
  34. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  35. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  36. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  37. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  38. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  39. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  40. package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
  41. package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
  42. package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
  43. package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
  44. package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
  45. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +86 -0
  46. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +162 -0
  47. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +189 -0
  48. package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
  49. package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
  50. package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
  51. package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
  52. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  53. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  54. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  55. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  56. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  57. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  58. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  59. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  60. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  61. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  62. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  63. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  64. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  65. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  66. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  67. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  68. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  69. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  70. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  71. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  72. package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
  73. package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
  74. package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
  75. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
  76. package/bin/runners/lib/analysis-core.js +220 -182
  77. package/bin/runners/lib/analyzers.js +2145 -224
  78. package/bin/runners/lib/api-client.js +269 -0
  79. package/bin/runners/lib/authority-badge.js +425 -0
  80. package/bin/runners/lib/cli-output.js +242 -210
  81. package/bin/runners/lib/default-config.js +127 -0
  82. package/bin/runners/lib/detectors-v2.js +547 -785
  83. package/bin/runners/lib/doctor/modules/security.js +3 -1
  84. package/bin/runners/lib/engine/ast-cache.js +210 -0
  85. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  86. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  87. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  88. package/bin/runners/lib/engine/env-extractor.js +207 -0
  89. package/bin/runners/lib/engine/express-extractor.js +208 -0
  90. package/bin/runners/lib/engine/extractors.js +849 -0
  91. package/bin/runners/lib/engine/index.js +207 -0
  92. package/bin/runners/lib/engine/repo-index.js +514 -0
  93. package/bin/runners/lib/engine/types.js +124 -0
  94. package/bin/runners/lib/engines/accessibility-engine.js +190 -0
  95. package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
  96. package/bin/runners/lib/engines/ast-cache.js +99 -0
  97. package/bin/runners/lib/engines/code-quality-engine.js +255 -0
  98. package/bin/runners/lib/engines/console-logs-engine.js +115 -0
  99. package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
  100. package/bin/runners/lib/engines/dead-code-engine.js +198 -0
  101. package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
  102. package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
  103. package/bin/runners/lib/engines/file-filter.js +131 -0
  104. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
  105. package/bin/runners/lib/engines/mock-data-engine.js +272 -0
  106. package/bin/runners/lib/engines/parallel-processor.js +71 -0
  107. package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
  108. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
  109. package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
  110. package/bin/runners/lib/engines/type-aware-engine.js +152 -0
  111. package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
  112. package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
  113. package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
  114. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  115. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  116. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  117. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  118. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  119. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  120. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  121. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
  122. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  123. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  124. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  125. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  126. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  127. package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
  128. package/bin/runners/lib/entitlements-v2.js +152 -446
  129. package/bin/runners/lib/error-handler.js +60 -12
  130. package/bin/runners/lib/error-messages.js +289 -0
  131. package/bin/runners/lib/evidence-pack.js +7 -1
  132. package/bin/runners/lib/exit-codes.js +275 -0
  133. package/bin/runners/lib/finding-id.js +69 -0
  134. package/bin/runners/lib/finding-sorter.js +89 -0
  135. package/bin/runners/lib/fingerprint.js +377 -0
  136. package/bin/runners/lib/global-flags.js +37 -0
  137. package/bin/runners/lib/help-formatter.js +413 -0
  138. package/bin/runners/lib/logger.js +38 -0
  139. package/bin/runners/lib/next-action.js +560 -0
  140. package/bin/runners/lib/prerequisites.js +149 -0
  141. package/bin/runners/lib/route-detection.js +137 -68
  142. package/bin/runners/lib/route-truth.js +1167 -322
  143. package/bin/runners/lib/scan-output.js +504 -463
  144. package/bin/runners/lib/scan-runner.js +135 -0
  145. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  146. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  147. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  148. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  149. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  150. package/bin/runners/lib/schemas/validator.js +27 -0
  151. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  152. package/bin/runners/lib/ship-output-enterprise.js +239 -0
  153. package/bin/runners/lib/ship-output.js +328 -31
  154. package/bin/runners/lib/terminal-ui.js +234 -731
  155. package/bin/runners/lib/truth.js +1332 -308
  156. package/bin/runners/lib/unified-cli-output.js +604 -0
  157. package/bin/runners/lib/unified-output.js +163 -155
  158. package/bin/runners/lib/upsell.js +104 -204
  159. package/bin/runners/runAgent.d.ts +5 -0
  160. package/bin/runners/runAgent.js +161 -0
  161. package/bin/runners/runAllowlist.js +166 -101
  162. package/bin/runners/runApprove.js +1200 -0
  163. package/bin/runners/runAuth.js +373 -95
  164. package/bin/runners/runCheckpoint.js +59 -21
  165. package/bin/runners/runClassify.js +926 -0
  166. package/bin/runners/runContext.d.ts +4 -0
  167. package/bin/runners/runContext.js +136 -24
  168. package/bin/runners/runDoctor.js +115 -67
  169. package/bin/runners/runEvidencePack.js +239 -96
  170. package/bin/runners/runFirewall.d.ts +5 -0
  171. package/bin/runners/runFirewall.js +134 -0
  172. package/bin/runners/runFirewallHook.d.ts +5 -0
  173. package/bin/runners/runFirewallHook.js +56 -0
  174. package/bin/runners/runFix.js +6 -5
  175. package/bin/runners/runGuard.js +212 -118
  176. package/bin/runners/runInit.js +66 -21
  177. package/bin/runners/runLabs.js +204 -121
  178. package/bin/runners/runMcp.js +131 -60
  179. package/bin/runners/runPolish.d.ts +4 -0
  180. package/bin/runners/runPolish.js +43 -20
  181. package/bin/runners/runProof.zip +0 -0
  182. package/bin/runners/runProve.js +15 -5
  183. package/bin/runners/runQuickstart.js +531 -0
  184. package/bin/runners/runReality.js +14 -0
  185. package/bin/runners/runReport.js +36 -4
  186. package/bin/runners/runScan.js +689 -91
  187. package/bin/runners/runShip.js +96 -40
  188. package/bin/runners/runTruth.d.ts +5 -0
  189. package/bin/runners/runTruth.js +101 -0
  190. package/bin/runners/runValidate.js +21 -4
  191. package/bin/runners/runWatch.js +118 -54
  192. package/bin/scan.js +6 -1
  193. package/bin/vibecheck.js +297 -52
  194. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  195. package/mcp-server/agent-firewall-interceptor.js +500 -0
  196. package/mcp-server/authority-tools.js +569 -0
  197. package/mcp-server/conductor/conflict-resolver.js +588 -0
  198. package/mcp-server/conductor/execution-planner.js +544 -0
  199. package/mcp-server/conductor/index.js +377 -0
  200. package/mcp-server/conductor/lock-manager.js +615 -0
  201. package/mcp-server/conductor/request-queue.js +550 -0
  202. package/mcp-server/conductor/session-manager.js +500 -0
  203. package/mcp-server/conductor/tools.js +510 -0
  204. package/mcp-server/deprecation-middleware.js +282 -0
  205. package/mcp-server/handlers/index.ts +15 -0
  206. package/mcp-server/handlers/tool-handler.ts +474 -591
  207. package/mcp-server/index.js +1748 -1099
  208. package/mcp-server/lib/api-client.cjs +13 -0
  209. package/mcp-server/lib/cache-wrapper.cjs +383 -0
  210. package/mcp-server/lib/error-envelope.js +138 -0
  211. package/mcp-server/lib/executor.ts +428 -721
  212. package/mcp-server/lib/index.ts +19 -0
  213. package/mcp-server/lib/logger.cjs +30 -0
  214. package/mcp-server/lib/rate-limiter.js +166 -0
  215. package/mcp-server/lib/sandbox.test.ts +519 -0
  216. package/mcp-server/lib/sandbox.ts +342 -284
  217. package/mcp-server/lib/types.ts +267 -0
  218. package/mcp-server/logger.js +173 -0
  219. package/mcp-server/package.json +11 -27
  220. package/mcp-server/premium-tools.js +2 -2
  221. package/mcp-server/registry/tool-registry.js +794 -0
  222. package/mcp-server/registry/tools.json +507 -378
  223. package/mcp-server/registry.test.ts +334 -0
  224. package/mcp-server/tests/tier-gating.test.js +297 -0
  225. package/mcp-server/tier-auth.js +492 -347
  226. package/mcp-server/tools-v3.js +950 -0
  227. package/mcp-server/truth-context.js +131 -90
  228. package/mcp-server/truth-firewall-tools.js +1612 -1001
  229. package/mcp-server/tsconfig.json +8 -5
  230. package/mcp-server/vibecheck-2.0-tools.js +14 -1
  231. package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
  232. package/mcp-server/vibecheck-tools.js +2 -2
  233. package/package.json +4 -3
  234. package/bin/runners/runInstall.js +0 -281
  235. package/mcp-server/ARCHITECTURE.md +0 -339
  236. package/mcp-server/__tests__/cache.test.ts +0 -313
  237. package/mcp-server/__tests__/executor.test.ts +0 -239
  238. package/mcp-server/__tests__/fixtures/exclusion-test/.cache/webpack/cache.pack +0 -1
  239. package/mcp-server/__tests__/fixtures/exclusion-test/.next/server/chunk.js +0 -3
  240. package/mcp-server/__tests__/fixtures/exclusion-test/.turbo/cache.json +0 -3
  241. package/mcp-server/__tests__/fixtures/exclusion-test/.venv/lib/env.py +0 -3
  242. package/mcp-server/__tests__/fixtures/exclusion-test/dist/bundle.js +0 -3
  243. package/mcp-server/__tests__/fixtures/exclusion-test/package.json +0 -5
  244. package/mcp-server/__tests__/fixtures/exclusion-test/src/app.ts +0 -5
  245. package/mcp-server/__tests__/fixtures/exclusion-test/venv/lib/config.py +0 -4
  246. package/mcp-server/__tests__/ids.test.ts +0 -345
  247. package/mcp-server/__tests__/integration/tools.test.ts +0 -410
  248. package/mcp-server/__tests__/registry.test.ts +0 -365
  249. package/mcp-server/__tests__/sandbox.test.ts +0 -323
  250. package/mcp-server/__tests__/schemas.test.ts +0 -372
  251. package/mcp-server/benchmarks/run-benchmarks.ts +0 -304
  252. package/mcp-server/examples/doctor.request.json +0 -14
  253. package/mcp-server/examples/doctor.response.json +0 -53
  254. package/mcp-server/examples/error.response.json +0 -15
  255. package/mcp-server/examples/scan.request.json +0 -14
  256. package/mcp-server/examples/scan.response.json +0 -108
  257. package/mcp-server/index-v3.ts +0 -293
  258. package/mcp-server/index.old.js +0 -4137
  259. package/mcp-server/lib/cache.ts +0 -341
  260. package/mcp-server/lib/errors.ts +0 -346
  261. package/mcp-server/lib/ids.ts +0 -238
  262. package/mcp-server/lib/logger.ts +0 -368
  263. package/mcp-server/lib/metrics.ts +0 -365
  264. package/mcp-server/lib/validator.ts +0 -229
  265. package/mcp-server/package-lock.json +0 -165
  266. package/mcp-server/schemas/error-envelope.schema.json +0 -125
  267. package/mcp-server/schemas/finding.schema.json +0 -167
  268. package/mcp-server/schemas/report-artifact.schema.json +0 -88
  269. package/mcp-server/schemas/run-request.schema.json +0 -75
  270. package/mcp-server/schemas/verdict.schema.json +0 -168
  271. package/mcp-server/tier-auth.d.ts +0 -71
  272. package/mcp-server/vitest.config.ts +0 -16
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Scan Runner - Timeout and Cancellation Support
3
+ *
4
+ * Provides timeout and cancellation capabilities for scan execution.
5
+ * Prevents runaway scans from hanging indefinitely.
6
+ */
7
+
8
+ const EventEmitter = require('events');
9
+
10
+ /**
11
+ * @typedef {Object} ScanOptions
12
+ * @property {number} [timeout] - Timeout in milliseconds (default: 5 minutes)
13
+ * @property {AbortSignal} [signal] - AbortSignal for cancellation
14
+ */
15
+
16
+ /**
17
+ * @typedef {Object} ScanResult
18
+ * @property {'completed'|'cancelled'|'failed'} status
19
+ * @property {Array} findings
20
+ * @property {string} [error]
21
+ */
22
+
23
+ class ScanRunner extends EventEmitter {
24
+ constructor() {
25
+ super();
26
+ this.aborted = false;
27
+ this.timeoutId = null;
28
+ }
29
+ constructor() {
30
+ super();
31
+ this.aborted = false;
32
+ this.timeoutId = null;
33
+ }
34
+
35
+ /**
36
+ * Run a scan with timeout and cancellation support
37
+ * @param {string} projectPath - Path to project to scan
38
+ * @param {ScanOptions} options - Scan options
39
+ * @returns {Promise<ScanResult>}
40
+ */
41
+ async run(projectPath, options = {}) {
42
+ const timeout = options.timeout || 5 * 60 * 1000; // Default 5 minutes
43
+
44
+ // Set up abort handling
45
+ if (options.signal) {
46
+ options.signal.addEventListener('abort', () => {
47
+ this.abort('Scan aborted via signal');
48
+ });
49
+ }
50
+
51
+ // Set up timeout
52
+ this.timeoutId = setTimeout(() => {
53
+ this.abort('Scan timed out');
54
+ }, timeout);
55
+
56
+ try {
57
+ this.emit('start', { projectPath, timeout });
58
+
59
+ const result = await this.executeAnalyzers(projectPath);
60
+
61
+ if (this.aborted) {
62
+ return { status: 'cancelled', findings: [] };
63
+ }
64
+
65
+ return result;
66
+ } catch (error) {
67
+ if (this.aborted) {
68
+ return { status: 'cancelled', findings: [], error: error.message };
69
+ }
70
+ return { status: 'failed', findings: [], error: error.message };
71
+ } finally {
72
+ if (this.timeoutId) {
73
+ clearTimeout(this.timeoutId);
74
+ this.timeoutId = null;
75
+ }
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Abort the current scan
81
+ * @param {string} reason - Reason for abortion
82
+ */
83
+ abort(reason = 'Scan aborted') {
84
+ this.aborted = true;
85
+ this.emit('abort', { reason });
86
+ }
87
+
88
+ /**
89
+ * Execute analyzers with abort checks between each
90
+ * @private
91
+ * @param {string} projectPath - Path to project
92
+ * @returns {Promise<ScanResult>}
93
+ */
94
+ async executeAnalyzers(projectPath) {
95
+ // Import analysis core dynamically to avoid circular dependencies
96
+ const { runAnalysis } = require('./analysis-core');
97
+
98
+ // Check abort before starting
99
+ if (this.aborted) {
100
+ return { status: 'cancelled', findings: [] };
101
+ }
102
+
103
+ try {
104
+ // Run analysis with progress tracking
105
+ this.emit('progress', { phase: 'analysis', status: 'running' });
106
+
107
+ const result = await runAnalysis({
108
+ repoRoot: projectPath,
109
+ extended: true,
110
+ noWrite: false
111
+ });
112
+
113
+ // Check abort after analysis
114
+ if (this.aborted) {
115
+ return { status: 'cancelled', findings: result.findings || [] };
116
+ }
117
+
118
+ this.emit('progress', { phase: 'analysis', status: 'complete', count: result.findings?.length || 0 });
119
+
120
+ return {
121
+ status: 'completed',
122
+ findings: result.findings || [],
123
+ verdict: result.verdict,
124
+ report: result.report
125
+ };
126
+ } catch (error) {
127
+ if (this.aborted) {
128
+ return { status: 'cancelled', findings: [], error: error.message };
129
+ }
130
+ throw error;
131
+ }
132
+ }
133
+ }
134
+
135
+ module.exports = { ScanRunner };
@@ -0,0 +1,464 @@
1
+ /**
2
+ * Schema Validator v3 - Production AJV Implementation
3
+ *
4
+ * Full JSON Schema Draft 2020-12 validation using AJV.
5
+ * Replaces the minimal validator for production use.
6
+ */
7
+
8
+ "use strict";
9
+
10
+ const fs = require("fs");
11
+ const path = require("path");
12
+ const crypto = require("crypto");
13
+
14
+ // Lazy-load AJV to avoid startup cost if not needed
15
+ let ajv = null;
16
+ let ajvFormats = null;
17
+
18
+ function getAjv() {
19
+ if (!ajv) {
20
+ const Ajv = require("ajv");
21
+ ajvFormats = require("ajv-formats");
22
+
23
+ ajv = new Ajv({
24
+ strict: true,
25
+ allErrors: true,
26
+ verbose: true,
27
+ validateFormats: true,
28
+ // Allow unknown keywords for custom extensions
29
+ strictTypes: true,
30
+ strictTuples: true,
31
+ // Cache schemas for performance
32
+ cache: new Map(),
33
+ });
34
+
35
+ // Add standard formats (date-time, uri, email, etc.)
36
+ ajvFormats(ajv);
37
+
38
+ // Add custom formats
39
+ ajv.addFormat("sha256", /^sha256:[a-f0-9]{64}$/);
40
+ ajv.addFormat("fingerprint", /^sha256:[a-f0-9]{64}$/);
41
+ ajv.addFormat("finding-id", /^F_[A-Z0-9_]+$/);
42
+ ajv.addFormat("evidence-id", /^E_[A-Z0-9]+$/);
43
+ }
44
+
45
+ return ajv;
46
+ }
47
+
48
+ // Schema cache
49
+ const schemaCache = new Map();
50
+ const validatorCache = new Map();
51
+
52
+ // Schema IDs (same as validator.js for compatibility)
53
+ const SCHEMAS = {
54
+ FINDING: "finding.schema.json",
55
+ FINDING_V3: "finding-v3.schema.json",
56
+ SHIP_REPORT: "ship-report.schema.json",
57
+ REALITY_REPORT: "reality-report.schema.json",
58
+ TRUTHPACK_V2: "truthpack-v2.schema.json",
59
+ CONTRACTS: "contracts.schema.json",
60
+ PROOF_GRAPH: "proof-graph.schema.json",
61
+ MISSION_PACK: "mission-pack.schema.json",
62
+ SHARE_PACK: "share-pack.schema.json",
63
+ VERDICT: "verdict.schema.json",
64
+ ERROR_ENVELOPE: "error-envelope.schema.json",
65
+ RUN_REQUEST: "run-request.schema.json",
66
+ REPORT_ARTIFACT: "report-artifact.schema.json",
67
+ };
68
+
69
+ // =============================================================================
70
+ // SCHEMA LOADING
71
+ // =============================================================================
72
+
73
+ /**
74
+ * Load a schema by ID
75
+ */
76
+ function loadSchema(schemaId) {
77
+ if (schemaCache.has(schemaId)) {
78
+ return schemaCache.get(schemaId);
79
+ }
80
+
81
+ const schemaPath = path.join(__dirname, schemaId);
82
+ if (!fs.existsSync(schemaPath)) {
83
+ return null;
84
+ }
85
+
86
+ try {
87
+ const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8"));
88
+ schemaCache.set(schemaId, schema);
89
+ return schema;
90
+ } catch (e) {
91
+ console.error(`Failed to load schema ${schemaId}:`, e.message);
92
+ return null;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Get compiled validator for schema
98
+ */
99
+ function getValidator(schemaId) {
100
+ if (validatorCache.has(schemaId)) {
101
+ return validatorCache.get(schemaId);
102
+ }
103
+
104
+ const schema = loadSchema(schemaId);
105
+ if (!schema) {
106
+ return null;
107
+ }
108
+
109
+ try {
110
+ const ajvInstance = getAjv();
111
+
112
+ // Remove $id to avoid conflicts when compiling multiple schemas
113
+ const schemaCopy = { ...schema };
114
+ delete schemaCopy.$id;
115
+
116
+ const validator = ajvInstance.compile(schemaCopy);
117
+ validatorCache.set(schemaId, validator);
118
+ return validator;
119
+ } catch (e) {
120
+ console.error(`Failed to compile schema ${schemaId}:`, e.message);
121
+ return null;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Validate data against schema using AJV
127
+ */
128
+ function validateAgainstSchema(data, schema, contextPath = "") {
129
+ if (!schema || data === undefined) {
130
+ return [];
131
+ }
132
+
133
+ try {
134
+ const ajvInstance = getAjv();
135
+ const schemaCopy = { ...schema };
136
+ delete schemaCopy.$id;
137
+
138
+ const validate = ajvInstance.compile(schemaCopy);
139
+ const valid = validate(data);
140
+
141
+ if (valid) {
142
+ return [];
143
+ }
144
+
145
+ // Convert AJV errors to our format
146
+ return (validate.errors || []).map(err => ({
147
+ path: contextPath + (err.instancePath || ""),
148
+ message: err.message || "Validation failed",
149
+ keyword: err.keyword,
150
+ params: err.params,
151
+ }));
152
+ } catch (e) {
153
+ return [{
154
+ path: contextPath,
155
+ message: `Schema compilation error: ${e.message}`,
156
+ keyword: "compile",
157
+ }];
158
+ }
159
+ }
160
+
161
+ // =============================================================================
162
+ // ARTIFACT VALIDATION
163
+ // =============================================================================
164
+
165
+ /**
166
+ * Validate an artifact file against its schema
167
+ */
168
+ function validateArtifact(filePath, schemaId) {
169
+ const validator = getValidator(schemaId);
170
+
171
+ if (!validator) {
172
+ return {
173
+ valid: false,
174
+ errors: [{ path: "", message: `Schema ${schemaId} not found or invalid`, keyword: "schema" }],
175
+ };
176
+ }
177
+
178
+ let data;
179
+ try {
180
+ data = JSON.parse(fs.readFileSync(filePath, "utf8"));
181
+ } catch (e) {
182
+ return {
183
+ valid: false,
184
+ errors: [{ path: "", message: `Failed to read/parse file: ${e.message}`, keyword: "parse" }],
185
+ };
186
+ }
187
+
188
+ const valid = validator(data);
189
+
190
+ if (valid) {
191
+ return { valid: true, errors: [], data };
192
+ }
193
+
194
+ const errors = (validator.errors || []).map(err => ({
195
+ path: err.instancePath || "",
196
+ message: err.message || "Validation failed",
197
+ keyword: err.keyword,
198
+ params: err.params,
199
+ }));
200
+
201
+ return { valid: false, errors, data };
202
+ }
203
+
204
+ /**
205
+ * Validate data object against schema
206
+ */
207
+ function validateData(data, schemaId) {
208
+ const validator = getValidator(schemaId);
209
+
210
+ if (!validator) {
211
+ return {
212
+ valid: false,
213
+ errors: [{ path: "", message: `Schema ${schemaId} not found`, keyword: "schema" }],
214
+ };
215
+ }
216
+
217
+ const valid = validator(data);
218
+
219
+ if (valid) {
220
+ return { valid: true, errors: [] };
221
+ }
222
+
223
+ const errors = (validator.errors || []).map(err => ({
224
+ path: err.instancePath || "",
225
+ message: err.message || "Validation failed",
226
+ keyword: err.keyword,
227
+ }));
228
+
229
+ return { valid: false, errors };
230
+ }
231
+
232
+ /**
233
+ * Validate and write artifact with schema check
234
+ */
235
+ function writeValidatedArtifact(filePath, data, schemaId, options = {}) {
236
+ const { strict = false, warnOnly = true } = options;
237
+
238
+ const result = validateData(data, schemaId);
239
+
240
+ if (!result.valid) {
241
+ const message = `Artifact ${filePath} has ${result.errors.length} schema violations`;
242
+
243
+ if (strict) {
244
+ throw new Error(`${message}: ${result.errors.map(e => e.message).join(", ")}`);
245
+ }
246
+
247
+ if (warnOnly) {
248
+ console.warn(`Warning: ${message}:`);
249
+ result.errors.slice(0, 5).forEach(e =>
250
+ console.warn(` - ${e.path || "/"}: ${e.message}`)
251
+ );
252
+ if (result.errors.length > 5) {
253
+ console.warn(` ... and ${result.errors.length - 5} more errors`);
254
+ }
255
+ }
256
+ }
257
+
258
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
259
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
260
+
261
+ return {
262
+ written: true,
263
+ path: filePath,
264
+ valid: result.valid,
265
+ errors: result.errors,
266
+ };
267
+ }
268
+
269
+ // =============================================================================
270
+ // FINDING GENERATION (kept for compatibility with validator.js)
271
+ // =============================================================================
272
+
273
+ /**
274
+ * Generate stable fingerprint for deduplication
275
+ */
276
+ function generateFingerprint(parts) {
277
+ const content = parts.filter(Boolean).join("|");
278
+ return crypto.createHash("sha256").update(content).digest("hex");
279
+ }
280
+
281
+ /**
282
+ * Generate finding ID
283
+ */
284
+ function generateFindingId(detectorId, fingerprint) {
285
+ return `F_${detectorId}_${fingerprint.slice(0, 8).toUpperCase()}`;
286
+ }
287
+
288
+ /**
289
+ * Generate evidence ID
290
+ */
291
+ function generateEvidenceId(fingerprint) {
292
+ return `E_${fingerprint.slice(0, 12).toUpperCase()}`;
293
+ }
294
+
295
+ /**
296
+ * Create a spec-compliant finding
297
+ */
298
+ function createFinding(options = {}) {
299
+ const {
300
+ detectorId,
301
+ severity = "WARN",
302
+ category = "Routes",
303
+ scope = "client",
304
+ title,
305
+ why,
306
+ confidence = "medium",
307
+ evidence = [],
308
+ repro = null,
309
+ related = [],
310
+ proofNode = null,
311
+ missionType = null,
312
+ file = null,
313
+ path: routePath = null,
314
+ method = null,
315
+ } = options;
316
+
317
+ const fingerprint = generateFingerprint([
318
+ detectorId,
319
+ file,
320
+ routePath,
321
+ method,
322
+ title,
323
+ ]);
324
+
325
+ const finding = {
326
+ id: generateFindingId(detectorId, fingerprint),
327
+ detectorId,
328
+ fingerprint: `sha256:${fingerprint}`,
329
+ severity,
330
+ category,
331
+ scope,
332
+ title,
333
+ why,
334
+ confidence,
335
+ evidence: evidence.map((e, i) => ({
336
+ id: e.id || generateEvidenceId(fingerprint + i),
337
+ kind: e.kind || "file",
338
+ ...e,
339
+ })),
340
+ repro,
341
+ related,
342
+ proofNode,
343
+ missionType,
344
+ };
345
+
346
+ // Validate the finding
347
+ const result = validateData(finding, SCHEMAS.FINDING_V3);
348
+ if (!result.valid) {
349
+ console.warn(`Warning: Created finding has schema violations:`, result.errors.slice(0, 3));
350
+ }
351
+
352
+ return finding;
353
+ }
354
+
355
+ /**
356
+ * Create file evidence
357
+ */
358
+ function createFileEvidence(options = {}) {
359
+ const { file, lines, snippetHash, reason } = options;
360
+ const fp = generateFingerprint([file, lines, reason]);
361
+
362
+ return {
363
+ id: generateEvidenceId(fp),
364
+ kind: "file",
365
+ file,
366
+ lines,
367
+ snippetHash,
368
+ reason,
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Create runtime evidence
374
+ */
375
+ function createRuntimeEvidence(options = {}) {
376
+ const { url, httpStatus, reason, data } = options;
377
+ const fp = generateFingerprint([url, httpStatus, reason]);
378
+
379
+ return {
380
+ id: generateEvidenceId(fp),
381
+ kind: "request",
382
+ url,
383
+ httpStatus,
384
+ reason,
385
+ data,
386
+ };
387
+ }
388
+
389
+ // =============================================================================
390
+ // SEVERITY POLICY (kept for compatibility with validator.js)
391
+ // =============================================================================
392
+
393
+ const SEVERITY_POLICY = {
394
+ ROUTE_MISSING: { default: "BLOCK", withRuntimeProof: "BLOCK" },
395
+ ROUTE_404: { default: "BLOCK" },
396
+ ROUTE_405: { default: "WARN" },
397
+ AUTH_BYPASS: { default: "BLOCK" },
398
+ AUTH_MISSING: { default: "WARN", criticalPath: "BLOCK" },
399
+ FAKE_SUCCESS: { default: "BLOCK" },
400
+ SUCCESS_TOAST_NO_CHANGE: { default: "BLOCK" },
401
+ SUCCESS_BEFORE_REQUEST: { default: "BLOCK" },
402
+ DEAD_CLICK: { default: "BLOCK" },
403
+ NO_FEEDBACK: { default: "WARN" },
404
+ CONTRACT_DRIFT_ROUTE: { default: "WARN", blocking: "BLOCK" },
405
+ CONTRACT_DRIFT_ENV: { default: "WARN", required: "BLOCK" },
406
+ CONTRACT_DRIFT_AUTH: { default: "BLOCK" },
407
+ STRIPE_WEBHOOK_UNVERIFIED: { default: "BLOCK" },
408
+ PAID_SURFACE_UNENFORCED: { default: "BLOCK" },
409
+ OWNER_MODE_BYPASS: { default: "BLOCK" },
410
+ HARDCODED_SECRET: { default: "BLOCK" },
411
+ };
412
+
413
+ /**
414
+ * Get severity based on policy
415
+ */
416
+ function getSeverity(issueType, context = {}) {
417
+ const policy = SEVERITY_POLICY[issueType];
418
+ if (!policy) return "WARN";
419
+
420
+ if (context.hasRuntimeProof && policy.withRuntimeProof) {
421
+ return policy.withRuntimeProof;
422
+ }
423
+ if (context.isCriticalPath && policy.criticalPath) {
424
+ return policy.criticalPath;
425
+ }
426
+ if (context.isBlocking && policy.blocking) {
427
+ return policy.blocking;
428
+ }
429
+ if (context.isRequired && policy.required) {
430
+ return policy.required;
431
+ }
432
+
433
+ return policy.default;
434
+ }
435
+
436
+ // =============================================================================
437
+ // EXPORTS
438
+ // =============================================================================
439
+
440
+ module.exports = {
441
+ // Schema operations
442
+ SCHEMAS,
443
+ loadSchema,
444
+ getValidator,
445
+ validateAgainstSchema,
446
+ validateArtifact,
447
+ validateData,
448
+ writeValidatedArtifact,
449
+
450
+ // Finding generation
451
+ generateFingerprint,
452
+ generateFindingId,
453
+ generateEvidenceId,
454
+ createFinding,
455
+ createFileEvidence,
456
+ createRuntimeEvidence,
457
+
458
+ // Severity policy
459
+ SEVERITY_POLICY,
460
+ getSeverity,
461
+
462
+ // AJV access for advanced usage
463
+ getAjv,
464
+ };
@@ -0,0 +1,105 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://vibecheck.dev/schemas/error-envelope.schema.json",
4
+ "x-schemaVersion": "1.0.0",
5
+ "title": "Vibecheck Error Envelope",
6
+ "description": "Standardized error response wrapper",
7
+ "type": "object",
8
+ "required": [
9
+ "error",
10
+ "code",
11
+ "message"
12
+ ],
13
+ "properties": {
14
+ "error": {
15
+ "type": "boolean",
16
+ "const": true,
17
+ "description": "Always true for error responses"
18
+ },
19
+ "code": {
20
+ "type": "string",
21
+ "enum": [
22
+ "SCHEMA_INVALID",
23
+ "TOOL_NOT_FOUND",
24
+ "TIER_REQUIRED",
25
+ "AUTH_REQUIRED",
26
+ "AUTH_INVALID",
27
+ "RATE_LIMITED",
28
+ "TIMEOUT",
29
+ "PROJECT_NOT_FOUND",
30
+ "CONFIG_INVALID",
31
+ "INTERNAL_ERROR",
32
+ "NETWORK_ERROR",
33
+ "PARSE_ERROR"
34
+ ],
35
+ "description": "Machine-readable error code"
36
+ },
37
+ "message": {
38
+ "type": "string",
39
+ "minLength": 1,
40
+ "description": "Human-readable error message"
41
+ },
42
+ "details": {
43
+ "type": ["object", "null"],
44
+ "description": "Additional error details",
45
+ "properties": {
46
+ "path": {
47
+ "type": "string",
48
+ "description": "JSON path to invalid field (for SCHEMA_INVALID)"
49
+ },
50
+ "expected": {
51
+ "type": "string",
52
+ "description": "Expected value or type"
53
+ },
54
+ "received": {
55
+ "type": "string",
56
+ "description": "Received value or type"
57
+ },
58
+ "schema_errors": {
59
+ "type": "array",
60
+ "items": {
61
+ "type": "object",
62
+ "properties": {
63
+ "instancePath": { "type": "string" },
64
+ "schemaPath": { "type": "string" },
65
+ "keyword": { "type": "string" },
66
+ "params": { "type": "object" },
67
+ "message": { "type": "string" }
68
+ }
69
+ },
70
+ "description": "Detailed AJV validation errors"
71
+ },
72
+ "required_tier": {
73
+ "type": "string",
74
+ "enum": ["free", "pro", "enterprise"],
75
+ "description": "Required tier (for TIER_REQUIRED)"
76
+ },
77
+ "current_tier": {
78
+ "type": "string",
79
+ "enum": ["free", "pro", "enterprise"],
80
+ "description": "Current user tier"
81
+ },
82
+ "retry_after_ms": {
83
+ "type": "integer",
84
+ "minimum": 0,
85
+ "description": "Milliseconds to wait before retry (for RATE_LIMITED)"
86
+ }
87
+ }
88
+ },
89
+ "timestamp": {
90
+ "type": "string",
91
+ "format": "date-time",
92
+ "description": "ISO 8601 timestamp of error occurrence"
93
+ },
94
+ "correlation_id": {
95
+ "type": ["string", "null"],
96
+ "description": "Correlation ID for tracing"
97
+ },
98
+ "help_url": {
99
+ "type": ["string", "null"],
100
+ "format": "uri",
101
+ "description": "URL to documentation for this error"
102
+ }
103
+ },
104
+ "additionalProperties": false
105
+ }