@clear-capabilities/agentic-security-scanner 0.78.0 → 0.80.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 (126) hide show
  1. package/bin/.agentic-security/findings.json +16 -16
  2. package/bin/.agentic-security/last-scan.json +16 -16
  3. package/bin/.agentic-security/last-scan.json.sig +1 -1
  4. package/bin/.agentic-security/scan-history.json +51 -0
  5. package/bin/.agentic-security/streak.json +5 -5
  6. package/bin/agentic-security.js +22 -7
  7. package/dist/178.index.js +1 -1
  8. package/dist/333.index.js +283 -0
  9. package/dist/384.index.js +1 -1
  10. package/dist/476.index.js +5 -5
  11. package/dist/637.index.js +1 -1
  12. package/dist/700.index.js +138 -0
  13. package/dist/718.index.js +53 -0
  14. package/dist/838.index.js +1 -1
  15. package/dist/985.index.js +95 -1
  16. package/dist/agentic-security.mjs +83 -83
  17. package/dist/agentic-security.mjs.sha256 +1 -1
  18. package/package.json +6 -4
  19. package/src/.agentic-security/findings.json +29799 -7803
  20. package/src/.agentic-security/last-scan.json +29799 -7803
  21. package/src/.agentic-security/last-scan.json.sig +1 -1
  22. package/src/.agentic-security/scan-history.json +5119 -2611
  23. package/src/.agentic-security/streak.json +6 -6
  24. package/src/dataflow/.agentic-security/findings.json +2879 -308
  25. package/src/dataflow/.agentic-security/last-scan.json +2879 -308
  26. package/src/dataflow/.agentic-security/last-scan.json.sig +1 -1
  27. package/src/dataflow/.agentic-security/scan-history.json +68 -520
  28. package/src/dataflow/.agentic-security/streak.json +6 -7
  29. package/src/dataflow/cross-service-taint.js +201 -0
  30. package/src/dataflow/engine.js +52 -8
  31. package/src/dataflow/formal-verify.js +204 -0
  32. package/src/dataflow/ifds-precise.js +222 -0
  33. package/src/dataflow/k2-summary-cache.js +153 -0
  34. package/src/dataflow/lib-taint-summaries.js +198 -0
  35. package/src/dataflow/privacy-taint.js +205 -0
  36. package/src/dataflow/smt-feasibility.js +189 -0
  37. package/src/engine.js +890 -132
  38. package/src/integrations/index.js +2 -1
  39. package/src/ir/.agentic-security/findings.json +240 -6
  40. package/src/ir/.agentic-security/last-scan.json +240 -6
  41. package/src/ir/.agentic-security/last-scan.json.sig +1 -1
  42. package/src/ir/.agentic-security/scan-history.json +16 -594
  43. package/src/ir/.agentic-security/streak.json +8 -9
  44. package/src/ir/callgraph.js +27 -7
  45. package/src/ir/cpp-preprocessor.js +142 -0
  46. package/src/ir/csharp-ir.js +604 -0
  47. package/src/ir/universal-ir.js +403 -0
  48. package/src/llm-validator/index.js +7 -5
  49. package/src/mcp/.agentic-security/findings.json +8632 -0
  50. package/src/mcp/.agentic-security/last-scan.json +8632 -0
  51. package/src/mcp/.agentic-security/last-scan.json.sig +1 -0
  52. package/src/mcp/.agentic-security/scan-history.json +143 -0
  53. package/src/mcp/.agentic-security/streak.json +20 -0
  54. package/src/mcp/audit.js +5 -0
  55. package/src/mcp/tools.js +90 -1
  56. package/src/posture/.agentic-security/findings.json +16809 -4367
  57. package/src/posture/.agentic-security/last-scan.json +16809 -4367
  58. package/src/posture/.agentic-security/last-scan.json.sig +1 -1
  59. package/src/posture/.agentic-security/scan-history.json +6689 -177
  60. package/src/posture/.agentic-security/streak.json +8 -7
  61. package/src/posture/api-contract.js +193 -0
  62. package/src/posture/attack-taxonomy.js +227 -0
  63. package/src/posture/calibration-drift.js +2 -1
  64. package/src/posture/calibration.js +3 -2
  65. package/src/posture/compliance-policy.js +218 -0
  66. package/src/posture/composite-risk.js +122 -0
  67. package/src/posture/csharp-analysis.js +330 -0
  68. package/src/posture/exploit-bundle.js +210 -0
  69. package/src/posture/federated-learning.js +172 -0
  70. package/src/posture/fix-history.js +8 -2
  71. package/src/posture/license-attributions.js +94 -0
  72. package/src/posture/license-graph.js +238 -0
  73. package/src/posture/pqc-migration-plan.js +158 -0
  74. package/src/posture/profile.js +4 -5
  75. package/src/posture/reachability-filter.js +33 -2
  76. package/src/posture/realtime-cve-monitor.js +214 -0
  77. package/src/posture/rule-overrides.js +2 -3
  78. package/src/posture/rule-pack-signing.js +2 -3
  79. package/src/posture/rule-synthesis.js +5 -6
  80. package/src/posture/runtime-correlation.js +174 -0
  81. package/src/posture/sbom-diff.js +171 -0
  82. package/src/posture/sca-policy.js +235 -0
  83. package/src/posture/sca-upgrade.js +259 -0
  84. package/src/posture/security-trend.js +4 -7
  85. package/src/posture/state-dir.js +124 -0
  86. package/src/posture/streak.js +3 -0
  87. package/src/posture/suppressions.js +5 -8
  88. package/src/posture/threat-model-auto.js +268 -0
  89. package/src/posture/triage-learning.js +170 -0
  90. package/src/posture/triage.js +29 -6
  91. package/src/posture/validator-metrics.js +3 -6
  92. package/src/sast/.agentic-security/findings.json +996 -32
  93. package/src/sast/.agentic-security/last-scan.json +996 -32
  94. package/src/sast/.agentic-security/last-scan.json.sig +1 -1
  95. package/src/sast/.agentic-security/scan-history.json +565 -32
  96. package/src/sast/.agentic-security/streak.json +10 -8
  97. package/src/sast/_secret-entropy.js +145 -0
  98. package/src/sast/cloud-iam.js +312 -0
  99. package/src/sast/cpp.js +138 -4
  100. package/src/sast/crypto-protocol.js +388 -0
  101. package/src/sast/csharp-tokenizer.js +392 -0
  102. package/src/sast/csharp.js +924 -138
  103. package/src/sast/dapp-frontend.js +200 -0
  104. package/src/sast/db-taint.js +24 -0
  105. package/src/sast/k8s-admission.js +271 -0
  106. package/src/sast/llm-app.js +272 -0
  107. package/src/sast/ml-supply-chain.js +259 -0
  108. package/src/sast/mobile.js +224 -0
  109. package/src/sast/post-quantum-crypto.js +348 -0
  110. package/src/sast/rust.js +26 -0
  111. package/src/sast/web3-advanced.js +375 -0
  112. package/src/sca/.agentic-security/findings.json +6044 -171
  113. package/src/sca/.agentic-security/last-scan.json +6044 -171
  114. package/src/sca/.agentic-security/last-scan.json.sig +1 -1
  115. package/src/sca/.agentic-security/scan-history.json +83 -6
  116. package/src/sca/.agentic-security/streak.json +9 -9
  117. package/src/sca/CLAUDE.md +161 -0
  118. package/src/sca/binary-metadata.js +146 -0
  119. package/src/sca/py-package-functions.js +118 -0
  120. package/src/sca/sigstore-verify.js +215 -0
  121. package/src/sca/vendor-detect.js +53 -0
  122. package/src/report/.agentic-security/findings.json +0 -80
  123. package/src/report/.agentic-security/last-scan.json +0 -80
  124. package/src/report/.agentic-security/last-scan.json.sig +0 -1
  125. package/src/report/.agentic-security/scan-history.json +0 -35
  126. package/src/report/.agentic-security/streak.json +0 -22
