@clear-capabilities/agentic-security-scanner 0.168.0 → 0.170.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 (42) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/bin/agentic-security.js +567 -0
  3. package/dist/2199.index.js +1 -1
  4. package/dist/2675.index.js +174 -0
  5. package/dist/2923.index.js +369 -1
  6. package/dist/4142.index.js +6 -6
  7. package/dist/4700.index.js +151 -0
  8. package/dist/5014.index.js +2 -2
  9. package/dist/5086.index.js +645 -0
  10. package/dist/5144.index.js +2 -2
  11. package/dist/5206.index.js +32 -0
  12. package/dist/642.index.js +197 -0
  13. package/dist/6447.index.js +131 -0
  14. package/dist/6645.index.js +87 -0
  15. package/dist/6730.index.js +2 -2
  16. package/dist/6932.index.js +2 -2
  17. package/dist/7055.index.js +369 -0
  18. package/dist/7232.index.js +24 -0
  19. package/dist/7552.index.js +2 -2
  20. package/dist/7952.index.js +301 -0
  21. package/dist/8714.index.js +2 -2
  22. package/dist/9102.index.js +110 -0
  23. package/dist/9800.index.js +1 -1
  24. package/dist/agentic-security.mjs +2 -2
  25. package/dist/agentic-security.mjs.sha256 +1 -1
  26. package/package.json +3 -3
  27. package/src/artifact/CLAUDE.md +100 -0
  28. package/src/artifact/filesystem.js +100 -0
  29. package/src/artifact/image-archive.js +159 -0
  30. package/src/artifact/inventory.js +69 -0
  31. package/src/artifact/layer-secrets.js +92 -0
  32. package/src/artifact/mismatch.js +72 -0
  33. package/src/artifact/provenance-graph.js +115 -0
  34. package/src/artifact/safe-tar.js +175 -0
  35. package/src/artifact/signature.js +156 -0
  36. package/src/artifact/vex.js +94 -0
  37. package/src/artifact/vuln-correlate.js +17 -0
  38. package/src/lineage/CLAUDE.md +19 -0
  39. package/src/lineage/observation-adapters.js +368 -0
  40. package/src/lineage/runtime-assurance.js +135 -0
  41. package/src/lineage/runtime-observation.js +37 -4
  42. package/src/posture/artifact-registry.js +8 -0
