@clear-capabilities/agentic-security-scanner 0.166.0 → 0.168.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 +91 -0
- package/bin/agentic-security.js +40 -4
- package/dist/2199.index.js +348 -0
- package/dist/3736.index.js +2 -1
- package/dist/3740.index.js +722 -0
- package/dist/4113.index.js +1 -1
- package/dist/4142.index.js +929 -0
- package/dist/5738.index.js +240 -0
- package/dist/6932.index.js +1190 -0
- package/dist/7838.index.js +1 -1
- package/dist/808.index.js +1330 -0
- package/dist/818.index.js +93 -0
- package/dist/9800.index.js +245 -0
- package/dist/9999.index.js +2 -2
- package/dist/agentic-security.mjs +2 -2
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +2 -2
- package/src/posture/artifact-registry.js +6 -0
- package/src/posture/fleet/cli.js +103 -0
- package/src/posture/fleet/fleet-graph.js +142 -0
- package/src/posture/fleet/fleet-manifest.js +77 -0
- package/src/posture/proof-fabric/cli.js +115 -0
- package/src/posture/proof-fabric/fix-proof.js +73 -0
- package/src/posture/proof-fabric/oracles.js +101 -0
- package/src/posture/proof-fabric/orchestrator.js +129 -0
- package/src/posture/proof-fabric/reproducer.js +108 -0
- package/src/posture/proof-fabric/runner.js +243 -0
- package/src/posture/proof-fabric/states.js +53 -0
- package/src/posture/proof-fabric/store.js +83 -0
- package/src/posture/rule-compiler/cli.js +141 -0
- package/src/posture/rule-compiler/corpus.js +61 -0
- package/src/posture/rule-compiler/eligibility.js +25 -0
- package/src/posture/rule-compiler/ir.js +87 -0
- package/src/posture/rule-compiler/lifecycle.js +57 -0
- package/src/posture/rule-compiler/mutation.js +60 -0
- package/src/posture/rule-compiler/promotion.js +47 -0
- package/src/posture/rule-compiler/store.js +96 -0
- package/src/sandbox/backend-userspace.js +7 -1
- package/src/sandbox/trust-boundary.js +2 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export const id = 818;
|
|
2
|
+
export const ids = [818];
|
|
3
|
+
export const modules = {
|
|
4
|
+
|
|
5
|
+
/***/ 818:
|
|
6
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
7
|
+
|
|
8
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
9
|
+
/* harmony export */ formatFixProof: () => (/* binding */ formatFixProof),
|
|
10
|
+
/* harmony export */ verifyFixWithProof: () => (/* binding */ verifyFixWithProof)
|
|
11
|
+
/* harmony export */ });
|
|
12
|
+
/* harmony import */ var _states_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12090);
|
|
13
|
+
/* harmony import */ var _orchestrator_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3740);
|
|
14
|
+
/* harmony import */ var _runner_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2998);
|
|
15
|
+
/* harmony import */ var _reproducer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37055);
|
|
16
|
+
// Verified remediation, extended with exploit replay. This EXTENDS the fix-verify vocabulary (`verifiedFull`,
|
|
17
|
+
// `degradedLegs`); it does not define a competing meaning of "verified".
|
|
18
|
+
//
|
|
19
|
+
// 1. pre-patch: the original exploit must be EXPLOIT_CONFIRMED (3/3 + independent replay) on the unpatched code;
|
|
20
|
+
// 2. the candidate patch is overlaid on the imported sources and the SAME exploit is replayed;
|
|
21
|
+
// 3. the patched replay must COMPLETE in every attempt and the oracle must not fire in any: BLOCKED.
|
|
22
|
+
// An attempt that did not complete (timeout, build failure, no environment) is inconclusive, never "blocked";
|
|
23
|
+
// 4. static legs (re-scan, lint, tests, honesty) come from `verifyFix`, passed in so they are not re-implemented;
|
|
24
|
+
// 5. FIX_VERIFIED only when 1-4 hold and the static verification had no degraded leg.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async function verifyFixWithProof({ finding, reproducer, files, scanRoot, revision = null, policy = {}, staticVerification = null, siblings = null, signal, deps = {} } = {}) {
|
|
31
|
+
const t0 = Date.now();
|
|
32
|
+
const attemptFn = deps.attemptFn ?? _runner_js__WEBPACK_IMPORTED_MODULE_2__/* .runAttempt */ .Tm;
|
|
33
|
+
const patchHash = (0,_reproducer_js__WEBPACK_IMPORTED_MODULE_3__/* .sha256 */ .sc)((0,_reproducer_js__WEBPACK_IMPORTED_MODULE_3__/* .canonicalize */ .dw)(files || {}));
|
|
34
|
+
const legs = { prePatch: null, postPatch: null, regression: staticVerification ? { ok: !!staticVerification.ok, verifiedFull: !!staticVerification.verifiedFull } : { status: 'not-run' }, rescan: staticVerification?.rescan ?? { status: 'not-run' } };
|
|
35
|
+
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 });
|
|
36
|
+
|
|
37
|
+
const pre = await (0,_orchestrator_js__WEBPACK_IMPORTED_MODULE_1__/* .proveFinding */ .kO)({ finding, revision, reproducer, policy, signal, deps, sourceRoot: scanRoot });
|
|
38
|
+
legs.prePatch = { state: pre.state, outcome: pre.outcome, completeness: pre.completeness };
|
|
39
|
+
if (pre.state !== 'EXPLOIT_CONFIRMED') {
|
|
40
|
+
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` });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const attempts = Math.max(1, Math.min(10, policy.attempts ?? 3));
|
|
44
|
+
const results = [];
|
|
45
|
+
for (let i = 0; i < attempts; i++) {
|
|
46
|
+
if (signal?.aborted) break;
|
|
47
|
+
results.push(await attemptFn(structuredClone(reproducer), { limits: { timeoutMs: policy.timeoutMs }, signal, sourceRoot: scanRoot, overlay: files, requireContainer: policy.requireContainer, force: policy.force }));
|
|
48
|
+
}
|
|
49
|
+
const completed = results.filter((r) => r.status === 'completed' && !r.oracle?.inconclusive);
|
|
50
|
+
const fired = completed.filter((r) => r.oracle?.fired).length;
|
|
51
|
+
legs.postPatch = { attempts: results.length, completed: completed.length, exploitSucceeded: fired, statuses: results.map((r) => r.status) };
|
|
52
|
+
|
|
53
|
+
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' });
|
|
54
|
+
if (completed.length < results.length || results.length === 0) {
|
|
55
|
+
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' });
|
|
56
|
+
}
|
|
57
|
+
let state = (0,_states_js__WEBPACK_IMPORTED_MODULE_0__/* .advance */ .np)('EXPLOIT_CONFIRMED', 'FIX_REPLAY_BLOCKED').state;
|
|
58
|
+
|
|
59
|
+
const degraded = [];
|
|
60
|
+
if (!staticVerification) degraded.push('static-verification-not-run');
|
|
61
|
+
else {
|
|
62
|
+
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'}` });
|
|
63
|
+
for (const d of staticVerification.degradedLegs || []) degraded.push(d);
|
|
64
|
+
}
|
|
65
|
+
const lowAssurance = pre.environment?.assurance === 'lower';
|
|
66
|
+
if (lowAssurance) degraded.push('lower-assurance-local-confinement');
|
|
67
|
+
const siblingCount = Array.isArray(siblings) ? siblings.length : null;
|
|
68
|
+
if (siblingCount === null) degraded.push('sibling-search-not-run');
|
|
69
|
+
else if (siblingCount > 0) degraded.push(`sibling-exposures:${siblingCount}`);
|
|
70
|
+
|
|
71
|
+
const full = degraded.length === 0;
|
|
72
|
+
// Same split as fix-verify: `ok` (nothing that ran failed) earns FIX_VERIFIED; `completeness` says whether anything was skipped.
|
|
73
|
+
if (staticVerification && staticVerification.ok) state = (0,_states_js__WEBPACK_IMPORTED_MODULE_0__/* .advance */ .np)(state, 'FIX_VERIFIED').state;
|
|
74
|
+
return out({ state, verified: state === 'FIX_VERIFIED', completeness: full ? 'FULL' : 'DEGRADED', degradedLegs: degraded, siblings: siblings ?? null });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function formatFixProof(r) {
|
|
78
|
+
const L = r.legs || {};
|
|
79
|
+
return [
|
|
80
|
+
`Pre-patch exploit: ${L.prePatch?.state === 'EXPLOIT_CONFIRMED' ? 'PASS' : 'NOT CONFIRMED'}`,
|
|
81
|
+
`Post-patch exploit: ${!L.postPatch ? 'NOT RUN' : L.postPatch.exploitSucceeded > 0 ? 'STILL SUCCEEDS' : L.postPatch.completed === L.postPatch.attempts ? 'BLOCKED' : 'INCONCLUSIVE'}`,
|
|
82
|
+
`Regression tests: ${L.regression?.status === 'not-run' ? 'not run' : L.regression?.verifiedFull ? 'PASS' : L.regression?.ok ? 'PASS (degraded)' : 'FAIL'}`,
|
|
83
|
+
`Security rescan: ${L.rescan?.ok === true ? 'PASS' : L.rescan?.status === 'not-run' ? 'not run' : 'FAIL'}`,
|
|
84
|
+
`Completeness: ${r.completeness}${r.degradedLegs?.length ? ` (${r.degradedLegs.join('; ')})` : ''}`,
|
|
85
|
+
'',
|
|
86
|
+
`Evidence: ${r.state}${r.verified ? '' : ` (not verified: ${r.reason || r.incompleteStep || 'degraded'})`}`,
|
|
87
|
+
].join('\n');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/***/ })
|
|
92
|
+
|
|
93
|
+
};
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
export const id = 9800;
|
|
2
|
+
export const ids = [9800];
|
|
3
|
+
export const modules = {
|
|
4
|
+
|
|
5
|
+
/***/ 59800:
|
|
6
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
7
|
+
|
|
8
|
+
__webpack_require__.r(__webpack_exports__);
|
|
9
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
10
|
+
/* harmony export */ cmdProof: () => (/* binding */ cmdProof),
|
|
11
|
+
/* harmony export */ cmdProve: () => (/* binding */ cmdProve),
|
|
12
|
+
/* harmony export */ loadReproducerFor: () => (/* binding */ loadReproducerFor)
|
|
13
|
+
/* harmony export */ });
|
|
14
|
+
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73024);
|
|
15
|
+
/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(48161);
|
|
16
|
+
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(76760);
|
|
17
|
+
/* harmony import */ var _state_dir_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(31174);
|
|
18
|
+
/* harmony import */ var _orchestrator_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3740);
|
|
19
|
+
/* harmony import */ var _store_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(62199);
|
|
20
|
+
/* harmony import */ var _runner_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(2998);
|
|
21
|
+
/* harmony import */ var _reproducer_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(37055);
|
|
22
|
+
// CLI surface for the proof fabric: `proof show|replay|doctor`, `triage exploit|validate`. Non-interactive by design: no
|
|
23
|
+
// command reads stdin, every run is bounded by the policy timeouts, and a missing reproducer is a typed exit code, not a
|
|
24
|
+
// prompt. Exit codes: 0 confirmed/ok, 1 not confirmed (any reason), 4 usage/precondition.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
function loadFinding(root, id) {
|
|
36
|
+
const p = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_3__.statePath)(root, 'last-scan.json');
|
|
37
|
+
if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(p)) return null;
|
|
38
|
+
const last = JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(p, 'utf8'));
|
|
39
|
+
return (last.findings || []).find((f) => f.id === id || f.stableId === id) ?? null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function loadReproducerFor(root, id, flagPath) { return loadReproducer(root, id, flagPath); }
|
|
43
|
+
|
|
44
|
+
function loadReproducer(root, id, flagPath) {
|
|
45
|
+
const candidates = [flagPath && node_path__WEBPACK_IMPORTED_MODULE_2__.resolve(String(flagPath)), (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_3__.statePath)(root, 'reproducers', `${(0,_store_js__WEBPACK_IMPORTED_MODULE_5__.findingKey)(id)}.json`)].filter(Boolean);
|
|
46
|
+
for (const c of candidates) {
|
|
47
|
+
try { return { reproducer: JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(c, 'utf8')), file: c }; } catch { /* next */ }
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function formatResult(r) {
|
|
53
|
+
const env = r.environment ? `${r.environment.mode} (${r.environment.assurance} assurance)` : 'none';
|
|
54
|
+
return [
|
|
55
|
+
`Finding: ${r.findingId}`,
|
|
56
|
+
`Evidence: ${r.state}`,
|
|
57
|
+
`Oracle: ${r.oracle}`,
|
|
58
|
+
`Reproductions: ${r.attempts?.successes ?? 0}/${r.attempts?.run ?? 0} (required ${r.attempts?.required})`,
|
|
59
|
+
`Independent replay: ${r.independentReplay?.status ?? 'not-run'}`,
|
|
60
|
+
`Environment: ${env}`,
|
|
61
|
+
`Completeness: ${r.completeness}`,
|
|
62
|
+
`Duration: ${(r.timing.proofMs / 1000).toFixed(1)}s`,
|
|
63
|
+
...(r.degradation?.length ? [`Degraded: ${r.degradation.join(', ')}`] : []),
|
|
64
|
+
...(r.note ? [`Note: ${r.note}`] : []),
|
|
65
|
+
].join('\n');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function cmdProve(args, root, { json = false } = {}) {
|
|
69
|
+
const id = String(args._[2] ?? '');
|
|
70
|
+
if (!id) { console.error('usage: triage exploit <finding-id> --prove [--reproducer file] [--attempts N] [--required N]'); return 4; }
|
|
71
|
+
const finding = loadFinding(root, id);
|
|
72
|
+
if (!finding) { console.error(`Finding ${id} not found in last scan.`); return 4; }
|
|
73
|
+
const loaded = loadReproducer(root, id, args.flags.reproducer);
|
|
74
|
+
if (!loaded) { console.error(`No reproducer for ${id}. Supply one with --reproducer <file> or place it at .agentic-security/reproducers/. Nothing was executed.`); return 4; }
|
|
75
|
+
const errs = (0,_reproducer_js__WEBPACK_IMPORTED_MODULE_7__/* .validateReproducer */ .mC)(loaded.reproducer);
|
|
76
|
+
if (errs.length) { console.error(`Invalid reproducer: ${errs.join('; ')}`); return 4; }
|
|
77
|
+
const policy = {};
|
|
78
|
+
if (args.flags.attempts) policy.attempts = Number(args.flags.attempts);
|
|
79
|
+
if (args.flags.required) policy.required = Number(args.flags.required);
|
|
80
|
+
if (args.flags.timeout) policy.timeoutMs = Number(args.flags.timeout) * 1000;
|
|
81
|
+
if (args.flags['require-container']) policy.requireContainer = true;
|
|
82
|
+
const ac = new AbortController();
|
|
83
|
+
const onSig = () => ac.abort();
|
|
84
|
+
process.once('SIGINT', onSig);
|
|
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); }
|
|
87
|
+
const saved = (0,_store_js__WEBPACK_IMPORTED_MODULE_5__.saveProof)(root, { ...result, reproducer: loaded.reproducer });
|
|
88
|
+
// Printed output gets the same secret-scrubbing pass as what is persisted (defense in depth: a free-text reason/note
|
|
89
|
+
// field that captured something from stdout/stderr should never reach a terminal unredacted either).
|
|
90
|
+
if (json || args.flags.json) console.log(JSON.stringify((0,_store_js__WEBPACK_IMPORTED_MODULE_5__.scrubDeep)({ ...result, stored: saved.ok ? saved.file : null }), null, 2));
|
|
91
|
+
else { console.log(formatResult(result)); if (!saved.ok) console.log(`(proof not stored: ${saved.reason})`); }
|
|
92
|
+
return result.state === 'EXPLOIT_CONFIRMED' ? 0 : 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function cmdProof(args, root) {
|
|
96
|
+
const sub = args._[1];
|
|
97
|
+
if (sub === 'doctor') return doctor(args);
|
|
98
|
+
const id = String(args._[2] ?? '');
|
|
99
|
+
if (!id) { console.error('usage: proof show <finding-id> | proof replay <finding-id> | proof doctor'); return 4; }
|
|
100
|
+
if (sub === 'show') {
|
|
101
|
+
const all = (0,_store_js__WEBPACK_IMPORTED_MODULE_5__.listProofs)(root, id);
|
|
102
|
+
if (!all.length) { console.error(`No stored proof for ${id}.`); return 4; }
|
|
103
|
+
const latest = all.find((p) => p.record);
|
|
104
|
+
if (all.some((p) => p.tampered)) console.error(`WARNING: ${all.filter((p) => p.tampered).length} stored record(s) failed their integrity check and are not trusted.`);
|
|
105
|
+
const good = all.find((p) => p.record && !p.tampered);
|
|
106
|
+
if (!good) { console.error('No intact proof record.'); return 1; }
|
|
107
|
+
if (args.flags.json) console.log(JSON.stringify(good.record, null, 2)); else console.log(formatResult(good.record));
|
|
108
|
+
void latest;
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
if (sub === 'replay') {
|
|
112
|
+
const stored = (0,_store_js__WEBPACK_IMPORTED_MODULE_5__.latestProof)(root, id);
|
|
113
|
+
if (!stored?.record?.reproducer) { console.error(`No stored reproducer for ${id}.`); return 4; }
|
|
114
|
+
const tmpDir = node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(node_path__WEBPACK_IMPORTED_MODULE_2__.join(node_os__WEBPACK_IMPORTED_MODULE_1__.tmpdir(), 'proof-replay-'));
|
|
115
|
+
const tmp = node_path__WEBPACK_IMPORTED_MODULE_2__.join(tmpDir, 'reproducer.json');
|
|
116
|
+
node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(tmp, JSON.stringify(stored.record.reproducer));
|
|
117
|
+
args.flags.reproducer = tmp;
|
|
118
|
+
args._ = ['triage', 'exploit', id];
|
|
119
|
+
try { return await cmdProve(args, root); } finally { node_fs__WEBPACK_IMPORTED_MODULE_0__.rmSync(tmpDir, { recursive: true, force: true }); }
|
|
120
|
+
}
|
|
121
|
+
console.error('usage: proof show|replay <finding-id> | proof doctor');
|
|
122
|
+
return 4;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function doctor(args) {
|
|
126
|
+
const tools = (0,_runner_js__WEBPACK_IMPORTED_MODULE_6__/* .hostTools */ .qV)();
|
|
127
|
+
const rows = _reproducer_js__WEBPACK_IMPORTED_MODULE_7__/* .LANGUAGES */ .Yj.map((l) => ({ lang: l, ...(0,_runner_js__WEBPACK_IMPORTED_MODULE_6__/* .languageSupport */ .ql)(l, tools) }));
|
|
128
|
+
const envs = ['javascript', 'python'].map((l) => ({ lang: l, ...(0,_runner_js__WEBPACK_IMPORTED_MODULE_6__/* .selectEnvironment */ .aP)({ lang: l }) }));
|
|
129
|
+
if (args.flags.json) { console.log(JSON.stringify({ tools, languages: rows, environments: envs }, null, 2)); return 0; }
|
|
130
|
+
console.log('Proof fabric doctor');
|
|
131
|
+
for (const r of rows) console.log(` ${r.lang.padEnd(11)} ${r.supported ? 'supported' : `unsupported (${r.reason})`}`);
|
|
132
|
+
for (const e of envs) console.log(` environment for ${e.lang}: ${e.mode}, ${e.assurance} assurance${e.reason ? ` (${e.reason})` : ''}${e.containerSkipped ? `; container skipped: ${e.containerSkipped}` : ''}`);
|
|
133
|
+
const usable = envs.some((e) => e.mode !== 'unavailable');
|
|
134
|
+
if (!usable) console.log(' RESULT: no execution environment available; proofs will report blocked, never clean.');
|
|
135
|
+
return usable ? 0 : 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
/***/ }),
|
|
140
|
+
|
|
141
|
+
/***/ 62199:
|
|
142
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
143
|
+
|
|
144
|
+
__webpack_require__.r(__webpack_exports__);
|
|
145
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
146
|
+
/* harmony export */ findingKey: () => (/* binding */ findingKey),
|
|
147
|
+
/* harmony export */ latestProof: () => (/* binding */ latestProof),
|
|
148
|
+
/* harmony export */ listProofs: () => (/* binding */ listProofs),
|
|
149
|
+
/* harmony export */ saveProof: () => (/* binding */ saveProof),
|
|
150
|
+
/* harmony export */ scrubDeep: () => (/* binding */ scrubDeep)
|
|
151
|
+
/* harmony export */ });
|
|
152
|
+
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73024);
|
|
153
|
+
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(76760);
|
|
154
|
+
/* harmony import */ var _state_dir_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(31174);
|
|
155
|
+
/* harmony import */ var _encryption_provider_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(39984);
|
|
156
|
+
/* harmony import */ var _llm_validator_redact_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(65388);
|
|
157
|
+
/* harmony import */ var _reproducer_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(37055);
|
|
158
|
+
// Proof artifact store: `.agentic-security/proofs/<findingKey>/<recordDigest>.json`.
|
|
159
|
+
//
|
|
160
|
+
// Reuses the existing state machinery rather than adding another: `safeWriteState` (refuses unsafe dirs and symlinks),
|
|
161
|
+
// `maybeEncryptForWrite` / `maybeDecryptForRead` (the `proofs` artifact is registered `confidential`), retention
|
|
162
|
+
// (evidence class) and legal holds (a hold on `proofs` blocks purge). Nothing persisted contains a plaintext credential:
|
|
163
|
+
// records are passed through a recursive secret filter first, and the runner never returns its per-run nonce or secrets.
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
const PROOF_RECORD_SCHEMA = 'agentic-security/proof-record';
|
|
172
|
+
const PROOFS_DIR = 'proofs';
|
|
173
|
+
const MAX_RECORD_BYTES = 512 * 1024;
|
|
174
|
+
|
|
175
|
+
const findingKey = (id) => `${String(id).replace(/[^A-Za-z0-9._-]/g, '_').slice(0, 80)}-${(0,_reproducer_js__WEBPACK_IMPORTED_MODULE_5__/* .sha256 */ .sc)(String(id)).slice(0, 8)}`;
|
|
176
|
+
|
|
177
|
+
// The shared redactor catches key=value shapes; bare tokens need their own pass, so persisted evidence cannot carry one.
|
|
178
|
+
const BARE_SECRET_RES = [
|
|
179
|
+
/\b(?:ghp|gho|ghu|ghs|ghr|github_pat)_[A-Za-z0-9_]{20,}\b/g, /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g, /\bsk-[A-Za-z0-9_-]{20,}\b/g,
|
|
180
|
+
/\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g, /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,
|
|
181
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g, /\bSECRET-[0-9a-f]{24}-[a-z0-9_-]+\b/g,
|
|
182
|
+
];
|
|
183
|
+
function scrubString(text) {
|
|
184
|
+
let t = String(text);
|
|
185
|
+
try { t = (0,_llm_validator_redact_js__WEBPACK_IMPORTED_MODULE_4__/* .redactSecrets */ .f)(t).text; } catch { return '[unredactable]'; }
|
|
186
|
+
for (const re of BARE_SECRET_RES) t = t.replace(re, '[REDACTED-SECRET]');
|
|
187
|
+
return t;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Deep-copy `v` with every string passed through the secret redactor. */
|
|
191
|
+
function scrubDeep(v) {
|
|
192
|
+
if (typeof v === 'string') return scrubString(v);
|
|
193
|
+
if (Array.isArray(v)) return v.map(scrubDeep);
|
|
194
|
+
if (v && typeof v === 'object') return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, scrubDeep(x)]));
|
|
195
|
+
return v;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function recordDigest(record) {
|
|
199
|
+
const { recordDigest: _omit, ...rest } = record;
|
|
200
|
+
return (0,_reproducer_js__WEBPACK_IMPORTED_MODULE_5__/* .sha256 */ .sc)((0,_reproducer_js__WEBPACK_IMPORTED_MODULE_5__/* .canonicalize */ .dw)(rest));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function saveProof(scanRoot, record) {
|
|
204
|
+
const safe = scrubDeep(record);
|
|
205
|
+
safe.schema = PROOF_RECORD_SCHEMA;
|
|
206
|
+
safe.recordDigest = recordDigest(safe);
|
|
207
|
+
const text = JSON.stringify(safe, null, 2);
|
|
208
|
+
if (Buffer.byteLength(text) > MAX_RECORD_BYTES) return { ok: false, reason: 'proof record exceeds the size limit' };
|
|
209
|
+
if (!(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .ensureStateDir */ .xH)(scanRoot)) return { ok: false, reason: 'no safe state directory for this project' };
|
|
210
|
+
const enc = (0,_encryption_provider_js__WEBPACK_IMPORTED_MODULE_3__/* .maybeEncryptForWrite */ .v2)(scanRoot, PROOFS_DIR, text);
|
|
211
|
+
if (!enc.ok) return { ok: false, reason: enc.reason };
|
|
212
|
+
const file = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.statePath)(scanRoot, PROOFS_DIR, findingKey(record.findingId), `${safe.recordDigest}.json`);
|
|
213
|
+
if (!(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .safeWriteState */ .Ep)(file, enc.content)) return { ok: false, reason: 'state write refused' };
|
|
214
|
+
return { ok: true, file, digest: safe.recordDigest, encrypted: enc.encrypted };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function readRecord(file) {
|
|
218
|
+
const text = (0,_encryption_provider_js__WEBPACK_IMPORTED_MODULE_3__.maybeDecryptForRead)(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(file, 'utf8'));
|
|
219
|
+
const rec = JSON.parse(text);
|
|
220
|
+
// A record whose content no longer matches its own digest was modified after it was written.
|
|
221
|
+
if (rec.recordDigest !== recordDigest(rec)) return { tampered: true, record: rec };
|
|
222
|
+
return { tampered: false, record: rec };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Newest-first records for a finding. Tampered records are returned flagged, never silently dropped or trusted. */
|
|
226
|
+
function listProofs(scanRoot, findingId) {
|
|
227
|
+
const dir = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.statePath)(scanRoot, PROOFS_DIR, findingKey(findingId));
|
|
228
|
+
let names = [];
|
|
229
|
+
try { names = node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync(dir).filter((n) => n.endsWith('.json')); } catch { return []; }
|
|
230
|
+
const out = [];
|
|
231
|
+
for (const n of names) {
|
|
232
|
+
const f = node_path__WEBPACK_IMPORTED_MODULE_1__.join(dir, n);
|
|
233
|
+
try { const { tampered, record } = readRecord(f); out.push({ file: f, tampered, record, mtime: node_fs__WEBPACK_IMPORTED_MODULE_0__.statSync(f).mtimeMs }); } catch { out.push({ file: f, tampered: true, record: null, mtime: 0 }); }
|
|
234
|
+
}
|
|
235
|
+
return out.sort((a, b) => b.mtime - a.mtime);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function latestProof(scanRoot, findingId) {
|
|
239
|
+
return listProofs(scanRoot, findingId).find((p) => p.record) ?? null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
/***/ })
|
|
244
|
+
|
|
245
|
+
};
|
package/dist/9999.index.js
CHANGED
|
@@ -959,8 +959,8 @@ function forgetRefuted(memory) {
|
|
|
959
959
|
|
|
960
960
|
// EXTERNAL MODULE: ./src/posture/verification/emit.js
|
|
961
961
|
var emit = __webpack_require__(85578);
|
|
962
|
-
// EXTERNAL MODULE: ./src/posture/oracles/oracle.js
|
|
963
|
-
var oracle = __webpack_require__(
|
|
962
|
+
// EXTERNAL MODULE: ./src/posture/oracles/oracle.js
|
|
963
|
+
var oracle = __webpack_require__(15991);
|
|
964
964
|
// EXTERNAL MODULE: ./src/posture/assurance/verification-record.js
|
|
965
965
|
var verification_record = __webpack_require__(29668);
|
|
966
966
|
// EXTERNAL MODULE: ./src/posture/assurance/identity.js
|