@@ -0,0 +1,283 @@
1
+ export const id = 333;
2
+ export const ids = [333];
3
+ export const modules = {
4
+
5
+ /***/ 5333:
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 */ applyScaUpgrade: () => (/* binding */ applyScaUpgrade),
11
+ /* harmony export */ planScaUpgrade: () => (/* binding */ planScaUpgrade)
12
+ /* harmony export */ });
13
+ /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3024);
14
+ /* harmony import */ var node_fs_promises__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1455);
15
+ /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6760);
16
+ /* harmony import */ var node_crypto__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7598);
17
+ /* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1421);
18
+ /* harmony import */ var node_util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7975);
19
+ /* harmony import */ var _state_dir_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1174);
20
+ // SCA upgrade engine: dry-run plan + worktree-isolated apply.
21
+ //
22
+ // Phase 3 / Item 5 of the SCA improvement plan. The MCP `apply_fix` path
23
+ // refuses to write manifest files (package.json, *-lock.*, poetry.lock,
24
+ // Cargo.lock, etc.) for safety. SCA findings need a separate path that:
25
+ // 1. Generates an upgrade *plan* via the ecosystem's native dry-run
26
+ // command (npm install --dry-run, pip install --dry-run, etc.).
27
+ // 2. Applies the upgrade via the package manager itself, with a backup
28
+ // + test-gate so a peer-dep break or test regression rolls back.
29
+ //
30
+ // Caller pattern: plan first (read-only), inspect the breaking-change
31
+ // flag / peer warnings, then apply with confirm:true.
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+ const execFileAsync = (0,node_util__WEBPACK_IMPORTED_MODULE_5__.promisify)(node_child_process__WEBPACK_IMPORTED_MODULE_4__.execFile);
42
+
43
+ // Per-ecosystem command/manifest map. Add ecosystems by extending this
44
+ // table — every other place in the module reads it.
45
+ const ECOSYSTEM = {
46
+ npm: {
47
+ manifests: ['package.json', 'package-lock.json'],
48
+ altManifests: [['yarn.lock'], ['pnpm-lock.yaml']],
49
+ dryRun: (pkg, ver) => ({ cmd: 'npm', args: ['install', `${pkg}@${ver}`, '--dry-run', '--json'] }),
50
+ apply: (pkg, ver) => ({ cmd: 'npm', args: ['install', `${pkg}@${ver}`, '--save'] }),
51
+ parseDryRun(stdout) {
52
+ try {
53
+ const j = JSON.parse(stdout);
54
+ const peerDeps = Array.isArray(j.warnings) ? j.warnings.filter(w => /peer dep/i.test(w)) : [];
55
+ const transitiveImpact = (j.added || []).length + (j.updated || []).length + (j.removed || []).length;
56
+ return { peerDeps, transitiveImpact, rawSummary: { added: (j.added || []).length, updated: (j.updated || []).length, removed: (j.removed || []).length } };
57
+ } catch { return { peerDeps: [], transitiveImpact: 0, rawSummary: null }; }
58
+ },
59
+ },
60
+ pypi: {
61
+ manifests: ['requirements.txt', 'pyproject.toml'],
62
+ altManifests: [['poetry.lock'], ['Pipfile.lock']],
63
+ dryRun: (pkg, ver) => ({ cmd: 'pip', args: ['install', '--dry-run', `${pkg}==${ver}`] }),
64
+ apply: (pkg, ver) => ({ cmd: 'pip', args: ['install', '--upgrade', `${pkg}==${ver}`] }),
65
+ parseDryRun() {
66
+ // pip --dry-run output is human-readable; we don't parse it for v1.
67
+ return { peerDeps: [], transitiveImpact: 0, rawSummary: null };
68
+ },
69
+ },
70
+ cargo: {
71
+ manifests: ['Cargo.toml', 'Cargo.lock'],
72
+ altManifests: [],
73
+ dryRun: (pkg, _ver) => ({ cmd: 'cargo', args: ['update', '--package', pkg, '--dry-run'] }),
74
+ apply: (pkg, _ver) => ({ cmd: 'cargo', args: ['update', '--package', pkg] }),
75
+ parseDryRun() { return { peerDeps: [], transitiveImpact: 0, rawSummary: null }; },
76
+ },
77
+ golang: {
78
+ manifests: ['go.mod', 'go.sum'],
79
+ altManifests: [],
80
+ dryRun: (_pkg, _ver) => null, // `go get` has no dry-run flag; we skip dry-run in v1.
81
+ apply: (pkg, ver) => ({ cmd: 'go', args: ['get', `${pkg}@v${ver}`] }),
82
+ parseDryRun() { return { peerDeps: [], transitiveImpact: 0, rawSummary: null }; },
83
+ },
84
+ // Other ecosystems (rubygems, packagist, pub, maven) return a structured
85
+ // "manual" plan in v1 — no native dry-run + the install side-effects
86
+ // (gem build artifacts, composer cache) are easier for the user to
87
+ // confirm interactively.
88
+ };
89
+
90
+ function _majorVersion(v) {
91
+ const m = String(v || '').match(/^(\d+)/);
92
+ return m ? parseInt(m[1], 10) : null;
93
+ }
94
+
95
+ function _detectTestCommand(scanRoot) {
96
+ try {
97
+ const pkg = node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, 'package.json');
98
+ if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(pkg)) {
99
+ const j = JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(pkg, 'utf8'));
100
+ if (j.scripts?.test && !/no test specified/i.test(j.scripts.test)) {
101
+ return { cmd: 'npm', args: ['test'] };
102
+ }
103
+ }
104
+ } catch {}
105
+ if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, 'Cargo.toml'))) return { cmd: 'cargo', args: ['test'] };
106
+ if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, 'go.mod'))) return { cmd: 'go', args: ['test', './...'] };
107
+ if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, 'pyproject.toml'))) return { cmd: 'pytest', args: [] };
108
+ return null;
109
+ }
110
+
111
+ // Produce a structured upgrade plan WITHOUT modifying anything on disk.
112
+ // Safe to call repeatedly; runs the ecosystem's --dry-run command.
113
+ async function planScaUpgrade({ scanRoot, finding }) {
114
+ if (!finding || finding.type !== 'vulnerable_dep') {
115
+ return { ok: false, reason: 'not a vulnerable_dep finding' };
116
+ }
117
+ const eco = ECOSYSTEM[finding.ecosystem];
118
+ if (!eco) {
119
+ return {
120
+ ok: true,
121
+ mode: 'manual',
122
+ reason: `ecosystem '${finding.ecosystem}' has no automated upgrade in v1`,
123
+ package: finding.name, currentVersion: finding.version,
124
+ targetVersion: (finding.fixedVersions && finding.fixedVersions[0]) || null,
125
+ command: null,
126
+ };
127
+ }
128
+ const target = (finding.fixedVersions && finding.fixedVersions[0]) || null;
129
+ if (!target) {
130
+ return { ok: false, reason: 'no fixed version in OSV record' };
131
+ }
132
+ const isBreaking = (_majorVersion(target) ?? 0) > (_majorVersion(finding.version) ?? 0);
133
+ const apply = eco.apply(finding.name, target);
134
+ const dryRunSpec = eco.dryRun(finding.name, target);
135
+ let peerDeps = [], transitiveImpact = 0, rawSummary = null, dryRunOk = null;
136
+ if (dryRunSpec) {
137
+ try {
138
+ const r = await execFileAsync(dryRunSpec.cmd, dryRunSpec.args, {
139
+ cwd: scanRoot, timeout: 60_000, maxBuffer: 8 * 1024 * 1024,
140
+ });
141
+ const parsed = eco.parseDryRun(r.stdout);
142
+ peerDeps = parsed.peerDeps;
143
+ transitiveImpact = parsed.transitiveImpact;
144
+ rawSummary = parsed.rawSummary;
145
+ dryRunOk = true;
146
+ } catch (e) {
147
+ // Dry-run failed (e.g. peer-dep resolution conflict). Surface the
148
+ // error structurally so the caller can decide whether to proceed.
149
+ dryRunOk = false;
150
+ const stderr = (e && e.stderr) || (e && e.message) || '';
151
+ peerDeps = /peer dep/i.test(stderr) ? [String(stderr).slice(0, 500)] : [];
152
+ }
153
+ }
154
+ return {
155
+ ok: true,
156
+ mode: 'auto',
157
+ ecosystem: finding.ecosystem,
158
+ package: finding.name,
159
+ currentVersion: finding.version,
160
+ targetVersion: target,
161
+ isBreaking,
162
+ command: `${apply.cmd} ${apply.args.join(' ')}`,
163
+ manifestFiles: eco.manifests,
164
+ dryRun: { ok: dryRunOk, command: dryRunSpec ? `${dryRunSpec.cmd} ${dryRunSpec.args.join(' ')}` : null, peerDeps, transitiveImpact, rawSummary },
165
+ testCommand: (() => { const t = _detectTestCommand(scanRoot); return t ? `${t.cmd} ${t.args.join(' ')}` : null; })(),
166
+ };
167
+ }
168
+
169
+ // Apply the upgrade. Backs up affected manifests, runs the install, runs
170
+ // the project's test command if detected, and ROLLS BACK on failure.
171
+ // Audit-logged via the MCP audit layer at the call site.
172
+ async function applyScaUpgrade({ scanRoot, finding, runTests = true }) {
173
+ const plan = await planScaUpgrade({ scanRoot, finding });
174
+ if (!plan.ok) return { applied: false, reason: plan.reason };
175
+ if (plan.mode === 'manual') {
176
+ return { applied: false, reason: plan.reason, plan };
177
+ }
178
+ const eco = ECOSYSTEM[finding.ecosystem];
179
+ const target = plan.targetVersion;
180
+
181
+ // Backup pass — record original contents of every relevant manifest so
182
+ // we can restore on test failure. node_modules / vendor dirs are NOT
183
+ // backed up (too big); they'll be rebuilt by re-running the install on
184
+ // restore.
185
+ const stateDir = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_6__/* .statePath */ .BQ)(scanRoot, 'sca-upgrade-history');
186
+ node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(stateDir, { recursive: true });
187
+ const upgradeId = node_crypto__WEBPACK_IMPORTED_MODULE_3__.randomBytes(8).toString('hex');
188
+ const backups = {};
189
+ for (const mf of eco.manifests) {
190
+ const abs = node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, mf);
191
+ if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(abs)) continue;
192
+ const content = await node_fs_promises__WEBPACK_IMPORTED_MODULE_1__.readFile(abs, 'utf8');
193
+ const backupPath = node_path__WEBPACK_IMPORTED_MODULE_2__.join(stateDir, `${upgradeId}-${mf.replace(/[\/\\]/g, '_')}.bak`);
194
+ await node_fs_promises__WEBPACK_IMPORTED_MODULE_1__.writeFile(backupPath, content);
195
+ backups[mf] = { abs, backupPath };
196
+ }
197
+ if (!Object.keys(backups).length) {
198
+ return { applied: false, reason: `no ${finding.ecosystem} manifest files found in scan root` };
199
+ }
200
+
201
+ // Run the install.
202
+ const apply = eco.apply(finding.name, target);
203
+ let installOutput = '';
204
+ try {
205
+ const r = await execFileAsync(apply.cmd, apply.args, {
206
+ cwd: scanRoot, timeout: 300_000, maxBuffer: 16 * 1024 * 1024,
207
+ });
208
+ installOutput = (r.stdout || '') + (r.stderr || '');
209
+ } catch (e) {
210
+ // Install failed; restore backups (manifests may have been touched).
211
+ for (const { abs, backupPath } of Object.values(backups)) {
212
+ try { await node_fs_promises__WEBPACK_IMPORTED_MODULE_1__.copyFile(backupPath, abs); } catch {}
213
+ }
214
+ return {
215
+ applied: false,
216
+ reason: `install failed: ${(e && e.message) || e}`.slice(0, 600),
217
+ installOutput: ((e && e.stdout) || '').slice(0, 1500),
218
+ restored: true,
219
+ upgradeId,
220
+ };
221
+ }
222
+
223
+ // Optionally run the project's test command. On failure, restore.
224
+ let testResult = null;
225
+ if (runTests) {
226
+ const test = _detectTestCommand(scanRoot);
227
+ if (test) {
228
+ try {
229
+ const r = await execFileAsync(test.cmd, test.args, {
230
+ cwd: scanRoot, timeout: 600_000, maxBuffer: 16 * 1024 * 1024,
231
+ });
232
+ testResult = { ok: true, command: `${test.cmd} ${test.args.join(' ')}`, output: ((r.stdout || '') + (r.stderr || '')).slice(0, 2000) };
233
+ } catch (e) {
234
+ // Tests failed — restore manifests so the working tree is clean.
235
+ for (const { abs, backupPath } of Object.values(backups)) {
236
+ try { await node_fs_promises__WEBPACK_IMPORTED_MODULE_1__.copyFile(backupPath, abs); } catch {}
237
+ }
238
+ return {
239
+ applied: false,
240
+ reason: `tests failed after upgrade: ${(e && e.message) || e}`.slice(0, 300),
241
+ testOutput: ((e && e.stdout) || '').slice(0, 2000),
242
+ restored: true,
243
+ upgradeId,
244
+ };
245
+ }
246
+ }
247
+ }
248
+
249
+ // Success path — write a log entry so the user can audit / undo.
250
+ const logEntry = {
251
+ id: upgradeId,
252
+ timestamp: new Date().toISOString(),
253
+ ecosystem: finding.ecosystem,
254
+ package: finding.name,
255
+ from: finding.version,
256
+ to: target,
257
+ backups: Object.fromEntries(Object.entries(backups).map(([k, v]) => [k, v.backupPath])),
258
+ testResult,
259
+ isBreaking: plan.isBreaking,
260
+ finding: { id: finding.id, osvId: finding.osvId, cveAliases: finding.cveAliases },
261
+ };
262
+ const logFp = node_path__WEBPACK_IMPORTED_MODULE_2__.join(stateDir, 'log.json');
263
+ let log = [];
264
+ try { log = JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(logFp, 'utf8')); } catch {}
265
+ log.push(logEntry);
266
+ node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(logFp, JSON.stringify(log, null, 2));
267
+
268
+ return {
269
+ applied: true,
270
+ upgradeId,
271
+ package: finding.name,
272
+ from: finding.version,
273
+ to: target,
274
+ isBreaking: plan.isBreaking,
275
+ testResult,
276
+ installOutput: installOutput.slice(0, 1500),
277
+ };
278
+ }
279
+
280
+
281
+ /***/ })
282
+
283
+ };
package/dist/384.index.js CHANGED
@@ -8,7 +8,7 @@ export const modules = {
8
8
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
9
  /* harmony export */ scanCredentials: () => (/* reexport safe */ _engine_js__WEBPACK_IMPORTED_MODULE_0__.Sv)
10
10
  /* harmony export */ });
