@vibecheckai/cli 3.2.5 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/registry.js +192 -5
  4. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  5. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  6. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  7. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  8. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  11. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  12. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  13. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  14. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  15. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  16. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  17. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  18. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  19. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  20. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  21. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  22. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  23. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  24. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  25. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  26. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  27. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  28. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  29. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  30. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  31. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  32. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  35. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  36. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  37. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  38. package/bin/runners/lib/analyzers.js +81 -18
  39. package/bin/runners/lib/api-client.js +269 -0
  40. package/bin/runners/lib/auth-truth.js +193 -193
  41. package/bin/runners/lib/authority-badge.js +425 -0
  42. package/bin/runners/lib/backup.js +62 -62
  43. package/bin/runners/lib/billing.js +107 -107
  44. package/bin/runners/lib/claims.js +118 -118
  45. package/bin/runners/lib/cli-output.js +7 -1
  46. package/bin/runners/lib/cli-ui.js +540 -540
  47. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  48. package/bin/runners/lib/contracts/env-contract.js +181 -181
  49. package/bin/runners/lib/contracts/external-contract.js +206 -206
  50. package/bin/runners/lib/contracts/guard.js +168 -168
  51. package/bin/runners/lib/contracts/index.js +89 -89
  52. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  53. package/bin/runners/lib/contracts/route-contract.js +199 -199
  54. package/bin/runners/lib/contracts.js +804 -804
  55. package/bin/runners/lib/detect.js +89 -89
  56. package/bin/runners/lib/doctor/autofix.js +254 -254
  57. package/bin/runners/lib/doctor/index.js +37 -37
  58. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  59. package/bin/runners/lib/doctor/modules/index.js +46 -46
  60. package/bin/runners/lib/doctor/modules/network.js +250 -250
  61. package/bin/runners/lib/doctor/modules/project.js +312 -312
  62. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  63. package/bin/runners/lib/doctor/modules/security.js +348 -348
  64. package/bin/runners/lib/doctor/modules/system.js +213 -213
  65. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  66. package/bin/runners/lib/doctor/reporter.js +262 -262
  67. package/bin/runners/lib/doctor/service.js +262 -262
  68. package/bin/runners/lib/doctor/types.js +113 -113
  69. package/bin/runners/lib/doctor/ui.js +263 -263
  70. package/bin/runners/lib/doctor-v2.js +608 -608
  71. package/bin/runners/lib/drift.js +425 -425
  72. package/bin/runners/lib/enforcement.js +72 -72
  73. package/bin/runners/lib/enterprise-detect.js +603 -603
  74. package/bin/runners/lib/enterprise-init.js +942 -942
  75. package/bin/runners/lib/env-resolver.js +417 -417
  76. package/bin/runners/lib/env-template.js +66 -66
  77. package/bin/runners/lib/env.js +189 -189
  78. package/bin/runners/lib/error-handler.js +16 -9
  79. package/bin/runners/lib/exit-codes.js +275 -0
  80. package/bin/runners/lib/extractors/client-calls.js +990 -990
  81. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  82. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  83. package/bin/runners/lib/extractors/index.js +363 -363
  84. package/bin/runners/lib/extractors/next-routes.js +524 -524
  85. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  86. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  87. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  88. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  89. package/bin/runners/lib/findings-schema.js +281 -281
  90. package/bin/runners/lib/firewall-prompt.js +50 -50
  91. package/bin/runners/lib/global-flags.js +37 -0
  92. package/bin/runners/lib/graph/graph-builder.js +265 -265
  93. package/bin/runners/lib/graph/html-renderer.js +413 -413
  94. package/bin/runners/lib/graph/index.js +32 -32
  95. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  96. package/bin/runners/lib/graph/static-extractor.js +518 -518
  97. package/bin/runners/lib/help-formatter.js +413 -0
  98. package/bin/runners/lib/html-report.js +650 -650
  99. package/bin/runners/lib/llm.js +75 -75
  100. package/bin/runners/lib/logger.js +38 -0
  101. package/bin/runners/lib/meter.js +61 -61
  102. package/bin/runners/lib/missions/evidence.js +126 -126
  103. package/bin/runners/lib/patch.js +40 -40
  104. package/bin/runners/lib/permissions/auth-model.js +213 -213
  105. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  106. package/bin/runners/lib/permissions/index.js +45 -45
  107. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  108. package/bin/runners/lib/pkgjson.js +28 -28
  109. package/bin/runners/lib/policy.js +295 -295
  110. package/bin/runners/lib/preflight.js +142 -142
  111. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  112. package/bin/runners/lib/reality/index.js +318 -318
  113. package/bin/runners/lib/reality/request-hashing.js +416 -416
  114. package/bin/runners/lib/reality/request-mapper.js +453 -453
  115. package/bin/runners/lib/reality/safety-rails.js +463 -463
  116. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  117. package/bin/runners/lib/reality/toast-detector.js +393 -393
  118. package/bin/runners/lib/reality-findings.js +84 -84
  119. package/bin/runners/lib/receipts.js +179 -179
  120. package/bin/runners/lib/redact.js +29 -29
  121. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  122. package/bin/runners/lib/replay/index.js +263 -263
  123. package/bin/runners/lib/replay/player.js +348 -348
  124. package/bin/runners/lib/replay/recorder.js +331 -331
  125. package/bin/runners/lib/report.js +135 -135
  126. package/bin/runners/lib/route-detection.js +1140 -1140
  127. package/bin/runners/lib/sandbox/index.js +59 -59
  128. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  129. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  130. package/bin/runners/lib/sandbox/worktree.js +174 -174
  131. package/bin/runners/lib/schema-validator.js +350 -350
  132. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  133. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  134. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  135. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  136. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  137. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  138. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  139. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  140. package/bin/runners/lib/schemas/validator.js +438 -438
  141. package/bin/runners/lib/score-history.js +282 -282
  142. package/bin/runners/lib/share-pack.js +239 -239
  143. package/bin/runners/lib/snippets.js +67 -67
  144. package/bin/runners/lib/unified-cli-output.js +604 -0
  145. package/bin/runners/lib/upsell.js +658 -510
  146. package/bin/runners/lib/usage.js +153 -153
  147. package/bin/runners/lib/validate-patch.js +156 -156
  148. package/bin/runners/lib/verdict-engine.js +628 -628
  149. package/bin/runners/reality/engine.js +917 -917
  150. package/bin/runners/reality/flows.js +122 -122
  151. package/bin/runners/reality/report.js +378 -378
  152. package/bin/runners/reality/session.js +193 -193
  153. package/bin/runners/runAgent.d.ts +5 -0
  154. package/bin/runners/runApprove.js +1200 -0
  155. package/bin/runners/runAuth.js +324 -95
  156. package/bin/runners/runCheckpoint.js +39 -21
  157. package/bin/runners/runClassify.js +859 -0
  158. package/bin/runners/runContext.js +136 -24
  159. package/bin/runners/runDoctor.js +108 -68
  160. package/bin/runners/runFirewall.d.ts +5 -0
  161. package/bin/runners/runFirewallHook.d.ts +5 -0
  162. package/bin/runners/runFix.js +6 -5
  163. package/bin/runners/runGuard.js +262 -168
  164. package/bin/runners/runInit.js +3 -2
  165. package/bin/runners/runMcp.js +130 -52
  166. package/bin/runners/runPolish.js +43 -20
  167. package/bin/runners/runProve.js +1 -2
  168. package/bin/runners/runReport.js +3 -2
  169. package/bin/runners/runScan.js +145 -44
  170. package/bin/runners/runShip.js +3 -4
  171. package/bin/runners/runTruth.d.ts +5 -0
  172. package/bin/runners/runValidate.js +19 -2
  173. package/bin/runners/runWatch.js +104 -53
  174. package/bin/vibecheck.js +106 -19
  175. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  176. package/mcp-server/agent-firewall-interceptor.js +367 -31
  177. package/mcp-server/authority-tools.js +569 -0
  178. package/mcp-server/conductor/conflict-resolver.js +588 -0
  179. package/mcp-server/conductor/execution-planner.js +544 -0
  180. package/mcp-server/conductor/index.js +377 -0
  181. package/mcp-server/conductor/lock-manager.js +615 -0
  182. package/mcp-server/conductor/request-queue.js +550 -0
  183. package/mcp-server/conductor/session-manager.js +500 -0
  184. package/mcp-server/conductor/tools.js +510 -0
  185. package/mcp-server/index.js +1199 -208
  186. package/mcp-server/lib/api-client.cjs +305 -0
  187. package/mcp-server/lib/logger.cjs +30 -0
  188. package/mcp-server/logger.js +173 -0
  189. package/mcp-server/package.json +2 -2
  190. package/mcp-server/premium-tools.js +2 -2
  191. package/mcp-server/tier-auth.js +351 -136
  192. package/mcp-server/tools/index.js +72 -72
  193. package/mcp-server/truth-firewall-tools.js +145 -15
  194. package/mcp-server/vibecheck-tools.js +2 -2
  195. package/package.json +2 -3
  196. package/mcp-server/index.old.js +0 -4137
  197. package/mcp-server/package-lock.json +0 -165
