@clear-capabilities/agentic-security-scanner 0.175.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.
- package/CHANGELOG.md +16 -0
- package/bin/agentic-security.js +199 -28
- package/dist/2066.index.js +850 -0
- package/dist/2199.index.js +1 -1
- package/dist/2584.index.js +3332 -0
- package/dist/2923.index.js +13 -0
- package/dist/2946.index.js +81 -0
- package/dist/3196.index.js +27 -0
- package/dist/3727.index.js +292 -0
- package/dist/4168.index.js +509 -0
- package/dist/4281.index.js +993 -0
- package/dist/4978bec8fdf5c733dc85.json +283 -0
- package/dist/5099.index.js +96 -0
- package/dist/5616.index.js +1471 -0
- package/dist/5620.index.js +2370 -0
- package/dist/5817.index.js +714 -0
- package/dist/6333.index.js +98 -0
- package/dist/6655.index.js +3221 -0
- package/dist/7838.index.js +446 -974
- package/dist/818.index.js +4 -3
- package/dist/83.index.js +159 -0
- package/dist/8551.index.js +82 -0
- package/dist/8633.index.js +93 -0
- package/dist/8714.index.js +76 -76
- package/dist/8825.index.js +84 -0
- package/dist/932.index.js +186 -0
- package/dist/9560.index.js +358 -19
- package/dist/9800.index.js +6 -1
- package/dist/agentic-security.mjs +10 -10
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/dist/df1e8683e7eda7b2b79c.js +29 -0
- package/package.json +5 -4
- package/src/artifact/CLAUDE.md +4 -0
- package/src/artifact/artifact-evidence.js +63 -0
- package/src/artifact/cosign.js +61 -0
- package/src/artifact/engine-source.js +72 -0
- package/src/artifact/oci-layout.js +47 -0
- package/src/artifact/registry.js +213 -0
- package/src/capabilities/tool-registry.js +2 -0
- package/src/lineage/CLAUDE.md +4 -0
- package/src/lineage/identity-token.js +11 -0
- package/src/lineage/observation-adapters.js +13 -0
- package/src/lineage/runtime-edge-states.js +139 -0
- package/src/lineage/runtime-explorer-view.js +82 -0
- package/src/lineage/runtime-observation.js +11 -0
- package/src/mcp/CLAUDE.md +3 -1
- package/src/mcp/proof-tools.js +132 -0
- package/src/mcp/server.js +1 -1
- package/src/mcp/tools.js +3 -1
- package/src/posture/CLAUDE.md +23 -0
- package/src/posture/artifact-registry.js +4 -0
- package/src/posture/dnr/attack-facts.js +31 -0
- package/src/posture/dnr/cli.js +138 -0
- package/src/posture/dnr/detection-ir.js +123 -0
- package/src/posture/dnr/exposure-window.js +134 -0
- package/src/posture/dnr/hunt.js +84 -0
- package/src/posture/dnr/log-reader.js +189 -0
- package/src/posture/dnr/matchers.js +90 -0
- package/src/posture/dnr/outputs.js +262 -0
- package/src/posture/dnr/payload-classes.js +120 -0
- package/src/posture/dnr/redact.js +25 -0
- package/src/posture/dnr/store.js +57 -0
- package/src/posture/dnr/validate.js +64 -0
- package/src/posture/dnr/view.js +51 -0
- package/src/posture/evaluation/lab/arm-ollama.js +88 -0
- package/src/posture/evaluation/lab/arms.js +142 -0
- package/src/posture/evaluation/lab/cli.js +135 -0
- package/src/posture/evaluation/lab/dataset.js +139 -0
- package/src/posture/evaluation/lab/materialize.js +44 -0
- package/src/posture/evaluation/lab/neutralize.js +144 -0
- package/src/posture/evaluation/lab/report.js +176 -0
- package/src/posture/evaluation/lab/run.js +225 -0
- package/src/posture/evaluation/lab/score.js +135 -0
- package/src/posture/evaluation/lab/scoreboard.js +48 -0
- package/src/posture/evaluation/lab/stats.js +41 -0
- package/src/posture/evaluation/lab/store.js +53 -0
- package/src/posture/fleet/cli.js +248 -63
- package/src/posture/fleet/discover-edges.js +135 -0
- package/src/posture/fleet/enterprise-graph.js +148 -0
- package/src/posture/fleet/fleet-graph.js +9 -4
- package/src/posture/fleet/fleet-manifest.js +50 -5
- package/src/posture/fleet/job-runner.js +153 -0
- package/src/posture/fleet/job-store.js +136 -0
- package/src/posture/fleet/org-health.js +56 -0
- package/src/posture/fleet/scan-cache.js +112 -0
- package/src/posture/fleet/scan-child.js +29 -0
- package/src/posture/proof-fabric/cli.js +34 -6
- package/src/posture/proof-fabric/container.js +57 -0
- package/src/posture/proof-fabric/fix-proof.js +2 -1
- package/src/posture/proof-fabric/generate-python.js +129 -0
- package/src/posture/proof-fabric/generate.js +213 -0
- package/src/posture/proof-fabric/reproducer.js +3 -0
- package/src/posture/proof-fabric/runner.js +20 -11
- package/src/posture/proof-fabric/siblings.js +77 -0
- package/src/posture/routing/policy-router.js +103 -0
- package/src/posture/rule-compiler/cli.js +64 -6
- package/src/posture/rule-compiler/corpus.js +10 -2
- package/src/posture/rule-compiler/mutation.js +72 -1
- package/src/posture/rule-compiler/promotion.js +21 -5
- package/src/posture/rule-compiler/proposal.js +132 -0
- package/src/posture/rule-compiler/store.js +16 -0
package/dist/9560.index.js
CHANGED
|
@@ -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
|
|
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
|
|
2944
|
-
/* harmony import */ var
|
|
2945
|
-
var
|
|
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__]
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
package/dist/9800.index.js
CHANGED
|
@@ -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
|
}
|