11
- /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8636);
11
+ /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9072);
12
12
  // Secrets submodule view of the engine — credential + entropy + TODO scanning.
13
13
 
14
14
 
package/dist/476.index.js CHANGED
@@ -11,6 +11,7 @@ export const modules = {
11
11
  /* unused harmony export _internals */
12
12
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3024);
13
13
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6760);
14
+ /* harmony import */ var _state_dir_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1174);
14
15
  // Auto-rule synthesis from repeated FPs (FR-LEARN-6).
15
16
  //
16
17
  // Reads `.agentic-security/triage-feedback.json` (populated by the /triage
@@ -27,13 +28,11 @@ export const modules = {
27
28
 
28
29
 
29
30
 
30
- const TRIAGE_PATH = node_path__WEBPACK_IMPORTED_MODULE_1__.join('.agentic-security', 'triage-feedback.json');
31
- const PROPOSED_DIR = node_path__WEBPACK_IMPORTED_MODULE_1__.join('.agentic-security', 'rules-proposed');
32
31
 
33
32
  const DEFAULT_FP_THRESHOLD = 5;
34
33
 
35
34
  function _readTriage(scanRoot) {
36
- const fp = node_path__WEBPACK_IMPORTED_MODULE_1__.join(scanRoot || process.cwd(), TRIAGE_PATH);
35
+ const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .statePath */ .BQ)(scanRoot, 'triage-feedback.json');
37
36
  if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(fp)) return null;
