@clear-capabilities/agentic-security-scanner 0.174.0 → 0.176.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/bin/agentic-security.js +199 -28
  3. package/dist/2066.index.js +850 -0
  4. package/dist/2199.index.js +1 -1
  5. package/dist/2584.index.js +3332 -0
  6. package/dist/2923.index.js +13 -0
  7. package/dist/2946.index.js +81 -0
  8. package/dist/3196.index.js +27 -0
  9. package/dist/3727.index.js +292 -0
  10. package/dist/4168.index.js +509 -0
  11. package/dist/4281.index.js +993 -0
  12. package/dist/4978bec8fdf5c733dc85.json +283 -0
  13. package/dist/5099.index.js +96 -0
  14. package/dist/5616.index.js +1471 -0
  15. package/dist/5620.index.js +2370 -0
  16. package/dist/5817.index.js +714 -0
  17. package/dist/6333.index.js +98 -0
  18. package/dist/6655.index.js +3221 -0
  19. package/dist/7838.index.js +446 -974
  20. package/dist/818.index.js +4 -3
  21. package/dist/83.index.js +159 -0
  22. package/dist/8551.index.js +82 -0
  23. package/dist/8633.index.js +93 -0
  24. package/dist/8714.index.js +76 -76
  25. package/dist/8825.index.js +84 -0
  26. package/dist/932.index.js +186 -0
  27. package/dist/9560.index.js +358 -19
  28. package/dist/9800.index.js +6 -1
  29. package/dist/agentic-security.mjs +10 -10
  30. package/dist/agentic-security.mjs.sha256 +1 -1
  31. package/dist/df1e8683e7eda7b2b79c.js +29 -0
  32. package/package.json +7 -6
  33. package/src/artifact/CLAUDE.md +4 -0
  34. package/src/artifact/artifact-evidence.js +63 -0
  35. package/src/artifact/cosign.js +61 -0
  36. package/src/artifact/engine-source.js +72 -0
  37. package/src/artifact/oci-layout.js +47 -0
  38. package/src/artifact/registry.js +213 -0
  39. package/src/capabilities/tool-registry.js +2 -0
  40. package/src/language/haskell-security-rules.js +1 -1
  41. package/src/language/nixos-hardening.js +37 -0
  42. package/src/lineage/CLAUDE.md +4 -0
  43. package/src/lineage/identity-token.js +11 -0
  44. package/src/lineage/observation-adapters.js +13 -0
  45. package/src/lineage/runtime-edge-states.js +139 -0
  46. package/src/lineage/runtime-explorer-view.js +82 -0
  47. package/src/lineage/runtime-observation.js +11 -0
  48. package/src/mcp/CLAUDE.md +3 -1
  49. package/src/mcp/proof-tools.js +132 -0
  50. package/src/mcp/server.js +1 -1
  51. package/src/mcp/tools.js +3 -1
  52. package/src/posture/CLAUDE.md +23 -0
  53. package/src/posture/artifact-registry.js +4 -0
  54. package/src/posture/dnr/attack-facts.js +31 -0
  55. package/src/posture/dnr/cli.js +138 -0
  56. package/src/posture/dnr/detection-ir.js +123 -0
  57. package/src/posture/dnr/exposure-window.js +134 -0
  58. package/src/posture/dnr/hunt.js +84 -0
  59. package/src/posture/dnr/log-reader.js +189 -0
  60. package/src/posture/dnr/matchers.js +90 -0
  61. package/src/posture/dnr/outputs.js +262 -0
  62. package/src/posture/dnr/payload-classes.js +120 -0
  63. package/src/posture/dnr/redact.js +25 -0
  64. package/src/posture/dnr/store.js +57 -0
  65. package/src/posture/dnr/validate.js +64 -0
  66. package/src/posture/dnr/view.js +51 -0
  67. package/src/posture/evaluation/lab/arm-ollama.js +88 -0
  68. package/src/posture/evaluation/lab/arms.js +142 -0
  69. package/src/posture/evaluation/lab/cli.js +135 -0
  70. package/src/posture/evaluation/lab/dataset.js +139 -0
  71. package/src/posture/evaluation/lab/materialize.js +44 -0
  72. package/src/posture/evaluation/lab/neutralize.js +144 -0
  73. package/src/posture/evaluation/lab/report.js +176 -0
  74. package/src/posture/evaluation/lab/run.js +225 -0
  75. package/src/posture/evaluation/lab/score.js +135 -0
  76. package/src/posture/evaluation/lab/scoreboard.js +48 -0
  77. package/src/posture/evaluation/lab/stats.js +41 -0
  78. package/src/posture/evaluation/lab/store.js +53 -0
  79. package/src/posture/fleet/cli.js +248 -63
  80. package/src/posture/fleet/discover-edges.js +135 -0
  81. package/src/posture/fleet/enterprise-graph.js +148 -0
  82. package/src/posture/fleet/fleet-graph.js +9 -4
  83. package/src/posture/fleet/fleet-manifest.js +50 -5
  84. package/src/posture/fleet/job-runner.js +153 -0
  85. package/src/posture/fleet/job-store.js +136 -0
  86. package/src/posture/fleet/org-health.js +56 -0
  87. package/src/posture/fleet/scan-cache.js +112 -0
  88. package/src/posture/fleet/scan-child.js +29 -0
  89. package/src/posture/proof-fabric/cli.js +34 -6
  90. package/src/posture/proof-fabric/container.js +57 -0
  91. package/src/posture/proof-fabric/fix-proof.js +2 -1
  92. package/src/posture/proof-fabric/generate-python.js +129 -0
  93. package/src/posture/proof-fabric/generate.js +213 -0
  94. package/src/posture/proof-fabric/reproducer.js +3 -0
  95. package/src/posture/proof-fabric/runner.js +20 -11
  96. package/src/posture/proof-fabric/siblings.js +77 -0
  97. package/src/posture/routing/policy-router.js +103 -0
  98. package/src/posture/rule-compiler/cli.js +64 -6
  99. package/src/posture/rule-compiler/corpus.js +10 -2
  100. package/src/posture/rule-compiler/mutation.js +72 -1
  101. package/src/posture/rule-compiler/promotion.js +21 -5
  102. package/src/posture/rule-compiler/proposal.js +132 -0
  103. package/src/posture/rule-compiler/store.js +16 -0
@@ -1,5 +1,5 @@
1
1
  export const id = 9560;
