@vibecheckai/cli 2.8.2 → 3.0.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.
- package/README.md +8 -8
- package/bin/_deprecations.js +35 -0
- package/bin/_router.js +46 -0
- package/bin/cli-hygiene.js +241 -0
- package/bin/guardrail.js +834 -0
- package/bin/runners/cli-utils.js +1070 -0
- package/bin/runners/context/ai-task-decomposer.js +337 -0
- package/bin/runners/context/analyzer.js +462 -0
- package/bin/runners/context/api-contracts.js +427 -0
- package/bin/runners/context/context-diff.js +342 -0
- package/bin/runners/context/context-pruner.js +291 -0
- package/bin/runners/context/dependency-graph.js +414 -0
- package/bin/runners/context/generators/claude.js +107 -0
- package/bin/runners/context/generators/codex.js +108 -0
- package/bin/runners/context/generators/copilot.js +119 -0
- package/bin/runners/context/generators/cursor.js +514 -0
- package/bin/runners/context/generators/mcp.js +151 -0
- package/bin/runners/context/generators/windsurf.js +180 -0
- package/bin/runners/context/git-context.js +302 -0
- package/bin/runners/context/index.js +1042 -0
- package/bin/runners/context/insights.js +173 -0
- package/bin/runners/context/mcp-server/generate-rules.js +337 -0
- package/bin/runners/context/mcp-server/index.js +1176 -0
- package/bin/runners/context/mcp-server/package.json +24 -0
- package/bin/runners/context/memory.js +200 -0
- package/bin/runners/context/monorepo.js +215 -0
- package/bin/runners/context/multi-repo-federation.js +404 -0
- package/bin/runners/context/patterns.js +253 -0
- package/bin/runners/context/proof-context.js +972 -0
- package/bin/runners/context/security-scanner.js +303 -0
- package/bin/runners/context/semantic-search.js +350 -0
- package/bin/runners/context/shared.js +264 -0
- package/bin/runners/context/team-conventions.js +310 -0
- package/bin/runners/lib/ai-bridge.js +416 -0
- package/bin/runners/lib/analysis-core.js +271 -0
- package/bin/runners/lib/analyzers.js +541 -0
- package/bin/runners/lib/audit-bridge.js +391 -0
- package/bin/runners/lib/auth-truth.js +193 -0
- package/bin/runners/lib/auth.js +215 -0
- package/bin/runners/lib/backup.js +62 -0
- package/bin/runners/lib/billing.js +107 -0
- package/bin/runners/lib/claims.js +118 -0
- package/bin/runners/lib/cli-ui.js +540 -0
- package/bin/runners/lib/compliance-bridge-new.js +0 -0
- package/bin/runners/lib/compliance-bridge.js +165 -0
- package/bin/runners/lib/contracts/auth-contract.js +194 -0
- package/bin/runners/lib/contracts/env-contract.js +178 -0
- package/bin/runners/lib/contracts/external-contract.js +198 -0
- package/bin/runners/lib/contracts/guard.js +168 -0
- package/bin/runners/lib/contracts/index.js +89 -0
- package/bin/runners/lib/contracts/plan-validator.js +311 -0
- package/bin/runners/lib/contracts/route-contract.js +192 -0
- package/bin/runners/lib/detect.js +89 -0
- package/bin/runners/lib/doctor/autofix.js +254 -0
- package/bin/runners/lib/doctor/index.js +37 -0
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
- package/bin/runners/lib/doctor/modules/index.js +46 -0
- package/bin/runners/lib/doctor/modules/network.js +250 -0
- package/bin/runners/lib/doctor/modules/project.js +312 -0
- package/bin/runners/lib/doctor/modules/runtime.js +224 -0
- package/bin/runners/lib/doctor/modules/security.js +348 -0
- package/bin/runners/lib/doctor/modules/system.js +213 -0
- package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
- package/bin/runners/lib/doctor/reporter.js +262 -0
- package/bin/runners/lib/doctor/service.js +262 -0
- package/bin/runners/lib/doctor/types.js +113 -0
- package/bin/runners/lib/doctor/ui.js +263 -0
- package/bin/runners/lib/doctor-enhanced.js +233 -0
- package/bin/runners/lib/doctor-v2.js +608 -0
- package/bin/runners/lib/enforcement.js +72 -0
- package/bin/runners/lib/enterprise-detect.js +603 -0
- package/bin/runners/lib/enterprise-init.js +942 -0
- package/bin/runners/lib/entitlements-v2.js +381 -0
- package/bin/runners/lib/entitlements.generated.js +0 -0
- package/bin/runners/lib/entitlements.js +332 -0
- package/bin/runners/lib/env-template.js +66 -0
- package/bin/runners/lib/env.js +189 -0
- package/bin/runners/lib/error-handler.js +320 -0
- package/bin/runners/lib/firewall-prompt.js +50 -0
- package/bin/runners/lib/graph/graph-builder.js +265 -0
- package/bin/runners/lib/graph/html-renderer.js +413 -0
- package/bin/runners/lib/graph/index.js +32 -0
- package/bin/runners/lib/graph/runtime-collector.js +215 -0
- package/bin/runners/lib/graph/static-extractor.js +518 -0
- package/bin/runners/lib/init-wizard.js +308 -0
- package/bin/runners/lib/json-output.js +76 -0
- package/bin/runners/lib/llm.js +75 -0
- package/bin/runners/lib/meter.js +61 -0
- package/bin/runners/lib/missions/evidence.js +126 -0
- package/bin/runners/lib/missions/plan.js +69 -0
- package/bin/runners/lib/missions/templates.js +147 -0
- package/bin/runners/lib/patch.js +40 -0
- package/bin/runners/lib/permissions/auth-model.js +213 -0
- package/bin/runners/lib/permissions/idor-prover.js +205 -0
- package/bin/runners/lib/permissions/index.js +45 -0
- package/bin/runners/lib/permissions/matrix-builder.js +198 -0
- package/bin/runners/lib/pkgjson.js +28 -0
- package/bin/runners/lib/preflight.js +142 -0
- package/bin/runners/lib/reality-findings.js +84 -0
- package/bin/runners/lib/redact.js +29 -0
- package/bin/runners/lib/replay/capsule-manager.js +154 -0
- package/bin/runners/lib/replay/index.js +263 -0
- package/bin/runners/lib/replay/player.js +348 -0
- package/bin/runners/lib/replay/recorder.js +331 -0
- package/bin/runners/lib/report-engine.js +447 -0
- package/bin/runners/lib/report-html.js +1117 -0
- package/bin/runners/lib/report-templates.js +964 -0
- package/bin/runners/lib/route-detection.js +1140 -0
- package/bin/runners/lib/route-truth.js +477 -0
- package/bin/runners/lib/sandbox/index.js +59 -0
- package/bin/runners/lib/sandbox/proof-chain.js +399 -0
- package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
- package/bin/runners/lib/sandbox/worktree.js +174 -0
- package/bin/runners/lib/scan-cache.js +330 -0
- package/bin/runners/lib/scan-output-schema.js +344 -0
- package/bin/runners/lib/score-history.js +282 -0
- package/bin/runners/lib/security-bridge.js +249 -0
- package/bin/runners/lib/server-usage.js +513 -0
- package/bin/runners/lib/share-pack.js +239 -0
- package/bin/runners/lib/snippets.js +67 -0
- package/bin/runners/lib/truth.js +667 -0
- package/bin/runners/lib/unified-output.js +189 -0
- package/bin/runners/lib/validate-patch.js +156 -0
- package/bin/runners/lib/verification.js +345 -0
- package/bin/runners/reality/engine.js +917 -0
- package/bin/runners/reality/flows.js +122 -0
- package/bin/runners/reality/report.js +378 -0
- package/bin/runners/reality/session.js +193 -0
- package/bin/runners/runAIAgent.js +2 -0
- package/bin/runners/runAudit.js +2 -0
- package/bin/runners/runAuth.js +106 -0
- package/bin/runners/runAutopilot.js +2 -0
- package/bin/runners/runBadge.js +2 -0
- package/bin/runners/runCertify.js +2 -0
- package/bin/runners/runClaimVerifier.js +483 -0
- package/bin/runners/runContext.js +56 -0
- package/bin/runners/runContextCompiler.js +385 -0
- package/bin/runners/runCtx.js +187 -0
- package/bin/runners/runCtxGuard.js +176 -0
- package/bin/runners/runCtxSync.js +116 -0
- package/bin/runners/runDashboard.js +10 -0
- package/bin/runners/runDoctor.js +245 -0
- package/bin/runners/runEnhancedShip.js +2 -0
- package/bin/runners/runFix.js +735 -0
- package/bin/runners/runFixPacks.js +2 -0
- package/bin/runners/runGate.js +17 -0
- package/bin/runners/runGraph.js +283 -0
- package/bin/runners/runInit.js +260 -0
- package/bin/runners/runInitGha.js +101 -0
- package/bin/runners/runInstall.js +76 -0
- package/bin/runners/runInteractive.js +388 -0
- package/bin/runners/runLaunch.js +2 -0
- package/bin/runners/runMcp.js +19 -0
- package/bin/runners/runMdc.js +2 -0
- package/bin/runners/runMissionGenerator.js +282 -0
- package/bin/runners/runNaturalLanguage.js +3 -0
- package/bin/runners/runPR.js +96 -0
- package/bin/runners/runPermissions.js +290 -0
- package/bin/runners/runPromptFirewall.js +211 -0
- package/bin/runners/runProof.js +2 -0
- package/bin/runners/runProve.js +392 -0
- package/bin/runners/runReality.js +489 -0
- package/bin/runners/runRealitySniff.js +2 -0
- package/bin/runners/runReplay.js +469 -0
- package/bin/runners/runReport.js +478 -0
- package/bin/runners/runScan.js +835 -0
- package/bin/runners/runShare.js +34 -0
- package/bin/runners/runShip.js +1062 -0
- package/bin/runners/runStatus.js +136 -0
- package/bin/runners/runTruthpack.js +634 -0
- package/bin/runners/runUpgrade.js +2 -0
- package/bin/runners/runValidate.js +2 -0
- package/bin/runners/runVerifyAgentOutput.js +2 -0
- package/bin/runners/runWatch.js +230 -0
- package/bin/runners/utils.js +360 -0
- package/bin/scan.js +612 -0
- package/bin/vibecheck.js +834 -0
- package/package.json +11 -11
- package/dist/autopatch/verified-autopatch.d.ts +0 -111
- package/dist/autopatch/verified-autopatch.d.ts.map +0 -1
- package/dist/autopatch/verified-autopatch.js +0 -503
- package/dist/autopatch/verified-autopatch.js.map +0 -1
- package/dist/bundles/index.js +0 -8
- package/dist/bundles/vibecheck-core.js +0 -25799
- package/dist/bundles/vibecheck-security.js +0 -208693
- package/dist/bundles/vibecheck-ship.js +0 -2318
- package/dist/commands/baseline.d.ts +0 -7
- package/dist/commands/baseline.d.ts.map +0 -1
- package/dist/commands/baseline.js +0 -79
- package/dist/commands/baseline.js.map +0 -1
- package/dist/commands/cache.d.ts +0 -13
- package/dist/commands/cache.d.ts.map +0 -1
- package/dist/commands/cache.js +0 -165
- package/dist/commands/cache.js.map +0 -1
- package/dist/commands/checkpoint.d.ts +0 -8
- package/dist/commands/checkpoint.d.ts.map +0 -1
- package/dist/commands/checkpoint.js +0 -35
- package/dist/commands/checkpoint.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -17
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -226
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/evidence.d.ts +0 -45
- package/dist/commands/evidence.d.ts.map +0 -1
- package/dist/commands/evidence.js +0 -197
- package/dist/commands/evidence.js.map +0 -1
- package/dist/commands/explain.d.ts +0 -8
- package/dist/commands/explain.d.ts.map +0 -1
- package/dist/commands/explain.js +0 -52
- package/dist/commands/explain.js.map +0 -1
- package/dist/commands/fix-consolidated.d.ts +0 -19
- package/dist/commands/fix-consolidated.d.ts.map +0 -1
- package/dist/commands/fix-consolidated.js +0 -165
- package/dist/commands/fix-consolidated.js.map +0 -1
- package/dist/commands/index.d.ts +0 -8
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js +0 -15
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -125
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/launcher.d.ts +0 -10
- package/dist/commands/launcher.d.ts.map +0 -1
- package/dist/commands/launcher.js +0 -174
- package/dist/commands/launcher.js.map +0 -1
- package/dist/commands/on.d.ts +0 -8
- package/dist/commands/on.d.ts.map +0 -1
- package/dist/commands/on.js +0 -123
- package/dist/commands/on.js.map +0 -1
- package/dist/commands/replay.d.ts +0 -8
- package/dist/commands/replay.d.ts.map +0 -1
- package/dist/commands/replay.js +0 -52
- package/dist/commands/replay.js.map +0 -1
- package/dist/commands/scan-consolidated.d.ts +0 -61
- package/dist/commands/scan-consolidated.d.ts.map +0 -1
- package/dist/commands/scan-consolidated.js +0 -243
- package/dist/commands/scan-consolidated.js.map +0 -1
- package/dist/commands/scan-secrets.d.ts +0 -47
- package/dist/commands/scan-secrets.d.ts.map +0 -1
- package/dist/commands/scan-secrets.js +0 -225
- package/dist/commands/scan-secrets.js.map +0 -1
- package/dist/commands/scan-vulnerabilities-enhanced.d.ts +0 -41
- package/dist/commands/scan-vulnerabilities-enhanced.d.ts.map +0 -1
- package/dist/commands/scan-vulnerabilities-enhanced.js +0 -368
- package/dist/commands/scan-vulnerabilities-enhanced.js.map +0 -1
- package/dist/commands/scan-vulnerabilities-osv.d.ts +0 -58
- package/dist/commands/scan-vulnerabilities-osv.d.ts.map +0 -1
- package/dist/commands/scan-vulnerabilities-osv.js +0 -722
- package/dist/commands/scan-vulnerabilities-osv.js.map +0 -1
- package/dist/commands/scan-vulnerabilities.d.ts +0 -32
- package/dist/commands/scan-vulnerabilities.d.ts.map +0 -1
- package/dist/commands/scan-vulnerabilities.js +0 -283
- package/dist/commands/scan-vulnerabilities.js.map +0 -1
- package/dist/commands/secrets-allowlist.d.ts +0 -7
- package/dist/commands/secrets-allowlist.d.ts.map +0 -1
- package/dist/commands/secrets-allowlist.js +0 -85
- package/dist/commands/secrets-allowlist.js.map +0 -1
- package/dist/commands/ship-consolidated.d.ts +0 -58
- package/dist/commands/ship-consolidated.d.ts.map +0 -1
- package/dist/commands/ship-consolidated.js +0 -515
- package/dist/commands/ship-consolidated.js.map +0 -1
- package/dist/commands/stats.d.ts +0 -8
- package/dist/commands/stats.d.ts.map +0 -1
- package/dist/commands/stats.js +0 -134
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/upgrade.d.ts +0 -8
- package/dist/commands/upgrade.d.ts.map +0 -1
- package/dist/commands/upgrade.js +0 -30
- package/dist/commands/upgrade.js.map +0 -1
- package/dist/fix/applicator.d.ts +0 -44
- package/dist/fix/applicator.d.ts.map +0 -1
- package/dist/fix/applicator.js +0 -144
- package/dist/fix/applicator.js.map +0 -1
- package/dist/fix/backup.d.ts +0 -38
- package/dist/fix/backup.d.ts.map +0 -1
- package/dist/fix/backup.js +0 -154
- package/dist/fix/backup.js.map +0 -1
- package/dist/fix/engine.d.ts +0 -55
- package/dist/fix/engine.d.ts.map +0 -1
- package/dist/fix/engine.js +0 -285
- package/dist/fix/engine.js.map +0 -1
- package/dist/fix/index.d.ts +0 -5
- package/dist/fix/index.d.ts.map +0 -1
- package/dist/fix/index.js +0 -12
- package/dist/fix/index.js.map +0 -1
- package/dist/fix/interactive.d.ts +0 -22
- package/dist/fix/interactive.d.ts.map +0 -1
- package/dist/fix/interactive.js +0 -172
- package/dist/fix/interactive.js.map +0 -1
- package/dist/formatters/index.d.ts +0 -6
- package/dist/formatters/index.d.ts.map +0 -1
- package/dist/formatters/index.js +0 -11
- package/dist/formatters/index.js.map +0 -1
- package/dist/formatters/sarif-enhanced.d.ts +0 -78
- package/dist/formatters/sarif-enhanced.d.ts.map +0 -1
- package/dist/formatters/sarif-enhanced.js +0 -144
- package/dist/formatters/sarif-enhanced.js.map +0 -1
- package/dist/formatters/sarif-v2.d.ts +0 -121
- package/dist/formatters/sarif-v2.d.ts.map +0 -1
- package/dist/formatters/sarif-v2.js +0 -356
- package/dist/formatters/sarif-v2.js.map +0 -1
- package/dist/formatters/sarif.d.ts +0 -72
- package/dist/formatters/sarif.d.ts.map +0 -1
- package/dist/formatters/sarif.js +0 -146
- package/dist/formatters/sarif.js.map +0 -1
- package/dist/index.d.ts +0 -61
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4388
- package/dist/index.js.map +0 -1
- package/dist/init/ci-generator.d.ts +0 -18
- package/dist/init/ci-generator.d.ts.map +0 -1
- package/dist/init/ci-generator.js +0 -317
- package/dist/init/ci-generator.js.map +0 -1
- package/dist/init/detect-framework.d.ts +0 -15
- package/dist/init/detect-framework.d.ts.map +0 -1
- package/dist/init/detect-framework.js +0 -301
- package/dist/init/detect-framework.js.map +0 -1
- package/dist/init/hooks-installer.d.ts +0 -22
- package/dist/init/hooks-installer.d.ts.map +0 -1
- package/dist/init/hooks-installer.js +0 -310
- package/dist/init/hooks-installer.js.map +0 -1
- package/dist/init/index.d.ts +0 -8
- package/dist/init/index.d.ts.map +0 -1
- package/dist/init/index.js +0 -22
- package/dist/init/index.js.map +0 -1
- package/dist/init/templates.d.ts +0 -402
- package/dist/init/templates.d.ts.map +0 -1
- package/dist/init/templates.js +0 -240
- package/dist/init/templates.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -12
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -42
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/telemetry.d.ts +0 -40
- package/dist/mcp/telemetry.d.ts.map +0 -1
- package/dist/mcp/telemetry.js +0 -98
- package/dist/mcp/telemetry.js.map +0 -1
- package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts +0 -32
- package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts.map +0 -1
- package/dist/reality/no-dead-buttons/button-sweep-generator.js +0 -236
- package/dist/reality/no-dead-buttons/button-sweep-generator.js.map +0 -1
- package/dist/reality/no-dead-buttons/index.d.ts +0 -11
- package/dist/reality/no-dead-buttons/index.d.ts.map +0 -1
- package/dist/reality/no-dead-buttons/index.js +0 -18
- package/dist/reality/no-dead-buttons/index.js.map +0 -1
- package/dist/reality/no-dead-buttons/static-scanner.d.ts +0 -34
- package/dist/reality/no-dead-buttons/static-scanner.d.ts.map +0 -1
- package/dist/reality/no-dead-buttons/static-scanner.js +0 -230
- package/dist/reality/no-dead-buttons/static-scanner.js.map +0 -1
- package/dist/reality/reality-graph.d.ts +0 -192
- package/dist/reality/reality-graph.d.ts.map +0 -1
- package/dist/reality/reality-graph.js +0 -600
- package/dist/reality/reality-graph.js.map +0 -1
- package/dist/reality/reality-runner.d.ts +0 -89
- package/dist/reality/reality-runner.d.ts.map +0 -1
- package/dist/reality/reality-runner.js +0 -540
- package/dist/reality/reality-runner.js.map +0 -1
- package/dist/reality/receipt-generator.d.ts +0 -152
- package/dist/reality/receipt-generator.d.ts.map +0 -1
- package/dist/reality/receipt-generator.js +0 -495
- package/dist/reality/receipt-generator.js.map +0 -1
- package/dist/reality/runtime-tracer.d.ts +0 -75
- package/dist/reality/runtime-tracer.d.ts.map +0 -1
- package/dist/reality/runtime-tracer.js +0 -109
- package/dist/reality/runtime-tracer.js.map +0 -1
- package/dist/runtime/auth-utils.d.ts +0 -43
- package/dist/runtime/auth-utils.d.ts.map +0 -1
- package/dist/runtime/auth-utils.js +0 -130
- package/dist/runtime/auth-utils.js.map +0 -1
- package/dist/runtime/client.d.ts +0 -74
- package/dist/runtime/client.d.ts.map +0 -1
- package/dist/runtime/client.js +0 -222
- package/dist/runtime/client.js.map +0 -1
- package/dist/runtime/creds.d.ts +0 -48
- package/dist/runtime/creds.d.ts.map +0 -1
- package/dist/runtime/creds.js +0 -245
- package/dist/runtime/creds.js.map +0 -1
- package/dist/runtime/exit-codes.d.ts +0 -49
- package/dist/runtime/exit-codes.d.ts.map +0 -1
- package/dist/runtime/exit-codes.js +0 -93
- package/dist/runtime/exit-codes.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -9
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js +0 -25
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/json-output.d.ts +0 -42
- package/dist/runtime/json-output.d.ts.map +0 -1
- package/dist/runtime/json-output.js +0 -59
- package/dist/runtime/json-output.js.map +0 -1
- package/dist/runtime/semver.d.ts +0 -37
- package/dist/runtime/semver.d.ts.map +0 -1
- package/dist/runtime/semver.js +0 -110
- package/dist/runtime/semver.js.map +0 -1
- package/dist/scan/dead-ui-detector.d.ts +0 -48
- package/dist/scan/dead-ui-detector.d.ts.map +0 -1
- package/dist/scan/dead-ui-detector.js +0 -170
- package/dist/scan/dead-ui-detector.js.map +0 -1
- package/dist/scan/playwright-sweep.d.ts +0 -40
- package/dist/scan/playwright-sweep.d.ts.map +0 -1
- package/dist/scan/playwright-sweep.js +0 -216
- package/dist/scan/playwright-sweep.js.map +0 -1
- package/dist/scan/proof-bundle.d.ts +0 -25
- package/dist/scan/proof-bundle.d.ts.map +0 -1
- package/dist/scan/proof-bundle.js +0 -203
- package/dist/scan/proof-bundle.js.map +0 -1
- package/dist/scan/proof-graph.d.ts +0 -59
- package/dist/scan/proof-graph.d.ts.map +0 -1
- package/dist/scan/proof-graph.js +0 -64
- package/dist/scan/proof-graph.js.map +0 -1
- package/dist/scan/reality-sniff.d.ts +0 -56
- package/dist/scan/reality-sniff.d.ts.map +0 -1
- package/dist/scan/reality-sniff.js +0 -200
- package/dist/scan/reality-sniff.js.map +0 -1
- package/dist/scan/structural-verifier.d.ts +0 -20
- package/dist/scan/structural-verifier.d.ts.map +0 -1
- package/dist/scan/structural-verifier.js +0 -112
- package/dist/scan/structural-verifier.js.map +0 -1
- package/dist/scan/verification-engine.d.ts +0 -47
- package/dist/scan/verification-engine.d.ts.map +0 -1
- package/dist/scan/verification-engine.js +0 -141
- package/dist/scan/verification-engine.js.map +0 -1
- package/dist/scanner/baseline.d.ts +0 -52
- package/dist/scanner/baseline.d.ts.map +0 -1
- package/dist/scanner/baseline.js +0 -85
- package/dist/scanner/baseline.js.map +0 -1
- package/dist/scanner/incremental.d.ts +0 -30
- package/dist/scanner/incremental.d.ts.map +0 -1
- package/dist/scanner/incremental.js +0 -82
- package/dist/scanner/incremental.js.map +0 -1
- package/dist/scanner/parallel.d.ts +0 -43
- package/dist/scanner/parallel.d.ts.map +0 -1
- package/dist/scanner/parallel.js +0 -99
- package/dist/scanner/parallel.js.map +0 -1
- package/dist/standalone.d.ts +0 -1
- package/dist/standalone.d.ts.map +0 -1
- package/dist/standalone.js +0 -1
- package/dist/standalone.js.map +0 -1
- package/dist/truth-pack/index.d.ts +0 -102
- package/dist/truth-pack/index.d.ts.map +0 -1
- package/dist/truth-pack/index.js +0 -694
- package/dist/truth-pack/index.js.map +0 -1
- package/dist/ui/frame.d.ts +0 -68
- package/dist/ui/frame.d.ts.map +0 -1
- package/dist/ui/frame.js +0 -165
- package/dist/ui/frame.js.map +0 -1
- package/dist/ui/index.d.ts +0 -5
- package/dist/ui/index.d.ts.map +0 -1
- package/dist/ui/index.js +0 -16
- package/dist/ui/index.js.map +0 -1
- package/dist/ui.d.ts +0 -36
- package/dist/ui.d.ts.map +0 -1
- package/dist/ui.js +0 -45
- package/dist/ui.js.map +0 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Mission Generator v1
|
|
4
|
+
*
|
|
5
|
+
* Generates Assist Mission files from ship findings.
|
|
6
|
+
* Each mission is a Markdown file with YAML frontmatter.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* generateMissions(findings, projectPath)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs/promises';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import yaml from 'js-yaml';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate mission files from findings
|
|
18
|
+
*
|
|
19
|
+
* @param {Object[]} findings - Array of findings from vibecheck ship
|
|
20
|
+
* @param {string} projectPath - Project root path
|
|
21
|
+
* @returns {Object} Generated missions info
|
|
22
|
+
*/
|
|
23
|
+
export async function generateMissions(findings, projectPath = process.cwd()) {
|
|
24
|
+
const assistDir = path.join(projectPath, '.vibecheck', 'assist');
|
|
25
|
+
const missionsDir = path.join(assistDir, 'missions');
|
|
26
|
+
|
|
27
|
+
await fs.mkdir(missionsDir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
// Group findings by category
|
|
30
|
+
const grouped = groupFindings(findings);
|
|
31
|
+
|
|
32
|
+
// Generate mission files
|
|
33
|
+
const missions = [];
|
|
34
|
+
let missionNumber = 1;
|
|
35
|
+
|
|
36
|
+
for (const [category, categoryFindings] of Object.entries(grouped)) {
|
|
37
|
+
for (const finding of categoryFindings) {
|
|
38
|
+
const mission = createMission(finding, missionNumber, category);
|
|
39
|
+
const filename = `${String(missionNumber).padStart(2, '0')}_${slugify(mission.title)}.md`;
|
|
40
|
+
const filePath = path.join(missionsDir, filename);
|
|
41
|
+
|
|
42
|
+
await fs.writeFile(filePath, formatMission(mission));
|
|
43
|
+
|
|
44
|
+
missions.push({
|
|
45
|
+
id: mission.missionId,
|
|
46
|
+
title: mission.title,
|
|
47
|
+
file: filename,
|
|
48
|
+
severity: mission.severity,
|
|
49
|
+
category: mission.category,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
missionNumber++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Write plan.json
|
|
57
|
+
const plan = {
|
|
58
|
+
generatedAt: new Date().toISOString(),
|
|
59
|
+
totalMissions: missions.length,
|
|
60
|
+
byCategory: Object.fromEntries(
|
|
61
|
+
Object.entries(grouped).map(([cat, items]) => [cat, items.length])
|
|
62
|
+
),
|
|
63
|
+
missions,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
await fs.writeFile(
|
|
67
|
+
path.join(assistDir, 'plan.json'),
|
|
68
|
+
JSON.stringify(plan, null, 2)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
console.log(`\n📋 Generated ${missions.length} missions in ${missionsDir}`);
|
|
72
|
+
|
|
73
|
+
return plan;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Group findings by category
|
|
78
|
+
*/
|
|
79
|
+
function groupFindings(findings) {
|
|
80
|
+
const groups = {};
|
|
81
|
+
|
|
82
|
+
for (const finding of findings) {
|
|
83
|
+
const category = finding.category || 'general';
|
|
84
|
+
if (!groups[category]) groups[category] = [];
|
|
85
|
+
groups[category].push(finding);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Sort by severity within each category
|
|
89
|
+
const severityOrder = { BLOCK: 0, WARN: 1, INFO: 2 };
|
|
90
|
+
for (const category of Object.keys(groups)) {
|
|
91
|
+
groups[category].sort((a, b) =>
|
|
92
|
+
(severityOrder[a.severity] || 3) - (severityOrder[b.severity] || 3)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return groups;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create a mission object from a finding
|
|
101
|
+
*/
|
|
102
|
+
function createMission(finding, number, category) {
|
|
103
|
+
const missionId = `M${String(number).padStart(2, '0')}`;
|
|
104
|
+
|
|
105
|
+
// Determine required claims based on finding type
|
|
106
|
+
const dependsOnClaims = [];
|
|
107
|
+
if (finding.type === 'dead_ui' || finding.type === 'route_mismatch') {
|
|
108
|
+
dependsOnClaims.push({
|
|
109
|
+
type: 'route_exists',
|
|
110
|
+
subject: { path: finding.route || finding.expectedRoute },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (finding.type === 'auth_gap') {
|
|
114
|
+
dependsOnClaims.push({
|
|
115
|
+
type: 'auth_enforced',
|
|
116
|
+
subject: { path: finding.route },
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Determine applicable invariants
|
|
121
|
+
const invariants = [];
|
|
122
|
+
if (category === 'DeadUI' || finding.type === 'dead_ui') {
|
|
123
|
+
invariants.push('INV_NO_FAKE_SUCCESS', 'INV_NO_ROUTE_INVENTION');
|
|
124
|
+
}
|
|
125
|
+
if (category === 'Auth' || finding.type === 'auth_gap') {
|
|
126
|
+
invariants.push('INV_NO_BYPASS_ENTITLEMENTS', 'INV_NO_SILENT_CATCH_AUTH');
|
|
127
|
+
}
|
|
128
|
+
if (category === 'Billing') {
|
|
129
|
+
invariants.push('INV_NO_BYPASS_ENTITLEMENTS');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
missionId,
|
|
134
|
+
title: finding.title || `Fix ${category} issue`,
|
|
135
|
+
severity: finding.severity || 'WARN',
|
|
136
|
+
category,
|
|
137
|
+
scopeFiles: finding.files || [],
|
|
138
|
+
dependsOnClaims,
|
|
139
|
+
invariants,
|
|
140
|
+
assumptionBudget: 2,
|
|
141
|
+
finding,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Format a mission as Markdown with YAML frontmatter
|
|
147
|
+
*/
|
|
148
|
+
function formatMission(mission) {
|
|
149
|
+
const frontmatter = {
|
|
150
|
+
missionId: mission.missionId,
|
|
151
|
+
title: mission.title,
|
|
152
|
+
severity: mission.severity,
|
|
153
|
+
category: mission.category,
|
|
154
|
+
scopeFiles: mission.scopeFiles,
|
|
155
|
+
dependsOnClaims: mission.dependsOnClaims,
|
|
156
|
+
invariants: mission.invariants,
|
|
157
|
+
assumptionBudget: mission.assumptionBudget,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const finding = mission.finding;
|
|
161
|
+
|
|
162
|
+
const content = `---
|
|
163
|
+
${yaml.dump(frontmatter, { lineWidth: -1 })}---
|
|
164
|
+
|
|
165
|
+
# Objective
|
|
166
|
+
${finding.description || finding.title || 'Fix the identified issue.'}
|
|
167
|
+
|
|
168
|
+
# Truth Pack (authoritative)
|
|
169
|
+
Use the provided context slice and do not invent endpoints, env vars, or auth assumptions.
|
|
170
|
+
|
|
171
|
+
# Evidence Pack (must reference when editing)
|
|
172
|
+
- Finding ${finding.id || mission.missionId}:
|
|
173
|
+
${mission.scopeFiles.map(f => ` - ${f}`).join('\n') || ' - (no specific files identified)'}
|
|
174
|
+
- Reason: ${finding.reason || finding.description || 'See finding details'}
|
|
175
|
+
|
|
176
|
+
# Required tool calls (before making claims)
|
|
177
|
+
${generateRequiredToolCalls(mission)}
|
|
178
|
+
|
|
179
|
+
# Steps
|
|
180
|
+
${generateSteps(mission)}
|
|
181
|
+
|
|
182
|
+
# Acceptance tests (must pass)
|
|
183
|
+
- vibecheck ship
|
|
184
|
+
- ${findTestCommand(mission)}
|
|
185
|
+
- No new blockers introduced
|
|
186
|
+
|
|
187
|
+
# Output requirements
|
|
188
|
+
- List changed files
|
|
189
|
+
- Explain each change with evidence refs
|
|
190
|
+
- Provide final ship verdict result
|
|
191
|
+
`;
|
|
192
|
+
|
|
193
|
+
return content;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Generate required tool calls for the mission
|
|
198
|
+
*/
|
|
199
|
+
function generateRequiredToolCalls(mission) {
|
|
200
|
+
const calls = [];
|
|
201
|
+
let callNum = 1;
|
|
202
|
+
|
|
203
|
+
for (const claim of mission.dependsOnClaims) {
|
|
204
|
+
calls.push(`${callNum}) validate_claim(${claim.type} ${JSON.stringify(claim.subject)})`);
|
|
205
|
+
callNum++;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (calls.length === 0) {
|
|
209
|
+
calls.push('1) vibecheck.get_truthpack() - Get current truth state');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
calls.push(`${callNum}) search_evidence("${mission.category.toLowerCase()}", globs=["src/**","apps/**"])`);
|
|
213
|
+
|
|
214
|
+
return calls.join('\n');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Generate steps for the mission
|
|
219
|
+
*/
|
|
220
|
+
function generateSteps(mission) {
|
|
221
|
+
const steps = [];
|
|
222
|
+
const finding = mission.finding;
|
|
223
|
+
|
|
224
|
+
switch (mission.category) {
|
|
225
|
+
case 'DeadUI':
|
|
226
|
+
steps.push('1) Identify why the UI action is dead (early return / missing handler / missing await).');
|
|
227
|
+
steps.push('2) If route mismatch exists, align client call to an existing proven route (do not invent).');
|
|
228
|
+
steps.push('3) Ensure success UI happens only after response ok.');
|
|
229
|
+
steps.push('4) Ensure errors surface (no empty catch).');
|
|
230
|
+
break;
|
|
231
|
+
|
|
232
|
+
case 'Auth':
|
|
233
|
+
steps.push('1) Verify the auth gap is real by checking middleware/guard configuration.');
|
|
234
|
+
steps.push('2) Add or fix the auth middleware on the affected route.');
|
|
235
|
+
steps.push('3) Ensure auth errors are properly handled (no silent failures).');
|
|
236
|
+
steps.push('4) Test both authenticated and unauthenticated access.');
|
|
237
|
+
break;
|
|
238
|
+
|
|
239
|
+
case 'Billing':
|
|
240
|
+
steps.push('1) Verify the billing gate is missing or bypassable.');
|
|
241
|
+
steps.push('2) Add server-side tier/entitlement check.');
|
|
242
|
+
steps.push('3) Ensure client-side checks match server-side enforcement.');
|
|
243
|
+
steps.push('4) Remove any bypass flags or dev-only overrides.');
|
|
244
|
+
break;
|
|
245
|
+
|
|
246
|
+
case 'Security':
|
|
247
|
+
steps.push('1) Identify the security vulnerability.');
|
|
248
|
+
steps.push('2) Apply the appropriate fix without breaking functionality.');
|
|
249
|
+
steps.push('3) Add validation/sanitization as needed.');
|
|
250
|
+
steps.push('4) Verify the fix does not introduce new vulnerabilities.');
|
|
251
|
+
break;
|
|
252
|
+
|
|
253
|
+
default:
|
|
254
|
+
steps.push('1) Analyze the finding to understand the root cause.');
|
|
255
|
+
steps.push('2) Identify the minimal change needed to fix the issue.');
|
|
256
|
+
steps.push('3) Implement the fix with proper error handling.');
|
|
257
|
+
steps.push('4) Verify the fix resolves the finding.');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return steps.join('\n');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Find the appropriate test command
|
|
265
|
+
*/
|
|
266
|
+
function findTestCommand(mission) {
|
|
267
|
+
// This would ideally come from the truth pack's project.scripts
|
|
268
|
+
return 'pnpm test OR npm test (if present)';
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Convert title to slug
|
|
273
|
+
*/
|
|
274
|
+
function slugify(text) {
|
|
275
|
+
return text
|
|
276
|
+
.toLowerCase()
|
|
277
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
278
|
+
.replace(/^_+|_+$/g, '')
|
|
279
|
+
.slice(0, 40);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export default { generateMissions };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// bin/runners/runPR.js
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { shipCore } = require("./runShip");
|
|
5
|
+
|
|
6
|
+
function ensureDir(p) {
|
|
7
|
+
fs.mkdirSync(p, { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function severityCounts(findings) {
|
|
11
|
+
const c = { BLOCK: 0, WARN: 0, INFO: 0 };
|
|
12
|
+
for (const f of findings || []) {
|
|
13
|
+
if (f.severity === "BLOCK") c.BLOCK++;
|
|
14
|
+
else if (f.severity === "WARN") c.WARN++;
|
|
15
|
+
else c.INFO++;
|
|
16
|
+
}
|
|
17
|
+
return c;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function toEmojiVerdict(v) {
|
|
21
|
+
if (v === "SHIP") return "✅ SHIP";
|
|
22
|
+
if (v === "WARN") return "⚠️ WARN";
|
|
23
|
+
return "🛑 BLOCK";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function buildPrMarkdown({ report, maxFindings = 12 } = {}) {
|
|
27
|
+
const verdict = report?.meta?.verdict || "unknown";
|
|
28
|
+
const findings = report?.findings || [];
|
|
29
|
+
const counts = severityCounts(findings);
|
|
30
|
+
|
|
31
|
+
const top = findings
|
|
32
|
+
.filter(f => f.severity === "BLOCK" || f.severity === "WARN")
|
|
33
|
+
.slice(0, maxFindings);
|
|
34
|
+
|
|
35
|
+
const lines = [];
|
|
36
|
+
lines.push(`## vibecheck — ${toEmojiVerdict(verdict)}`);
|
|
37
|
+
lines.push(``);
|
|
38
|
+
lines.push(`**Reality summary:** BLOCK=${counts.BLOCK} • WARN=${counts.WARN}`);
|
|
39
|
+
lines.push(``);
|
|
40
|
+
|
|
41
|
+
if (!top.length) {
|
|
42
|
+
lines.push(`✅ No blockers. Ship it.`);
|
|
43
|
+
return lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
lines.push(`### Top findings`);
|
|
47
|
+
for (const f of top) {
|
|
48
|
+
lines.push(`- **${f.severity}** \`${f.id}\` — ${f.title}`);
|
|
49
|
+
const ev = (f.evidence || [])[0];
|
|
50
|
+
if (ev?.file) {
|
|
51
|
+
lines.push(` - Evidence: \`${ev.file}:${ev.lines}\` (${ev.reason})`);
|
|
52
|
+
if (ev.snippetHash) lines.push(` - SnipHash: \`${ev.snippetHash}\``);
|
|
53
|
+
}
|
|
54
|
+
const hint = (f.fixHints || [])[0];
|
|
55
|
+
if (hint) lines.push(` - Fix: ${hint}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (findings.length > top.length) {
|
|
59
|
+
lines.push(``);
|
|
60
|
+
lines.push(`_…and ${findings.length - top.length} more finding(s). See \`.vibecheck/last_ship.json\` for full details._`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function exitCodeForVerdict(verdict, { failOnWarn = false } = {}) {
|
|
67
|
+
if (verdict === "SHIP") return 0;
|
|
68
|
+
if (verdict === "WARN") return failOnWarn ? 1 : 0;
|
|
69
|
+
return 2; // BLOCK
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function runPR({
|
|
73
|
+
repoRoot,
|
|
74
|
+
fastifyEntry,
|
|
75
|
+
out,
|
|
76
|
+
failOnWarn = false,
|
|
77
|
+
maxFindings = 12
|
|
78
|
+
} = {}) {
|
|
79
|
+
const root = repoRoot || process.cwd();
|
|
80
|
+
|
|
81
|
+
const { report, verdict } = await shipCore({ repoRoot: root, fastifyEntry, noWrite: false });
|
|
82
|
+
|
|
83
|
+
const md = buildPrMarkdown({ report, maxFindings });
|
|
84
|
+
|
|
85
|
+
if (out) {
|
|
86
|
+
const outAbs = path.isAbsolute(out) ? out : path.join(root, out);
|
|
87
|
+
ensureDir(path.dirname(outAbs));
|
|
88
|
+
fs.writeFileSync(outAbs, md, "utf8");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(md);
|
|
92
|
+
|
|
93
|
+
process.exitCode = exitCodeForVerdict(verdict, { failOnWarn });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = { runPR };
|
|
@@ -0,0 +1,290 @@
|
|
|
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
|
+
|
|
24
|
+
const c = {
|
|
25
|
+
reset: '\x1b[0m',
|
|
26
|
+
bold: '\x1b[1m',
|
|
27
|
+
dim: '\x1b[2m',
|
|
28
|
+
green: '\x1b[32m',
|
|
29
|
+
yellow: '\x1b[33m',
|
|
30
|
+
cyan: '\x1b[36m',
|
|
31
|
+
red: '\x1b[31m',
|
|
32
|
+
blue: '\x1b[34m',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function ensureDir(p) {
|
|
36
|
+
fs.mkdirSync(p, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function runPermissions(args) {
|
|
40
|
+
const opts = parseArgs(args);
|
|
41
|
+
|
|
42
|
+
if (opts.help) {
|
|
43
|
+
printHelp();
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const root = path.resolve(opts.path || process.cwd());
|
|
48
|
+
const outDir = path.join(root, ".vibecheck", "permissions");
|
|
49
|
+
ensureDir(outDir);
|
|
50
|
+
|
|
51
|
+
console.log(`\n${c.cyan}${c.bold}🔐 vibecheck permissions${c.reset}`);
|
|
52
|
+
|
|
53
|
+
// Load or build truthpack
|
|
54
|
+
let truthpack = loadTruthpack(root);
|
|
55
|
+
if (!truthpack) {
|
|
56
|
+
console.log(`${c.dim}Building truthpack...${c.reset}`);
|
|
57
|
+
truthpack = await buildTruthpack({ repoRoot: root, fastifyEntry: opts.fastifyEntry });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Extract auth model
|
|
61
|
+
console.log(`${c.dim}Extracting auth model...${c.reset}`);
|
|
62
|
+
const authModel = await extractAuthModel(root, truthpack);
|
|
63
|
+
|
|
64
|
+
// Save auth model
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(outDir, "auth-model.json"),
|
|
67
|
+
JSON.stringify(authModel, null, 2),
|
|
68
|
+
"utf8"
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (opts.learn) {
|
|
72
|
+
// Learning mode - just extract and display
|
|
73
|
+
console.log(`\n${c.bold}Auth Model${c.reset}`);
|
|
74
|
+
console.log(` Roles: ${authModel.roles.map(r => r.name).join(", ")}`);
|
|
75
|
+
console.log(` Protected patterns: ${authModel.protectedPatterns?.length || 0}`);
|
|
76
|
+
console.log(` Routes: ${authModel.routes.length}`);
|
|
77
|
+
console.log(` RBAC patterns: ${authModel.rbacPatterns.length}`);
|
|
78
|
+
|
|
79
|
+
if (authModel.roles.length > 0) {
|
|
80
|
+
console.log(`\n${c.bold}Detected Roles${c.reset}`);
|
|
81
|
+
for (const role of authModel.roles) {
|
|
82
|
+
console.log(` - ${role.name} (${role.evidence.length} references)`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(`\n${c.dim}Auth model saved to: .vibecheck/permissions/auth-model.json${c.reset}`);
|
|
87
|
+
console.log(`${c.dim}Run 'vibecheck permissions --prove' to verify at runtime${c.reset}\n`);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (opts.prove) {
|
|
92
|
+
// Runtime verification mode
|
|
93
|
+
if (!opts.url) {
|
|
94
|
+
console.log(`${c.red}Error: --prove requires --url${c.reset}`);
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(`${c.dim}Running permission verification against ${opts.url}...${c.reset}`);
|
|
99
|
+
|
|
100
|
+
// This would run actual browser tests
|
|
101
|
+
// For now, show what would be tested
|
|
102
|
+
const matrix = buildAuthZMatrix(authModel, null);
|
|
103
|
+
|
|
104
|
+
console.log(`\n${c.bold}AuthZ Matrix${c.reset}`);
|
|
105
|
+
console.log(` Routes to verify: ${matrix.routes.length}`);
|
|
106
|
+
console.log(` Roles to test: ${matrix.roles.join(", ")}`);
|
|
107
|
+
|
|
108
|
+
// Save matrix
|
|
109
|
+
fs.writeFileSync(
|
|
110
|
+
path.join(outDir, "authz-matrix.json"),
|
|
111
|
+
JSON.stringify(matrix, null, 2),
|
|
112
|
+
"utf8"
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
fs.writeFileSync(
|
|
116
|
+
path.join(outDir, "authz-matrix.md"),
|
|
117
|
+
formatMatrix(matrix),
|
|
118
|
+
"utf8"
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const blocks = matrix.violations.filter(v => v.severity === "BLOCK").length;
|
|
122
|
+
const warns = matrix.violations.filter(v => v.severity === "WARN").length;
|
|
123
|
+
|
|
124
|
+
if (matrix.violations.length > 0) {
|
|
125
|
+
console.log(`\n${c.bold}Violations${c.reset}`);
|
|
126
|
+
for (const v of matrix.violations.slice(0, 10)) {
|
|
127
|
+
const icon = v.severity === "BLOCK" ? `${c.red}✗` : `${c.yellow}⚠`;
|
|
128
|
+
console.log(` ${icon} ${v.message}${c.reset}`);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
console.log(`\n${c.green}✓ No violations detected${c.reset}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.log(`\n${c.dim}Matrix saved to: .vibecheck/permissions/authz-matrix.json${c.reset}`);
|
|
135
|
+
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}`}`);
|
|
136
|
+
|
|
137
|
+
return blocks ? 2 : warns ? 1 : 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (opts.matrix) {
|
|
141
|
+
// Output matrix mode
|
|
142
|
+
const matrix = buildAuthZMatrix(authModel, null);
|
|
143
|
+
console.log("\n" + formatMatrix(matrix));
|
|
144
|
+
|
|
145
|
+
fs.writeFileSync(
|
|
146
|
+
path.join(outDir, "authz-matrix.json"),
|
|
147
|
+
JSON.stringify(matrix, null, 2),
|
|
148
|
+
"utf8"
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
fs.writeFileSync(
|
|
152
|
+
path.join(outDir, "authz-matrix.md"),
|
|
153
|
+
formatMatrix(matrix),
|
|
154
|
+
"utf8"
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (opts.idor) {
|
|
161
|
+
// IDOR detection mode
|
|
162
|
+
console.log(`${c.dim}Detecting IDOR candidates...${c.reset}`);
|
|
163
|
+
|
|
164
|
+
const candidates = detectIDORCandidates(authModel);
|
|
165
|
+
const plan = buildIDORTestPlan(candidates, { safe: opts.safe });
|
|
166
|
+
|
|
167
|
+
console.log(`\n${c.bold}IDOR Candidates${c.reset}`);
|
|
168
|
+
console.log(` Detected: ${candidates.length}`);
|
|
169
|
+
|
|
170
|
+
if (candidates.length > 0) {
|
|
171
|
+
for (const c of candidates.slice(0, 10)) {
|
|
172
|
+
console.log(` - ${c.resourceType}: ${c.path}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Save plan
|
|
177
|
+
fs.writeFileSync(
|
|
178
|
+
path.join(outDir, "idor-plan.json"),
|
|
179
|
+
JSON.stringify(plan, null, 2),
|
|
180
|
+
"utf8"
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
fs.writeFileSync(
|
|
184
|
+
path.join(outDir, "idor-plan.md"),
|
|
185
|
+
formatIDORPlan(plan),
|
|
186
|
+
"utf8"
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
console.log(`\n${c.dim}IDOR plan saved to: .vibecheck/permissions/idor-plan.json${c.reset}`);
|
|
190
|
+
|
|
191
|
+
if (!opts.safe) {
|
|
192
|
+
console.log(`\n${c.yellow}⚠️ IDOR tests require --safe flag for first-party testing${c.reset}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Default: show summary
|
|
199
|
+
console.log(`\n${c.bold}Summary${c.reset}`);
|
|
200
|
+
console.log(` Roles: ${authModel.roles.length}`);
|
|
201
|
+
console.log(` Routes: ${authModel.routes.length}`);
|
|
202
|
+
console.log(` Protected patterns: ${authModel.protectedPatterns?.length || 0}`);
|
|
203
|
+
|
|
204
|
+
console.log(`\n${c.bold}Run one of:${c.reset}`);
|
|
205
|
+
console.log(` ${c.cyan}vibecheck permissions --learn${c.reset} Extract auth model from code`);
|
|
206
|
+
console.log(` ${c.cyan}vibecheck permissions --prove${c.reset} Runtime verification`);
|
|
207
|
+
console.log(` ${c.cyan}vibecheck permissions --matrix${c.reset} Output AuthZ matrix`);
|
|
208
|
+
console.log(` ${c.cyan}vibecheck permissions --idor${c.reset} Detect IDOR candidates\n`);
|
|
209
|
+
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function parseArgs(args) {
|
|
214
|
+
const opts = {
|
|
215
|
+
path: process.cwd(),
|
|
216
|
+
url: null,
|
|
217
|
+
learn: false,
|
|
218
|
+
prove: false,
|
|
219
|
+
matrix: false,
|
|
220
|
+
idor: false,
|
|
221
|
+
safe: false,
|
|
222
|
+
fastifyEntry: null,
|
|
223
|
+
help: false,
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
for (let i = 0; i < args.length; i++) {
|
|
227
|
+
const arg = args[i];
|
|
228
|
+
if (arg === "--learn") opts.learn = true;
|
|
229
|
+
else if (arg === "--prove") opts.prove = true;
|
|
230
|
+
else if (arg === "--matrix") opts.matrix = true;
|
|
231
|
+
else if (arg === "--idor") opts.idor = true;
|
|
232
|
+
else if (arg === "--safe") opts.safe = true;
|
|
233
|
+
else if (arg === "--url") opts.url = args[++i];
|
|
234
|
+
else if (arg === "--fastify-entry") opts.fastifyEntry = args[++i];
|
|
235
|
+
else if (arg === "--path" || arg === "-p") opts.path = args[++i];
|
|
236
|
+
else if (arg === "--help" || arg === "-h") opts.help = true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return opts;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function printHelp() {
|
|
243
|
+
console.log(`
|
|
244
|
+
${c.cyan}${c.bold}🔐 vibecheck permissions${c.reset} - AuthZ Matrix & IDOR Detection
|
|
245
|
+
|
|
246
|
+
Verify authorization is correct, not just present.
|
|
247
|
+
|
|
248
|
+
${c.bold}USAGE${c.reset}
|
|
249
|
+
vibecheck permissions --learn ${c.dim}# Extract auth model from code${c.reset}
|
|
250
|
+
vibecheck permissions --prove --url ${c.dim}# Runtime verification${c.reset}
|
|
251
|
+
vibecheck permissions --matrix ${c.dim}# Output full AuthZ matrix${c.reset}
|
|
252
|
+
vibecheck permissions --idor --safe ${c.dim}# IDOR detection (first-party)${c.reset}
|
|
253
|
+
|
|
254
|
+
${c.bold}OPTIONS${c.reset}
|
|
255
|
+
--learn Extract auth model from code
|
|
256
|
+
--prove Runtime verification of permissions
|
|
257
|
+
--matrix Output AuthZ matrix
|
|
258
|
+
--idor Detect IDOR candidates
|
|
259
|
+
--safe Enable safe mode for IDOR testing (required)
|
|
260
|
+
--url <url> Target URL for runtime testing
|
|
261
|
+
--fastify-entry Fastify entry file (e.g. src/server.ts)
|
|
262
|
+
--path, -p Project path (default: current directory)
|
|
263
|
+
--help, -h Show this help
|
|
264
|
+
|
|
265
|
+
${c.bold}FINDINGS${c.reset}
|
|
266
|
+
${c.red}BLOCK${c.reset} Endpoint accessible as anon that should require auth
|
|
267
|
+
${c.red}BLOCK${c.reset} User A can access User B's resource (IDOR)
|
|
268
|
+
${c.red}BLOCK${c.reset} Role mismatch between UI + server
|
|
269
|
+
${c.yellow}WARN${c.reset} Admin endpoint missing role check (static)
|
|
270
|
+
|
|
271
|
+
${c.bold}OUTPUT${c.reset}
|
|
272
|
+
.vibecheck/permissions/
|
|
273
|
+
auth-model.json Extracted auth model
|
|
274
|
+
authz-matrix.json Full authorization matrix
|
|
275
|
+
authz-matrix.md Human-readable matrix
|
|
276
|
+
idor-plan.json IDOR test plan
|
|
277
|
+
|
|
278
|
+
${c.bold}SAFETY${c.reset}
|
|
279
|
+
IDOR tests only run with --idor --safe flag
|
|
280
|
+
Only use on local dev/staging with explicit consent
|
|
281
|
+
Configure test users in .vibecheck/config.json
|
|
282
|
+
|
|
283
|
+
${c.bold}EXAMPLES${c.reset}
|
|
284
|
+
vibecheck permissions --learn ${c.dim}# Extract model${c.reset}
|
|
285
|
+
vibecheck permissions --prove --url http://localhost:3000
|
|
286
|
+
vibecheck permissions --idor --safe ${c.dim}# IDOR detection${c.reset}
|
|
287
|
+
`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
module.exports = { runPermissions };
|