38
37
  try { return JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(fp, 'utf8')); } catch { return null; }
39
38
  }
@@ -100,7 +99,8 @@ function synthesizeRules(scanRoot, opts = {}) {
100
99
  groups.get(k).push(e);
101
100
  }
102
101
  const proposals = [];
103
- const dir = node_path__WEBPACK_IMPORTED_MODULE_1__.join(scanRoot || process.cwd(), PROPOSED_DIR);
102
+ const dir = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .statePath */ .BQ)(scanRoot, 'rules-proposed');
103
+ if (!opts.dryRun && !(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.isSafeStateDir)(node_path__WEBPACK_IMPORTED_MODULE_1__.dirname(dir))) return [];
104
104
  for (const [, group] of groups) {
105
105
  if (group.length < threshold) continue;
106
106
  const summary = _summarizeGroup(group);
@@ -118,7 +118,7 @@ function synthesizeRules(scanRoot, opts = {}) {
118
118
  return proposals;
119
119
  }
120
120
 
121
- const _internals = { DEFAULT_FP_THRESHOLD, TRIAGE_PATH, PROPOSED_DIR };
121
+ const _internals = { DEFAULT_FP_THRESHOLD };
122
122
 
123
123
 
124
124
  /***/ })
package/dist/637.index.js CHANGED
@@ -10,7 +10,7 @@ export const modules = {
10
10
  /* harmony export */ renderPrDeltaText: () => (/* binding */ renderPrDeltaText)
11
11
  /* harmony export */ });