2
- export const ids = [9560,8218,9390,8752];
2
+ export const ids = [9560,8218,5099,9390,8752];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 99405:
@@ -162,6 +162,8 @@ const TOOL_CAPABILITIES = Object.freeze({
162
162
  portfolio_progress: read('builds a read-only progress view from a portfolio store, ledger and optional inputs, confined to the session root'),
163
163
  apply_fix: mutating('writes verified patches into the project'),
164
164
  verify_fix: mutating('runs the project linter and tests and appends fix metrics'),
165
+ prove_finding: mutating('runs a reproducer in the confined proof environment and writes a proof record'),
166
+ prove_fix: mutating('replays the original exploit against a copy of the patched sources and runs the project tests; writes nothing to the project'),
165
167
  append_scratchpad: mutating('writes under the agent scratchpad'),
166
168
  append_agents_memory: mutating('appends to the continual-learning file'),
167
169
  synthesize_sca_upgrade: external('runs a package manager dry-run, which may reach a registry'),
@@ -2607,6 +2609,160 @@ function makePortfolioTools({ confine, META }) {
2607
2609
  }
2608
2610
 
2609
2611
 
2612
+ /***/ }),
2613
+
2614
+ /***/ 52197:
2615
+ /***/ ((__webpack_module__, __webpack_exports__, __webpack_require__) => {
2616
+
2617
+ __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
2618
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2619
+ /* harmony export */ c: () => (/* binding */ makeProofTools)
2620
+ /* harmony export */ });
2621
+ /* harmony import */ var _posture_proof_fabric_orchestrator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3740);
2622
+ /* harmony import */ var _posture_proof_fabric_fix_proof_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(818);
2623
+ /* harmony import */ var _posture_proof_fabric_cli_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(92066);
2624
+ /* harmony import */ var _posture_proof_fabric_store_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(62199);
2625
+ /* harmony import */ var _posture_proof_fabric_reproducer_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(37055);
2626
+ /* harmony import */ var _posture_proof_fabric_siblings_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25099);
2627
+ /* harmony import */ var _posture_fix_verify_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(27838);
2628
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_posture_fix_verify_js__WEBPACK_IMPORTED_MODULE_6__]);
2629
+ _posture_fix_verify_js__WEBPACK_IMPORTED_MODULE_6__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
2630
+ // proof-tools.js: the MCP surface for execution-backed exploit proof (PRD 1).
2631
+ //
2632
+ // Two tools, both of which RUN CODE in the proof fabric's confined environment, so both are classified `mutating` and both require
2633
+ // `confirm: true`:
2634
+ // prove_finding execute a reproducer (supplied, stored, or generated from the finding) and report the evidence state
2635
+ // prove_fix overlay a patch on a COPY of the sources, replay the original exploit against it, run the static verification,
2636
+ // and search for sibling exposures; the patch is never written to the project
2637
+ //
2638
+ // Guarantees, each with a test:
2639
+ // - nothing runs without `confirm: true`, without a verified (HMAC-checked) last scan, or for a shadow finding;
2640
+ // - a reproducer an agent supplies is validated as untrusted input (closed schema, argv only, bounded files, safe paths) before
2641
+ // it reaches the runner, and it runs under the same sandbox, limits, network policy and 3-of-3 plus independent replay as any other;
2642
+ // - patch paths are confined to the session root and the reserved write paths are refused, though nothing is written;
2643
+ // - the result carries evidence STATE and counts, never the target's output, and is scrubbed before it is returned;
2644
+ // - a model decides nothing: the oracle does.
2645
+ // The factory shape (rather than importing helpers from tools.js) avoids a cycle between this file and the registry.
2646
+
2647
+
2648
+
2649
+
2650
+
2651
+
2652
+
2653
+
2654
+ const MAX_RESPONSE_BYTES = 200_000;
2655
+
2656
+ function makeProofTools({ confine, META, readLastScanVerified, findById, isReservedWritePath, redactString }) {
2657
+ const refuse = (reason, extra = {}) => ({ _meta: META, ok: false, reason, ...extra });
2658
+
2659
+ async function load(args, ctx) {
2660
+ if (args.confirm !== true) return { error: refuse('this tool executes code in the proof environment and requires confirm: true.') };
2661
+ const { scan, status } = readLastScanVerified(ctx.sessionRoot, { allowUnsigned: false });
2662
+ if (!scan) return { error: refuse(`last-scan.json failed integrity check: ${status}. Run a fresh scan.`) };
2663
+ const finding = findById(scan, args.finding_id);
2664
+ if (!finding) return { error: refuse(`Finding not found: ${args.finding_id}`) };
2665
+ if (finding._shadow === true) return { error: refuse('shadow findings cannot be proven') };
2666
+ let reproducer = null; let generated = null;
2667
+ if (args.reproducer) {
2668
+ const errs = (0,_posture_proof_fabric_reproducer_js__WEBPACK_IMPORTED_MODULE_4__/* .validateReproducer */ .mC)(args.reproducer);
2669
+ if (errs.length) return { error: refuse(`the reproducer is not acceptable: ${errs.slice(0, 5).join('; ')}`) };
2670
+ reproducer = args.reproducer;
2671
+ } else {
2672
+ const r = (0,_posture_proof_fabric_cli_js__WEBPACK_IMPORTED_MODULE_2__.resolveReproducer)(ctx.sessionRoot, finding, null);
2673
+ if (!r.reproducer) return { error: refuse(`no reproducer was supplied or stored, and none could be generated: ${r.reason}`) };
2674
+ reproducer = r.reproducer; generated = r.generated;
2675
+ }
2676
+ return { scan, finding, reproducer, generated };
2677
+ }
2678
+
2679
+ const finish = (obj) => {
2680
+ const safe = (0,_posture_proof_fabric_store_js__WEBPACK_IMPORTED_MODULE_3__.scrubDeep)(obj);
2681
+ const text = redactString(JSON.stringify(safe));
2682
+ if (text.length > MAX_RESPONSE_BYTES) return refuse('the result is too large for one response');
2683
+ return { _meta: META, ...JSON.parse(text) };
2684
+ };
2685
+
2686
+ const prove_finding = {
2687
+ name: 'prove_finding',
2688
+ description: 'Execute a reproducer for a finding in the confined proof environment and report its evidence state (CANDIDATE ... EXPLOIT_CONFIRMED). The reproducer is supplied, stored, or generated from the finding; EXPLOIT_CONFIRMED needs 3 of 3 reproductions and an independent replay, decided by a deterministic oracle, never by a model. Runs code: requires confirm: true. Returns state and counts, never the target\'s output.',
2689
+ inputSchema: {
2690
+ type: 'object',
2691
+ additionalProperties: false,
2692
+ properties: {
2693
+ finding_id: { type: 'string', minLength: 1, maxLength: 256 },
2694
+ confirm: { type: 'boolean' },
2695
+ reproducer: { type: 'object' },
2696
+ attempts: { type: 'integer', minimum: 1, maximum: 10 },
2697
+ required: { type: 'integer', minimum: 1, maximum: 10 },
2698
+ require_container: { type: 'boolean' },
2699
+ },
2700
+ required: ['finding_id', 'confirm'],
2701
+ },
2702
+ async handler(args, ctx) {
2703
+ const l = await load(args, ctx);
2704
+ if (l.error) return l.error;
2705
+ const policy = {};
2706
+ if (args.attempts) policy.attempts = args.attempts;
2707
+ if (args.required) policy.required = Math.min(args.required, args.attempts ?? 10);
2708
+ if (args.require_container) policy.requireContainer = true;
2709
+ let result;
2710
+ try { result = await (0,_posture_proof_fabric_orchestrator_js__WEBPACK_IMPORTED_MODULE_0__/* .proveFinding */ .kO)({ finding: l.finding, reproducer: l.reproducer, policy, sourceRoot: ctx.sessionRoot }); } catch (e) { return refuse(`the proof could not run: ${String(e.message).slice(0, 200)}`); }
2711
+ const saved = (0,_posture_proof_fabric_store_js__WEBPACK_IMPORTED_MODULE_3__.saveProof)(ctx.sessionRoot, { ...result, reproducer: l.reproducer, ...(l.generated ? { generatedFrom: l.generated } : {}) });
2712
+ return finish({
2713
+ ok: true, findingId: result.findingId, state: result.state, outcome: result.outcome, oracle: result.oracle, completeness: result.completeness,
2714
+ attempts: result.attempts, independentReplay: result.independentReplay?.status ?? 'not-run', environment: result.environment ? { mode: result.environment.mode, assurance: result.environment.assurance } : null,
2715
+ degradation: result.degradation, durationMs: result.timing?.proofMs ?? null, generated: l.generated, stored: saved.ok,
2716
+ note: 'Not reproduced is not proof of safety.',
2717
+ });
2718
+ },
2719
+ };
2720
+
2721
+ const prove_fix = {
2722
+ name: 'prove_fix',
2723
+ description: 'Check a proposed patch against the original exploit: confirm the exploit before the patch, overlay the patch on a COPY of the sources, replay the exploit, run the static verification, and search for sibling exposures. Reports FIX_VERIFIED only when the exploit is blocked in every replay and nothing was skipped. Nothing is written to the project. Runs code (and the project tests): requires confirm: true.',
2724
+ inputSchema: {
2725
+ type: 'object',
2726
+ additionalProperties: false,
2727
+ properties: {
2728
+ finding_id: { type: 'string', minLength: 1, maxLength: 256 },
2729
+ confirm: { type: 'boolean' },
2730
+ patch: { type: 'object', additionalProperties: { type: 'string', maxLength: 500_000 }, minProperties: 1, maxProperties: 8 },
2731
+ reproducer: { type: 'object' },
2732
+ },
2733
+ required: ['finding_id', 'confirm', 'patch'],
2734
+ },
2735
+ async handler(args, ctx) {
2736
+ const l = await load(args, ctx);
2737
+ if (l.error) return l.error;
2738
+ const files = {};
2739
+ for (const [rel, content] of Object.entries(args.patch)) {
2740
+ let abs;
2741
+ try { abs = confine(ctx.sessionRoot, rel, 'patch key'); } catch (e) { return refuse(`path-escape refused: ${String(e.message).replace(ctx.sessionRoot, '<root>')}`); }
2742
+ if (isReservedWritePath(ctx.sessionRoot, abs)) return refuse(`reserved path refused: ${rel}`);
2743
+ files[rel] = String(content);
2744
+ }
2745
+ let staticVerification = null;
2746
+ try { staticVerification = l.finding.stableId ? await (0,_posture_fix_verify_js__WEBPACK_IMPORTED_MODULE_6__.verifyFix)({ scanRoot: ctx.sessionRoot, originalFindingStableId: l.finding.stableId, files, recordMetrics: false }) : null; } catch { staticVerification = null; }
2747
+ const sib = (0,_posture_proof_fabric_siblings_js__WEBPACK_IMPORTED_MODULE_5__.findSiblings)({ root: ctx.sessionRoot, finding: l.finding, scanFindings: l.scan.findings || [] });
2748
+ let fp;
2749
+ try {
2750
+ fp = await (0,_posture_proof_fabric_fix_proof_js__WEBPACK_IMPORTED_MODULE_1__.verifyFixWithProof)({ finding: l.finding, reproducer: l.reproducer, files, scanRoot: ctx.sessionRoot, staticVerification, siblings: sib.siblings.map((x) => ({ file: x.file, line: x.line, source: x.source })), siblingSearchTruncated: sib.truncated });
2751
+ } catch (e) { return refuse(`the fix proof could not run: ${String(e.message).slice(0, 200)}`); }
2752
+ return finish({
2753
+ ok: true, findingId: fp.findingId, state: fp.state, verified: fp.verified, completeness: fp.completeness, degradedLegs: fp.degradedLegs ?? [], legs: fp.legs,
2754
+ reason: fp.reason ?? null, incompleteStep: fp.incompleteStep ?? null, siblings: sib.siblings.slice(0, 20), siblingSearchTruncated: sib.truncated, report: (0,_posture_proof_fabric_fix_proof_js__WEBPACK_IMPORTED_MODULE_1__.formatFixProof)(fp), generated: l.generated,
2755
+ note: 'The patch was not written. Apply it with apply_fix once it is verified.',
2756
+ });
2757
+ },
2758
+ };
2759
+
2760
+ return { prove_finding, prove_fix };
2761
+ }
2762
+
2763
+ __webpack_async_result__();
2764
+ } catch(e) { __webpack_async_result__(e); } });
2765
+
2610
2766
  /***/ }),
