@clear-capabilities/agentic-security-scanner 0.124.1 → 0.128.1

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 (40) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/bin/agentic-security.js +75 -2
  3. package/dist/11.index.js +353 -0
  4. package/dist/113.index.js +525 -0
  5. package/dist/178.index.js +1 -1
  6. package/dist/220.index.js +193 -0
  7. package/dist/384.index.js +1 -1
  8. package/dist/435.index.js +2406 -0
  9. package/dist/449.index.js +135 -0
  10. package/dist/637.index.js +1 -1
  11. package/dist/752.index.js +7 -4
  12. package/dist/801.index.js +87 -0
  13. package/dist/826.index.js +4 -1
  14. package/dist/838.index.js +1 -1
  15. package/dist/agentic-security.mjs +1 -2
  16. package/dist/agentic-security.mjs.sha256 +1 -1
  17. package/package.json +6 -6
  18. package/src/engine.js +31 -1
  19. package/src/integrations/tickets.js +9 -3
  20. package/src/ir/CLAUDE.md +22 -17
  21. package/src/llm-validator/index.js +47 -12
  22. package/src/mcp/tools.js +108 -3
  23. package/src/posture/CLAUDE.md +10 -1
  24. package/src/posture/cache-economics.js +7 -4
  25. package/src/posture/deterministic-fix.js +65 -0
  26. package/src/posture/entrypoint-inventory.js +248 -0
  27. package/src/posture/falsification.js +121 -0
  28. package/src/posture/fix-honesty-gate.js +175 -0
  29. package/src/posture/fix-verify.js +18 -3
  30. package/src/posture/model-routing.js +126 -0
  31. package/src/posture/mttr.js +25 -0
  32. package/src/posture/provider-catalog.js +108 -0
  33. package/src/posture/root-cause-sweep.js +262 -0
  34. package/src/posture/secret-live-check.js +71 -0
  35. package/src/pr-comment.js +3 -1
  36. package/src/sast/CLAUDE.md +1 -1
  37. package/src/sast/api-authz.js +36 -0
  38. package/src/sast/file-upload.js +118 -0
  39. package/src/sast/llm-cost-advisor.js +88 -0
  40. package/src/util/untrusted.js +148 -0