12
12
  /* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1421);
13
- /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8636);
13
+ /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9072);
14
14
  // Shadowscan / security-DELTA on PR (v0.72).
15
15
  //
16
16
  // Most SAST PR-comment integrations show absolute counts — "12 findings
@@ -0,0 +1,138 @@
1
+ export const id = 700;
2
+ export const ids = [700];
3
+ export const modules = {
4
+
5
+ /***/ 1700:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
+ /* harmony export */ validateOsvFunctionsExist: () => (/* binding */ validateOsvFunctionsExist)
10
+ /* harmony export */ });
11
+ /* unused harmony export extractPythonPackageFunctions */
12
+ /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3024);
13
+ /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6760);
14
+ /* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1421);
15
+ /* harmony import */ var _ir_parser_py_cst_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(682);
16
+ // Python package function extraction via the CST parser.
17
+ //
18
+ // Locates an installed Python package in site-packages or .venv,
19
+ // parses its source files via the Python CST parser, and returns
20
+ // a map of exported function names. Used by markUsedVulnFunctions
21
+ // to validate that OSV-named vulnerable functions actually exist
22
+ // in the installed version.
23
+
24
+
25
+
26
+
27
+
28
+
29
+ const VENV_DIRS = ['.venv', 'venv', '.env', 'env'];
30
+
31
+ function _findSitePackages(scanRoot) {
32
+ for (const vdir of VENV_DIRS) {
33
+ const base = node_path__WEBPACK_IMPORTED_MODULE_1__.join(scanRoot || '.', vdir);
34
+ if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(base)) continue;
35
+ const lib = node_path__WEBPACK_IMPORTED_MODULE_1__.join(base, 'lib');
36
+ if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(lib)) continue;
37
+ const pydirs = node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync(lib).filter(d => d.startsWith('python'));
38
+ for (const pydir of pydirs) {
39
+ const sp = node_path__WEBPACK_IMPORTED_MODULE_1__.join(lib, pydir, 'site-packages');
40
+ if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sp)) return sp;
41
+ }
42
+ }
43
+ // Fallback: ask python3 directly
44
+ try {
45
+ const out = (0,node_child_process__WEBPACK_IMPORTED_MODULE_2__.execFileSync)('python3', ['-c', 'import site; print(site.getsitepackages()[0])'], {
46
+ encoding: 'utf8', timeout: 5000,
47
+ }).trim();
48
+ if (out && node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(out)) return out;
49
+ } catch { /* no python3 or no site-packages */ }
50
+ return null;
51
+ }
52
+
53
+ function _findPackageDir(sitePackages, packageName) {
54
+ if (!sitePackages) return null;
55
+ const normalized = packageName.replace(/-/g, '_').toLowerCase();
56
+ const candidates = [
57
+ normalized,
58
+ packageName.toLowerCase(),
59
+ packageName,
60
+ ];
61
+ for (const name of candidates) {
62
+ const dir = node_path__WEBPACK_IMPORTED_MODULE_1__.join(sitePackages, name);
63
+ if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(dir) && node_fs__WEBPACK_IMPORTED_MODULE_0__.statSync(dir).isDirectory()) return dir;
64
+ }
65
+ return null;
66
+ }
67
+
68
+ function _readPyFilesFromDir(dir, maxFiles = 50) {
69
+ const entries = [];
70
+ try {
71
+ const files = node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync(dir, { recursive: true })
72
+ .filter(f => f.endsWith('.py'))
73
+ .slice(0, maxFiles);
74
+ for (const f of files) {
75
+ const fp = node_path__WEBPACK_IMPORTED_MODULE_1__.join(dir, f);
76
+ try {
77
+ const content = node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(fp, 'utf8');
78
+ if (content.length < 1_000_000) {
79
+ entries.push({ file: f, content });
80
+ }
81
+ } catch { /* skip unreadable files */ }
82
+ }
83
+ } catch { /* dir not readable */ }
84
+ return entries;
85
+ }
86
+
87
+ function extractPythonPackageFunctions(packageName, scanRoot) {
88
+ const cap = (0,_ir_parser_py_cst_js__WEBPACK_IMPORTED_MODULE_3__/* .probePythonAvailable */ .w4)();
89
+ if (!cap.ok) return null;
90
+
91
+ const sitePackages = _findSitePackages(scanRoot);
92
+ const pkgDir = _findPackageDir(sitePackages, packageName);
93
+ if (!pkgDir) return null;
94
+
95
+ const pyFiles = _readPyFilesFromDir(pkgDir);
96
+ if (!pyFiles.length) return null;
97
+
98
+ const batch = (0,_ir_parser_py_cst_js__WEBPACK_IMPORTED_MODULE_3__/* .parsePythonFilesBatch */ .H2)(pyFiles);
99
+ if (!batch || !Array.isArray(batch)) return null;
100
+
101
+ const functionMap = new Map();
102
+ for (const fileIR of batch) {
103
+ if (!fileIR || !fileIR.functions) continue;
104
+ for (const fn of fileIR.functions) {
105
+ if (fn.name && !fn.name.startsWith('_')) {
106
+ functionMap.set(fn.name, {
107
+ file: fileIR.file,
108
+ line: fn.line,
109
+ qid: fn.qid,
110
+ params: fn.params,
111
+ });
112
+ }
113
+ }
114
+ }
115
+ return functionMap;
116
+ }
117
+
118
+ function validateOsvFunctionsExist(packageName, osvFunctions, scanRoot) {
119
+ if (!osvFunctions || !osvFunctions.length) return { validated: [], missing: [] };
120
+ const fnMap = extractPythonPackageFunctions(packageName, scanRoot);
121
+ if (!fnMap) return { validated: osvFunctions, missing: [] };
122
+ const validated = [];
123
+ const missing = [];
124
+ for (const fn of osvFunctions) {
125
+ const shortFn = fn.includes('.') ? fn.split('.').pop() : fn;
126
+ if (fnMap.has(shortFn) || fnMap.has(fn)) {
127
+ validated.push(shortFn);
128
+ } else {
129
+ missing.push(fn);
130
+ }
131
+ }
132
+ return { validated, missing };
133
+ }
134
+
135
+
136
+ /***/ })
137
+
138
+ };
package/dist/718.index.js CHANGED
@@ -97,6 +97,59 @@ function detectVendoredLibraries(fileContents) {
97
97
  }