@@ -0,0 +1,151 @@
1
+ export const id = 4700;
2
+ export const ids = [4700];
3
+ export const modules = {
4
+
5
+ /***/ 94700:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
+ /* harmony export */ computeRuntimeAssurance: () => (/* binding */ computeRuntimeAssurance)
10
+ /* harmony export */ });
11
+ /* unused harmony export RUNTIME_STATUS_VALUES */
12
+ // runtime-assurance.js — PRD "Runtime-Corroborated Security Twin" P0-8
13
+ // (Runtime Assurance). A pure aggregation over already-loaded observation
14
+ // imports and an already-computed `correlateObservations` result — never
15
+ // re-reads a file, never re-runs the match ladder. Honest by construction:
16
+ // the one rule this module exists to enforce is that a MISSING or STALE
17
+ // telemetry source can never collapse into "no runtime risk" — the
18
+ // `runtimeStatus` field is always exactly one of `'complete'`, `'partial'`,
19
+ // or `'unavailable'`, and `'unavailable'` is the answer whenever no
20
+ // observation store was consulted at all, never a silent empty report.
21
+ //
22
+ // `parseFailures` is always reported as 0, with an explicit note why:
23
+ // `dataflow observations import` REFUSES the whole import the moment any
24
+ // record fails to parse or validate (AC-29 clause 5) — a failed import is
25
+ // never persisted, so there is no on-disk history of parse failures for
26
+ // this module to read. This is a real, disclosed limitation, not a false
27
+ // "zero failures ever happened" claim.
28
+
29
+ const RUNTIME_STATUS_VALUES = Object.freeze(['complete', 'partial', 'unavailable']);
30
+
31
+ function _isPlainObject(v) {
32
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
33
+ }
34
+
35
+ function _maxIso(list) {
36
+ let best = null;
37
+ let bestT = -Infinity;
38
+ for (const s of list) {
39
+ const t = Date.parse(s);
40
+ if (Number.isFinite(t) && t > bestT) { bestT = t; best = s; }
41
+ }
42
+ return best;
43
+ }
44
+
45
+ function _minIso(list) {
46
+ let best = null;
47
+ let bestT = Infinity;
48
+ for (const s of list) {
49
+ const t = Date.parse(s);
50
+ if (Number.isFinite(t) && t < bestT) { bestT = t; best = s; }
51
+ }
52
+ return best;
53
+ }
54
+
55
+ /**
56
+ * `computeRuntimeAssurance(opts) -> RuntimeAssurance`
57
+ *
58
+ * `opts`:
59
+ * - `importRecords`: the `ObservationImport[]` read back from the store
60
+ * (`loadObservationImports`), or `null`/`undefined` when the store was
61
+ * never consulted at all (mirrors `correlateObservations`'s own
62
+ * `observations === null` convention).
63
+ * - `correlation`: the `CorrelationResult` from `correlateObservations`
64
+ * for the SAME graph/observations/window this call is reporting on.
65
+ * - `now`: an ISO-8601 string (defaults to `new Date().toISOString()`,
66
+ * injectable for deterministic tests).
67
+ * - `staleAfterHours`: how old the most recent observed event can be
68
+ * before freshness is reported stale (default 24 * 30 = 720, i.e. 30
69
+ * days — telemetry windows in this package's own fixtures/CLI default
70
+ * to month-long exports, so a 30-day staleness bar is the honest
71
+ * "this is still describing roughly the current system" line, not an
72
+ * arbitrary short window).
73
+ *
74
+ * Never throws.
75
+ */
76
+ function computeRuntimeAssurance(opts) {
77
+ const o = opts && typeof opts === 'object' ? opts : {};
78
+ const now = typeof o.now === 'string' && Number.isFinite(Date.parse(o.now)) ? o.now : new Date().toISOString();
79
+ const staleAfterHours = Number.isFinite(o.staleAfterHours) ? o.staleAfterHours : 720;
80
+
81
+ const importRecords = Array.isArray(o.importRecords) ? o.importRecords : null;
82
+ const correlation = _isPlainObject(o.correlation) ? o.correlation : null;
83
+
84
+ const base = {
85
+ runtimeStatus: 'unavailable',
86
+ telemetryWindow: { start: null, end: null },
87
+ freshness: { lastObservedAt: null, lastImportedAt: null, staleHours: null, stale: true },
88
+ parseFailures: 0,
89
+ parseFailuresNote: 'A failed import is refused in full and never persisted (AC-29 clause 5) — '
90
+ + 'this count reflects the import store, not the history of every attempt. Check `runtime ingest`\'s '
91
+ + 'own exit code/stderr at import time for parse failures.',
92
+ mappingPercentage: null,
93
+ unmatchedObservationCount: 0,
94
+ totalObservationCount: 0,
95
+ missingTelemetry: true,
96
+ limitations: [],
97
+ };
98
+
99
+ // No store was ever consulted — the honest 'unavailable' case, never a
100
+ // fabricated empty-but-fine report.
101
+ if (importRecords === null || importRecords.length === 0 || !correlation || correlation.evaluated !== true) {
102
+ base.limitations.push(
103
+ 'No runtime observation import exists for this scan — runtimeStatus is \'unavailable\', never \'complete\' '
104
+ + 'or a silent absence of risk. Import telemetry with `runtime ingest` before relying on this report.',
105
+ );
106
+ return base;
107
+ }
108
+
109
+ const windowStart = _minIso(importRecords.map((r) => r?.windowStart));
110
+ const windowEnd = _maxIso(importRecords.map((r) => r?.windowEnd));
111
+ base.telemetryWindow = { start: windowStart, end: windowEnd };
112
+ base.missingTelemetry = false;
113
+
114
+ const allObservations = importRecords.flatMap((r) => (Array.isArray(r?.observations) ? r.observations : []));
115
+ const total = allObservations.length;
116
+ const unmatched = allObservations.filter((obs) => obs && obs.matchMethod === 'unmatched').length;
117
+ base.totalObservationCount = total;
118
+ base.unmatchedObservationCount = unmatched;
119
+ base.mappingPercentage = total > 0 ? Math.round(((total - unmatched) / total) * 10000) / 100 : null;
120
+
121
+ const lastObservedAt = _maxIso(allObservations.map((obs) => obs?.lastObservedAt));
122
+ const lastImportedAt = _maxIso(importRecords.map((r) => r?.importedAt));
123
+ base.freshness.lastObservedAt = lastObservedAt;
124
+ base.freshness.lastImportedAt = lastImportedAt;
125
+ if (lastObservedAt !== null) {
126
+ const ageMs = Date.parse(now) - Date.parse(lastObservedAt);
127
+ const ageHours = Math.round((ageMs / 3600000) * 100) / 100;
128
+ base.freshness.staleHours = ageHours;
129
+ base.freshness.stale = ageHours > staleAfterHours;
130
+ }
131
+
132
+ if (total === 0) {
133
+ base.limitations.push('The import store exists but carries zero observation records.');
134
+ }
135
+ if (unmatched > 0) {
136
+ base.limitations.push(`${unmatched} of ${total} imported observation(s) never matched any graph node (matchMethod 'unmatched') — these contribute no corroboration to any flow.`);
137
+ }
138
+ if (base.freshness.stale) {
139
+ base.limitations.push(`The most recent observed event is ${base.freshness.staleHours} hour(s) old (beyond the ${staleAfterHours}-hour staleness bar) — this twin may no longer describe current production behavior.`);
140
+ }
141
+
142
+ const complete = total > 0 && unmatched === 0 && !base.freshness.stale;
143
+ base.runtimeStatus = complete ? 'complete' : 'partial';
144
+
145
+ return base;
146
+ }
147
+
148
+
149
+ /***/ })
150
+
151
+ };
@@ -136,7 +136,7 @@ function addLegalHold(scanRoot, { artifact, owner, reason, expires_at } = {}) {
136
136
  const holds = _loadRaw(scanRoot);
137
137
  holds.push(hold);
138
138
  const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.statePath)(scanRoot, LEGAL_HOLD_FILE);
139
- if (!(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__/* .safeWriteState */ .Ep)(fp, JSON.stringify(holds, null, 2) + '\n')) {
139
+ if (!(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.safeWriteState)(fp, JSON.stringify(holds, null, 2) + '\n')) {
140
140
  return { ok: false, reason: 'state writes are disabled (--no-state) or this is not a safe state directory' };
141
141
  }
142
142
  return { ok: true, hold };
@@ -152,7 +152,7 @@ function removeLegalHold(scanRoot, artifact) {
152
152
  const removedCount = holds.length - remaining.length;
153
153
  if (removedCount > 0) {
154
154
  const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.statePath)(scanRoot, LEGAL_HOLD_FILE);
155
- (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__/* .safeWriteState */ .Ep)(fp, JSON.stringify(remaining, null, 2) + '\n');
155
+ (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.safeWriteState)(fp, JSON.stringify(remaining, null, 2) + '\n');
156
156
  }
157
157
  return removedCount;
158
158
  }