@@ -0,0 +1,193 @@
1
+ export const id = 220;
2
+ export const ids = [220];
3
+ export const modules = {
4
+
5
+ /***/ 9220:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
+ /* harmony export */ computeDelta: () => (/* binding */ computeDelta),
10
+ /* harmony export */ persistStatus: () => (/* binding */ persistStatus),
11
+ /* harmony export */ renderStatusLine: () => (/* binding */ renderStatusLine),
12
+ /* harmony export */ watchProject: () => (/* binding */ watchProject)
13
+ /* harmony export */ });
14
+ /* unused harmony exports readStatus, _internals */
15
+ /* harmony import */ var node_fs_promises__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1455);
16
+ /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3024);
17
+ /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6760);
18
+ // Watch mode — continuous incremental scan as the developer edits.
19
+ //
20
+ // Spawns a long-running scan watcher that:
21
+ // 1. Subscribes to file-system events under the project root
22
+ // 2. When a file matching the scan glob changes, re-scans incrementally
23
+ // using dataflow/incremental-cache.js (per-file cache hits avoid the
24
+ // full IR build)
25
+ // 3. Diffs against the prior scan to compute a "risk delta" string
26
+ // (added/removed/changed criticals + highs)
27
+ // 4. Writes the delta to .agentic-security/watch-status.{md,json}
28
+ //
29
+ // The Claude Code statusline / a chat command can poll watch-status.md
30
+ // (cheap file read) to surface the delta inline without re-running anything.
31
+ //
32
+ // Implementation is deliberately node-only — no chokidar dep, uses
33
+ // fs.promises.watch (Node ≥ 20). Debounces to 350ms.
34
+ //
35
+ // Lifecycle: start() returns an AbortController-like handle. The caller
36
+ // (a /watch slash command or a long-running daemon spawn) is responsible
37
+ // for keeping the process alive; this module is the pure logic.
38
+
39
+
40
+
41
+
42
+
43
+ const STATE = '.agentic-security';
44
+ const STATUS_MD = 'watch-status.md';
45
+ const STATUS_JSON = 'watch-status.json';
46
+ const DEBOUNCE_MS = 350;
47
+ const MAX_BURST = 50; // ignore beyond this # of rapid events
48
+
49
+ const SCAN_EXT_RE = /\.(?:[jt]sx?|mjs|cjs|py|java|kt|go|rb|php|cs|c|cc|cpp|h|hpp|rs|sol|vy|swift|dart|toml|yml|yaml|json|tf|tfvars|bicep)$/i;
50
+ const IGNORE_DIR_RE = /(?:^|\/)(?:\.git|node_modules|\.bench-cache|dist|build|\.next|coverage|\.agentic-security)(?:$|\/)/;
51
+
52
+ function _isScanable(rel) {
53
+ if (!rel || IGNORE_DIR_RE.test(rel)) return false;
54
+ return SCAN_EXT_RE.test(rel);
55
+ }
56
+
57
+ function _readJsonSafe(fp) {
58
+ try { return JSON.parse(fsSync.readFileSync(fp, 'utf8')); } catch { return null; }
59
+ }
60
+
61
+ function _sevRank(s) { return ['info', 'low', 'medium', 'high', 'critical'].indexOf(s) + 1; }
62
+
63
+ /**
64
+ * Pure delta computation between two finding arrays. Same logic
65
+ * baseline-compare uses, surfaced as a single ASCII status line.
66
+ */
67
+ function computeDelta(prevFindings, currFindings) {
68
+ const key = (f) => `${f.file || ''}::${f.line || 0}::${f.family || f.parser || ''}`;
69
+ const prev = new Map();
70
+ for (const f of prevFindings || []) prev.set(key(f), f);
71
+ const cur = new Map();
72
+ for (const f of currFindings || []) cur.set(key(f), f);
73
+ const added = [], removed = [];
74
+ for (const [k, f] of cur) if (!prev.has(k)) added.push(f);
75
+ for (const [k, f] of prev) if (!cur.has(k)) removed.push(f);
76
+ const newCrit = added.filter(f => f.severity === 'critical').length;
77
+ const newHigh = added.filter(f => f.severity === 'high').length;
78
+ const fixedCrit = removed.filter(f => f.severity === 'critical').length;
79
+ const fixedHigh = removed.filter(f => f.severity === 'high').length;
80
+ return {
81
+ addedCount: added.length, removedCount: removed.length,
82
+ newCritical: newCrit, newHigh, fixedCritical: fixedCrit, fixedHigh,
83
+ added, removed,
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Render a one-line status string for the Claude Code statusline.
89
+ */
90
+ function renderStatusLine(delta) {
91
+ const parts = [];
92
+ if (delta.newCritical) parts.push(`🛑 +${delta.newCritical} crit`);
93
+ if (delta.newHigh) parts.push(`⚠️ +${delta.newHigh} high`);
94
+ if (delta.fixedCritical) parts.push(`✅ -${delta.fixedCritical} crit`);
95
+ if (delta.fixedHigh) parts.push(`✅ -${delta.fixedHigh} high`);
96
+ if (!parts.length && (delta.addedCount + delta.removedCount) === 0) return 'agentic-security: clean';
97
+ if (!parts.length) return `agentic-security: +${delta.addedCount} / -${delta.removedCount}`;
98
+ return 'agentic-security: ' + parts.join(' · ');
99
+ }
100
+
101
+ /**
102
+ * Persist watch-status.{md,json}. Cheap atomic write (write tmp, rename).
103
+ */
104
+ function persistStatus(scanRoot, delta) {
105
+ const dir = node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, STATE);
106
+ try { node_fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(dir, { recursive: true }); } catch {}
107
+ const status = {
108
+ ts: new Date().toISOString(),
109
+ line: renderStatusLine(delta),
110
+ delta: {
111
+ addedCount: delta.addedCount, removedCount: delta.removedCount,
112
+ newCritical: delta.newCritical, newHigh: delta.newHigh,
113
+ fixedCritical: delta.fixedCritical, fixedHigh: delta.fixedHigh,
114
+ },
115
+ addedTop5: (delta.added || []).slice(0, 5).map(f => ({
116
+ file: f.file, line: f.line, family: f.family, severity: f.severity, vuln: f.vuln,
117
+ })),
118
+ };
119
+ const jsonPath = node_path__WEBPACK_IMPORTED_MODULE_2__.join(dir, STATUS_JSON);
120
+ const mdPath = node_path__WEBPACK_IMPORTED_MODULE_2__.join(dir, STATUS_MD);
121
+ try { node_fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(jsonPath, JSON.stringify(status, null, 2)); } catch {}
122
+ const md = [
123
+ `# Watch status — ${status.ts.slice(11, 19)} UTC`,
124
+ '',
125
+ status.line,
126
+ '',
127
+ ];
128
+ if (status.addedTop5.length) {
129
+ md.push('## New findings');
130
+ for (const f of status.addedTop5) {
131
+ md.push(`- **[${(f.severity || '?').toUpperCase()}]** ${f.vuln || f.family || 'finding'} — \`${f.file}:${f.line}\``);
132
+ }
133
+ }
134
+ try { node_fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(mdPath, md.join('\n')); } catch {}
135
+ return status;
136
+ }
137
+
138
+ /**
139
+ * Read the latest watch-status (returns null if none).
140
+ */
141
+ function readStatus(scanRoot) {
142
+ return _readJsonSafe(path.join(scanRoot, STATE, STATUS_JSON));
143
+ }
144
+
145
+ /**
146
+ * Subscribe to FS events and call onChange(absPath, eventType) for each
147
+ * matching event. Debounces bursts. Returns a controller with stop().
148
+ *
149
+ * The actual incremental scan call lives in the caller — this module
150
+ * stays pure for testability.
151
+ */
152
+ async function watchProject(scanRoot, onChange, opts = {}) {
153
+ if (process.env.AGENTIC_SECURITY_NO_WATCH === '1') return { stop: async () => {}, _disabled: true };
154
+ const recursive = opts.recursive !== false;
155
+ const ac = new AbortController();
156
+ let timer = null;
157
+ const pending = new Set();
158
+ const flush = () => {
159
+ timer = null;
160
+ if (pending.size > MAX_BURST) { pending.clear(); return; }
161
+ const batch = Array.from(pending);
162
+ pending.clear();
163
+ try { onChange(batch); } catch {}
164
+ };
165
+ let stopped = false;
166
+ (async () => {
167
+ try {
168
+ for await (const evt of node_fs_promises__WEBPACK_IMPORTED_MODULE_0__.watch(scanRoot, { recursive, signal: ac.signal })) {
169
+ if (stopped) break;
170
+ const rel = String(evt.filename || '').replace(/\\/g, '/');
171
+ if (!_isScanable(rel)) continue;
172
+ pending.add(node_path__WEBPACK_IMPORTED_MODULE_2__.join(scanRoot, rel));
173
+ if (timer) clearTimeout(timer);
174
+ timer = setTimeout(flush, DEBOUNCE_MS);
175
+ }
176
+ } catch (e) {
177
+ if (e && e.name !== 'AbortError') {
178
+ // Surface but don't crash — caller decides how to handle.
179
+ try { onChange([], e); } catch {}
180
+ }
181
+ }
182
+ })();
183
+ return {
184
+ stop: async () => { stopped = true; ac.abort(); if (timer) clearTimeout(timer); },
185
+ };
186
+ }
187
+
188
+ const _internals = { _isScanable, SCAN_EXT_RE, IGNORE_DIR_RE };
189
+
190
+
191
+ /***/ })
192
+
193
+ };
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__(5099);
11
+ /* harmony import */ var _engine_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8215);
12
12
  // Secrets submodule view of the engine — credential + entropy + TODO scanning.
13
13
 
14
14