@@ -1,72 +1,72 @@
1
- /**
2
- * MCP Tools Index - Single Entry Point for All Tools
3
- *
4
- * This module exports all MCP tools in a unified structure.
5
- * Internal modules are organized by category but presented as one toolset.
6
- *
7
- * Tool Categories:
8
- * - Core: scan, ship, reality, fix, prove, report
9
- * - Truth: ctx, guard, validate_claim, compile_context
10
- * - AI: checkpoint, architect, intelligence
11
- *
12
- * Usage:
13
- * import { ALL_TOOLS, handleTool } from './tools/index.js';
14
- */
15
-
16
- // Re-export consolidated tools as the primary interface
17
- export { CONSOLIDATED_TOOLS, handleConsolidatedTool } from '../consolidated-tools.js';
18
-
19
- // Re-export truth firewall (hallucination stopper)
20
- export { TRUTH_FIREWALL_TOOLS, handleTruthFirewallTool } from '../truth-firewall-tools.js';
21
-
22
- // Re-export truth context
23
- export { TRUTH_CONTEXT_TOOLS, handleTruthContextTool } from '../truth-context.js';
24
-
25
- /**
26
- * Get all recommended tools (consolidated + truth firewall)
27
- */
28
- export function getRecommendedTools() {
29
- const { CONSOLIDATED_TOOLS } = require('../consolidated-tools.js');
30
- const { TRUTH_FIREWALL_TOOLS } = require('../truth-firewall-tools.js');
31
- return [...CONSOLIDATED_TOOLS, ...TRUTH_FIREWALL_TOOLS];
32
- }
33
-
34
- /**
35
- * Handle any tool call by routing to the appropriate handler
36
- */
37
- export async function handleToolCall(toolName, args) {
38
- // Route to consolidated handler first
39
- const { handleConsolidatedTool, CONSOLIDATED_TOOLS } = await import('../consolidated-tools.js');
40
- const consolidatedNames = CONSOLIDATED_TOOLS.map(t => t.name);
41
-
42
- if (consolidatedNames.includes(toolName)) {
43
- return handleConsolidatedTool(toolName, args);
44
- }
45
-
46
- // Route to truth firewall
47
- const { handleTruthFirewallTool, TRUTH_FIREWALL_TOOLS } = await import('../truth-firewall-tools.js');
48
- const firewallNames = TRUTH_FIREWALL_TOOLS.map(t => t.name);
49
-
50
- if (firewallNames.includes(toolName)) {
51
- return handleTruthFirewallTool(toolName, args);
52
- }
53
-
54
- // Route to truth context
55
- const { handleTruthContextTool, TRUTH_CONTEXT_TOOLS } = await import('../truth-context.js');
56
- const contextNames = TRUTH_CONTEXT_TOOLS.map(t => t.name);
57
-
58
- if (contextNames.includes(toolName)) {
59
- return handleTruthContextTool(toolName, args);
60
- }
61
-
62
- throw new Error(`Unknown tool: ${toolName}`);
63
- }
64
-
65
- /**
66
- * Tool categories for documentation
67
- */
68
- export const TOOL_CATEGORIES = {
69
- core: ['vibecheck.scan', 'vibecheck.ship', 'vibecheck.reality', 'vibecheck.fix', 'vibecheck.prove', 'vibecheck.report'],
70
- truth: ['vibecheck.ctx', 'vibecheck.get_truthpack', 'vibecheck.validate_claim', 'vibecheck.compile_context'],
71
- guard: ['vibecheck.guard', 'vibecheck.check_route', 'vibecheck.check_env', 'vibecheck.check_auth'],
72
- };
1
+ /**
2
+ * MCP Tools Index - Single Entry Point for All Tools
3
+ *
4
+ * This module exports all MCP tools in a unified structure.
5
+ * Internal modules are organized by category but presented as one toolset.
6
+ *
7
+ * Tool Categories:
8
+ * - Core: scan, ship, reality, fix, prove, report
9
+ * - Truth: ctx, guard, validate_claim, compile_context
10
+ * - AI: checkpoint, architect, intelligence
11
+ *
12
+ * Usage:
13
+ * import { ALL_TOOLS, handleTool } from './tools/index.js';
14
+ */
15
+
16
+ // Re-export consolidated tools as the primary interface
17
+ export { CONSOLIDATED_TOOLS, handleConsolidatedTool } from '../consolidated-tools.js';
18
+
19
+ // Re-export truth firewall (hallucination stopper)
20
+ export { TRUTH_FIREWALL_TOOLS, handleTruthFirewallTool } from '../truth-firewall-tools.js';
21
+
22
+ // Re-export truth context
23
+ export { TRUTH_CONTEXT_TOOLS, handleTruthContextTool } from '../truth-context.js';
24
+
25
+ /**
26
+ * Get all recommended tools (consolidated + truth firewall)
27
+ */
28
+ export function getRecommendedTools() {
29
+ const { CONSOLIDATED_TOOLS } = require('../consolidated-tools.js');
30
+ const { TRUTH_FIREWALL_TOOLS } = require('../truth-firewall-tools.js');
31
+ return [...CONSOLIDATED_TOOLS, ...TRUTH_FIREWALL_TOOLS];
32
+ }
33
+
34
+ /**
35
+ * Handle any tool call by routing to the appropriate handler
36
+ */
37
+ export async function handleToolCall(toolName, args) {
38
+ // Route to consolidated handler first
39
+ const { handleConsolidatedTool, CONSOLIDATED_TOOLS } = await import('../consolidated-tools.js');
40
+ const consolidatedNames = CONSOLIDATED_TOOLS.map(t => t.name);
41
+
42
+ if (consolidatedNames.includes(toolName)) {
43
+ return handleConsolidatedTool(toolName, args);
44
+ }
45
+
46
+ // Route to truth firewall
47
+ const { handleTruthFirewallTool, TRUTH_FIREWALL_TOOLS } = await import('../truth-firewall-tools.js');
48
+ const firewallNames = TRUTH_FIREWALL_TOOLS.map(t => t.name);
49
+
50
+ if (firewallNames.includes(toolName)) {
51
+ return handleTruthFirewallTool(toolName, args);
52
+ }
53
+
54
+ // Route to truth context
55
+ const { handleTruthContextTool, TRUTH_CONTEXT_TOOLS } = await import('../truth-context.js');
56
+ const contextNames = TRUTH_CONTEXT_TOOLS.map(t => t.name);
57
+
58
+ if (contextNames.includes(toolName)) {
59
+ return handleTruthContextTool(toolName, args);
60
+ }
61
+
62
+ throw new Error(`Unknown tool: ${toolName}`);
63
+ }
64
+
65
+ /**
66
+ * Tool categories for documentation
67
+ */
68
+ export const TOOL_CATEGORIES = {
69
+ core: ['vibecheck.scan', 'vibecheck.ship', 'vibecheck.reality', 'vibecheck.fix', 'vibecheck.prove', 'vibecheck.report'],
70
+ truth: ['vibecheck.ctx', 'vibecheck.get_truthpack', 'vibecheck.validate_claim', 'vibecheck.compile_context'],
71
+ guard: ['vibecheck.guard', 'vibecheck.check_route', 'vibecheck.check_env', 'vibecheck.check_auth'],
72
+ };
@@ -570,8 +570,47 @@ export function enforceClaimResult(result, policy = "strict") {
570
570
  return { allowed: true, confidence: derived };
571
571
  }
