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,648 @@
|
|
|
1
|
+
// bin/runners/lib/missions/plan.js
|
|
2
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
3
|
+
// MISSION PLANNING V2 - Enhanced with dependency-aware grouping, blast radius
|
|
4
|
+
// analysis, and risk-based batching. "Missions, not chaos."
|
|
5
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
createMission,
|
|
9
|
+
calculateBlastRadius,
|
|
10
|
+
calculateRiskLevel,
|
|
11
|
+
RISK_LEVEL,
|
|
12
|
+
BLAST_RADIUS,
|
|
13
|
+
} = require('./schema');
|
|
14
|
+
const { templateForMissionType } = require('./templates');
|
|
15
|
+
const {
|
|
16
|
+
ValidationError,
|
|
17
|
+
validateFinding,
|
|
18
|
+
validateOptions,
|
|
19
|
+
getAuditTrail,
|
|
20
|
+
} = require('./hardening');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Score a finding for priority ordering
|
|
24
|
+
* Enhanced with confidence-based scoring
|
|
25
|
+
*/
|
|
26
|
+
function scoreFinding(f) {
|
|
27
|
+
let score = 0;
|
|
28
|
+
|
|
29
|
+
// Base severity score
|
|
30
|
+
if (f.severity === "BLOCK") score += 100;
|
|
31
|
+
else if (f.severity === "WARN") score += 50;
|
|
32
|
+
|
|
33
|
+
// Confidence adjustment (findings with evidence are more reliable)
|
|
34
|
+
const confidence = f.confidence || (f.evidence?.length > 0 ? 0.8 : 0.5);
|
|
35
|
+
score = Math.round(score * confidence);
|
|
36
|
+
|
|
37
|
+
// Boost for findings with file evidence (more actionable)
|
|
38
|
+
if (f.file || f.evidence?.some(e => e.file)) {
|
|
39
|
+
score += 10;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Boost for security-related categories
|
|
43
|
+
if (['Security', 'GhostAuth', 'AuthCoverage', 'Billing'].includes(f.category)) {
|
|
44
|
+
score += 20;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return score;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generate a fingerprint for deduplication
|
|
52
|
+
* Uses multiple signals to identify truly unique findings
|
|
53
|
+
*/
|
|
54
|
+
function generateFingerprint(f) {
|
|
55
|
+
const parts = [];
|
|
56
|
+
|
|
57
|
+
// Primary: category + normalized title
|
|
58
|
+
parts.push(f.category || 'Unknown');
|
|
59
|
+
|
|
60
|
+
// Normalize title (remove specific IDs, file paths, line numbers)
|
|
61
|
+
let normalizedTitle = (f.title || '')
|
|
62
|
+
.replace(/[a-f0-9]{8,}/gi, 'HASH') // Remove hash-like IDs
|
|
63
|
+
.replace(/:\d+/g, ':LINE') // Normalize line numbers
|
|
64
|
+
.replace(/\/[^/\s]+\.(ts|js|tsx|jsx)/gi, '/FILE.$1') // Normalize file paths
|
|
65
|
+
.trim();
|
|
66
|
+
parts.push(normalizedTitle);
|
|
67
|
+
|
|
68
|
+
// Secondary: file if available (for file-specific issues)
|
|
69
|
+
if (f.file) {
|
|
70
|
+
// Normalize the file path to base name for grouping
|
|
71
|
+
const fileName = f.file.split(/[/\\]/).pop() || f.file;
|
|
72
|
+
parts.push(fileName);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return parts.join('|');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Extended category to mission type mapping
|
|
80
|
+
* Includes new categories from enhanced detection
|
|
81
|
+
*/
|
|
82
|
+
const CATEGORY_TO_MISSION_TYPE = {
|
|
83
|
+
// Security & Auth
|
|
84
|
+
Security: "REMOVE_OWNER_MODE",
|
|
85
|
+
GhostAuth: "ADD_SERVER_AUTH",
|
|
86
|
+
AuthCoverage: "ADD_SERVER_AUTH",
|
|
87
|
+
AuthDrift: "FIX_AUTH_DRIFT",
|
|
88
|
+
|
|
89
|
+
// Billing & Payments
|
|
90
|
+
Billing: "FIX_STRIPE_WEBHOOKS",
|
|
91
|
+
Entitlements: "ENFORCE_PAID_SURFACE",
|
|
92
|
+
|
|
93
|
+
// Routes & APIs
|
|
94
|
+
MissingRoute: "FIX_MISSING_ROUTE",
|
|
95
|
+
RouteDrift: "FIX_ROUTE_DRIFT",
|
|
96
|
+
|
|
97
|
+
// Environment & Config
|
|
98
|
+
EnvContract: "FIX_ENV_CONTRACT",
|
|
99
|
+
|
|
100
|
+
// Reality/Runtime issues
|
|
101
|
+
FakeSuccess: "FIX_FAKE_SUCCESS",
|
|
102
|
+
DeadUI: "FIX_DEAD_UI",
|
|
103
|
+
FakeDomain: "FIX_MOCK_DOMAINS",
|
|
104
|
+
FakeResponse: "FIX_PLACEHOLDER_DATA",
|
|
105
|
+
MockStatus: "FIX_MOCK_DOMAINS",
|
|
106
|
+
|
|
107
|
+
// Code Quality
|
|
108
|
+
EmptyCatch: "FIX_EMPTY_CATCH",
|
|
109
|
+
TestKeys: "FIX_TEST_KEYS",
|
|
110
|
+
HardcodedSecrets: "FIX_HARDCODED_SECRETS",
|
|
111
|
+
SilentFallback: "FIX_SILENT_FALLBACK",
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Mission type priority (lower = higher priority)
|
|
116
|
+
* Security issues come first, then billing, then everything else
|
|
117
|
+
*/
|
|
118
|
+
const MISSION_PRIORITY = {
|
|
119
|
+
// P0: Critical security (immediate fix required)
|
|
120
|
+
REMOVE_OWNER_MODE: 1,
|
|
121
|
+
FIX_HARDCODED_SECRETS: 2,
|
|
122
|
+
FIX_AUTH_DRIFT: 3,
|
|
123
|
+
|
|
124
|
+
// P1: Security & billing (fix before shipping)
|
|
125
|
+
FIX_STRIPE_WEBHOOKS: 10,
|
|
126
|
+
ENFORCE_PAID_SURFACE: 11,
|
|
127
|
+
ADD_SERVER_AUTH: 12,
|
|
128
|
+
FIX_TEST_KEYS: 13,
|
|
129
|
+
|
|
130
|
+
// P2: Fake data (fix before production)
|
|
131
|
+
FIX_MOCK_DOMAINS: 20,
|
|
132
|
+
FIX_PLACEHOLDER_DATA: 21,
|
|
133
|
+
FIX_FAKE_SUCCESS: 22,
|
|
134
|
+
|
|
135
|
+
// P3: Code quality (fix when possible)
|
|
136
|
+
FIX_MISSING_ROUTE: 30,
|
|
137
|
+
FIX_ROUTE_DRIFT: 31,
|
|
138
|
+
FIX_ENV_CONTRACT: 32,
|
|
139
|
+
FIX_EMPTY_CATCH: 33,
|
|
140
|
+
FIX_SILENT_FALLBACK: 34,
|
|
141
|
+
|
|
142
|
+
// P4: UI issues (fix before polish)
|
|
143
|
+
FIX_DEAD_UI: 40,
|
|
144
|
+
|
|
145
|
+
// P5: Generic (lowest priority)
|
|
146
|
+
GENERIC_FIX: 99,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Extract files from findings
|
|
151
|
+
* @param {Array} findings - Findings array
|
|
152
|
+
* @returns {string[]} Unique file paths
|
|
153
|
+
*/
|
|
154
|
+
function extractFilesFromFindings(findings) {
|
|
155
|
+
const files = new Set();
|
|
156
|
+
for (const f of findings) {
|
|
157
|
+
if (f.file) files.add(f.file);
|
|
158
|
+
for (const ev of (f.evidence || [])) {
|
|
159
|
+
if (ev.file) files.add(ev.file);
|
|
160
|
+
if (ev.path) files.add(ev.path);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return Array.from(files);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Build a simple import graph from truthpack
|
|
168
|
+
* @param {object} truthpack - Truthpack object
|
|
169
|
+
* @returns {Map} Map of file -> imported files
|
|
170
|
+
*/
|
|
171
|
+
function buildImportGraph(truthpack) {
|
|
172
|
+
const graph = new Map();
|
|
173
|
+
|
|
174
|
+
// Extract imports from truthpack if available
|
|
175
|
+
const imports = truthpack?.imports || truthpack?.dependencies?.imports || [];
|
|
176
|
+
for (const imp of imports) {
|
|
177
|
+
if (imp.from && imp.to) {
|
|
178
|
+
if (!graph.has(imp.from)) graph.set(imp.from, new Set());
|
|
179
|
+
graph.get(imp.from).add(imp.to);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return graph;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Find connected components in file graph
|
|
188
|
+
* Files that import each other should be grouped together
|
|
189
|
+
* @param {string[]} files - List of files
|
|
190
|
+
* @param {Map} importGraph - Import graph
|
|
191
|
+
* @returns {string[][]} Array of file clusters
|
|
192
|
+
*/
|
|
193
|
+
function findConnectedFileClusters(files, importGraph) {
|
|
194
|
+
const fileSet = new Set(files);
|
|
195
|
+
const visited = new Set();
|
|
196
|
+
const clusters = [];
|
|
197
|
+
|
|
198
|
+
function dfs(file, cluster) {
|
|
199
|
+
if (visited.has(file)) return;
|
|
200
|
+
visited.add(file);
|
|
201
|
+
cluster.push(file);
|
|
202
|
+
|
|
203
|
+
// Check files this one imports
|
|
204
|
+
const imports = importGraph.get(file) || new Set();
|
|
205
|
+
for (const imported of imports) {
|
|
206
|
+
if (fileSet.has(imported)) {
|
|
207
|
+
dfs(imported, cluster);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Check files that import this one
|
|
212
|
+
for (const [from, toSet] of importGraph) {
|
|
213
|
+
if (toSet.has(file) && fileSet.has(from)) {
|
|
214
|
+
dfs(from, cluster);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const file of files) {
|
|
220
|
+
if (!visited.has(file)) {
|
|
221
|
+
const cluster = [];
|
|
222
|
+
dfs(file, cluster);
|
|
223
|
+
if (cluster.length > 0) {
|
|
224
|
+
clusters.push(cluster);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return clusters;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Calculate cluster risk score
|
|
234
|
+
* @param {Array} findings - Findings in cluster
|
|
235
|
+
* @returns {number} Risk score 0-100
|
|
236
|
+
*/
|
|
237
|
+
function calculateClusterRisk(findings) {
|
|
238
|
+
let score = 0;
|
|
239
|
+
|
|
240
|
+
for (const f of findings) {
|
|
241
|
+
// Severity contribution
|
|
242
|
+
if (f.severity === 'BLOCK') score += 30;
|
|
243
|
+
else if (f.severity === 'WARN') score += 15;
|
|
244
|
+
else score += 5;
|
|
245
|
+
|
|
246
|
+
// Confidence inverse (lower confidence = higher risk)
|
|
247
|
+
const confidence = f.confidence || 0.5;
|
|
248
|
+
score += Math.round((1 - confidence) * 10);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Normalize by finding count, cap at 100
|
|
252
|
+
return Math.min(100, score);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Create a mission from a finding using the new schema
|
|
257
|
+
* Enhanced with confidence and better metadata
|
|
258
|
+
*/
|
|
259
|
+
function missionFromFinding(f, relatedFindings = [], options = {}) {
|
|
260
|
+
const type = CATEGORY_TO_MISSION_TYPE[f.category] || "GENERIC_FIX";
|
|
261
|
+
const allFindingIds = [f.id, ...relatedFindings.map(r => r.id)];
|
|
262
|
+
const allFindings = [f, ...relatedFindings];
|
|
263
|
+
|
|
264
|
+
// Calculate mission confidence based on findings
|
|
265
|
+
const confidences = [f.confidence || 0.5, ...relatedFindings.map(r => r.confidence || 0.5)];
|
|
266
|
+
const avgConfidence = confidences.reduce((a, b) => a + b, 0) / confidences.length;
|
|
267
|
+
|
|
268
|
+
// Extract all files from findings
|
|
269
|
+
const allowedFiles = extractFilesFromFindings(allFindings);
|
|
270
|
+
|
|
271
|
+
// Get template for this mission type
|
|
272
|
+
const template = templateForMissionType(type);
|
|
273
|
+
|
|
274
|
+
// Use the new schema to create a proper mission object
|
|
275
|
+
return createMission({
|
|
276
|
+
type,
|
|
277
|
+
title: f.title,
|
|
278
|
+
severity: f.severity,
|
|
279
|
+
category: f.category,
|
|
280
|
+
targetFindingIds: allFindingIds,
|
|
281
|
+
template,
|
|
282
|
+
allowedFiles,
|
|
283
|
+
readOnlyContext: options.readOnlyContext || [],
|
|
284
|
+
confidence: avgConfidence,
|
|
285
|
+
evidence: f.evidence || [],
|
|
286
|
+
file: f.file || null,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Group related findings that can be fixed together
|
|
292
|
+
* E.g., multiple Dead UI issues in the same file
|
|
293
|
+
* Now with dependency-aware clustering
|
|
294
|
+
*/
|
|
295
|
+
function groupRelatedFindings(findings, options = {}) {
|
|
296
|
+
const { importGraph = new Map(), maxClusterRisk = 80 } = options;
|
|
297
|
+
const groups = new Map();
|
|
298
|
+
|
|
299
|
+
// First pass: group by category
|
|
300
|
+
const byCategory = new Map();
|
|
301
|
+
for (const f of findings) {
|
|
302
|
+
const cat = f.category || 'Unknown';
|
|
303
|
+
if (!byCategory.has(cat)) byCategory.set(cat, []);
|
|
304
|
+
byCategory.get(cat).push(f);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Second pass: within each category, cluster by file dependencies
|
|
308
|
+
for (const [category, catFindings] of byCategory) {
|
|
309
|
+
const files = extractFilesFromFindings(catFindings);
|
|
310
|
+
const clusters = findConnectedFileClusters(files, importGraph);
|
|
311
|
+
|
|
312
|
+
// Map files to their cluster index
|
|
313
|
+
const fileToCluster = new Map();
|
|
314
|
+
clusters.forEach((cluster, idx) => {
|
|
315
|
+
for (const file of cluster) {
|
|
316
|
+
fileToCluster.set(file, idx);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Group findings by their file's cluster
|
|
321
|
+
const clusterGroups = new Map();
|
|
322
|
+
for (const f of catFindings) {
|
|
323
|
+
const file = f.file || f.evidence?.[0]?.file || f.evidence?.[0]?.path || 'unknown';
|
|
324
|
+
const clusterIdx = fileToCluster.get(file) ?? -1;
|
|
325
|
+
const groupKey = `${category}:cluster_${clusterIdx}:${file}`;
|
|
326
|
+
|
|
327
|
+
if (!clusterGroups.has(groupKey)) {
|
|
328
|
+
clusterGroups.set(groupKey, []);
|
|
329
|
+
}
|
|
330
|
+
clusterGroups.get(groupKey).push(f);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Third pass: split groups that exceed risk threshold
|
|
334
|
+
for (const [groupKey, groupFindings] of clusterGroups) {
|
|
335
|
+
const risk = calculateClusterRisk(groupFindings);
|
|
336
|
+
|
|
337
|
+
if (risk > maxClusterRisk && groupFindings.length > 1) {
|
|
338
|
+
// Split into individual findings for high-risk groups
|
|
339
|
+
for (let i = 0; i < groupFindings.length; i++) {
|
|
340
|
+
groups.set(`${groupKey}:split_${i}`, [groupFindings[i]]);
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
groups.set(groupKey, groupFindings);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return groups;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Advanced grouping with blast radius analysis
|
|
353
|
+
* Groups findings while respecting blast radius limits
|
|
354
|
+
*/
|
|
355
|
+
function groupWithBlastRadiusLimit(findings, options = {}) {
|
|
356
|
+
const { maxBlastRadius = 5, importGraph = new Map() } = options;
|
|
357
|
+
const groups = new Map();
|
|
358
|
+
|
|
359
|
+
// Start with basic grouping
|
|
360
|
+
const basicGroups = groupRelatedFindings(findings, { importGraph });
|
|
361
|
+
|
|
362
|
+
// Check each group's blast radius
|
|
363
|
+
for (const [key, groupFindings] of basicGroups) {
|
|
364
|
+
const files = extractFilesFromFindings(groupFindings);
|
|
365
|
+
|
|
366
|
+
if (files.length > maxBlastRadius) {
|
|
367
|
+
// Split into smaller groups by file
|
|
368
|
+
const byFile = new Map();
|
|
369
|
+
for (const f of groupFindings) {
|
|
370
|
+
const file = f.file || f.evidence?.[0]?.file || 'unknown';
|
|
371
|
+
if (!byFile.has(file)) byFile.set(file, []);
|
|
372
|
+
byFile.get(file).push(f);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Create separate groups for each file
|
|
376
|
+
let idx = 0;
|
|
377
|
+
for (const [file, fileFindings] of byFile) {
|
|
378
|
+
groups.set(`${key}:file_${idx++}`, fileFindings);
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
groups.set(key, groupFindings);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return groups;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Plan missions from findings with enhanced deduplication and prioritization
|
|
390
|
+
*
|
|
391
|
+
* @param {Array} findings - List of findings from ship/scan
|
|
392
|
+
* @param {Object} options - Planning options
|
|
393
|
+
* @param {number} [options.maxMissions=12] - Maximum missions to plan
|
|
394
|
+
* @param {boolean} [options.blocksOnlyFirst=true] - Prioritize BLOCK findings
|
|
395
|
+
* @param {boolean} [options.groupRelated=true] - Group related findings
|
|
396
|
+
* @param {object} [options.truthpack] - Truthpack for dependency analysis
|
|
397
|
+
* @param {number} [options.maxBlastRadius=5] - Maximum files per mission
|
|
398
|
+
* @param {number} [options.maxClusterRisk=80] - Maximum cluster risk score
|
|
399
|
+
* @param {number} [options.minConfidence=0] - Minimum confidence threshold
|
|
400
|
+
* @returns {Array} Planned missions
|
|
401
|
+
*/
|
|
402
|
+
function planMissions(findings, options = {}) {
|
|
403
|
+
const audit = getAuditTrail();
|
|
404
|
+
|
|
405
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
406
|
+
// INPUT VALIDATION
|
|
407
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
408
|
+
|
|
409
|
+
// Handle null/undefined findings
|
|
410
|
+
if (!findings) {
|
|
411
|
+
audit.warn('plan_missions_no_findings', { findings });
|
|
412
|
+
return [];
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Handle non-array findings
|
|
416
|
+
if (!Array.isArray(findings)) {
|
|
417
|
+
audit.error('plan_missions_invalid_findings', { type: typeof findings });
|
|
418
|
+
throw new ValidationError('findings must be an array', 'findings', findings);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Handle empty findings
|
|
422
|
+
if (findings.length === 0) {
|
|
423
|
+
audit.info('plan_missions_empty_findings');
|
|
424
|
+
return [];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Validate and sanitize options
|
|
428
|
+
const optionsSchema = {
|
|
429
|
+
maxMissions: { type: 'number', default: 12, min: 1, max: 100 },
|
|
430
|
+
blocksOnlyFirst: { type: 'boolean', default: true },
|
|
431
|
+
groupRelated: { type: 'boolean', default: true },
|
|
432
|
+
maxBlastRadius: { type: 'number', default: 5, min: 1, max: 50 },
|
|
433
|
+
maxClusterRisk: { type: 'number', default: 80, min: 0, max: 100 },
|
|
434
|
+
minConfidence: { type: 'number', default: 0, min: 0, max: 1 },
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const validatedOptions = validateOptions(options, optionsSchema);
|
|
438
|
+
if (!validatedOptions.valid) {
|
|
439
|
+
audit.warn('plan_missions_invalid_options', { errors: validatedOptions.errors });
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const {
|
|
443
|
+
maxMissions,
|
|
444
|
+
blocksOnlyFirst,
|
|
445
|
+
groupRelated,
|
|
446
|
+
maxBlastRadius,
|
|
447
|
+
maxClusterRisk,
|
|
448
|
+
minConfidence,
|
|
449
|
+
} = validatedOptions.sanitized;
|
|
450
|
+
|
|
451
|
+
const truthpack = options.truthpack || null;
|
|
452
|
+
|
|
453
|
+
audit.info('plan_missions_start', {
|
|
454
|
+
findingCount: findings.length,
|
|
455
|
+
maxMissions,
|
|
456
|
+
blocksOnlyFirst,
|
|
457
|
+
groupRelated,
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// Build import graph from truthpack if available
|
|
461
|
+
const importGraph = truthpack ? buildImportGraph(truthpack) : new Map();
|
|
462
|
+
|
|
463
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
464
|
+
// FINDING VALIDATION & FILTERING
|
|
465
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
466
|
+
|
|
467
|
+
// Validate and filter findings
|
|
468
|
+
const validFindings = [];
|
|
469
|
+
let invalidCount = 0;
|
|
470
|
+
|
|
471
|
+
for (const f of findings) {
|
|
472
|
+
const validation = validateFinding(f);
|
|
473
|
+
if (validation.valid) {
|
|
474
|
+
validFindings.push(f);
|
|
475
|
+
} else {
|
|
476
|
+
invalidCount++;
|
|
477
|
+
audit.debug('plan_missions_invalid_finding', { id: f?.id, errors: validation.errors });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (invalidCount > 0) {
|
|
482
|
+
audit.warn('plan_missions_invalid_findings_skipped', { invalidCount, validCount: validFindings.length });
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (validFindings.length === 0) {
|
|
486
|
+
audit.info('plan_missions_no_valid_findings');
|
|
487
|
+
return [];
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Step 1: Sort by score (severity + confidence + evidence)
|
|
491
|
+
const sorted = [...validFindings].sort((a, b) => scoreFinding(b) - scoreFinding(a));
|
|
492
|
+
|
|
493
|
+
// Step 2: Filter to BLOCKs only if we have them (cost control)
|
|
494
|
+
const hasBlocks = sorted.some(f => f.severity === "BLOCK");
|
|
495
|
+
const scoped = (blocksOnlyFirst && hasBlocks)
|
|
496
|
+
? sorted.filter(f => f.severity === "BLOCK")
|
|
497
|
+
: sorted;
|
|
498
|
+
|
|
499
|
+
// Step 3: Deduplicate using fingerprints
|
|
500
|
+
const seenFingerprints = new Set();
|
|
501
|
+
const deduplicated = [];
|
|
502
|
+
|
|
503
|
+
for (const f of scoped) {
|
|
504
|
+
const fingerprint = generateFingerprint(f);
|
|
505
|
+
|
|
506
|
+
// Skip exact duplicates
|
|
507
|
+
if (seenFingerprints.has(fingerprint)) continue;
|
|
508
|
+
seenFingerprints.add(fingerprint);
|
|
509
|
+
|
|
510
|
+
// Also check for near-duplicates (same category + similar title)
|
|
511
|
+
const nearDupeKey = `${f.category}:${(f.title || '').substring(0, 50)}`;
|
|
512
|
+
if (f.severity === "WARN" && seenFingerprints.has(nearDupeKey)) continue;
|
|
513
|
+
seenFingerprints.add(nearDupeKey);
|
|
514
|
+
|
|
515
|
+
// Filter by minimum confidence if specified
|
|
516
|
+
const confidence = f.confidence || 0.5;
|
|
517
|
+
if (confidence < minConfidence) continue;
|
|
518
|
+
|
|
519
|
+
deduplicated.push(f);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Step 4: Group related findings with enhanced heuristics
|
|
523
|
+
let missions = [];
|
|
524
|
+
|
|
525
|
+
if (groupRelated) {
|
|
526
|
+
// Use blast radius-aware grouping
|
|
527
|
+
const groups = groupWithBlastRadiusLimit(deduplicated, {
|
|
528
|
+
maxBlastRadius,
|
|
529
|
+
importGraph,
|
|
530
|
+
maxClusterRisk,
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
for (const [groupKey, groupFindings] of groups) {
|
|
534
|
+
// Take the highest severity finding as primary
|
|
535
|
+
const primary = groupFindings[0]; // Already sorted by score
|
|
536
|
+
const related = groupFindings.slice(1, 5); // Limit related findings
|
|
537
|
+
|
|
538
|
+
missions.push(missionFromFinding(primary, related, { importGraph }));
|
|
539
|
+
}
|
|
540
|
+
} else {
|
|
541
|
+
missions = deduplicated.map(f => missionFromFinding(f));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Step 5: Sort by priority and risk
|
|
545
|
+
missions.sort((a, b) => {
|
|
546
|
+
const prioA = MISSION_PRIORITY[a.type] || 50;
|
|
547
|
+
const prioB = MISSION_PRIORITY[b.type] || 50;
|
|
548
|
+
if (prioA !== prioB) return prioA - prioB;
|
|
549
|
+
|
|
550
|
+
// Secondary sort by risk level (lower risk first for safety)
|
|
551
|
+
const riskOrder = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
552
|
+
const riskA = riskOrder[a.safety?.riskLevel] ?? 1;
|
|
553
|
+
const riskB = riskOrder[b.safety?.riskLevel] ?? 1;
|
|
554
|
+
if (riskA !== riskB) return riskA - riskB;
|
|
555
|
+
|
|
556
|
+
// Tertiary sort by confidence (higher first)
|
|
557
|
+
return (b.safety?.confidence || 0.5) - (a.safety?.confidence || 0.5);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
const result = missions.slice(0, maxMissions);
|
|
561
|
+
|
|
562
|
+
// Log planning results
|
|
563
|
+
audit.info('plan_missions_complete', {
|
|
564
|
+
inputFindings: findings.length,
|
|
565
|
+
validFindings: validFindings.length,
|
|
566
|
+
deduplicated: deduplicated.length,
|
|
567
|
+
missions: result.length,
|
|
568
|
+
missionTypes: result.map(m => m.type),
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
return result;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Plan a single mission for a specific finding
|
|
576
|
+
* @param {object} finding - The finding to create a mission for
|
|
577
|
+
* @param {object} options - Planning options
|
|
578
|
+
* @returns {object} Mission object
|
|
579
|
+
*/
|
|
580
|
+
function planSingleMission(finding, options = {}) {
|
|
581
|
+
return missionFromFinding(finding, [], options);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Get mission statistics
|
|
586
|
+
* @param {Array} missions - Array of missions
|
|
587
|
+
* @returns {object} Statistics object
|
|
588
|
+
*/
|
|
589
|
+
function getMissionStats(missions) {
|
|
590
|
+
const stats = {
|
|
591
|
+
total: missions.length,
|
|
592
|
+
byType: {},
|
|
593
|
+
byRisk: { low: 0, medium: 0, high: 0, critical: 0 },
|
|
594
|
+
byBlastRadius: { low: 0, medium: 0, high: 0 },
|
|
595
|
+
totalFindings: 0,
|
|
596
|
+
avgConfidence: 0,
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
let totalConfidence = 0;
|
|
600
|
+
|
|
601
|
+
for (const m of missions) {
|
|
602
|
+
// By type
|
|
603
|
+
stats.byType[m.type] = (stats.byType[m.type] || 0) + 1;
|
|
604
|
+
|
|
605
|
+
// By risk
|
|
606
|
+
const risk = m.safety?.riskLevel || 'medium';
|
|
607
|
+
stats.byRisk[risk] = (stats.byRisk[risk] || 0) + 1;
|
|
608
|
+
|
|
609
|
+
// By blast radius
|
|
610
|
+
const blast = m.scope?.blastRadius || 'medium';
|
|
611
|
+
stats.byBlastRadius[blast] = (stats.byBlastRadius[blast] || 0) + 1;
|
|
612
|
+
|
|
613
|
+
// Finding count
|
|
614
|
+
stats.totalFindings += m.objective?.findingCount || 1;
|
|
615
|
+
|
|
616
|
+
// Confidence
|
|
617
|
+
totalConfidence += m.safety?.confidence || 0.5;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
stats.avgConfidence = missions.length > 0
|
|
621
|
+
? Math.round((totalConfidence / missions.length) * 100) / 100
|
|
622
|
+
: 0;
|
|
623
|
+
|
|
624
|
+
return stats;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
module.exports = {
|
|
628
|
+
// Main planning functions
|
|
629
|
+
planMissions,
|
|
630
|
+
planSingleMission,
|
|
631
|
+
getMissionStats,
|
|
632
|
+
|
|
633
|
+
// Grouping functions
|
|
634
|
+
groupRelatedFindings,
|
|
635
|
+
groupWithBlastRadiusLimit,
|
|
636
|
+
|
|
637
|
+
// Utility functions
|
|
638
|
+
scoreFinding,
|
|
639
|
+
generateFingerprint,
|
|
640
|
+
extractFilesFromFindings,
|
|
641
|
+
buildImportGraph,
|
|
642
|
+
findConnectedFileClusters,
|
|
643
|
+
calculateClusterRisk,
|
|
644
|
+
|
|
645
|
+
// Constants
|
|
646
|
+
CATEGORY_TO_MISSION_TYPE,
|
|
647
|
+
MISSION_PRIORITY,
|
|
648
|
+
};
|