vibecheck-ai 2.0.1 → 5.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/bin/.generated +25 -0
- package/bin/_deprecations.js +463 -0
- package/bin/_router.js +46 -0
- package/bin/cli-hygiene.js +241 -0
- package/bin/dev/run-v2-torture.js +30 -0
- package/bin/registry.js +656 -0
- package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
- package/bin/runners/ENHANCEMENT_GUIDE.md +121 -0
- package/bin/runners/REPORT_AUDIT.md +64 -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 +513 -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-enhanced.js +2525 -0
- package/bin/runners/context/generators/cursor.js +514 -0
- package/bin/runners/context/generators/mcp.js +169 -0
- package/bin/runners/context/generators/windsurf.js +180 -0
- package/bin/runners/context/git-context.js +304 -0
- package/bin/runners/context/index.js +1110 -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 +1264 -0
- package/bin/runners/context/security-scanner.js +541 -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 +336 -0
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -0
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
- package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
- package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
- package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
- package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
- package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
- package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
- package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
- package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
- package/bin/runners/lib/agent-firewall/index.js +200 -0
- package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
- package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
- package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
- package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
- package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
- package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
- package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
- package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
- package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
- package/bin/runners/lib/agent-firewall/interceptor/base.js +308 -0
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
- package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +79 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +227 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +191 -0
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
- package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
- package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
- package/bin/runners/lib/agent-firewall/session/index.js +26 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
- package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
- package/bin/runners/lib/ai-bridge.js +416 -0
- package/bin/runners/lib/analysis-core.js +309 -0
- package/bin/runners/lib/analyzers.js +2500 -0
- package/bin/runners/lib/api-client.js +269 -0
- package/bin/runners/lib/approve-output.js +235 -0
- package/bin/runners/lib/artifact-envelope.js +540 -0
- package/bin/runners/lib/assets/vibecheck-logo.png +0 -0
- package/bin/runners/lib/audit-bridge.js +391 -0
- package/bin/runners/lib/auth-shared.js +977 -0
- package/bin/runners/lib/auth-truth.js +193 -0
- package/bin/runners/lib/auth.js +215 -0
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/backup.js +62 -0
- package/bin/runners/lib/billing.js +107 -0
- package/bin/runners/lib/checkpoint.js +941 -0
- package/bin/runners/lib/claims.js +118 -0
- package/bin/runners/lib/classify-output.js +204 -0
- package/bin/runners/lib/cleanup/engine.js +571 -0
- package/bin/runners/lib/cleanup/index.js +53 -0
- package/bin/runners/lib/cleanup/output.js +375 -0
- package/bin/runners/lib/cleanup/rules.js +1060 -0
- package/bin/runners/lib/cli-output.js +400 -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 +202 -0
- package/bin/runners/lib/contracts/env-contract.js +181 -0
- package/bin/runners/lib/contracts/external-contract.js +206 -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 +199 -0
- package/bin/runners/lib/contracts.js +804 -0
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/detect.js +89 -0
- package/bin/runners/lib/detectors-v2.js +622 -0
- package/bin/runners/lib/doctor/autofix.js +254 -0
- package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
- package/bin/runners/lib/doctor/failure-signatures.js +526 -0
- package/bin/runners/lib/doctor/fix-script.js +336 -0
- package/bin/runners/lib/doctor/index.js +37 -0
- package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
- package/bin/runners/lib/doctor/modules/index.js +105 -0
- package/bin/runners/lib/doctor/modules/network.js +250 -0
- package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
- package/bin/runners/lib/doctor/modules/project.js +312 -0
- package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
- package/bin/runners/lib/doctor/modules/runtime.js +224 -0
- package/bin/runners/lib/doctor/modules/security.js +350 -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/safe-repair.js +384 -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-output.js +226 -0
- package/bin/runners/lib/doctor-v2.js +608 -0
- package/bin/runners/lib/drift.js +425 -0
- package/bin/runners/lib/enforcement.js +72 -0
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +190 -0
- package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
- package/bin/runners/lib/engines/ast-cache.js +99 -0
- package/bin/runners/lib/engines/attack-detector.js +1192 -0
- package/bin/runners/lib/engines/code-quality-engine.js +255 -0
- package/bin/runners/lib/engines/console-logs-engine.js +115 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
- package/bin/runners/lib/engines/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
- package/bin/runners/lib/engines/file-filter.js +131 -0
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
- package/bin/runners/lib/engines/mock-data-engine.js +272 -0
- package/bin/runners/lib/engines/parallel-processor.js +71 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
- package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
- package/bin/runners/lib/engines/type-aware-engine.js +152 -0
- package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
- package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
- package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -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 +265 -0
- package/bin/runners/lib/entitlements.generated.js +0 -0
- package/bin/runners/lib/entitlements.js +340 -0
- package/bin/runners/lib/env-resolver.js +417 -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 +368 -0
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +684 -0
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/extractors/client-calls.js +990 -0
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -0
- package/bin/runners/lib/extractors/fastify-routes.js +426 -0
- package/bin/runners/lib/extractors/index.js +363 -0
- package/bin/runners/lib/extractors/next-routes.js +524 -0
- package/bin/runners/lib/extractors/proof-graph.js +431 -0
- package/bin/runners/lib/extractors/route-matcher.js +451 -0
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -0
- package/bin/runners/lib/extractors/ui-bindings.js +547 -0
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/findings-schema.js +281 -0
- package/bin/runners/lib/fingerprint.js +377 -0
- package/bin/runners/lib/firewall-prompt.js +50 -0
- package/bin/runners/lib/fix-output.js +228 -0
- package/bin/runners/lib/global-flags.js +250 -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/help-formatter.js +413 -0
- package/bin/runners/lib/html-proof-report.js +913 -0
- package/bin/runners/lib/html-report.js +650 -0
- package/bin/runners/lib/init-wizard.js +601 -0
- package/bin/runners/lib/interactive-menu.js +1496 -0
- package/bin/runners/lib/json-output.js +76 -0
- package/bin/runners/lib/llm.js +75 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/meter.js +61 -0
- package/bin/runners/lib/missions/briefing.js +427 -0
- package/bin/runners/lib/missions/checkpoint.js +753 -0
- package/bin/runners/lib/missions/evidence.js +126 -0
- package/bin/runners/lib/missions/hardening.js +851 -0
- package/bin/runners/lib/missions/plan.js +648 -0
- package/bin/runners/lib/missions/safety-gates.js +645 -0
- package/bin/runners/lib/missions/schema.js +478 -0
- package/bin/runners/lib/missions/templates.js +317 -0
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/packs/bundle.js +675 -0
- package/bin/runners/lib/packs/evidence-pack.js +671 -0
- package/bin/runners/lib/packs/pack-factory.js +837 -0
- package/bin/runners/lib/packs/permissions-pack.js +686 -0
- package/bin/runners/lib/packs/proof-graph-pack.js +779 -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/policy.js +295 -0
- package/bin/runners/lib/polish/accessibility.js +62 -0
- package/bin/runners/lib/polish/analyzer.js +93 -0
- package/bin/runners/lib/polish/backend.js +87 -0
- package/bin/runners/lib/polish/configuration.js +83 -0
- package/bin/runners/lib/polish/documentation.js +83 -0
- package/bin/runners/lib/polish/frontend.js +817 -0
- package/bin/runners/lib/polish/index.js +27 -0
- package/bin/runners/lib/polish/infrastructure.js +80 -0
- package/bin/runners/lib/polish/internationalization.js +85 -0
- package/bin/runners/lib/polish/libraries.js +180 -0
- package/bin/runners/lib/polish/observability.js +75 -0
- package/bin/runners/lib/polish/performance.js +64 -0
- package/bin/runners/lib/polish/privacy.js +110 -0
- package/bin/runners/lib/polish/resilience.js +92 -0
- package/bin/runners/lib/polish/security.js +78 -0
- package/bin/runners/lib/polish/seo.js +71 -0
- package/bin/runners/lib/polish/styles.js +62 -0
- package/bin/runners/lib/polish/utils.js +104 -0
- package/bin/runners/lib/preflight.js +142 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/prove-output.js +220 -0
- package/bin/runners/lib/reality/correlation-detectors.js +359 -0
- package/bin/runners/lib/reality/index.js +318 -0
- package/bin/runners/lib/reality/request-hashing.js +416 -0
- package/bin/runners/lib/reality/request-mapper.js +453 -0
- package/bin/runners/lib/reality/safety-rails.js +463 -0
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -0
- package/bin/runners/lib/reality/toast-detector.js +393 -0
- package/bin/runners/lib/reality-findings.js +84 -0
- package/bin/runners/lib/reality-output.js +231 -0
- package/bin/runners/lib/receipts.js +179 -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 +626 -0
- package/bin/runners/lib/report-html.js +1233 -0
- package/bin/runners/lib/report-output.js +366 -0
- package/bin/runners/lib/report-templates.js +967 -0
- package/bin/runners/lib/report.js +135 -0
- package/bin/runners/lib/route-detection.js +1209 -0
- package/bin/runners/lib/route-truth.js +1322 -0
- package/bin/runners/lib/safelist/index.js +96 -0
- package/bin/runners/lib/safelist/integration.js +334 -0
- package/bin/runners/lib/safelist/matcher.js +696 -0
- package/bin/runners/lib/safelist/schema.js +948 -0
- package/bin/runners/lib/safelist/store.js +438 -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/scan-output.js +631 -0
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schema-validator.js +350 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/contracts.schema.json +160 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/finding.schema.json +100 -0
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -0
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -0
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -0
- package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -0
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -0
- package/bin/runners/lib/schemas/validator.js +465 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -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/ship-gate.js +832 -0
- package/bin/runners/lib/ship-manifest.js +1153 -0
- package/bin/runners/lib/ship-output-enterprise.js +239 -0
- package/bin/runners/lib/ship-output.js +1128 -0
- package/bin/runners/lib/snippets.js +67 -0
- package/bin/runners/lib/status-output.js +340 -0
- package/bin/runners/lib/terminal-ui.js +356 -0
- package/bin/runners/lib/truth.js +1691 -0
- package/bin/runners/lib/ui.js +562 -0
- package/bin/runners/lib/unified-cli-output.js +947 -0
- package/bin/runners/lib/unified-output.js +197 -0
- package/bin/runners/lib/upsell.js +410 -0
- package/bin/runners/lib/usage.js +153 -0
- package/bin/runners/lib/validate-patch.js +156 -0
- package/bin/runners/lib/verdict-engine.js +628 -0
- package/bin/runners/lib/verification.js +345 -0
- package/bin/runners/lib/why-tree.js +650 -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 +229 -0
- package/bin/runners/runAgent.d.ts +5 -0
- package/bin/runners/runAgent.js +161 -0
- package/bin/runners/runAllowlist.js +418 -0
- package/bin/runners/runApprove.js +320 -0
- package/bin/runners/runAudit.js +692 -0
- package/bin/runners/runAuth.js +731 -0
- package/bin/runners/runCI.js +353 -0
- package/bin/runners/runCheckpoint.js +530 -0
- package/bin/runners/runClassify.js +928 -0
- package/bin/runners/runCleanup.js +343 -0
- package/bin/runners/runContext.d.ts +4 -0
- package/bin/runners/runContext.js +175 -0
- package/bin/runners/runDoctor.js +877 -0
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.d.ts +5 -0
- package/bin/runners/runFirewall.js +134 -0
- package/bin/runners/runFirewallHook.d.ts +5 -0
- package/bin/runners/runFirewallHook.js +56 -0
- package/bin/runners/runFix.js +1355 -0
- package/bin/runners/runForge.js +451 -0
- package/bin/runners/runGuard.js +262 -0
- package/bin/runners/runInit.js +1927 -0
- package/bin/runners/runIntent.js +906 -0
- package/bin/runners/runKickoff.js +878 -0
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runLaunch.js +2000 -0
- package/bin/runners/runLink.js +785 -0
- package/bin/runners/runMcp.js +1875 -0
- package/bin/runners/runPacks.js +2089 -0
- package/bin/runners/runPolish.d.ts +4 -0
- package/bin/runners/runPolish.js +390 -0
- package/bin/runners/runPromptFirewall.js +211 -0
- package/bin/runners/runProve.js +1411 -0
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +2260 -0
- package/bin/runners/runReport.js +726 -0
- package/bin/runners/runRuntime.js +110 -0
- package/bin/runners/runSafelist.js +1190 -0
- package/bin/runners/runScan.js +688 -0
- package/bin/runners/runShield.js +1282 -0
- package/bin/runners/runShip.js +1660 -0
- package/bin/runners/runTruth.d.ts +5 -0
- package/bin/runners/runTruth.js +101 -0
- package/bin/runners/runValidate.js +179 -0
- package/bin/runners/runWatch.js +478 -0
- package/bin/runners/utils.js +360 -0
- package/bin/scan.js +617 -0
- package/bin/vibecheck.js +1617 -0
- package/dist/guardrail/index.d.ts +2405 -0
- package/dist/guardrail/index.js +9747 -0
- package/dist/guardrail/index.js.map +1 -0
- package/dist/scanner/index.d.ts +282 -0
- package/dist/scanner/index.js +3395 -0
- package/dist/scanner/index.js.map +1 -0
- package/package.json +123 -104
- package/README.md +0 -491
- package/dist/index.js +0 -99711
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,1059 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Firewall Enforcement Gateway v3.0
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* AGENT FIREWALL™ - ENFORCEMENT GATEWAY
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
*
|
|
8
|
+
* THE SINGLE ENTRY POINT for all enforcement operations.
|
|
9
|
+
* All intercepted changes MUST flow through this gateway.
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Real-time blocking (blocks at write-time, not after)
|
|
13
|
+
* - Explainable blocks (exact reason + evidence + fix path)
|
|
14
|
+
* - Modes: ENFORCE (default), OBSERVE, CI, IDE
|
|
15
|
+
* - Signed verdicts for audit trail
|
|
16
|
+
* - Hash chain for tamper detection
|
|
17
|
+
*
|
|
18
|
+
* @module enforcement/gateway
|
|
19
|
+
* @version 3.0.0
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
"use strict";
|
|
23
|
+
|
|
24
|
+
const crypto = require("crypto");
|
|
25
|
+
const path = require("path");
|
|
26
|
+
const fs = require("fs");
|
|
27
|
+
|
|
28
|
+
// Import schema validator
|
|
29
|
+
const Ajv = require("ajv").default || require("ajv");
|
|
30
|
+
const addFormats = require("ajv-formats").default || require("ajv-formats");
|
|
31
|
+
|
|
32
|
+
// Import existing modules
|
|
33
|
+
const { IntentStore } = require("../intent/store");
|
|
34
|
+
const { checkAlignment, checkAlignmentBatch, VIOLATION_CODES } = require("../intent/alignment-engine");
|
|
35
|
+
const { verifyIntentIntegrity, isIntentExpired } = require("../intent/schema");
|
|
36
|
+
const { resolveEvidence } = require("../evidence/resolver");
|
|
37
|
+
const { evaluatePolicy } = require("../policy/engine");
|
|
38
|
+
const { SessionCollector } = require("../session/collector");
|
|
39
|
+
|
|
40
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
41
|
+
// CONSTANTS
|
|
42
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
43
|
+
|
|
44
|
+
const MODE = {
|
|
45
|
+
ENFORCE: "ENFORCE", // Block on violation (default when intent exists)
|
|
46
|
+
OBSERVE: "OBSERVE", // Log only (default when no intent)
|
|
47
|
+
CI: "CI", // Fail pipeline on BLOCK
|
|
48
|
+
IDE: "IDE", // Real-time interception, block writes
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const VERDICT = {
|
|
52
|
+
PASS: "PASS",
|
|
53
|
+
BLOCK: "BLOCK",
|
|
54
|
+
WOULD_PASS: "WOULD_PASS", // OBSERVE mode
|
|
55
|
+
WOULD_BLOCK: "WOULD_BLOCK", // OBSERVE mode
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Block patterns - code quality issues that always block
|
|
59
|
+
const BLOCK_PATTERNS = [
|
|
60
|
+
{ pattern: /\bTODO\b/i, code: "TODO_DETECTED", message: "TODO comment found - resolve before shipping" },
|
|
61
|
+
{ pattern: /\bFIXME\b/i, code: "FIXME_DETECTED", message: "FIXME comment found - resolve before shipping" },
|
|
62
|
+
{ pattern: /\bXXX\b/, code: "XXX_DETECTED", message: "XXX placeholder found - resolve before shipping" },
|
|
63
|
+
{ pattern: /mock[A-Z]\w*\s*[=:]/, code: "MOCK_DATA", message: "Mock data detected in code" },
|
|
64
|
+
{ pattern: /fakeDat[ae]|fakeUser|fakeResponse/i, code: "FAKE_DATA", message: "Fake data detected in code" },
|
|
65
|
+
{ pattern: /placeholder|dummy/i, code: "PLACEHOLDER_DETECTED", message: "Placeholder code detected" },
|
|
66
|
+
{ pattern: /console\.(log|debug|info)\(/, code: "CONSOLE_LOG", message: "Console statement in production code", severity: "warn" },
|
|
67
|
+
{ pattern: /:\s*any\b/, code: "ANY_TYPE", message: "TypeScript 'any' type detected", severity: "warn" },
|
|
68
|
+
{ pattern: /throw new Error\(['"]not implemented/i, code: "NOT_IMPLEMENTED", message: "Not implemented error found" },
|
|
69
|
+
{ pattern: /\/\/ @ts-ignore|\/\/ @ts-nocheck/, code: "TS_IGNORE", message: "TypeScript ignore directive", severity: "warn" },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
73
|
+
// SCHEMA VALIDATION
|
|
74
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
75
|
+
|
|
76
|
+
let ajv = null;
|
|
77
|
+
let validators = {};
|
|
78
|
+
|
|
79
|
+
function initializeValidators() {
|
|
80
|
+
if (ajv) return;
|
|
81
|
+
|
|
82
|
+
ajv = new Ajv({ allErrors: true, strict: false });
|
|
83
|
+
addFormats(ajv);
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const schemaDir = path.join(__dirname, "schemas");
|
|
87
|
+
|
|
88
|
+
const intentSchema = JSON.parse(fs.readFileSync(path.join(schemaDir, "intent.schema.json"), "utf-8"));
|
|
89
|
+
const changeSchema = JSON.parse(fs.readFileSync(path.join(schemaDir, "change-event.schema.json"), "utf-8"));
|
|
90
|
+
const verdictSchema = JSON.parse(fs.readFileSync(path.join(schemaDir, "verdict.schema.json"), "utf-8"));
|
|
91
|
+
|
|
92
|
+
validators.intent = ajv.compile(intentSchema);
|
|
93
|
+
validators.changeEvent = ajv.compile(changeSchema);
|
|
94
|
+
validators.verdict = ajv.compile(verdictSchema);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
// Fallback to no validation if schemas not found
|
|
97
|
+
validators.intent = () => true;
|
|
98
|
+
validators.changeEvent = () => true;
|
|
99
|
+
validators.verdict = () => true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
104
|
+
// CHANGE EVENT BUILDER
|
|
105
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
106
|
+
|
|
107
|
+
let changeCounter = 0;
|
|
108
|
+
|
|
109
|
+
function generateChangeId() {
|
|
110
|
+
return `chg-${Date.now().toString(36)}-${crypto.randomBytes(4).toString("hex")}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function generateVerdictId() {
|
|
114
|
+
return `vrd-${Date.now().toString(36)}-${crypto.randomBytes(6).toString("hex")}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Build a normalized change event from raw input
|
|
119
|
+
*/
|
|
120
|
+
function buildChangeEvent(rawChange, source) {
|
|
121
|
+
const id = generateChangeId();
|
|
122
|
+
|
|
123
|
+
const event = {
|
|
124
|
+
id,
|
|
125
|
+
type: rawChange.type || inferChangeType(rawChange),
|
|
126
|
+
source: {
|
|
127
|
+
agent_id: source?.agentId || rawChange.agentId || "unknown",
|
|
128
|
+
interception_point: source?.interceptionPoint || "cli",
|
|
129
|
+
tool_name: source?.toolName || null,
|
|
130
|
+
session_id: source?.sessionId || null,
|
|
131
|
+
},
|
|
132
|
+
location: rawChange.path || rawChange.file || rawChange.location,
|
|
133
|
+
diff: rawChange.diff || null,
|
|
134
|
+
content: rawChange.content || null,
|
|
135
|
+
domain: rawChange.domain || classifyDomain(rawChange.path || rawChange.location),
|
|
136
|
+
claims: rawChange.claims || [],
|
|
137
|
+
code_quality: null, // Will be populated by analyzeCodeQuality
|
|
138
|
+
timestamp: new Date().toISOString(),
|
|
139
|
+
metadata: rawChange.metadata || {},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Analyze code quality if content is available
|
|
143
|
+
if (event.content || event.diff?.after) {
|
|
144
|
+
event.code_quality = analyzeCodeQuality(event.content || event.diff.after);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return event;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Infer change type from raw change
|
|
152
|
+
*/
|
|
153
|
+
function inferChangeType(rawChange) {
|
|
154
|
+
if (rawChange.type) return rawChange.type;
|
|
155
|
+
|
|
156
|
+
const loc = rawChange.path || rawChange.location || "";
|
|
157
|
+
|
|
158
|
+
// Check for route changes
|
|
159
|
+
if (rawChange.route || loc.includes("route") || rawChange.method) {
|
|
160
|
+
return rawChange.diff ? "route_modify" : "route_add";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check for env changes
|
|
164
|
+
if (rawChange.envVar || loc.includes(".env")) {
|
|
165
|
+
return rawChange.diff ? "env_write" : "env_ref";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check for file changes
|
|
169
|
+
if (rawChange.content && !rawChange.diff) {
|
|
170
|
+
return "file_create";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return "file_write";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Classify file domain
|
|
178
|
+
*/
|
|
179
|
+
function classifyDomain(filePath) {
|
|
180
|
+
if (!filePath) return "general";
|
|
181
|
+
const s = filePath.toLowerCase();
|
|
182
|
+
|
|
183
|
+
if (s.includes("auth") || s.includes("login") || s.includes("session")) return "auth";
|
|
184
|
+
if (s.includes("stripe") || s.includes("payment") || s.includes("billing")) return "payments";
|
|
185
|
+
if (s.includes("route") || s.includes("api/") || s.includes("endpoint")) return "routes";
|
|
186
|
+
if (s.includes("schema") || s.includes("contract") || s.includes("types")) return "contracts";
|
|
187
|
+
if (s.includes("component") || s.includes("page") || s.includes("/ui/")) return "ui";
|
|
188
|
+
if (s.includes("database") || s.includes("prisma") || s.includes("migration")) return "database";
|
|
189
|
+
if (s.includes("config") || s.includes(".env") || s.includes("setting")) return "config";
|
|
190
|
+
if (s.includes("test") || s.includes("spec") || s.includes("__tests__")) return "tests";
|
|
191
|
+
|
|
192
|
+
return "general";
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Analyze code quality in content
|
|
197
|
+
*/
|
|
198
|
+
function analyzeCodeQuality(content) {
|
|
199
|
+
if (!content) return null;
|
|
200
|
+
|
|
201
|
+
const result = {
|
|
202
|
+
has_mock_data: false,
|
|
203
|
+
has_todo: false,
|
|
204
|
+
has_fixme: false,
|
|
205
|
+
has_placeholder: false,
|
|
206
|
+
has_fake_handler: false,
|
|
207
|
+
has_console_log: false,
|
|
208
|
+
has_any_type: false,
|
|
209
|
+
detected_patterns: [],
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const lines = content.split("\n");
|
|
213
|
+
|
|
214
|
+
for (let i = 0; i < lines.length; i++) {
|
|
215
|
+
const line = lines[i];
|
|
216
|
+
|
|
217
|
+
for (const pattern of BLOCK_PATTERNS) {
|
|
218
|
+
if (pattern.pattern.test(line)) {
|
|
219
|
+
result.detected_patterns.push({
|
|
220
|
+
pattern: pattern.code,
|
|
221
|
+
line: i + 1,
|
|
222
|
+
severity: pattern.severity || "block",
|
|
223
|
+
snippet: line.trim().substring(0, 100),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Set flags
|
|
227
|
+
if (pattern.code === "TODO_DETECTED") result.has_todo = true;
|
|
228
|
+
if (pattern.code === "FIXME_DETECTED") result.has_fixme = true;
|
|
229
|
+
if (pattern.code.includes("MOCK") || pattern.code.includes("FAKE")) result.has_mock_data = true;
|
|
230
|
+
if (pattern.code === "PLACEHOLDER_DETECTED") result.has_placeholder = true;
|
|
231
|
+
if (pattern.code === "CONSOLE_LOG") result.has_console_log = true;
|
|
232
|
+
if (pattern.code === "ANY_TYPE") result.has_any_type = true;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check for fake handlers
|
|
237
|
+
if (/function\s+\w*[Hh]andler\s*\([^)]*\)\s*\{\s*\}/.test(line) ||
|
|
238
|
+
/=>\s*\{\s*\}/.test(line) ||
|
|
239
|
+
/return\s+null\s*;?\s*\/\/\s*todo/i.test(line)) {
|
|
240
|
+
result.has_fake_handler = true;
|
|
241
|
+
result.detected_patterns.push({
|
|
242
|
+
pattern: "FAKE_HANDLER",
|
|
243
|
+
line: i + 1,
|
|
244
|
+
severity: "block",
|
|
245
|
+
snippet: line.trim().substring(0, 100),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
254
|
+
// ENFORCEMENT GATEWAY
|
|
255
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
256
|
+
|
|
257
|
+
class EnforcementGateway {
|
|
258
|
+
constructor(projectRoot, options = {}) {
|
|
259
|
+
this.projectRoot = projectRoot;
|
|
260
|
+
this.options = options;
|
|
261
|
+
|
|
262
|
+
// Initialize components
|
|
263
|
+
this.intentStore = new IntentStore(projectRoot);
|
|
264
|
+
this.sessionCollector = new SessionCollector(projectRoot);
|
|
265
|
+
|
|
266
|
+
// Session tracking
|
|
267
|
+
this.sessionId = options.sessionId || `session-${Date.now()}`;
|
|
268
|
+
this.verdictSequence = 0;
|
|
269
|
+
this.previousVerdictHash = null;
|
|
270
|
+
|
|
271
|
+
// Initialize validators
|
|
272
|
+
initializeValidators();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get current mode based on intent and options
|
|
277
|
+
*/
|
|
278
|
+
getMode() {
|
|
279
|
+
// Explicit mode override
|
|
280
|
+
if (this.options.mode) return this.options.mode;
|
|
281
|
+
|
|
282
|
+
// Environment override
|
|
283
|
+
if (process.env.VIBECHECK_FIREWALL_MODE) {
|
|
284
|
+
return process.env.VIBECHECK_FIREWALL_MODE.toUpperCase();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// CI detection
|
|
288
|
+
if (process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI) {
|
|
289
|
+
return MODE.CI;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Default: OBSERVE if no intent, ENFORCE if intent exists
|
|
293
|
+
return this.intentStore.hasIntent() ? MODE.ENFORCE : MODE.OBSERVE;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* MAIN ENTRY POINT - Intercept and evaluate a change
|
|
298
|
+
*
|
|
299
|
+
* This is THE function all interception points should call.
|
|
300
|
+
* Returns a verdict that determines if the change is allowed.
|
|
301
|
+
*
|
|
302
|
+
* @param {Object} rawChange - Raw change data
|
|
303
|
+
* @param {Object} source - Source information (agent, interception point)
|
|
304
|
+
* @returns {Promise<Object>} Verdict with decision and details
|
|
305
|
+
*/
|
|
306
|
+
async intercept(rawChange, source = {}) {
|
|
307
|
+
const startTime = Date.now();
|
|
308
|
+
const mode = this.getMode();
|
|
309
|
+
|
|
310
|
+
// Build normalized change event
|
|
311
|
+
const changeEvent = buildChangeEvent(rawChange, source);
|
|
312
|
+
|
|
313
|
+
// Get current intent
|
|
314
|
+
const intent = this.intentStore.getCurrent({ allowMissing: true });
|
|
315
|
+
const hasIntent = this.intentStore.hasIntent();
|
|
316
|
+
|
|
317
|
+
// In OBSERVE mode without intent, log and allow
|
|
318
|
+
if (mode === MODE.OBSERVE && !hasIntent) {
|
|
319
|
+
this.sessionCollector.record({
|
|
320
|
+
type: changeEvent.type,
|
|
321
|
+
path: changeEvent.location,
|
|
322
|
+
agent_id: changeEvent.source.agent_id,
|
|
323
|
+
lines_added: changeEvent.diff?.lines_added || 0,
|
|
324
|
+
lines_removed: changeEvent.diff?.lines_removed || 0,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return this._buildVerdict({
|
|
328
|
+
decision: VERDICT.WOULD_PASS,
|
|
329
|
+
mode,
|
|
330
|
+
intent_hash: null,
|
|
331
|
+
change_events: [changeEvent.id],
|
|
332
|
+
violations: [],
|
|
333
|
+
proofs: [],
|
|
334
|
+
summary: "OBSERVE mode - change logged for later review",
|
|
335
|
+
duration_ms: Date.now() - startTime,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Run enforcement checks
|
|
340
|
+
const violations = [];
|
|
341
|
+
|
|
342
|
+
// 1. Intent integrity check
|
|
343
|
+
if (intent) {
|
|
344
|
+
const integrityCheck = verifyIntentIntegrity(intent);
|
|
345
|
+
if (!integrityCheck.valid) {
|
|
346
|
+
violations.push(this._buildViolation(
|
|
347
|
+
VIOLATION_CODES.INTENT_CORRUPTED,
|
|
348
|
+
"intent_integrity",
|
|
349
|
+
`Intent integrity failed: ${integrityCheck.reason}`,
|
|
350
|
+
"intent",
|
|
351
|
+
{ expected: "valid hash", actual: "hash mismatch" }
|
|
352
|
+
));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (isIntentExpired(intent)) {
|
|
356
|
+
violations.push(this._buildViolation(
|
|
357
|
+
VIOLATION_CODES.INTENT_EXPIRED,
|
|
358
|
+
"intent_expiration",
|
|
359
|
+
"Intent has expired - declare new intent",
|
|
360
|
+
"intent",
|
|
361
|
+
{ expected: "not expired", actual: `expired at ${intent.expires_at}` }
|
|
362
|
+
));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// 2. Intent alignment check
|
|
367
|
+
const alignmentResult = checkAlignment(intent, changeEvent);
|
|
368
|
+
if (!alignmentResult.aligned) {
|
|
369
|
+
violations.push(...alignmentResult.violations);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// 3. Code quality check
|
|
373
|
+
if (changeEvent.code_quality) {
|
|
374
|
+
const qualityViolations = this._checkCodeQuality(changeEvent);
|
|
375
|
+
violations.push(...qualityViolations);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// 4. Domain/scope check
|
|
379
|
+
if (intent?.scope) {
|
|
380
|
+
const scopeViolations = this._checkScope(changeEvent, intent);
|
|
381
|
+
violations.push(...scopeViolations);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 5. Protected files check
|
|
385
|
+
if (intent?.scope?.protected_files) {
|
|
386
|
+
const protectedViolations = this._checkProtectedFiles(changeEvent, intent);
|
|
387
|
+
violations.push(...protectedViolations);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// 6. Evidence resolution (existing system)
|
|
391
|
+
const evidence = resolveEvidence(this.projectRoot, changeEvent.claims || []);
|
|
392
|
+
|
|
393
|
+
// 7. Policy evaluation (existing system)
|
|
394
|
+
const policyResult = await evaluatePolicy({
|
|
395
|
+
policy: this._loadPolicy(),
|
|
396
|
+
claims: changeEvent.claims || [],
|
|
397
|
+
evidence,
|
|
398
|
+
files: [{ path: changeEvent.location, domain: changeEvent.domain }],
|
|
399
|
+
intent: intent?.summary || "",
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
if (policyResult.violations) {
|
|
403
|
+
violations.push(...policyResult.violations.map(v => this._buildViolation(
|
|
404
|
+
v.rule?.toUpperCase().replace(/-/g, "_") || "POLICY_VIOLATION",
|
|
405
|
+
v.rule || "policy",
|
|
406
|
+
v.message || "Policy violation",
|
|
407
|
+
v.claimId || v.file || "unknown"
|
|
408
|
+
)));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Build proofs from evidence
|
|
412
|
+
const proofs = evidence.map(e => ({
|
|
413
|
+
id: `prf-${e.type}-${crypto.randomBytes(4).toString("hex")}`,
|
|
414
|
+
type: this._mapClaimTypeToProofType(e.type),
|
|
415
|
+
status: e.result === "PROVEN" ? "verified" : e.result === "UNPROVEN" ? "failed" : "pending",
|
|
416
|
+
target: e.pointer || e.claimId,
|
|
417
|
+
trace: e.sources?.[0]?.pointer,
|
|
418
|
+
verified_at: new Date().toISOString(),
|
|
419
|
+
method: "static",
|
|
420
|
+
error: e.result !== "PROVEN" ? e.reason : null,
|
|
421
|
+
}));
|
|
422
|
+
|
|
423
|
+
// Determine final decision
|
|
424
|
+
const blockViolations = violations.filter(v => v.severity === "block");
|
|
425
|
+
let decision;
|
|
426
|
+
|
|
427
|
+
if (mode === MODE.OBSERVE) {
|
|
428
|
+
decision = blockViolations.length > 0 ? VERDICT.WOULD_BLOCK : VERDICT.WOULD_PASS;
|
|
429
|
+
} else {
|
|
430
|
+
decision = blockViolations.length > 0 ? VERDICT.BLOCK : VERDICT.PASS;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Build verdict
|
|
434
|
+
const verdict = this._buildVerdict({
|
|
435
|
+
decision,
|
|
436
|
+
mode,
|
|
437
|
+
intent_hash: intent?.hash || null,
|
|
438
|
+
change_events: [changeEvent.id],
|
|
439
|
+
violations,
|
|
440
|
+
proofs,
|
|
441
|
+
summary: this._generateSummary(decision, violations),
|
|
442
|
+
duration_ms: Date.now() - startTime,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// Store verdict
|
|
446
|
+
this._storeVerdict(verdict);
|
|
447
|
+
|
|
448
|
+
// In OBSERVE mode, still log to session
|
|
449
|
+
if (mode === MODE.OBSERVE) {
|
|
450
|
+
this.sessionCollector.record({
|
|
451
|
+
type: changeEvent.type,
|
|
452
|
+
path: changeEvent.location,
|
|
453
|
+
agent_id: changeEvent.source.agent_id,
|
|
454
|
+
verdict_id: verdict.id,
|
|
455
|
+
would_block: verdict.decision === VERDICT.WOULD_BLOCK,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return verdict;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Intercept multiple changes in batch
|
|
464
|
+
*/
|
|
465
|
+
async interceptBatch(rawChanges, source = {}) {
|
|
466
|
+
const startTime = Date.now();
|
|
467
|
+
const mode = this.getMode();
|
|
468
|
+
|
|
469
|
+
// Build normalized change events
|
|
470
|
+
const changeEvents = rawChanges.map(rc => buildChangeEvent(rc, source));
|
|
471
|
+
|
|
472
|
+
// Get intent
|
|
473
|
+
const intent = this.intentStore.getCurrent({ allowMissing: true });
|
|
474
|
+
const hasIntent = this.intentStore.hasIntent();
|
|
475
|
+
|
|
476
|
+
// In OBSERVE mode without intent
|
|
477
|
+
if (mode === MODE.OBSERVE && !hasIntent) {
|
|
478
|
+
for (const ce of changeEvents) {
|
|
479
|
+
this.sessionCollector.record({
|
|
480
|
+
type: ce.type,
|
|
481
|
+
path: ce.location,
|
|
482
|
+
agent_id: ce.source.agent_id,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return this._buildVerdict({
|
|
487
|
+
decision: VERDICT.WOULD_PASS,
|
|
488
|
+
mode,
|
|
489
|
+
intent_hash: null,
|
|
490
|
+
change_events: changeEvents.map(e => e.id),
|
|
491
|
+
violations: [],
|
|
492
|
+
proofs: [],
|
|
493
|
+
summary: "OBSERVE mode - changes logged for later review",
|
|
494
|
+
duration_ms: Date.now() - startTime,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Run batch alignment
|
|
499
|
+
const alignmentResult = checkAlignmentBatch(intent, changeEvents);
|
|
500
|
+
const violations = [...alignmentResult.violations];
|
|
501
|
+
|
|
502
|
+
// Check code quality for each
|
|
503
|
+
for (const ce of changeEvents) {
|
|
504
|
+
if (ce.code_quality) {
|
|
505
|
+
violations.push(...this._checkCodeQuality(ce));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Determine decision
|
|
510
|
+
const blockViolations = violations.filter(v => v.severity === "block");
|
|
511
|
+
let decision;
|
|
512
|
+
|
|
513
|
+
if (mode === MODE.OBSERVE) {
|
|
514
|
+
decision = blockViolations.length > 0 ? VERDICT.WOULD_BLOCK : VERDICT.WOULD_PASS;
|
|
515
|
+
} else {
|
|
516
|
+
decision = blockViolations.length > 0 ? VERDICT.BLOCK : VERDICT.PASS;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const verdict = this._buildVerdict({
|
|
520
|
+
decision,
|
|
521
|
+
mode,
|
|
522
|
+
intent_hash: intent?.hash || null,
|
|
523
|
+
change_events: changeEvents.map(e => e.id),
|
|
524
|
+
violations,
|
|
525
|
+
proofs: [],
|
|
526
|
+
summary: this._generateSummary(decision, violations),
|
|
527
|
+
duration_ms: Date.now() - startTime,
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
this._storeVerdict(verdict);
|
|
531
|
+
|
|
532
|
+
return verdict;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Quick check - fast path for simple validation
|
|
537
|
+
*/
|
|
538
|
+
quickCheck(rawChange) {
|
|
539
|
+
const changeEvent = buildChangeEvent(rawChange, {});
|
|
540
|
+
const intent = this.intentStore.getCurrent({ allowMissing: true });
|
|
541
|
+
const alignmentResult = checkAlignment(intent, changeEvent);
|
|
542
|
+
|
|
543
|
+
return {
|
|
544
|
+
allowed: alignmentResult.aligned,
|
|
545
|
+
decision: alignmentResult.decision,
|
|
546
|
+
violations: alignmentResult.violations,
|
|
547
|
+
intent_hash: intent?.hash || null,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Get verdict required for ship
|
|
553
|
+
*/
|
|
554
|
+
async getShipVerdict(options = {}) {
|
|
555
|
+
const latestVerdict = this._getLatestVerdict();
|
|
556
|
+
|
|
557
|
+
if (!latestVerdict) {
|
|
558
|
+
return {
|
|
559
|
+
can_ship: false,
|
|
560
|
+
reason: "NO_VERDICT",
|
|
561
|
+
message: "No enforcement verdict found. Run vibecheck shield first.",
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Verify verdict integrity
|
|
566
|
+
const integrity = this._verifyVerdictIntegrity(latestVerdict);
|
|
567
|
+
if (!integrity.valid) {
|
|
568
|
+
return {
|
|
569
|
+
can_ship: false,
|
|
570
|
+
reason: "VERDICT_TAMPERED",
|
|
571
|
+
message: `Verdict integrity check failed: ${integrity.reason}`,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Check verdict is recent enough
|
|
576
|
+
const verdictAge = Date.now() - new Date(latestVerdict.timestamp).getTime();
|
|
577
|
+
const maxAge = options.maxAge || 30 * 60 * 1000; // 30 minutes default
|
|
578
|
+
|
|
579
|
+
if (verdictAge > maxAge) {
|
|
580
|
+
return {
|
|
581
|
+
can_ship: false,
|
|
582
|
+
reason: "VERDICT_STALE",
|
|
583
|
+
message: `Verdict is ${Math.round(verdictAge / 60000)} minutes old. Re-run vibecheck shield.`,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return {
|
|
588
|
+
can_ship: latestVerdict.decision === VERDICT.PASS,
|
|
589
|
+
verdict: latestVerdict,
|
|
590
|
+
reason: latestVerdict.decision,
|
|
591
|
+
message: latestVerdict.summary,
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
596
|
+
// PRIVATE METHODS
|
|
597
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
598
|
+
|
|
599
|
+
_buildViolation(code, rule, message, resource, evidence = null) {
|
|
600
|
+
const violation = {
|
|
601
|
+
code,
|
|
602
|
+
rule,
|
|
603
|
+
message,
|
|
604
|
+
resource,
|
|
605
|
+
intent_ref: rule,
|
|
606
|
+
severity: "block",
|
|
607
|
+
evidence: evidence || null,
|
|
608
|
+
fix_hint: this._getFixHint(code, resource),
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
return violation;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
_buildVerdict({ decision, mode, intent_hash, change_events, violations, proofs, summary, duration_ms }) {
|
|
615
|
+
const id = generateVerdictId();
|
|
616
|
+
const timestamp = new Date().toISOString();
|
|
617
|
+
|
|
618
|
+
this.verdictSequence++;
|
|
619
|
+
|
|
620
|
+
const verdict = {
|
|
621
|
+
id,
|
|
622
|
+
decision,
|
|
623
|
+
mode,
|
|
624
|
+
violations,
|
|
625
|
+
proofs,
|
|
626
|
+
intent_hash,
|
|
627
|
+
change_events,
|
|
628
|
+
timestamp,
|
|
629
|
+
verdict_hash: "", // Will be computed
|
|
630
|
+
signature: null,
|
|
631
|
+
chain: {
|
|
632
|
+
previous_verdict_hash: this.previousVerdictHash,
|
|
633
|
+
sequence_number: this.verdictSequence,
|
|
634
|
+
session_id: this.sessionId,
|
|
635
|
+
},
|
|
636
|
+
summary,
|
|
637
|
+
block_message: decision === VERDICT.BLOCK ? this._formatBlockMessage(violations) : null,
|
|
638
|
+
fix_guidance: this._generateFixGuidance(violations),
|
|
639
|
+
metadata: {
|
|
640
|
+
run_id: crypto.randomBytes(8).toString("hex"),
|
|
641
|
+
agent_id: change_events[0]?.source?.agent_id || "unknown",
|
|
642
|
+
project_root: this.projectRoot,
|
|
643
|
+
file_count: change_events.length,
|
|
644
|
+
evaluation_duration_ms: duration_ms,
|
|
645
|
+
vibecheck_version: "3.0.0",
|
|
646
|
+
},
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
// Compute verdict hash
|
|
650
|
+
verdict.verdict_hash = this._computeVerdictHash(verdict);
|
|
651
|
+
|
|
652
|
+
// Sign verdict
|
|
653
|
+
verdict.signature = this._signVerdict(verdict);
|
|
654
|
+
|
|
655
|
+
// Update chain
|
|
656
|
+
this.previousVerdictHash = verdict.verdict_hash;
|
|
657
|
+
|
|
658
|
+
return verdict;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
_checkCodeQuality(changeEvent) {
|
|
662
|
+
const violations = [];
|
|
663
|
+
const cq = changeEvent.code_quality;
|
|
664
|
+
|
|
665
|
+
if (!cq || !cq.detected_patterns) return violations;
|
|
666
|
+
|
|
667
|
+
for (const pattern of cq.detected_patterns) {
|
|
668
|
+
if (pattern.severity === "block") {
|
|
669
|
+
violations.push(this._buildViolation(
|
|
670
|
+
pattern.pattern,
|
|
671
|
+
"code_quality",
|
|
672
|
+
BLOCK_PATTERNS.find(p => p.code === pattern.pattern)?.message || `Code quality issue: ${pattern.pattern}`,
|
|
673
|
+
changeEvent.location,
|
|
674
|
+
{
|
|
675
|
+
file: changeEvent.location,
|
|
676
|
+
line: pattern.line,
|
|
677
|
+
snippet: pattern.snippet,
|
|
678
|
+
}
|
|
679
|
+
));
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return violations;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
_checkScope(changeEvent, intent) {
|
|
687
|
+
const violations = [];
|
|
688
|
+
|
|
689
|
+
if (intent.scope?.directories) {
|
|
690
|
+
const loc = changeEvent.location;
|
|
691
|
+
const inScope = intent.scope.directories.some(dir =>
|
|
692
|
+
loc.startsWith(dir) || loc.includes(`/${dir}`) || loc.includes(`\\${dir}`)
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
if (!inScope) {
|
|
696
|
+
violations.push(this._buildViolation(
|
|
697
|
+
VIOLATION_CODES.SCOPE_VIOLATION,
|
|
698
|
+
"scope_check",
|
|
699
|
+
`File outside allowed directories: ${changeEvent.location}`,
|
|
700
|
+
changeEvent.location,
|
|
701
|
+
{
|
|
702
|
+
expected: intent.scope.directories.join(", "),
|
|
703
|
+
actual: changeEvent.location,
|
|
704
|
+
}
|
|
705
|
+
));
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if (intent.scope?.domains) {
|
|
710
|
+
if (!intent.scope.domains.includes(changeEvent.domain)) {
|
|
711
|
+
violations.push(this._buildViolation(
|
|
712
|
+
VIOLATION_CODES.DOMAIN_VIOLATION,
|
|
713
|
+
"domain_check",
|
|
714
|
+
`Domain '${changeEvent.domain}' not in allowed domains`,
|
|
715
|
+
changeEvent.location,
|
|
716
|
+
{
|
|
717
|
+
expected: intent.scope.domains.join(", "),
|
|
718
|
+
actual: changeEvent.domain,
|
|
719
|
+
}
|
|
720
|
+
));
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (intent.scope?.excluded_paths) {
|
|
725
|
+
const isExcluded = intent.scope.excluded_paths.some(ex =>
|
|
726
|
+
changeEvent.location.includes(ex)
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
if (isExcluded) {
|
|
730
|
+
violations.push(this._buildViolation(
|
|
731
|
+
VIOLATION_CODES.SCOPE_VIOLATION,
|
|
732
|
+
"excluded_path",
|
|
733
|
+
`File is in excluded paths: ${changeEvent.location}`,
|
|
734
|
+
changeEvent.location
|
|
735
|
+
));
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return violations;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
_checkProtectedFiles(changeEvent, intent) {
|
|
743
|
+
const violations = [];
|
|
744
|
+
|
|
745
|
+
for (const protectedFile of intent.scope.protected_files) {
|
|
746
|
+
if (changeEvent.location.includes(protectedFile)) {
|
|
747
|
+
violations.push(this._buildViolation(
|
|
748
|
+
"PROTECTED_FILE_MODIFICATION",
|
|
749
|
+
"protected_file",
|
|
750
|
+
`Protected file cannot be modified: ${protectedFile}`,
|
|
751
|
+
changeEvent.location
|
|
752
|
+
));
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return violations;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
_computeVerdictHash(verdict) {
|
|
760
|
+
const content = JSON.stringify({
|
|
761
|
+
decision: verdict.decision,
|
|
762
|
+
mode: verdict.mode,
|
|
763
|
+
violations: verdict.violations.map(v => ({ code: v.code, resource: v.resource })),
|
|
764
|
+
proofs: verdict.proofs.map(p => ({ id: p.id, status: p.status })),
|
|
765
|
+
intent_hash: verdict.intent_hash,
|
|
766
|
+
timestamp: verdict.timestamp,
|
|
767
|
+
chain: verdict.chain,
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
_signVerdict(verdict) {
|
|
774
|
+
// Use HMAC signing with a local key (would be replaced with proper key management)
|
|
775
|
+
const secret = process.env.VIBECHECK_SIGN_KEY || "vibecheck-local-signing-key";
|
|
776
|
+
const signature = crypto.createHmac("sha256", secret)
|
|
777
|
+
.update(verdict.verdict_hash)
|
|
778
|
+
.digest("hex");
|
|
779
|
+
|
|
780
|
+
return {
|
|
781
|
+
algorithm: "sha256-hmac",
|
|
782
|
+
value: signature,
|
|
783
|
+
key_id: "local",
|
|
784
|
+
signed_at: new Date().toISOString(),
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
_verifyVerdictIntegrity(verdict) {
|
|
789
|
+
if (!verdict || !verdict.verdict_hash) {
|
|
790
|
+
return { valid: false, reason: "MISSING_HASH" };
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
const computed = this._computeVerdictHash(verdict);
|
|
794
|
+
|
|
795
|
+
if (computed !== verdict.verdict_hash) {
|
|
796
|
+
return { valid: false, reason: "HASH_MISMATCH" };
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Verify signature if present
|
|
800
|
+
if (verdict.signature && verdict.signature.algorithm === "sha256-hmac") {
|
|
801
|
+
const secret = process.env.VIBECHECK_SIGN_KEY || "vibecheck-local-signing-key";
|
|
802
|
+
const expected = crypto.createHmac("sha256", secret)
|
|
803
|
+
.update(verdict.verdict_hash)
|
|
804
|
+
.digest("hex");
|
|
805
|
+
|
|
806
|
+
if (expected !== verdict.signature.value) {
|
|
807
|
+
return { valid: false, reason: "SIGNATURE_INVALID" };
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
return { valid: true, reason: "VERIFIED" };
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
_formatBlockMessage(violations) {
|
|
815
|
+
if (violations.length === 0) {
|
|
816
|
+
return "BLOCKED_BY_AGENT_FIREWALL: Unknown reason";
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const lines = ["═══════════════════════════════════════════════════════════════════════════════"];
|
|
820
|
+
lines.push("BLOCKED BY AGENT FIREWALL");
|
|
821
|
+
lines.push("═══════════════════════════════════════════════════════════════════════════════");
|
|
822
|
+
lines.push("");
|
|
823
|
+
|
|
824
|
+
for (const v of violations.filter(v => v.severity === "block").slice(0, 5)) {
|
|
825
|
+
lines.push(`❌ [${v.code}]`);
|
|
826
|
+
lines.push(` Resource: ${v.resource}`);
|
|
827
|
+
lines.push(` Reason: ${v.message}`);
|
|
828
|
+
|
|
829
|
+
if (v.evidence) {
|
|
830
|
+
if (v.evidence.file) lines.push(` File: ${v.evidence.file}:${v.evidence.line || ''}`);
|
|
831
|
+
if (v.evidence.snippet) lines.push(` Snippet: ${v.evidence.snippet.substring(0, 60)}...`);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (v.fix_hint) {
|
|
835
|
+
lines.push(` Fix: ${v.fix_hint}`);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
lines.push("");
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (violations.length > 5) {
|
|
842
|
+
lines.push(`... and ${violations.length - 5} more violations`);
|
|
843
|
+
lines.push("");
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
lines.push("═══════════════════════════════════════════════════════════════════════════════");
|
|
847
|
+
|
|
848
|
+
return lines.join("\n");
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
_generateSummary(decision, violations) {
|
|
852
|
+
if (decision === VERDICT.PASS || decision === VERDICT.WOULD_PASS) {
|
|
853
|
+
return "All enforcement checks passed";
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const blockCount = violations.filter(v => v.severity === "block").length;
|
|
857
|
+
const warnCount = violations.filter(v => v.severity === "warn").length;
|
|
858
|
+
|
|
859
|
+
const topIssues = violations
|
|
860
|
+
.filter(v => v.severity === "block")
|
|
861
|
+
.slice(0, 3)
|
|
862
|
+
.map(v => v.code)
|
|
863
|
+
.join(", ");
|
|
864
|
+
|
|
865
|
+
return `BLOCKED: ${blockCount} violation(s), ${warnCount} warning(s). Top issues: ${topIssues}`;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
_generateFixGuidance(violations) {
|
|
869
|
+
const guidance = [];
|
|
870
|
+
|
|
871
|
+
for (const v of violations.filter(v => v.severity === "block")) {
|
|
872
|
+
const fix = this._getFixGuidanceForViolation(v);
|
|
873
|
+
if (fix) guidance.push(fix);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
return guidance;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
_getFixGuidanceForViolation(violation) {
|
|
880
|
+
const fixMap = {
|
|
881
|
+
"TODO_DETECTED": {
|
|
882
|
+
action: "remove_code",
|
|
883
|
+
explanation: "Remove or resolve TODO comment before shipping",
|
|
884
|
+
auto_fixable: false,
|
|
885
|
+
},
|
|
886
|
+
"FIXME_DETECTED": {
|
|
887
|
+
action: "remove_code",
|
|
888
|
+
explanation: "Resolve FIXME issue before shipping",
|
|
889
|
+
auto_fixable: false,
|
|
890
|
+
},
|
|
891
|
+
"MOCK_DATA": {
|
|
892
|
+
action: "modify_file",
|
|
893
|
+
explanation: "Replace mock data with real implementation or move to test files",
|
|
894
|
+
auto_fixable: false,
|
|
895
|
+
},
|
|
896
|
+
"UNDECLARED_ROUTE": {
|
|
897
|
+
action: "update_intent",
|
|
898
|
+
command: "vibecheck intent amend --allow-route",
|
|
899
|
+
explanation: "Add route to allowed_changes in intent",
|
|
900
|
+
auto_fixable: false,
|
|
901
|
+
},
|
|
902
|
+
"UNDECLARED_ENV_VAR": {
|
|
903
|
+
action: "add_env",
|
|
904
|
+
command: "vibecheck intent amend --allow-env",
|
|
905
|
+
explanation: "Declare env var in intent or add to .env",
|
|
906
|
+
auto_fixable: true,
|
|
907
|
+
},
|
|
908
|
+
"SCOPE_VIOLATION": {
|
|
909
|
+
action: "update_intent",
|
|
910
|
+
command: "vibecheck intent amend --allow-dir",
|
|
911
|
+
explanation: "Expand scope to include this directory",
|
|
912
|
+
auto_fixable: false,
|
|
913
|
+
},
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
const template = fixMap[violation.code];
|
|
917
|
+
if (!template) return null;
|
|
918
|
+
|
|
919
|
+
return {
|
|
920
|
+
violation_code: violation.code,
|
|
921
|
+
target: violation.resource,
|
|
922
|
+
...template,
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
_getFixHint(code, resource) {
|
|
927
|
+
const hints = {
|
|
928
|
+
"TODO_DETECTED": "Remove TODO or resolve the issue",
|
|
929
|
+
"FIXME_DETECTED": "Fix the issue or remove FIXME comment",
|
|
930
|
+
"MOCK_DATA": "Replace mock data with real implementation",
|
|
931
|
+
"FAKE_DATA": "Replace fake data with real implementation",
|
|
932
|
+
"PLACEHOLDER_DETECTED": "Replace placeholder with real code",
|
|
933
|
+
"CONSOLE_LOG": "Remove console statement or use proper logger",
|
|
934
|
+
"ANY_TYPE": "Add proper TypeScript type",
|
|
935
|
+
"NOT_IMPLEMENTED": "Implement the function",
|
|
936
|
+
"TS_IGNORE": "Fix the TypeScript error instead of ignoring",
|
|
937
|
+
"UNDECLARED_ROUTE": `Run: vibecheck intent amend --allow-route "${resource}"`,
|
|
938
|
+
"UNDECLARED_ENV_VAR": `Run: vibecheck intent amend --allow-env "${resource}"`,
|
|
939
|
+
"UNDECLARED_FILE_CHANGE": `Run: vibecheck intent amend --allow-file "${resource}"`,
|
|
940
|
+
"SCOPE_VIOLATION": `Update intent scope or move file to allowed directory`,
|
|
941
|
+
"DOMAIN_NOT_ALLOWED": `Add domain to intent: vibecheck intent amend --domain`,
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
return hints[code] || "Review and fix the violation";
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
_mapClaimTypeToProofType(claimType) {
|
|
948
|
+
const map = {
|
|
949
|
+
route: "route",
|
|
950
|
+
auth_boundary: "auth",
|
|
951
|
+
ui_success_claim: "ui",
|
|
952
|
+
http_call: "integration",
|
|
953
|
+
env_used: "env",
|
|
954
|
+
env_declared: "env",
|
|
955
|
+
data_contract: "contract",
|
|
956
|
+
};
|
|
957
|
+
return map[claimType] || "integration";
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
_loadPolicy() {
|
|
961
|
+
const policyPath = path.join(this.projectRoot, ".vibecheck", "policy.json");
|
|
962
|
+
|
|
963
|
+
if (fs.existsSync(policyPath)) {
|
|
964
|
+
try {
|
|
965
|
+
return JSON.parse(fs.readFileSync(policyPath, "utf-8"));
|
|
966
|
+
} catch {
|
|
967
|
+
// Return default
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
return {
|
|
972
|
+
version: "3.0.0",
|
|
973
|
+
profile: "strict",
|
|
974
|
+
rules: {},
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
_storeVerdict(verdict) {
|
|
979
|
+
const verdictDir = path.join(this.projectRoot, ".vibecheck", "verdicts");
|
|
980
|
+
|
|
981
|
+
try {
|
|
982
|
+
if (!fs.existsSync(verdictDir)) {
|
|
983
|
+
fs.mkdirSync(verdictDir, { recursive: true });
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// Store by ID
|
|
987
|
+
fs.writeFileSync(
|
|
988
|
+
path.join(verdictDir, `${verdict.id}.json`),
|
|
989
|
+
JSON.stringify(verdict, null, 2)
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
// Store as latest
|
|
993
|
+
fs.writeFileSync(
|
|
994
|
+
path.join(verdictDir, "latest.json"),
|
|
995
|
+
JSON.stringify(verdict, null, 2)
|
|
996
|
+
);
|
|
997
|
+
} catch (err) {
|
|
998
|
+
// Silent fail - verdict storage is not critical
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
_getLatestVerdict() {
|
|
1003
|
+
const latestPath = path.join(this.projectRoot, ".vibecheck", "verdicts", "latest.json");
|
|
1004
|
+
|
|
1005
|
+
if (fs.existsSync(latestPath)) {
|
|
1006
|
+
try {
|
|
1007
|
+
return JSON.parse(fs.readFileSync(latestPath, "utf-8"));
|
|
1008
|
+
} catch {
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1018
|
+
// FACTORY FUNCTIONS
|
|
1019
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* Create an enforcement gateway instance
|
|
1023
|
+
*/
|
|
1024
|
+
function createGateway(projectRoot, options = {}) {
|
|
1025
|
+
return new EnforcementGateway(projectRoot, options);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Quick intercept - one-shot enforcement without persisting gateway
|
|
1030
|
+
*/
|
|
1031
|
+
async function intercept(projectRoot, rawChange, source = {}) {
|
|
1032
|
+
const gateway = createGateway(projectRoot);
|
|
1033
|
+
return gateway.intercept(rawChange, source);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* Quick check - fast validation without full enforcement
|
|
1038
|
+
*/
|
|
1039
|
+
function quickCheck(projectRoot, rawChange) {
|
|
1040
|
+
const gateway = createGateway(projectRoot);
|
|
1041
|
+
return gateway.quickCheck(rawChange);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1045
|
+
// EXPORTS
|
|
1046
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1047
|
+
|
|
1048
|
+
module.exports = {
|
|
1049
|
+
EnforcementGateway,
|
|
1050
|
+
createGateway,
|
|
1051
|
+
intercept,
|
|
1052
|
+
quickCheck,
|
|
1053
|
+
buildChangeEvent,
|
|
1054
|
+
analyzeCodeQuality,
|
|
1055
|
+
classifyDomain,
|
|
1056
|
+
MODE,
|
|
1057
|
+
VERDICT,
|
|
1058
|
+
BLOCK_PATTERNS,
|
|
1059
|
+
};
|