@vibecheckai/cli 3.1.6 → 3.2.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 (56) hide show
  1. package/README.md +27 -32
  2. package/bin/registry.js +208 -343
  3. package/bin/runners/context/generators/mcp.js +18 -0
  4. package/bin/runners/context/index.js +72 -4
  5. package/bin/runners/context/proof-context.js +293 -1
  6. package/bin/runners/context/security-scanner.js +311 -73
  7. package/bin/runners/lib/analyzers.js +607 -20
  8. package/bin/runners/lib/detectors-v2.js +172 -15
  9. package/bin/runners/lib/entitlements-v2.js +48 -1
  10. package/bin/runners/lib/evidence-pack.js +678 -0
  11. package/bin/runners/lib/html-proof-report.js +913 -0
  12. package/bin/runners/lib/missions/plan.js +231 -41
  13. package/bin/runners/lib/missions/templates.js +125 -0
  14. package/bin/runners/lib/scan-output.js +492 -253
  15. package/bin/runners/lib/ship-output.js +901 -641
  16. package/bin/runners/runCheckpoint.js +44 -3
  17. package/bin/runners/runContext.d.ts +4 -0
  18. package/bin/runners/runContext.js +2 -3
  19. package/bin/runners/runDoctor.js +11 -4
  20. package/bin/runners/runFix.js +51 -341
  21. package/bin/runners/runInit.js +37 -20
  22. package/bin/runners/runPolish.d.ts +4 -0
  23. package/bin/runners/runPolish.js +608 -29
  24. package/bin/runners/runProve.js +210 -25
  25. package/bin/runners/runReality.js +861 -107
  26. package/bin/runners/runScan.js +238 -4
  27. package/bin/runners/runShip.js +19 -3
  28. package/bin/runners/runWatch.js +25 -5
  29. package/bin/vibecheck.js +35 -47
  30. package/mcp-server/consolidated-tools.js +408 -42
  31. package/mcp-server/index.js +152 -15
  32. package/mcp-server/package.json +1 -1
  33. package/mcp-server/proof-tools.js +571 -0
  34. package/mcp-server/tier-auth.js +22 -19
  35. package/mcp-server/tools-v3.js +744 -0
  36. package/mcp-server/truth-firewall-tools.js +190 -4
  37. package/package.json +3 -1
  38. package/bin/runners/runBadge.js +0 -916
  39. package/bin/runners/runContracts.js +0 -105
  40. package/bin/runners/runCtx.js +0 -680
  41. package/bin/runners/runCtxDiff.js +0 -301
  42. package/bin/runners/runCtxGuard.js +0 -176
  43. package/bin/runners/runCtxSync.js +0 -116
  44. package/bin/runners/runExport.js +0 -93
  45. package/bin/runners/runGraph.js +0 -454
  46. package/bin/runners/runInstall.js +0 -273
  47. package/bin/runners/runLabs.js +0 -341
  48. package/bin/runners/runLaunch.js +0 -181
  49. package/bin/runners/runPR.js +0 -255
  50. package/bin/runners/runPermissions.js +0 -310
  51. package/bin/runners/runPreflight.js +0 -580
  52. package/bin/runners/runReplay.js +0 -499
  53. package/bin/runners/runSecurity.js +0 -92
  54. package/bin/runners/runShare.js +0 -212
  55. package/bin/runners/runStatus.js +0 -102
  56. package/bin/runners/runVerify.js +0 -272