572
572
 
573
+ // =============================================================================
574
+ // CLAIM VALIDATION WITH RACE CONDITION PROTECTION
575
+ //
576
+ // SECURITY FIX: Previous implementation had a TOCTOU race condition:
577
+ // 1. Thread A: hasRecentClaimValidation() returns true
578
+ // 2. Thread B: invalidates the claim (file change, etc.)
579
+ // 3. Thread A: proceeds with stale claim → invalid state
580
+ //
581
+ // New implementation uses atomic check-and-consume pattern with per-project locks.
582
+ // =============================================================================
583
+
584
+ /**
585
+ * Per-project validation locks to prevent concurrent operations
586
+ * from using the same validation state.
587
+ */
588
+ const validationLocks = new Map(); // Map<projectPath, { locked: boolean, queue: Promise }>
589
+
590
+ /**
591
+ * Acquire a validation lock for a project (serializes validation checks).
592
+ */
593
+ function acquireValidationLock(projectPath) {
594
+ let lockState = validationLocks.get(projectPath);
595
+ if (!lockState) {
596
+ lockState = { locked: false, queue: Promise.resolve() };
597
+ validationLocks.set(projectPath, lockState);
598
+ }
599
+
600
+ const acquirePromise = lockState.queue.then(() => {
601
+ lockState.locked = true;
602
+ return () => {
603
+ lockState.locked = false;
604
+ };
605
+ });
606
+
607
+ lockState.queue = acquirePromise.catch(() => {});
608
+ return acquirePromise;
609
+ }
610
+
573
611
  /**
574
- * Claim validation freshness per policy TTL.
612
+ * Check claim validation freshness (basic check, no lock).
613
+ * Use checkAndConsumeClaimValidation for atomic operations.
575
614
  */