98
98
  }
99
99
  }
100
+ // Pass 2: Function-body structural matching for minified/forked copies
101
+ const FUNCTION_BODY_SIGS = [
102
+ { pkg: 'lodash', ecosystem: 'npm', fn: 'merge', paramMin: 1,
103
+ bodyContains: ['assignValue', 'baseFor', 'isObject', 'baseMerge'] },
104
+ { pkg: 'lodash', ecosystem: 'npm', fn: 'template', paramMin: 1,
105
+ bodyContains: ['sourceURL', 'interpolate', 'evaluate', 'escape'] },
106
+ { pkg: 'lodash', ecosystem: 'npm', fn: 'defaultsDeep', paramMin: 1,
107
+ bodyContains: ['baseMerge', 'isMergeableObject', 'customDefaultsMerge'] },
108
+ { pkg: 'jquery', ecosystem: 'npm', fn: 'ajax', paramMin: 1,
109
+ bodyContains: ['XMLHttpRequest', 'ajaxSettings', 'crossDomain', 'responseFields'] },
110
+ { pkg: 'handlebars', ecosystem: 'npm', fn: 'compile', paramMin: 1,
111
+ bodyContains: ['templateSpec', 'container', 'invokePartial', 'blockParams'] },
112
+ { pkg: 'marked', ecosystem: 'npm', fn: 'parse', paramMin: 1,
113
+ bodyContains: ['Lexer', 'Parser', 'blockTokens', 'walkTokens'] },
114
+ { pkg: 'ejs', ecosystem: 'npm', fn: 'render', paramMin: 1,
115
+ bodyContains: ['includeFile', 'resolveInclude', 'rethrow', 'escapeFn'] },
116
+ { pkg: 'moment', ecosystem: 'npm', fn: 'format', paramMin: 0,
117
+ bodyContains: ['formatMoment', 'expandFormat', 'makeFormatFunction', 'localFormattingTokens'] },
118
+ { pkg: 'underscore', ecosystem: 'npm', fn: 'template', paramMin: 1,
119
+ bodyContains: ['interpolate', 'evaluate', 'escape', 'templateSettings'] },
120
+ { pkg: 'minimist', ecosystem: 'npm', fn: 'parse', paramMin: 1,
121
+ bodyContains: ['boolean', 'alias', 'default', 'stopEarly', 'unknown'] },
122
+ ];
123
+
124
+ for (const [fp, content] of Object.entries(fileContents)) {
125
+ if (!content || typeof content !== 'string') continue;
126
+ if (SKIP_DIRS.test(fp)) continue;
127
+ if (!/\.(?:js|mjs|cjs)$/i.test(fp)) continue;
128
+ if (content.length < 200 || content.length > 500_000) continue;
129
+
130
+ for (const sig of FUNCTION_BODY_SIGS) {
131
+ const key = `${sig.pkg}:${fp}`;
132
+ if (seen.has(key)) continue;
133
+ const fnRe = new RegExp(`(?:function\\s+${sig.fn}|(?:const|let|var)\\s+${sig.fn}\\s*=|${sig.fn}\\s*[:=]\\s*function)\\s*\\(`, 'g');
134
+ const m = fnRe.exec(content);
135
+ if (!m) continue;
136
+ const bodyWindow = content.slice(m.index, m.index + 2000);
137
+ const matchCount = sig.bodyContains.filter(kw => bodyWindow.includes(kw)).length;
138
+ if (matchCount < Math.ceil(sig.bodyContains.length * 0.6)) continue;
139
+ seen.add(key);
140
+ detected.push({
141
+ name: sig.pkg,
142
+ version: 'unknown',
143
+ ecosystem: sig.ecosystem,
144
+ file: fp,
145
+ scope: 'vendored',
146
+ isVendored: true,
147
+ _detectionMethod: 'function-body-signature',
148
+ _matchedKeywords: matchCount,
149
+ });
150
+ }
151
+ }
152
+
100
153
  return detected;
101
154
  }
102
155
 
package/dist/838.index.js CHANGED
@@ -14,7 +14,7 @@ __webpack_require__.r(__webpack_exports__);
14
14
  /* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1421);
15
15
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3024);
16
16
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6760);
17
- /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8636);
17
+ /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9072);
18
18
  // Closed-loop /fix verification (Sentinel-parity FR-L4-4, FR-L4-5).
19
19
  //
20
20
  // Given a candidate patch (the new file content + the finding stableId being