@@ -1,310 +0,0 @@
1
- /**
2
- * vibecheck permissions - AuthZ Matrix & IDOR Detection
3
- *
4
- * Verifies authorization is correct, not just present:
5
- * - Which roles can hit which routes
6
- * - Which UI actions leak data cross-user (IDOR)
7
- * - Which admin endpoints are accidentally public
8
- */
9
-
10
- "use strict";
11
-
12
- const path = require("path");
13
- const fs = require("fs");
14
- const { buildTruthpack, loadTruthpack } = require("./lib/truth");
15
- const {
16
- extractAuthModel,
17
- buildAuthZMatrix,
18
- formatMatrix,
19
- detectIDORCandidates,
20
- buildIDORTestPlan,
21
- formatIDORPlan
22
- } = require("./lib/permissions");
23
- const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
24
-
25
- // Entitlements enforcement
26
- const entitlements = require("./lib/entitlements-v2");
27
-
28
- const c = {
29
- reset: '\x1b[0m',
30
- bold: '\x1b[1m',
31
- dim: '\x1b[2m',
32
- green: '\x1b[32m',
33
- yellow: '\x1b[33m',
34
- cyan: '\x1b[36m',
35
- red: '\x1b[31m',
36
- blue: '\x1b[34m',
37
- };
38
-
39
- function ensureDir(p) {
40
- fs.mkdirSync(p, { recursive: true });
41
- }
42
-
43
- async function runPermissions(args) {
44
- const opts = parseArgs(args);
45
-
46
- if (opts.help) {
47
- printHelp(shouldShowBanner(opts));
48
- return 0;
49
- }
50
-
51
- // TIER ENFORCEMENT: COMPLETE only
52
- const access = await entitlements.enforce("permissions", {
53
- projectPath: opts.path || process.cwd(),
54
- silent: false,
55
- });
56
-
57
- if (!access.allowed) {
58
- console.log(`\n${c.yellow}Tip:${c.reset} The permissions command requires COMPLETE tier for advanced AuthZ analysis.`);
59
- return entitlements.EXIT_FEATURE_NOT_ALLOWED;
60
- }
61
-
62
- const root = path.resolve(opts.path || process.cwd());
63
- const outDir = path.join(root, ".vibecheck", "permissions");
64
- ensureDir(outDir);
65
-
66
- console.log(`\n${c.cyan}${c.bold}🔐 vibecheck permissions${c.reset}`);
67
-
68
- // Load or build truthpack
69
- let truthpack = loadTruthpack(root);
70
- if (!truthpack) {
71
- console.log(`${c.dim}Building truthpack...${c.reset}`);
72
- truthpack = await buildTruthpack({ repoRoot: root, fastifyEntry: opts.fastifyEntry });
73
- }
74
-
75
- // Extract auth model
76
- console.log(`${c.dim}Extracting auth model...${c.reset}`);
77
- const authModel = await extractAuthModel(root, truthpack);
78
-
79
- // Save auth model
80
- fs.writeFileSync(
81
- path.join(outDir, "auth-model.json"),
82
- JSON.stringify(authModel, null, 2),
83
- "utf8"
84
- );
85
-
86
- if (opts.learn) {
87
- // Learning mode - just extract and display
88
- console.log(`\n${c.bold}Auth Model${c.reset}`);
89
- console.log(` Roles: ${authModel.roles.map(r => r.name).join(", ")}`);
90
- console.log(` Protected patterns: ${authModel.protectedPatterns?.length || 0}`);
91
- console.log(` Routes: ${authModel.routes.length}`);
92
- console.log(` RBAC patterns: ${authModel.rbacPatterns.length}`);
93
-
94
- if (authModel.roles.length > 0) {
95
- console.log(`\n${c.bold}Detected Roles${c.reset}`);
96
- for (const role of authModel.roles) {
97
- console.log(` - ${role.name} (${role.evidence.length} references)`);
98
- }
99
- }
100
-
101
- console.log(`\n${c.dim}Auth model saved to: .vibecheck/permissions/auth-model.json${c.reset}`);
102
- console.log(`${c.dim}Run 'vibecheck permissions --prove' to verify at runtime${c.reset}\n`);
103
- return 0;
104
- }
105
-
106
- if (opts.prove) {
107
- // Runtime verification mode
108
- if (!opts.url) {
109
- console.log(`${c.red}Error: --prove requires --url${c.reset}`);
110
- return 1;
111
- }
112
-
113
- console.log(`${c.dim}Running permission verification against ${opts.url}...${c.reset}`);
114
-
115
- // This would run actual browser tests
116
- // For now, show what would be tested
117
- const matrix = buildAuthZMatrix(authModel, null);
118
-
119
- console.log(`\n${c.bold}AuthZ Matrix${c.reset}`);
120
- console.log(` Routes to verify: ${matrix.routes.length}`);
121
- console.log(` Roles to test: ${matrix.roles.join(", ")}`);
122
-
123
- // Save matrix
124
- fs.writeFileSync(
125
- path.join(outDir, "authz-matrix.json"),
126
- JSON.stringify(matrix, null, 2),
127
- "utf8"
128
- );
129
-
130
- fs.writeFileSync(
131
- path.join(outDir, "authz-matrix.md"),
132
- formatMatrix(matrix),
133
- "utf8"
134
- );
135
-
136
- const blocks = matrix.violations.filter(v => v.severity === "BLOCK").length;
137
- const warns = matrix.violations.filter(v => v.severity === "WARN").length;
138
-
139
- if (matrix.violations.length > 0) {
140
- console.log(`\n${c.bold}Violations${c.reset}`);
141
- for (const v of matrix.violations.slice(0, 10)) {
142
- const icon = v.severity === "BLOCK" ? `${c.red}✗` : `${c.yellow}⚠`;
143
- console.log(` ${icon} ${v.message}${c.reset}`);
144
- }
145
- } else {
146
- console.log(`\n${c.green}✓ No violations detected${c.reset}`);
147
- }
148
-
149
- console.log(`\n${c.dim}Matrix saved to: .vibecheck/permissions/authz-matrix.json${c.reset}`);
150
- console.log(`\n${c.bold}Verdict:${c.reset} ${blocks ? `${c.red}🛑 BLOCK${c.reset}` : warns ? `${c.yellow}⚠️ WARN${c.reset}` : `${c.green}✅ CLEAN${c.reset}`}`);
151
-
152
- return blocks ? 2 : warns ? 1 : 0;
153
- }
154
-
155
- if (opts.matrix) {
156
- // Output matrix mode
157
- const matrix = buildAuthZMatrix(authModel, null);
158
- console.log("\n" + formatMatrix(matrix));
159
-
160
- fs.writeFileSync(
161
- path.join(outDir, "authz-matrix.json"),
162
- JSON.stringify(matrix, null, 2),
163
- "utf8"
164
- );
165
-
166
- fs.writeFileSync(
167
- path.join(outDir, "authz-matrix.md"),
168
- formatMatrix(matrix),
169
- "utf8"
170
- );
171
-
172
- return 0;
173
- }
174
-
175
- if (opts.idor) {
176
- // IDOR detection mode
177
- console.log(`${c.dim}Detecting IDOR candidates...${c.reset}`);
178
-
179
- const candidates = detectIDORCandidates(authModel);
180
- const plan = buildIDORTestPlan(candidates, { safe: opts.safe });
181
-
182
- console.log(`\n${c.bold}IDOR Candidates${c.reset}`);
183
- console.log(` Detected: ${candidates.length}`);
184
-
185
- if (candidates.length > 0) {
186
- for (const c of candidates.slice(0, 10)) {
187
- console.log(` - ${c.resourceType}: ${c.path}`);
188
- }
189
- }
190
-
191
- // Save plan
192
- fs.writeFileSync(
193
- path.join(outDir, "idor-plan.json"),
194
- JSON.stringify(plan, null, 2),
195
- "utf8"
196
- );
197
-
198
- fs.writeFileSync(
199
- path.join(outDir, "idor-plan.md"),
200
- formatIDORPlan(plan),
201
- "utf8"
202
- );
203
-
204
- console.log(`\n${c.dim}IDOR plan saved to: .vibecheck/permissions/idor-plan.json${c.reset}`);
205
-
206
- if (!opts.safe) {
207
- console.log(`\n${c.yellow}⚠️ IDOR tests require --safe flag for first-party testing${c.reset}`);
208
- }
209
-
210
- return 0;
211
- }
212
-
213
- // Default: show summary
214
- console.log(`\n${c.bold}Summary${c.reset}`);
215
- console.log(` Roles: ${authModel.roles.length}`);
216
- console.log(` Routes: ${authModel.routes.length}`);
217
- console.log(` Protected patterns: ${authModel.protectedPatterns?.length || 0}`);
218
-
219
- console.log(`\n${c.bold}Run one of:${c.reset}`);
220
- console.log(` ${c.cyan}vibecheck permissions --learn${c.reset} Extract auth model from code`);
221
- console.log(` ${c.cyan}vibecheck permissions --prove${c.reset} Runtime verification`);
222
- console.log(` ${c.cyan}vibecheck permissions --matrix${c.reset} Output AuthZ matrix`);
223
- console.log(` ${c.cyan}vibecheck permissions --idor${c.reset} Detect IDOR candidates\n`);
224
-
225
- return 0;
226
- }
227
-
228
- function parseArgs(args) {
229
- // Parse global flags first
230
- const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
231
-
232
- const opts = {
233
- ...globalFlags, // Merge global flags (json, verbose, noBanner, quiet, ci, etc.)
234
- path: globalFlags.path || process.cwd(),
235
- url: null,
236
- learn: false,
237
- prove: false,
238
- matrix: false,
239
- idor: false,
240
- safe: false,
241
- fastifyEntry: null,
242
- help: false,
243
- };
244
-
245
- // Parse command-specific args from cleanArgs
246
- for (let i = 0; i < cleanArgs.length; i++) {
247
- const arg = cleanArgs[i];
248
- if (arg === "--learn") opts.learn = true;
249
- else if (arg === "--prove") opts.prove = true;
250
- else if (arg === "--matrix") opts.matrix = true;
251
- else if (arg === "--idor") opts.idor = true;
252
- else if (arg === "--safe") opts.safe = true;
253
- else if (arg === "--url") opts.url = cleanArgs[++i];
254
- else if (arg === "--fastify-entry") opts.fastifyEntry = cleanArgs[++i];
255
- else if (arg === "--path" || arg === "-p") opts.path = cleanArgs[++i];
256
- else if (arg === "--help" || arg === "-h") opts.help = true;
257
- }
258
-
259
- return opts;
260
- }
261
-
262
- function printHelp() {
263
- console.log(`
264
- ${c.cyan}${c.bold}🔐 vibecheck permissions${c.reset} - AuthZ Matrix & IDOR Detection
265
-
266
- Verify authorization is correct, not just present.
267
-
268
- ${c.bold}USAGE${c.reset}
269
- vibecheck permissions --learn ${c.dim}# Extract auth model from code${c.reset}
270
- vibecheck permissions --prove --url ${c.dim}# Runtime verification${c.reset}
271
- vibecheck permissions --matrix ${c.dim}# Output full AuthZ matrix${c.reset}
272
- vibecheck permissions --idor --safe ${c.dim}# IDOR detection (first-party)${c.reset}
273
-
274
- ${c.bold}OPTIONS${c.reset}
275
- --learn Extract auth model from code
276
- --prove Runtime verification of permissions
277
- --matrix Output AuthZ matrix
278
- --idor Detect IDOR candidates
279
- --safe Enable safe mode for IDOR testing (required)
280
- --url <url> Target URL for runtime testing
281
- --fastify-entry Fastify entry file (e.g. src/server.ts)
282
- --path, -p Project path (default: current directory)
283
- --help, -h Show this help
284
-
285
- ${c.bold}FINDINGS${c.reset}
286
- ${c.red}BLOCK${c.reset} Endpoint accessible as anon that should require auth
287
- ${c.red}BLOCK${c.reset} User A can access User B's resource (IDOR)
288
- ${c.red}BLOCK${c.reset} Role mismatch between UI + server
289
- ${c.yellow}WARN${c.reset} Admin endpoint missing role check (static)
290
-
291
- ${c.bold}OUTPUT${c.reset}
292
- .vibecheck/permissions/
293
- auth-model.json Extracted auth model
294
- authz-matrix.json Full authorization matrix
295
- authz-matrix.md Human-readable matrix
296
- idor-plan.json IDOR test plan
297
-
298
- ${c.bold}SAFETY${c.reset}
299
- IDOR tests only run with --idor --safe flag
300
- Only use on local dev/staging with explicit consent
301
- Configure test users in .vibecheck/config.json
302
-
303
- ${c.bold}EXAMPLES${c.reset}
304
- vibecheck permissions --learn ${c.dim}# Extract model${c.reset}
305
- vibecheck permissions --prove --url http://localhost:3000
306
- vibecheck permissions --idor --safe ${c.dim}# IDOR detection${c.reset}
307
- `);
308
- }
309
-
310
- module.exports = { runPermissions };