576
615
  export function hasRecentClaimValidation(projectPath, policy = "strict") {
577
616
  const last = state.lastValidationByProject.get(projectPath);
@@ -580,6 +619,56 @@ export function hasRecentClaimValidation(projectPath, policy = "strict") {
580
619
  return Date.now() - last <= ttl;
581
620
  }
582
621
 
622
+ /**
623
+ * Atomic check-and-consume claim validation.
624
+ *
625
+ * SECURITY: Use this for operations that depend on claim validation.
626
+ * It ensures no other operation can use the same validation state concurrently.
627
+ *
628
+ * @param {string} projectPath - Project path
629
+ * @param {string} policy - Policy name (strict/balanced/permissive)
630
+ * @param {string} operationId - Unique ID for this operation (for audit)
631
+ * @returns {Promise<{ valid: boolean, consumedAt?: number, reason?: string }>}
632
+ */
633
+ export async function checkAndConsumeClaimValidation(projectPath, policy = "strict", operationId = null) {
634
+ const release = await acquireValidationLock(projectPath);
635
+
636
+ try {
637
+ const last = state.lastValidationByProject.get(projectPath);
638
+ const now = Date.now();
639
+
640
+ if (typeof last !== "number") {
641
+ return {
642
+ valid: false,
643
+ reason: "No claim validation found for this project"
644
+ };
645
+ }
646
+
647
+ const ttl = getPolicyConfig(policy).validationTTL;
648
+ const age = now - last;
649
+
650
+ if (age > ttl) {
651
+ return {
652
+ valid: false,
653
+ reason: `Claim validation expired (age: ${Math.round(age / 1000)}s, TTL: ${Math.round(ttl / 1000)}s)`
654
+ };
655
+ }
656
+
657
+ // Mark this validation as consumed by updating the timestamp
658
+ // This prevents replay/reuse of the same validation
659
+ state.lastValidationByProject.set(projectPath, now);
660
+
661
+ return {
662
+ valid: true,
663
+ consumedAt: now,
664
+ operationId,
665
+ };
666
+
667
+ } finally {
668
+ release();
669
+ }
670
+ }
671
+
583
672
  // =============================================================================
584
673
  // FINGERPRINT + WRAPPER
585
674
  // =============================================================================
@@ -1069,22 +1158,63 @@ async function proposePatch(projectPath, args) {
1069
1158
  return patch;
1070
1159
  }
1071
1160
 
1161
+ /**
1162
+ * Validate command against strict allowlist.
1163
+ *
1164
+ * SECURITY FIX: Previous allowlist was too permissive, allowing arbitrary code execution:
1165
+ * - "node -e 'require(\"child_process\").exec(\"rm -rf /\")'" would pass
1166
+ * - "npm exec malicious-package" would pass
1167
+ * - "pnpm dlx evil-tool" would pass
1168
+ *
1169
+ * New allowlist only permits specific safe subcommands.
1170
+ */
1072
1171
  function commandAllowlisted(cmd) {
1073
- // Keep this tight. Expand only if you mean it.
1074
- const allow = [
1075
- /^vibecheck(\s|$)/,
1076
- /^pnpm(\s|$)/,
1077
- /^npm(\s|$)/,
1078
- /^yarn(\s|$)/,
1079
- /^node(\s|$)/,
1080
- /^bun(\s|$)/,
1081
- /^vitest(\s|$)/,
1082
- /^jest(\s|$)/,
1083
- /^tsc(\s|$)/,
1084
- /^eslint(\s|$)/,
1085
- /^playwright(\s|$)/,
1172
+ const trimmed = cmd.trim();
1173
+
1174
+ // Reject commands with shell metacharacters that could enable injection
1175
+ // These are dangerous even in "safe" commands: ; | & $ ` \ ( ) { } < > \n
1176
+ if (/[;|&$`\\(){}<>\n]/.test(trimmed)) {
1177
+ return false;
1178
+ }
1179
+
1180
+ // Reject commands that use flags commonly used for code execution
1181
+ if (/\s-[eEc]\s|\s--eval\s|\s--exec\s/i.test(trimmed)) {
1182
+ return false;
1183
+ }
1184
+
1185
+ // Strict allowlist: only specific commands with specific safe subcommands
1186
+ const strictAllow = [
1187
+ // Vibecheck CLI - only specific safe commands
1188
+ /^vibecheck\s+(ship|scan|ctx|lint|status)\b/,
1189
+ /^vibecheck\s+--help\b/,
1190
+ /^vibecheck\s+--version\b/,
1191
+
1192
+ // Package managers - only test/build/lint (no exec, dlx, or install scripts)
1193
+ /^pnpm\s+(test|build|lint|typecheck|check|run\s+(test|build|lint|typecheck))\b/,
1194
+ /^npm\s+(test|run\s+(test|build|lint|typecheck))\b/,
1195
+ /^yarn\s+(test|build|lint|typecheck|run\s+(test|build|lint|typecheck))\b/,
1196
+ /^bun\s+(test|run\s+(test|build|lint))\b/,
1197
+
1198
+ // TypeScript compiler - only type checking (no emit)
1199
+ /^tsc\s+(--noEmit|--build)\b/,
1200
+ /^tsc$/, // Default tsc with no args is safe
1201
+
1202
+ // Linters - safe read-only operations
1203
+ /^eslint\s+/, // ESLint with any args (read-only)
1204
+ /^eslint$/,
1205
+
1206
+ // Test runners - only run tests
1207
+ /^vitest\s*(run|--run)?\b/,
1208
+ /^vitest$/,
1209
+ /^jest\s*(--ci|--coverage|--passWithNoTests)?\b/,
1210
+ /^jest$/,
1211
+
1212
+ // Playwright - only test mode (no codegen which opens browsers)
1213
+ /^playwright\s+test\b/,
1214
+ /^npx\s+playwright\s+test\b/,
1086
1215
  ];
1087
- return allow.some((re) => re.test(cmd.trim()));
1216
+
1217
+ return strictAllow.some((re) => re.test(trimmed));
1088
1218
  }
1089
1219
 
1090
1220
  async function verifyPatch(projectPath, args) {
@@ -13,7 +13,7 @@
13
13
  import path from "path";
14
14
  import fs from "fs/promises";
15
15
  import { execSync } from "child_process";
16
- import { withTierCheck, checkFeatureAccess } from "./tier-auth.js";
16
+ import { withTierCheck, getFeatureAccessStatus } from "./tier-auth.js";
17
17
 
18
18
  // ============================================================================
19
19
  // TOOL DEFINITIONS
@@ -292,7 +292,7 @@ export async function handleVibecheckTool(toolName, args) {
292
292
 
293
293
  const requiredFeature = featureMap[toolName];
294
294
  if (requiredFeature) {
295
- const access = await checkFeatureAccess(requiredFeature, args?.apiKey);
295
+ const access = await getFeatureAccessStatus(requiredFeature, args?.apiKey);
296
296
  if (!access.hasAccess) {
297
297
  return {
298
298
  content: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecheckai/cli",
3
- "version": "3.2.5",
3
+ "version": "3.3.0",
4
4
  "description": "Vibecheck CLI - Ship with confidence. One verdict: SHIP | WARN | BLOCK.",
5
5
  "main": "bin/vibecheck.js",
6
6
  "bin": {
@@ -37,7 +37,6 @@
37
37
  "js-yaml": "^4.1.0",
38
38
  "ora": "^8.0.0",
39
39
  "uuid": "^9.0.0",
40
- "yaml": "^2.3.0",
41
40
  "zod": "^3.23.0"
42
41
  },
43
42
  "optionalDependencies": {
@@ -77,7 +76,7 @@
77
76
  "url": "https://github.com/vibecheck-oss/vibecheck/issues"
78
77
  },
79
78
  "engines": {
80
- "node": ">=18.0.0"
79
+ "node": ">=20.11"
81
80
  },
82
81
  "publishConfig": {
83
82
  "access": "public"