@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.
- package/CHANGELOG.md +74 -0
- package/bin/agentic-security.js +567 -0
- package/dist/2199.index.js +1 -1
- package/dist/2675.index.js +174 -0
- package/dist/2923.index.js +369 -1
- package/dist/4142.index.js +6 -6
- package/dist/4700.index.js +151 -0
- package/dist/5014.index.js +2 -2
- package/dist/5086.index.js +645 -0
- package/dist/5144.index.js +2 -2
- package/dist/5206.index.js +32 -0
- package/dist/642.index.js +197 -0
- package/dist/6447.index.js +131 -0
- package/dist/6645.index.js +87 -0
- package/dist/6730.index.js +2 -2
- package/dist/6932.index.js +2 -2
- package/dist/7055.index.js +369 -0
- package/dist/7232.index.js +24 -0
- package/dist/7552.index.js +2 -2
- package/dist/7952.index.js +301 -0
- package/dist/8714.index.js +2 -2
- package/dist/9102.index.js +110 -0
- package/dist/9800.index.js +1 -1
- package/dist/agentic-security.mjs +2 -2
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +3 -3
- package/src/artifact/CLAUDE.md +100 -0
- package/src/artifact/filesystem.js +100 -0
- package/src/artifact/image-archive.js +159 -0
- package/src/artifact/inventory.js +69 -0
- package/src/artifact/layer-secrets.js +92 -0
- package/src/artifact/mismatch.js +72 -0
- package/src/artifact/provenance-graph.js +115 -0
- package/src/artifact/safe-tar.js +175 -0
- package/src/artifact/signature.js +156 -0
- package/src/artifact/vex.js +94 -0
- package/src/artifact/vuln-correlate.js +17 -0
- package/src/lineage/CLAUDE.md +19 -0
- package/src/lineage/observation-adapters.js +368 -0
- package/src/lineage/runtime-assurance.js +135 -0
- package/src/lineage/runtime-observation.js +37 -4
- 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
|
+
};
|
package/dist/5014.index.js
CHANGED
|
@@ -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__
|
|
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__
|
|
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
|
}
|