2611
2767
 
2612
2768
  /***/ 27438:
@@ -2674,7 +2830,7 @@ const TOOLS_BY_NAME = Object.fromEntries(_tools_js__WEBPACK_IMPORTED_MODULE_4__/
2674
2830
  function _codeFingerprint() {
2675
2831
  try {
2676
2832
  const here = node_path__WEBPACK_IMPORTED_MODULE_2__.dirname((0,node_url__WEBPACK_IMPORTED_MODULE_3__.fileURLToPath)(import.meta.url));
2677
- const files = ['server.js', 'tools.js', 'dataflow-tools.js', 'invariant-tools.js', 'portfolio-tools.js', 'stdio.js', 'audit.js', 'validate.js', 'redact.js'];
2833
+ const files = ['server.js', 'tools.js', 'dataflow-tools.js', 'invariant-tools.js', 'portfolio-tools.js', 'proof-tools.js', 'stdio.js', 'audit.js', 'validate.js', 'redact.js'];
2678
2834
  const h = node_crypto__WEBPACK_IMPORTED_MODULE_1__.createHash('sha256');
2679
2835
  for (const f of files) {
2680
2836
  try { h.update(f); h.update(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(node_path__WEBPACK_IMPORTED_MODULE_2__.join(here, f))); } catch {}
@@ -2931,7 +3087,7 @@ __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependen
2931
3087
  /* harmony import */ var _posture_integrity_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(71130);
2932
3088
  /* harmony import */ var _posture_state_dir_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(31174);
2933
3089
  /* harmony import */ var _posture_cache_economics_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(58752);
2934
- /* harmony import */ var _redact_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(83468);
3090
+ /* harmony import */ var _redact_js__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(83468);
2935
3091
  /* harmony import */ var _report_index_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(75917);
2936
3092
  /* harmony import */ var _posture_verification_projection_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(51864);
2937
3093
  /* harmony import */ var _fix_verify_patch_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(2046);
@@ -2940,10 +3096,11 @@ __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependen
2940
3096
  /* harmony import */ var _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(20095);
2941
3097
  /* harmony import */ var _invariant_tools_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(82407);
2942
3098
  /* harmony import */ var _portfolio_tools_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(99027);
2943
- /* harmony import */ var _posture_agents_memory_js__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(79907);
2944
- /* harmony import */ var _posture_cve_lookup_js__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(71364);
2945
- var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_fix_apply_fix_service_js__WEBPACK_IMPORTED_MODULE_5__, _report_index_js__WEBPACK_IMPORTED_MODULE_12__, _fix_verify_patch_js__WEBPACK_IMPORTED_MODULE_14__]);
2946
- ([_fix_apply_fix_service_js__WEBPACK_IMPORTED_MODULE_5__, _report_index_js__WEBPACK_IMPORTED_MODULE_12__, _fix_verify_patch_js__WEBPACK_IMPORTED_MODULE_14__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
3099
+ /* harmony import */ var _proof_tools_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(52197);
3100
+ /* harmony import */ var _posture_agents_memory_js__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(79907);
3101
+ /* harmony import */ var _posture_cve_lookup_js__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(71364);
3102
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_fix_apply_fix_service_js__WEBPACK_IMPORTED_MODULE_5__, _report_index_js__WEBPACK_IMPORTED_MODULE_12__, _fix_verify_patch_js__WEBPACK_IMPORTED_MODULE_14__, _proof_tools_js__WEBPACK_IMPORTED_MODULE_20__]);
3103
+ ([_fix_apply_fix_service_js__WEBPACK_IMPORTED_MODULE_5__, _report_index_js__WEBPACK_IMPORTED_MODULE_12__, _fix_verify_patch_js__WEBPACK_IMPORTED_MODULE_14__, _proof_tools_js__WEBPACK_IMPORTED_MODULE_20__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
2947
3104
  // MCP tool implementations — PRD Feature 2, hardened against the OWASP MCP
2948
3105
  // Top 10 (see ./redact.js, ./audit.js, ./server.js for sibling controls).
2949
3106
  //
@@ -2984,6 +3141,7 @@ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_fix
2984
3141
 
2985
3142
 
2986
3143
 
3144
+
2987
3145
  // Lazy-loaded: these transitively pull in npm packages (@babel/core and
2988
3146
  // friends) that aren't available in the plugin-cache install path
2989
3147
  // (no node_modules). Deferring keeps the MCP server bootable everywhere;
@@ -3390,7 +3548,7 @@ const scan_diff = {
3390
3548
  // scanning), left as-is rather than silently claimed fixed here.
3391
3549
  const findings = (0,_report_index_js__WEBPACK_IMPORTED_MODULE_12__.normalizeFindings)(result.scan)
3392
3550
  .filter(f => wantSet.has(String(f.file || '').replace(/\\/g, '/')) && (sevRank[f.severity] ?? 0) >= min)
3393
- .map(f => (0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactFinding */ .lE)({
3551
+ .map(f => (0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactFinding */ .lE)({
3394
3552
  id: f.id, severity: f.severity, file: f.file, line: f.line,
3395
3553
  title: f.vuln, cwe: f.cwe,
3396
3554
  description: f.description, remediation: f.remediation,
@@ -3453,7 +3611,7 @@ const query_taint = {
3453
3611
  const hay = [f.description, f.title, f.vuln, f.snippet, JSON.stringify(f.trace || '')].join(' ').toLowerCase();
3454
3612
  return hay.includes(srcL) && hay.includes(sinkL);
3455
3613
  });
3456
- const page = all.slice(off, off + lim).map(f => (0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactFinding */ .lE)({
3614
+ const page = all.slice(off, off + lim).map(f => (0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactFinding */ .lE)({
3457
3615
  id: f.id, severity: f.severity, file: f.file, line: f.line,
3458
3616
  title: f.title || f.vuln, description: f.description,
3459
3617
  trace: f.trace || null,
@@ -3491,7 +3649,7 @@ const explain_finding = {
3491
3649
  if (!scan) throw new Error(`No usable scan state (${status}).`);
3492
3650
  const f = _findById(scan, finding_id);
3493
3651
  if (!f) throw new Error(`Finding not found: ${finding_id}`);
3494
- const redacted = (0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactFinding */ .lE)({
3652
+ const redacted = (0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactFinding */ .lE)({
3495
3653
  id: f.id, severity: f.severity, file: f.file, line: f.line,
3496
3654
  title: f.title || f.vuln, cwe: f.cwe,
3497
3655
  description: f.description, remediation: f.remediation,
@@ -3636,7 +3794,7 @@ const _scrubRoot = (sessionRoot, text) => {
3636
3794
  const roots = new Set([node_path__WEBPACK_IMPORTED_MODULE_2__.resolve(sessionRoot)]);
3637
3795
  try { roots.add(node_fs__WEBPACK_IMPORTED_MODULE_0__.realpathSync(node_path__WEBPACK_IMPORTED_MODULE_2__.resolve(sessionRoot))); } catch { /* root vanished: the plain path is still scrubbed */ }
3638
3796
  for (const r of roots) out = out.split(r).join('<root>');
3639
- return (0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactString */ .rd)(out);
3797
+ return (0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactString */ .rd)(out);
3640
3798
  };
3641
3799
  const _gateSummary = (g) => (g ? {
3642
3800
  path: g.path ? g.path.ok : undefined, syntax: g.syntax ? g.syntax.ok : undefined,
@@ -4061,7 +4219,7 @@ const verify_fix = {
4061
4219
  _meta: META,
4062
4220
  ok: r.ok,
4063
4221
  rescan: { ok: r.rescan.ok, reason: r.rescan.reason, introduced: r.rescan.introduced || [] },
4064
- lint: { runner: r.lint.runner, ok: r.lint.ok, skipped: r.lint.skipped || false, output: (0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactString */ .rd)(r.lint.output || '').slice(0, 1500) },
4222
+ lint: { runner: r.lint.runner, ok: r.lint.ok, skipped: r.lint.skipped || false, output: (0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactString */ .rd)(r.lint.output || '').slice(0, 1500) },
4065
4223
  // verifyFix computes five legs, not two — tests/honesty/poc were
4066
4224
  // being silently dropped here, leaving an agent with no structured
4067
4225
  // way to see WHY verification failed when the failure was in one
@@ -4072,7 +4230,7 @@ const verify_fix = {
4072
4230
  // it can echo proof-harness detail derived from scanned source.
4073
4231
  tests: r.tests,
4074
4232
  honesty: r.honesty,
4075
- poc: r.poc ? { ...r.poc, reason: r.poc.reason ? (0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactString */ .rd)(r.poc.reason) : r.poc.reason } : r.poc,
4233
+ poc: r.poc ? { ...r.poc, reason: r.poc.reason ? (0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactString */ .rd)(r.poc.reason) : r.poc.reason } : r.poc,
4076
4234
  summary: r.summary,
4077
4235
  // X-201: the one version-1 verification record (additive). It states what was actually established, e.g.
4078
4236
  // `not-run` when no exploit oracle executed against the patch, never a bare pass/fail.
@@ -4421,7 +4579,7 @@ const append_agents_memory = {
4421
4579
  required: ['agent', 'body'],
4422
4580
  },
4423
4581
  async handler({ agent, body }, ctx) {
4424
- const r = (0,_posture_agents_memory_js__WEBPACK_IMPORTED_MODULE_21__/* .appendAgentsMemory */ .eu)(ctx.sessionRoot, { agent, body });
4582
+ const r = (0,_posture_agents_memory_js__WEBPACK_IMPORTED_MODULE_22__/* .appendAgentsMemory */ .eu)(ctx.sessionRoot, { agent, body });
4425
4583
  return { _meta: META, ...r };
4426
4584
  },
4427
4585
  };
@@ -4437,7 +4595,7 @@ const read_agents_memory = {
4437
4595
  },
4438
4596
  },
4439
4597
  async handler({ full }, ctx) {
4440
- const body = (0,_posture_agents_memory_js__WEBPACK_IMPORTED_MODULE_21__/* .readAgentsMemory */ .ox)(ctx.sessionRoot);
4598
+ const body = (0,_posture_agents_memory_js__WEBPACK_IMPORTED_MODULE_22__/* .readAgentsMemory */ .ox)(ctx.sessionRoot);
4441
4599
  if (!body) return { _meta: META, present: false };
4442
4600
  if (full) return { _meta: META, present: true, length: body.length, content: body };
4443
4601
  // Tail-only — same logic as summarizeForSession but inlined to avoid a
@@ -4481,7 +4639,7 @@ const query_triage_memory = {
4481
4639
  // they landed in, rather than hardcoding a field allowlist that could
4482
4640
  // miss one.
4483
4641
  let results;
4484
- try { results = JSON.parse((0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactString */ .rd)(JSON.stringify(raw))); }
4642
+ try { results = JSON.parse((0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactString */ .rd)(JSON.stringify(raw))); }
4485
4643
  catch { results = raw; }
4486
4644
  return {
4487
4645
  _meta: META,
@@ -4517,7 +4675,7 @@ const query_findings_memory = {
4517
4675
  // whole-structure redactString round-trip is applied rather than a
4518
4676
  // per-field allowlist that could miss one of the four shapes.
4519
4677
  let body;
4520
- try { body = JSON.parse((0,_redact_js__WEBPACK_IMPORTED_MODULE_20__/* .redactString */ .rd)(JSON.stringify(raw))); }
4678
+ try { body = JSON.parse((0,_redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactString */ .rd)(JSON.stringify(raw))); }
4521
4679
  catch { body = raw; }
4522
4680
  return { _meta: META, ...body };
4523
4681
  },
@@ -4539,7 +4697,7 @@ const lookup_cve = {
4539
4697
  required: ['cve'],
4540
4698
  },
4541
4699
  async handler({ cve }, _ctx) {
4542
- const r = (0,_posture_cve_lookup_js__WEBPACK_IMPORTED_MODULE_22__/* .lookupCve */ .x)(cve);
4700
+ const r = (0,_posture_cve_lookup_js__WEBPACK_IMPORTED_MODULE_23__/* .lookupCve */ .x)(cve);
4543
4701
  return { _meta: META, ...r };
4544
4702
  },
4545
4703
  };
@@ -4647,9 +4805,10 @@ const apply_sca_upgrade = {
4647
4805
  // X-407: read-only scenario export; the factory takes this file's confinement so the two modules do not import each other.
4648
4806
  const { invariant_scenario_export } = (0,_invariant_tools_js__WEBPACK_IMPORTED_MODULE_18__/* .makeInvariantTools */ ._)({ confine: _confine, META });
4649
4807
  // X-707: read-only portfolio progress view, same factory shape.
4808
+ const { prove_finding, prove_fix } = (0,_proof_tools_js__WEBPACK_IMPORTED_MODULE_20__/* .makeProofTools */ .c)({ confine: _confine, META, readLastScanVerified: _readLastScanVerified, findById: _findById, isReservedWritePath: _isReservedWritePath, redactString: _redact_js__WEBPACK_IMPORTED_MODULE_21__/* .redactString */ .rd });
4650
4809
  const { portfolio_progress } = (0,_portfolio_tools_js__WEBPACK_IMPORTED_MODULE_19__/* .makePortfolioTools */ ._)({ confine: _confine, META });
4651
4810
 
4652
- const ALL_TOOLS = [scan_diff, query_taint, explain_finding, apply_fix, verify_fix, synthesize_fix, find_rule_module, append_scratchpad, read_scratchpad, append_agents_memory, read_agents_memory, lookup_cve, synthesize_sca_upgrade, apply_sca_upgrade, query_triage_memory, query_findings_memory, query_cache_telemetry, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_graph */ .HX, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_node */ .HI, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_edge */ .gC, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_flow */ .ri, invariant_scenario_export, portfolio_progress];
4811
+ const ALL_TOOLS = [scan_diff, query_taint, explain_finding, apply_fix, verify_fix, synthesize_fix, find_rule_module, append_scratchpad, read_scratchpad, append_agents_memory, read_agents_memory, lookup_cve, synthesize_sca_upgrade, apply_sca_upgrade, query_triage_memory, query_findings_memory, query_cache_telemetry, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_graph */ .HX, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_node */ .HI, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_edge */ .gC, _dataflow_tools_js__WEBPACK_IMPORTED_MODULE_17__/* .dataflow_get_flow */ .ri, invariant_scenario_export, portfolio_progress, prove_finding, prove_fix];
4653
4812
 
4654
4813
  __webpack_async_result__();
4655
4814
  } catch(e) { __webpack_async_result__(e); } });
@@ -5383,6 +5542,186 @@ function synthesizeDeterministicPatch(finding, fileContent) {
5383
5542
  }
5384
5543
 
5385
5544
 
5545
+ /***/ }),
5546
+
5547
+ /***/ 818:
5548
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
5549
+
5550
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
5551
+ /* harmony export */ formatFixProof: () => (/* binding */ formatFixProof),
5552
+ /* harmony export */ verifyFixWithProof: () => (/* binding */ verifyFixWithProof)
5553
+ /* harmony export */ });
5554
+ /* harmony import */ var _states_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12090);
5555
+ /* harmony import */ var _orchestrator_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3740);
5556
+ /* harmony import */ var _runner_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(23081);
5557
+ /* harmony import */ var _reproducer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37055);
5558
+ // Verified remediation, extended with exploit replay. This EXTENDS the fix-verify vocabulary (`verifiedFull`,
5559
+ // `degradedLegs`); it does not define a competing meaning of "verified".
5560
+ //
5561
+ // 1. pre-patch: the original exploit must be EXPLOIT_CONFIRMED (3/3 + independent replay) on the unpatched code;
5562
+ // 2. the candidate patch is overlaid on the imported sources and the SAME exploit is replayed;
5563
+ // 3. the patched replay must COMPLETE in every attempt and the oracle must not fire in any: BLOCKED.
5564
+ // An attempt that did not complete (timeout, build failure, no environment) is inconclusive, never "blocked";
5565
+ // 4. static legs (re-scan, lint, tests, honesty) come from `verifyFix`, passed in so they are not re-implemented;
5566
+ // 5. FIX_VERIFIED only when 1-4 hold and the static verification had no degraded leg.
5567
+
5568
+
5569
+
5570
+
5571
+
5572
+ async function verifyFixWithProof({ finding, reproducer, files, scanRoot, revision = null, policy = {}, staticVerification = null, siblings = null, siblingSearchTruncated = [], signal, deps = {} } = {}) {
5573
+ const t0 = Date.now();
5574
+ const attemptFn = deps.attemptFn ?? _runner_js__WEBPACK_IMPORTED_MODULE_2__/* .runAttempt */ .Tm;
5575
+ const patchHash = (0,_reproducer_js__WEBPACK_IMPORTED_MODULE_3__/* .sha256 */ .sc)((0,_reproducer_js__WEBPACK_IMPORTED_MODULE_3__/* .canonicalize */ .dw)(files || {}));
5576
+ const legs = { prePatch: null, postPatch: null, regression: staticVerification ? { ok: !!staticVerification.ok, verifiedFull: !!staticVerification.verifiedFull } : { status: 'not-run' }, rescan: staticVerification?.rescan ?? { status: 'not-run' } };
5577
+ const out = (extra) => ({ schema: 'agentic-security/fix-proof', version: 1, findingId: finding?.stableId ?? finding?.id ?? null, patchHash, reproducerDigest: (0,_reproducer_js__WEBPACK_IMPORTED_MODULE_3__/* .reproducerDigest */ .we)(reproducer), legs, durationMs: Date.now() - t0, ...extra });
5578
+
5579
+ const pre = await (0,_orchestrator_js__WEBPACK_IMPORTED_MODULE_1__/* .proveFinding */ .kO)({ finding, revision, reproducer, policy, signal, deps, sourceRoot: scanRoot });
5580
+ legs.prePatch = { state: pre.state, outcome: pre.outcome, completeness: pre.completeness };
5581
+ if (pre.state !== 'EXPLOIT_CONFIRMED') {
5582
+ return out({ state: pre.state, verified: false, completeness: 'INCOMPLETE', incompleteStep: 'pre-patch-exploit', reason: `the original exploit was not confirmed before the patch (${pre.outcome}); a fix cannot be proven against an exploit that does not reproduce` });
5583
+ }
5584
+
5585
+ const attempts = Math.max(1, Math.min(10, policy.attempts ?? 3));
5586
+ const results = [];
5587
+ for (let i = 0; i < attempts; i++) {
5588
+ if (signal?.aborted) break;
5589
+ results.push(await attemptFn(structuredClone(reproducer), { limits: { timeoutMs: policy.timeoutMs }, signal, sourceRoot: scanRoot, overlay: files, requireContainer: policy.requireContainer, force: policy.force }));
5590
+ }
5591
+ const completed = results.filter((r) => r.status === 'completed' && !r.oracle?.inconclusive);
5592
+ const fired = completed.filter((r) => r.oracle?.fired).length;
5593
+ legs.postPatch = { attempts: results.length, completed: completed.length, exploitSucceeded: fired, statuses: results.map((r) => r.status) };
5594
+
5595
+ if (fired > 0) return out({ state: 'EXPLOIT_CONFIRMED', verified: false, completeness: 'FULL', incompleteStep: 'post-patch-exploit', reason: 'the exploit still succeeds against the patched code' });
5596
+ if (completed.length < results.length || results.length === 0) {
5597
+ return out({ state: 'EXPLOIT_CONFIRMED', verified: false, completeness: 'INCOMPLETE', incompleteStep: 'post-patch-replay', reason: 'the patched replay did not complete in every attempt, so the patch is not shown to block the exploit' });
5598
+ }
5599
+ let state = (0,_states_js__WEBPACK_IMPORTED_MODULE_0__/* .advance */ .np)('EXPLOIT_CONFIRMED', 'FIX_REPLAY_BLOCKED').state;
5600
+
5601
+ const degraded = [];
5602
+ if (!staticVerification) degraded.push('static-verification-not-run');
5603
+ else {
5604
+ if (!staticVerification.ok) return out({ state, verified: false, completeness: 'FULL', incompleteStep: 'static-verification', reason: `exploit blocked, but static verification failed: ${staticVerification.rescan?.reason || 'a leg failed'}` });
5605
+ for (const d of staticVerification.degradedLegs || []) degraded.push(d);
5606
+ }
5607
+ const lowAssurance = pre.environment?.assurance === 'lower';
5608
+ if (lowAssurance) degraded.push('lower-assurance-local-confinement');
5609
+ const siblingCount = Array.isArray(siblings) ? siblings.length : null;
5610
+ if (siblingCount === null) degraded.push('sibling-search-not-run');
5611
+ else if (siblingCount > 0) degraded.push(`sibling-exposures:${siblingCount}`);
5612
+ if (siblingCount !== null && siblingSearchTruncated?.length) degraded.push('sibling-search-incomplete');
5613
+
5614
+ const full = degraded.length === 0;
5615
+ // Same split as fix-verify: `ok` (nothing that ran failed) earns FIX_VERIFIED; `completeness` says whether anything was skipped.
5616
+ if (staticVerification && staticVerification.ok) state = (0,_states_js__WEBPACK_IMPORTED_MODULE_0__/* .advance */ .np)(state, 'FIX_VERIFIED').state;
5617
+ return out({ state, verified: state === 'FIX_VERIFIED', completeness: full ? 'FULL' : 'DEGRADED', degradedLegs: degraded, siblings: siblings ?? null });
5618
+ }
5619
+
5620
+ function formatFixProof(r) {
5621
+ const L = r.legs || {};
5622
+ return [
5623
+ `Pre-patch exploit: ${L.prePatch?.state === 'EXPLOIT_CONFIRMED' ? 'PASS' : 'NOT CONFIRMED'}`,
5624
+ `Post-patch exploit: ${!L.postPatch ? 'NOT RUN' : L.postPatch.exploitSucceeded > 0 ? 'STILL SUCCEEDS' : L.postPatch.completed === L.postPatch.attempts ? 'BLOCKED' : 'INCONCLUSIVE'}`,
5625
+ `Regression tests: ${L.regression?.status === 'not-run' ? 'not run' : L.regression?.verifiedFull ? 'PASS' : L.regression?.ok ? 'PASS (degraded)' : 'FAIL'}`,
5626
+ `Security rescan: ${L.rescan?.ok === true ? 'PASS' : L.rescan?.status === 'not-run' ? 'not run' : 'FAIL'}`,
5627
+ `Completeness: ${r.completeness}${r.degradedLegs?.length ? ` (${r.degradedLegs.join('; ')})` : ''}`,
5628
+ '',
5629
+ `Evidence: ${r.state}${r.verified ? '' : ` (not verified: ${r.reason || r.incompleteStep || 'degraded'})`}`,
5630
+ ].join('\n');
5631
+ }
5632
+
5633
+
5634
+ /***/ }),
5635
+
5636
+ /***/ 25099:
5637
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
5638
+
5639
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
5640
+ /* harmony export */ findSiblings: () => (/* binding */ findSiblings)
5641
+ /* harmony export */ });
5642
+ /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73024);
5643
+ /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(76760);
5644
+ /* harmony import */ var _rule_compiler_proposal_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(47838);
5645
+ /* harmony import */ var _state_dir_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(31174);
5646
+ // Sibling-exposure search for a verified fix (PRD 1, requirement 6, step 8: "look for equivalent sibling exposures").
5647
+ //
5648
+ // A fix that closes one instance of a flaw says nothing about the same shape written somewhere else. This finds candidates two ways,
5649
+ // and reports where each came from:
5650
+ // * `scan` other findings from the last scan with the same weakness or title (what the engine already believes);
5651
+ // * `structural` other places in the repository whose line has the SAME SHAPE as the vulnerable line: the vulnerable line is
5652
+ // generalized (call names kept, strings and other identifiers become classes) by the rule compiler's own
5653
+ // generalizer and searched across the source files. This finds copies the engine did not flag.
5654
+ // The result is a list of CANDIDATES for a person to look at, not a verdict that each one is exploitable. Bounded in files, bytes,
5655
+ // matches and time; a bound that is hit is reported (`truncated`), because "no siblings found" must never mean "stopped looking".
5656
+
5657
+
5658
+
5659
+
5660
+
5661
+ const SOURCE_EXT = /\.(?:js|mjs|cjs|jsx|ts|tsx|py|rb|php|java|kt|go|rs|cs|c|cc|cpp|h|hpp|sh|swift|scala)$/i;
5662
+ const SKIP = new Set(['.git', 'node_modules', 'dist', 'build', 'vendor', _state_dir_js__WEBPACK_IMPORTED_MODULE_3__/* .STATE_DIR_NAME */ .Ky, 'coverage', '__pycache__']);
5663
+ const SIBLING_LIMITS = Object.freeze({ maxFiles: 5000, maxFileBytes: 512 * 1024, maxMatches: 100, budgetMs: 8000 });
5664
+
5665
+ const sameSpot = (a, b) => node_path__WEBPACK_IMPORTED_MODULE_1__.resolve(a) === node_path__WEBPACK_IMPORTED_MODULE_1__.resolve(b);
5666
+
5667
+ /**
5668
+ * @param {object} o
5669
+ * @param {string} o.root repository root
5670
+ * @param {{file: string, line: number, id?: string, cwe?: string, vuln?: string}} o.finding
5671
+ * @param {object[]} [o.scanFindings] findings from the last scan
5672
+ * @returns {{siblings: object[], truncated: string[], pattern: string|null}}
5673
+ */
5674
+ function findSiblings({ root, finding, scanFindings = [], limits = SIBLING_LIMITS, now = Date.now }) {
5675
+ const out = []; const seen = new Set(); const truncated = [];
5676
+ const add = (s) => { const k = `${s.file}:${s.line ?? ''}`; if (!seen.has(k)) { seen.add(k); out.push(s); } };
5677
+ for (const x of scanFindings) {
5678
+ if (!x || x.id === finding.id || x.stableId === finding.stableId && finding.stableId) continue;
5679
+ if (x.file === finding.file && x.line === finding.line) continue;
5680
+ if ((finding.cwe && x.cwe === finding.cwe) || (finding.vuln && x.vuln === finding.vuln)) add({ source: 'scan', file: x.file, line: x.line ?? null, id: x.id ?? null });
5681
+ }
5682
+ let pattern = null;
5683
+ let line = '';
5684
+ try {
5685
+ const abs = node_path__WEBPACK_IMPORTED_MODULE_1__.resolve(root, finding.file);
5686
+ line = (node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(abs, 'utf8').split('\n')[finding.line - 1] ?? '').trim();
5687
+ } catch { /* the flagged file is gone; only the scan-based siblings are available */ }
5688
+ if (line.length >= 8) {
5689
+ pattern = (0,_rule_compiler_proposal_js__WEBPACK_IMPORTED_MODULE_2__/* .generalizeLine */ .Ry)(line);
5690
+ let rx = null;
5691
+ try { rx = new RegExp(pattern); } catch { rx = null; }
5692
+ if (rx) {
5693
+ const deadline = now() + limits.budgetMs; let files = 0; let matches = 0;
5694
+ const base = node_fs__WEBPACK_IMPORTED_MODULE_0__.realpathSync(root);
5695
+ const walk = (dir) => {
5696
+ if (truncated.length) return;
5697
+ let ents = [];
5698
+ try { ents = node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name)); } catch { return; }
5699
+ for (const e of ents) {
5700
+ if (truncated.length) return;
5701
+ if (SKIP.has(e.name) || e.isSymbolicLink()) continue;
5702
+ const p = node_path__WEBPACK_IMPORTED_MODULE_1__.join(dir, e.name);
5703
+ if (e.isDirectory()) { walk(p); continue; }
5704
+ if (!e.isFile() || !SOURCE_EXT.test(e.name)) continue;
5705
+ if (++files > limits.maxFiles) { truncated.push(`file limit (${limits.maxFiles})`); return; }
5706
+ if (now() > deadline) { truncated.push('time budget'); return; }
5707
+ let text; try { const st = node_fs__WEBPACK_IMPORTED_MODULE_0__.statSync(p); if (st.size > limits.maxFileBytes) continue; text = node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(p, 'utf8'); } catch { continue; }
5708
+ const lines = text.split('\n');
5709
+ for (let i = 0; i < lines.length; i++) {
5710
+ if (lines[i].length > 2000 || !rx.test(lines[i].trim())) continue;
5711
+ const rel = node_path__WEBPACK_IMPORTED_MODULE_1__.relative(base, node_fs__WEBPACK_IMPORTED_MODULE_0__.realpathSync(p));
5712
+ if (sameSpot(node_path__WEBPACK_IMPORTED_MODULE_1__.resolve(base, rel), node_path__WEBPACK_IMPORTED_MODULE_1__.resolve(base, finding.file)) && i + 1 === finding.line) continue;
5713
+ add({ source: 'structural', file: rel, line: i + 1, text: lines[i].trim().slice(0, 160) });
5714
+ if (++matches >= limits.maxMatches) { truncated.push(`match limit (${limits.maxMatches})`); return; }
5715
+ }
5716
+ }
5717
+ };
5718
+ walk(base);
5719
+ }
5720
+ }
5721
+ return { siblings: out, truncated, pattern };
5722
+ }
5723
+
5724
+
5386
5725
  /***/ }),
5387
5726
 
5388
5727
  /***/ 78218:
@@ -83,7 +83,7 @@ async function cmdProve(args, root, { json = false } = {}) {
83
83
  const onSig = () => ac.abort();
84
84
  process.once('SIGINT', onSig);
85
85
  let result;
86
- try { result = await (0,_orchestrator_js__WEBPACK_IMPORTED_MODULE_4__/* .proveFinding */ .kO)({ finding, reproducer: loaded.reproducer, revision: args.flags.revision ?? null, policy, signal: ac.signal }); } finally { process.off('SIGINT', onSig); }
86
+ try { result = await (0,_orchestrator_js__WEBPACK_IMPORTED_MODULE_4__/* .proveFinding */ .kO)({ finding, reproducer: loaded.reproducer, revision: args.flags.revision ?? null, policy, signal: ac.signal, sourceRoot: root }); } finally { process.off('SIGINT', onSig); }
87
87
  const saved = (0,_store_js__WEBPACK_IMPORTED_MODULE_5__.saveProof)(root, { ...result, reproducer: loaded.reproducer });
88
88
  // Printed output gets the same secret-scrubbing pass as what is persisted (defense in depth: a free-text reason/note
89
89
  // field that captured something from stdout/stderr should never reach a terminal unredacted either).
@@ -105,6 +105,11 @@ async function cmdProof(args, root) {
105
105
  const good = all.find((p) => p.record && !p.tampered);
106
106
  if (!good) { console.error('No intact proof record.'); return 1; }
107
107
  if (args.flags.json) console.log(JSON.stringify(good.record, null, 2)); else console.log(formatResult(good.record));
108
+ // the detection generated from this finding's proof (detection-and-response loop), when there is one
109
+ try {
110
+ const det = (await __webpack_require__.e(/* import() */ 8551).then(__webpack_require__.bind(__webpack_require__, 58551))).latestRecord(root, id, 'detection');
111
+ if (det && !args.flags.json) console.log(`Detection: ${det.record.ir?.id ?? 'unknown'} (${det.record.validation?.status ?? 'not validated'}${det.record.enabled ? ', enabled' : ''})`);
112
+ } catch { /* the proof output does not depend on it */ }
108
113
  void latest;
109
114
  return 0;
110
115
  }