@clear-capabilities/agentic-security-scanner 0.144.0 → 0.147.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 (209) hide show
  1. package/CHANGELOG.md +390 -0
  2. package/bin/agentic-security.js +3813 -83
  3. package/dist/1122.index.js +702 -0
  4. package/dist/{301.index.js → 1301.index.js} +2 -2
  5. package/dist/1379.index.js +591 -0
  6. package/dist/{444.index.js → 1444.index.js} +13 -4
  7. package/dist/{660.index.js → 1660.index.js} +2 -2
  8. package/dist/{700.index.js → 1700.index.js} +2 -2
  9. package/dist/{905.index.js → 1905.index.js} +3 -3
  10. package/dist/{920.index.js → 1920.index.js} +3 -3
  11. package/dist/{238.index.js → 2238.index.js} +3 -3
  12. package/dist/2271.index.js +165 -0
  13. package/dist/{985.index.js → 2376.index.js} +1260 -340
  14. package/dist/2432.index.js +793 -0
  15. package/dist/2659.index.js +93 -0
  16. package/dist/{826.index.js → 2826.index.js} +2 -2
  17. package/dist/{830.index.js → 2830.index.js} +2 -2
  18. package/dist/2923.index.js +298 -0
  19. package/dist/{1.index.js → 3001.index.js} +5 -5
  20. package/dist/{117.index.js → 3117.index.js} +3 -3
  21. package/dist/3180.index.js +307 -0
  22. package/dist/3276.index.js +117 -0
  23. package/dist/{415.index.js → 3415.index.js} +2 -2
  24. package/dist/{499.index.js → 3499.index.js} +2 -2
  25. package/dist/3518.index.js +450 -0
  26. package/dist/{526.index.js → 3526.index.js} +14 -6
  27. package/dist/{736.index.js → 3736.index.js} +4 -4
  28. package/dist/{839.index.js → 3839.index.js} +4 -4
  29. package/dist/{113.index.js → 4113.index.js} +14 -6
  30. package/dist/{265.index.js → 4265.index.js} +2 -2
  31. package/dist/{384.index.js → 4384.index.js} +3 -3
  32. package/dist/4547.index.js +268 -0
  33. package/dist/4863.index.js +422 -0
  34. package/dist/{970.index.js → 4970.index.js} +67 -3
  35. package/dist/5051.index.js +770 -0
  36. package/dist/{144.index.js → 5144.index.js} +5 -5
  37. package/dist/{333.index.js → 5333.index.js} +3 -3
  38. package/dist/5343.index.js +185 -0
  39. package/dist/5350.index.js +866 -0
  40. package/dist/5561.index.js +436 -0
  41. package/dist/{637.index.js → 5637.index.js} +29 -7
  42. package/dist/{449.index.js → 5830.index.js} +78 -14
  43. package/dist/6626.index.js +532 -0
  44. package/dist/6662.index.js +297 -0
  45. package/dist/{675.index.js → 6675.index.js} +5 -5
  46. package/dist/{730.index.js → 6730.index.js} +6 -6
  47. package/dist/6829.index.js +225 -0
  48. package/dist/6944.index.js +130 -0
  49. package/dist/{178.index.js → 7178.index.js} +26 -8
  50. package/dist/{227.index.js → 7227.index.js} +2 -2
  51. package/dist/7310.index.js +520 -0
  52. package/dist/{552.index.js → 7552.index.js} +4 -4
  53. package/dist/7709.index.js +78 -0
  54. package/dist/8218.index.js +160 -0
  55. package/dist/{476.index.js → 8476.index.js} +4 -4
  56. package/dist/{513.index.js → 8513.index.js} +5 -5
  57. package/dist/{520.index.js → 8520.index.js} +2 -2
  58. package/dist/{718.index.js → 8718.index.js} +2 -2
  59. package/dist/{752.index.js → 8752.index.js} +2 -2
  60. package/dist/8846.index.js +100 -0
  61. package/dist/{435.index.js → 9091.index.js} +580 -187
  62. package/dist/{207.index.js → 9207.index.js} +2 -2
  63. package/dist/{220.index.js → 9220.index.js} +2 -2
  64. package/dist/9390.index.js +163 -0
  65. package/dist/{503.index.js → 9503.index.js} +2 -2
  66. package/dist/{801.index.js → 9801.index.js} +2 -2
  67. package/dist/{824.index.js → 9824.index.js} +2 -2
  68. package/dist/agentic-security.mjs +16 -16
  69. package/dist/agentic-security.mjs.sha256 +1 -1
  70. package/dist/compliance-frameworks/hipaa-security-rule.json +3 -2
  71. package/package.json +23 -10
  72. package/src/compare.js +6 -1
  73. package/src/dataflow/CLAUDE.md +2 -2
  74. package/src/dataflow/catalog.js +42 -0
  75. package/src/dataflow/orm-write-catalog.js +175 -0
  76. package/src/engine.js +580 -30
  77. package/src/fix/apply-fix-service.js +1 -0
  78. package/src/history-scan.js +22 -5
  79. package/src/ir/CLAUDE.md +2 -1
  80. package/src/ir/chrome-probe.mjs +150 -0
  81. package/src/ir/parser-js.js +94 -7
  82. package/src/lineage/CLAUDE.md +1203 -0
  83. package/src/lineage/DESIGN_DESTINATION_RESOLVER.md +156 -0
  84. package/src/lineage/DESIGN_GRAPH_BUILDER.md +938 -0
  85. package/src/lineage/DESIGN_HANDLING_ANALYZER.md +355 -0
  86. package/src/lineage/DESIGN_INTRAPROCEDURAL.md +628 -0
  87. package/src/lineage/DESIGN_PATH_PROVENANCE.md +3451 -0
  88. package/src/lineage/DESIGN_QUEUE_DETAIL.md +120 -0
  89. package/src/lineage/DESIGN_REGISTRIES.md +880 -0
  90. package/src/lineage/DESIGN_STORE_DETAIL.md +143 -0
  91. package/src/lineage/DESIGN_TRANSIT_PROTECTION.md +245 -0
  92. package/src/lineage/classification.js +56 -0
  93. package/src/lineage/coverage.js +658 -0
  94. package/src/lineage/cross-repo-link.js +107 -0
  95. package/src/lineage/dataflow-graph.schema.json +184 -0
  96. package/src/lineage/decision-story.js +206 -0
  97. package/src/lineage/drift-policy.js +279 -0
  98. package/src/lineage/driver.js +135 -0
  99. package/src/lineage/engine.js +992 -0
  100. package/src/lineage/export-briefing.js +628 -0
  101. package/src/lineage/export-csv.js +62 -0
  102. package/src/lineage/export-json.js +238 -0
  103. package/src/lineage/export-privacy.js +258 -0
  104. package/src/lineage/federation-loader.js +111 -0
  105. package/src/lineage/field-identity.js +78 -0
  106. package/src/lineage/fixtures/build-flagship-fixture.mjs +272 -0
  107. package/src/lineage/fixtures/flagship-graph.json +1453 -0
  108. package/src/lineage/flow-grade.js +221 -0
  109. package/src/lineage/governance-edit.js +169 -0
  110. package/src/lineage/graph-builder.js +1114 -0
  111. package/src/lineage/graph-diff.js +431 -0
  112. package/src/lineage/graph-snapshot.js +180 -0
  113. package/src/lineage/handling-analyzer.js +168 -0
  114. package/src/lineage/ids.js +349 -0
  115. package/src/lineage/impact-assessment.js +76 -0
  116. package/src/lineage/impact-engine.js +268 -0
  117. package/src/lineage/index.js +281 -0
  118. package/src/lineage/language-coverage-tiers.js +58 -0
  119. package/src/lineage/obligation-mapping.js +126 -0
  120. package/src/lineage/obligation-predicates.js +235 -0
  121. package/src/lineage/observation-adapters.js +282 -0
  122. package/src/lineage/observation-correlation.js +622 -0
  123. package/src/lineage/observation-store.js +497 -0
  124. package/src/lineage/path-query.js +410 -0
  125. package/src/lineage/path-store.js +400 -0
  126. package/src/lineage/protection.js +53 -0
  127. package/src/lineage/recipient-profile.js +192 -0
  128. package/src/lineage/recipient-registry.js +394 -0
  129. package/src/lineage/redact-graph.js +224 -0
  130. package/src/lineage/remediation.js +417 -0
  131. package/src/lineage/resolve-destination.js +91 -0
  132. package/src/lineage/runtime-observation.js +464 -0
  133. package/src/lineage/scenario-diff.js +84 -0
  134. package/src/lineage/scenario-engine.js +251 -0
  135. package/src/lineage/scenario.js +101 -0
  136. package/src/lineage/schema.js +167 -0
  137. package/src/lineage/sink-registry.js +427 -0
  138. package/src/lineage/source-registry.js +357 -0
  139. package/src/lineage/source-seeding.js +212 -0
  140. package/src/lineage/summaries.js +590 -0
  141. package/src/lineage/transform-catalog.js +397 -0
  142. package/src/lineage/transit-protection.js +150 -0
  143. package/src/lineage/validate.js +285 -0
  144. package/src/lsp/server.js +49 -2
  145. package/src/mcp/CLAUDE.md +7 -1
  146. package/src/mcp/dataflow-tools.js +160 -0
  147. package/src/mcp/server.js +1 -1
  148. package/src/mcp/tools.js +22 -1
  149. package/src/pipeline/assurance-mode.js +64 -1
  150. package/src/pipeline/finding-schema.js +8 -1
  151. package/src/pipeline/scan-health.js +19 -1
  152. package/src/posture/CLAUDE.md +140 -0
  153. package/src/posture/accuracy-scorecard.js +60 -0
  154. package/src/posture/artifact-registry.js +76 -0
  155. package/src/posture/auditor-walkthrough.js +192 -13
  156. package/src/posture/compliance-frameworks/hipaa-security-rule.json +3 -2
  157. package/src/posture/compliance-policy.js +12 -2
  158. package/src/posture/cross-repo-memory.js +7 -2
  159. package/src/posture/fix-history.js +25 -2
  160. package/src/posture/fix-verify.js +9 -1
  161. package/src/posture/fleet.js +0 -0
  162. package/src/posture/git-history.js +13 -5
  163. package/src/posture/material-change.js +21 -2
  164. package/src/posture/mttr.js +75 -12
  165. package/src/posture/obligation-evidence-pack.js +202 -0
  166. package/src/posture/pre-incident-archaeology.js +39 -7
  167. package/src/posture/privacy-framework.js +14 -0
  168. package/src/posture/provenance/ai-authorship.js +68 -0
  169. package/src/posture/provenance/branch-entry.js +80 -0
  170. package/src/posture/provenance/cache.js +143 -0
  171. package/src/posture/provenance/confidence.js +36 -0
  172. package/src/posture/provenance/coordinator.js +786 -0
  173. package/src/posture/provenance/dag-walk.js +249 -0
  174. package/src/posture/provenance/evidence-attribution.js +59 -0
  175. package/src/posture/provenance/git-evidence.js +310 -0
  176. package/src/posture/provenance/lifecycle.js +208 -0
  177. package/src/posture/provenance/missing-control-resolver.js +137 -0
  178. package/src/posture/provenance/origin-resolver.js +342 -0
  179. package/src/posture/provenance/predicate-replay.js +133 -0
  180. package/src/posture/provenance/providers/config.js +39 -0
  181. package/src/posture/provenance/providers/github.js +62 -0
  182. package/src/posture/provenance/providers/gitlab.js +58 -0
  183. package/src/posture/provenance/repo-lineage.js +74 -0
  184. package/src/posture/provenance/sca-origin.js +139 -0
  185. package/src/posture/provenance/schema.js +255 -0
  186. package/src/posture/provenance/transitive-sca.js +147 -0
  187. package/src/posture/provenance/validate.js +30 -0
  188. package/src/posture/provenance-evidence-bundle.js +144 -0
  189. package/src/posture/remediation-ledger.js +337 -0
  190. package/src/posture/sbom-diff.js +15 -2
  191. package/src/posture/secret-history.js +10 -2
  192. package/src/posture/state-dir.js +38 -14
  193. package/src/posture/vuln-archaeology.js +8 -2
  194. package/src/pr-delta.js +25 -4
  195. package/src/report/index.js +197 -3
  196. package/src/runScan.js +34 -5
  197. package/src/sast/rate-limit.js +33 -3
  198. package/src/server/CLAUDE.md +47 -0
  199. package/src/server/graph-loader.js +141 -0
  200. package/src/server/http-server.js +325 -0
  201. package/src/server/routes.js +129 -0
  202. package/src/server/security.js +111 -0
  203. package/src/server/static-assets.js +139 -0
  204. package/src/util/git-hardening.js +128 -0
  205. package/dist/11.index.js +0 -353
  206. package/dist/259.index.js +0 -975
  207. package/dist/317.index.js +0 -300
  208. package/dist/609.index.js +0 -741
  209. package/dist/838.index.js +0 -152
@@ -0,0 +1,93 @@
1
+ export const id = 2659;
2
+ export const ids = [2659];
3
+ export const modules = {
4
+
5
+ /***/ 2659:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
+ /* harmony export */ qc: () => (/* binding */ IMPACT_VERSION),
10
+ /* harmony export */ validateImpactAssessment: () => (/* binding */ validateImpactAssessment)
11
+ /* harmony export */ });
12
+ /* unused harmony exports IMPACT_TARGET_KINDS, IMPACT_SCOPE_VALUES, IMPACT_TRACE_KINDS */
13
+ // impact-assessment.js — M5 deliverable #4 (FR-507 §10.10): the
14
+ // ImpactAssessment extension contract — the result of asking "what is
15
+ // reachable from this compromised node/edge/flow/data element, per the
16
+ // graph's own already-scanned evidence." NOT a DataFlowGraph v1 entity,
17
+ // mirrors recipient-profile.js's/scenario.js's own contract shape
18
+ // exactly (structural-only {valid, errors} validator, zero graph
19
+ // access at construction time).
20
+ //
21
+ // See docs/superpowers/plans/2026-09-02-data-flow-explorer-m5-blast-radius-impact-scoping.md
22
+ // for the full design reasoning, including why there is no
23
+ // affectedObligationIds field (ObligationMapping records are built on
24
+ // demand per compliance framework, not stored on the graph) and why
25
+ // `scope` is always 'possible' today (no runtime-corroboration layer
26
+ // exists yet).
27
+
28
+ const IMPACT_VERSION = '1.0.0';
29
+
30
+ const IMPACT_TARGET_KINDS = Object.freeze(['node', 'edge', 'flow', 'dataElement']);
31
+
32
+ // 'possible' is the only value any producer emits today — 'observed'
33
+ // is reserved for a future Digital Twin (M5 #7) increment with a real
34
+ // runtime-corroboration signal. Both are valid schema values now so
35
+ // that increment needs no breaking change to this contract later.
36
+ const IMPACT_SCOPE_VALUES = Object.freeze(['possible', 'observed']);
37
+
38
+ // Discloses WHICH of the two genuinely different traversal semantics
39
+ // produced this record (final-review I2 fix) — `scope` alone cannot
40
+ // distinguish them, since both families emit `scope: 'possible'`.
41
+ // 'topology_reachable': a `node` target's topology-wide showAllPaths
42
+ // BFS — "everything this compromised node could push to." 'flow_
43
+ // restricted': an `edge`/`flow`/`dataElement` target's direct trace
44
+ // over the flows that actually carry it — never the topology-wide BFS.
45
+ // Without this field a JSON consumer cannot tell "exact carrier trace"
46
+ // from "topological presumption" apart, the exact silent-conflation
47
+ // this codebase's own disclosure discipline exists to prevent.
48
+ const IMPACT_TRACE_KINDS = Object.freeze(['topology_reachable', 'flow_restricted']);
49
+
50
+ function _isNonEmptyString(v) { return typeof v === 'string' && v.length > 0; }
51
+ function _isStringArray(v) { return Array.isArray(v) && v.every((x) => typeof x === 'string'); }
52
+
53
+ /**
54
+ * Structural validation only — mirrors validateRecipientProfile's/
55
+ * validateScenario's own {valid, errors} shape and "never throws"
56
+ * contract.
57
+ */
58
+ function validateImpactAssessment(record) {
59
+ const errors = [];
60
+ const err = (p, message) => errors.push({ path: p, message });
61
+ if (!record || typeof record !== 'object' || Array.isArray(record)) {
62
+ err('$', 'ImpactAssessment record must be an object');
63
+ return { valid: false, errors };
64
+ }
65
+ if (!_isNonEmptyString(record.id) || !record.id.startsWith('impact:')) {
66
+ err('$.id', 'id is required and must start with "impact:"');
67
+ }
68
+ if (!_isNonEmptyString(record.version)) err('$.version', 'version is required');
69
+ if (!_isNonEmptyString(record.graphId)) err('$.graphId', 'graphId is required');
70
+ if (!_isNonEmptyString(record.graphDigest)) err('$.graphDigest', 'graphDigest is required');
71
+ if (!_isNonEmptyString(record.targetId)) err('$.targetId', 'targetId is required');
72
+ if (!IMPACT_TARGET_KINDS.includes(record.targetKind)) {
73
+ err('$.targetKind', `targetKind must be one of ${IMPACT_TARGET_KINDS.join('|')}`);
74
+ }
75
+ if (!IMPACT_SCOPE_VALUES.includes(record.scope)) {
76
+ err('$.scope', `scope must be one of ${IMPACT_SCOPE_VALUES.join('|')}`);
77
+ }
78
+ if (!IMPACT_TRACE_KINDS.includes(record.traceKind)) {
79
+ err('$.traceKind', `traceKind must be one of ${IMPACT_TRACE_KINDS.join('|')}`);
80
+ }
81
+ if (!_isStringArray(record.affectedNodeIds ?? [])) err('$.affectedNodeIds', 'affectedNodeIds must be an array of strings');
82
+ if (!_isStringArray(record.affectedEdgeIds ?? [])) err('$.affectedEdgeIds', 'affectedEdgeIds must be an array of strings');
83
+ if (!_isStringArray(record.affectedDataClasses ?? [])) err('$.affectedDataClasses', 'affectedDataClasses must be an array of strings');
84
+ if (!_isStringArray(record.affectedRecipientProfileIds ?? [])) err('$.affectedRecipientProfileIds', 'affectedRecipientProfileIds must be an array of strings');
85
+ if (!_isStringArray(record.coverageLimitations ?? [])) err('$.coverageLimitations', 'coverageLimitations must be an array of strings');
86
+ if (!_isNonEmptyString(record.generatedAt)) err('$.generatedAt', 'generatedAt is required');
87
+ return { valid: errors.length === 0, errors };
88
+ }
89
+
90
+
91
+ /***/ })
92
+
93
+ };
@@ -1,5 +1,5 @@
1
- export const id = 826;
2
- export const ids = [826];
1
+ export const id = 2826;
2
+ export const ids = [2826];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 2826:
@@ -1,5 +1,5 @@
1
- export const id = 830;
2
- export const ids = [830];
1
+ export const id = 2830;
2
+ export const ids = [2830];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 2830:
@@ -0,0 +1,298 @@
1
+ export const id = 2923;
2
+ export const ids = [2923];
3
+ export const modules = {
4
+
5
+ /***/ 2923:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
+ /* harmony export */ adapterFor: () => (/* binding */ adapterFor)
10
+ /* harmony export */ });
11
+ /* unused harmony exports NATIVE_JSONL_RECORD_KEYS, parseNativeJsonlObservations */
12
+ // observation-adapters.js — the RuntimeObservation ADAPTER interface, plus
13
+ // the one shipped implementation (`native-jsonl`) (M5 deliverable #7,
14
+ // "Runtime-Corroborated Digital Twin" — the runtime-observed half only,
15
+ // "7b"; "7a", config-declared edges, is out of scope for this whole
16
+ // sub-project — see the scoping doc's §4.0). FR-505, AC-29. Pure by
17
+ // contract: zero imports (mirrors `runtime-observation.js`'s/
18
+ // `observation-correlation.js`'s/`flow-grade.js`'s own precedent, one step
19
+ // stricter even than `observation-correlation.js`'s single-file import
20
+ // list — see AD/6a), no fs, no I/O, never throws.
21
+ //
22
+ // ── Why only ONE adapter ships here ─────────────────────────────────────
23
+ //
24
+ // FR-505 itself names an open-ended adapter list: "beginning with approved
25
+ // OpenTelemetry traces/service graphs, gateway/mesh metadata, cloud flow
26
+ // metadata, and application-provided schema-safe events." The scoping
27
+ // doc's §4.3 ruling is to ship the INTERFACE plus a native, operator-
28
+ // authored JSONL adapter first, and defer OTLP to a second increment —
29
+ // not because OTLP is unimportant, but because an OTLP `resourceSpans`
30
+ // document carries an unbounded attribute surface (`http.url` with a live
31
+ // query string, `db.statement`, `messaging.message.payload`, arbitrary
32
+ // `gen_ai.*` prompt/completion attributes under active, ongoing extension
33
+ // by the OpenTelemetry semantic-conventions project). Mapping that surface
34
+ // safely means writing and defending an allowlist against an adversarial,
35
+ // EVOLVING external vocabulary — real, separately-scoped work with its
36
+ // own review, not something to bundle into the increment that also
37
+ // invents the RuntimeObservation contract (Task 1), the correlation match
38
+ // ladder (Task 2), and the import-keyed store (Task 4). This module exists
39
+ // so THAT increment is "write a second implementation of an
40
+ // already-proven interface," not "invent the interface and the mapping at
41
+ // the same time."
42
+ //
43
+ // ── Why external evidence arrives as a FILE, never live ingestion ──────
44
+ //
45
+ // FR-505's own no-egress rule, the root `CLAUDE.md`'s "no runtime cloud
46
+ // calls" convention, and `posture/runtime-correlation.js`'s own already-
47
+ // proven offline-file contract (an operator-supplied eBPF trace JSONL,
48
+ // read from disk, never pulled from a live collector by this codebase)
49
+ // all point the same direction: this module takes a TEXT STRING an
50
+ // operator has already exported and already has on disk, and returns
51
+ // drafts — it has no fetch, no socket, no fs call of any kind (AD/6a pins
52
+ // this structurally, not just by convention). The CLI that will eventually
53
+ // call this (a future task) is what reads the file; this module never
54
+ // does.
55
+ //
56
+ // ── Why the wire key set is CLOSED, exactly like the record it feeds ───
57
+ //
58
+ // `runtime-observation.js`'s own header explains at length why a
59
+ // RuntimeObservation is closed-world rather than open-world: it is built
60
+ // from operator-supplied telemetry this codebase never generated and
61
+ // cannot vouch for, and PRD line 983's own "reject fields capable of
62
+ // carrying payload values" requirement is a REJECT requirement, not a
63
+ // redact-and-hope one. That reasoning applies one layer further out, at
64
+ // the WIRE itself: `NATIVE_JSONL_RECORD_KEYS` is a closed allowlist of the
65
+ // only top-level JSON keys a native-JSONL record may carry, and any other
66
+ // top-level key — an attacker's `prompt`, an operator's well-meaning
67
+ // `note`, or (the smuggling attempt nobody would think to test on their
68
+ // own) a pre-declared `matchedNodeIds`/`matchConfidence` — is rejected,
69
+ // never ignored (AD/4c). `id`/`matchedNodeIds`/`matchedEdgeIds`/
70
+ // `matchedFlowIds`/`matchMethod`/`matchConfidence` are refused from the
71
+ // wire for a reason specific to THIS module: those six fields are
72
+ // minted/derived downstream (an id at import time, a match at correlation
73
+ // time) — if the wire could supply them directly, a compromised exporter,
74
+ // or an operator simply copy-pasting an already-matched record from one
75
+ // import into a hand-edited new one, could dictate what the graph BELIEVES
76
+ // was observed, bypassing the match ladder (`observation-correlation.js`,
77
+ // Task 2) entirely. None of the six are members of `NATIVE_JSONL_RECORD_KEYS`,
78
+ // so the SAME closed-world sweep that rejects an unrecognized field also
79
+ // rejects every one of these — there is no separate check to keep in sync
80
+ // (AD/4b, error 4).
81
+ //
82
+ // ── The two-layer rejection split (this module vs. `validateRuntimeObservation`) ──
83
+ //
84
+ // This module enforces the WIRE SHAPE only: `attributes` must be a plain
85
+ // object whose every value is a scalar (string/number/boolean) or an
86
+ // array of strings, no top-level key outside `NATIVE_JSONL_RECORD_KEYS`,
87
+ // and `eventCountBand`/`firstObservedAt`/`lastObservedAt` must each be a
88
+ // non-empty string. It does NOT validate WHICH attribute keys are
89
+ // approved — `validateRuntimeObservation` (Task 1, `runtime-observation.js`)
90
+ // is the single authority on that allowlist, and this module never
91
+ // duplicates it (a duplicated allowlist is exactly the kind of thing that
92
+ // silently drifts). Against the payload fixture, this means the adapter
93
+ // itself catches only 2 of the fixture's 4 smuggling attempts (line 3's
94
+ // top-level `prompt`, line 4's `matchedNodeIds`/`matchConfidence`) — the
95
+ // other two (line 1's `http.url` attribute key, line 2's `db.statement`
96
+ // attribute key) are structurally fine at the wire layer and are caught
97
+ // one layer up, by `validateRuntimeObservation`, at IMPORT time
98
+ // (`CLI/import-4`, a future task's own test — not a hole in this one).
99
+ // Any adapter error means the whole file yields nothing usable: this
100
+ // module always returns whatever drafts it produced regardless of
101
+ // `errors.length`, but the IMPORT command (a future task) refuses the
102
+ // file WHOLE the moment `errors.length > 0` — that refuse-the-whole-import
103
+ // behavior is that future task's own to prove, not this module's.
104
+ //
105
+ // ── The native-JSONL wire format, worked example ────────────────────────
106
+ //
107
+ // One JSON object per line (no comments — JSONL admits none), each with
108
+ // up to 5 top-level keys (`NATIVE_JSONL_RECORD_KEYS`):
109
+ //
110
+ // {"environment":"production","attributes":{"destination.host":"api.stripe.com","destination.scheme":"https","tls.version":"1.3"},"eventCountBand":"101-1k","firstObservedAt":"2026-08-02T10:00:00.000Z","lastObservedAt":"2026-08-30T10:00:00.000Z"}
111
+ //
112
+ // `environment` is optional per line — when omitted, the record inherits
113
+ // the default environment of the surrounding call, `context.environment`
114
+ // (supplied by the CALLER, never by the file). `attributes` keys must be
115
+ // drawn from `RUNTIME_ATTRIBUTE_KEYS` (`runtime-observation.js`) — this
116
+ // module does not check that, but a key outside that list will be
117
+ // rejected one layer up, at import time. `eventCountBand` is a BAND
118
+ // (`RUNTIME_OBSERVATION_VERSION`'s sibling `EVENT_COUNT_BANDS`, e.g.
119
+ // `'1'`/`'2-10'`/`'11-100'`/`'101-1k'`/`'1k+'`), never a raw count.
120
+ // `firstObservedAt`/`lastObservedAt` are ISO-8601 date-times.
121
+ //
122
+ // ── `version` is caller-supplied, not read from `runtime-observation.js` ──
123
+ //
124
+ // This is precisely why this module has NO import at all, not even of
125
+ // `runtime-observation.js`'s own `RUNTIME_OBSERVATION_VERSION` constant:
126
+ // the CLI (a future task) passes that value in as `context.version`. A
127
+ // zero-import module can never itself drift from the contract it feeds —
128
+ // there is no cached/stale constant here to go stale.
129
+
130
+ // The 5 allowed top-level keys of a native-JSONL wire record. Any other
131
+ // top-level key — including every one of the six RuntimeObservation
132
+ // fields that are minted/derived downstream (`id`, `matchedNodeIds`,
133
+ // `matchedEdgeIds`, `matchedFlowIds`, `matchMethod`, `matchConfidence`) —
134
+ // is rejected by the closed-world sweep below, never ignored.
135
+ const NATIVE_JSONL_RECORD_KEYS = Object.freeze([
136
+ 'environment', 'attributes', 'eventCountBand', 'firstObservedAt', 'lastObservedAt',
137
+ ]);
138
+
139
+ function _isPlainObject(v) {
140
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
141
+ }
142
+
143
+ function _isNonEmptyString(v) {
144
+ return typeof v === 'string' && v.length > 0;
145
+ }
146
+
147
+ function _isScalar(v) {
148
+ const t = typeof v;
149
+ return t === 'string' || t === 'number' || t === 'boolean';
150
+ }
151
+
152
+ // The WIRE shape only — never which attribute keys are approved. A value
153
+ // must be a scalar, or an array of strings (mirroring
154
+ // `RUNTIME_ARRAY_ATTRIBUTE_KEYS`'s own shape one layer up, without this
155
+ // module knowing which specific key that applies to).
156
+ function _attributesShapeOk(attrs) {
157
+ if (!_isPlainObject(attrs)) return false;
158
+ for (const value of Object.values(attrs)) {
159
+ if (Array.isArray(value)) {
160
+ if (!value.every((x) => typeof x === 'string')) return false;
161
+ } else if (!_isScalar(value)) {
162
+ return false;
163
+ }
164
+ }
165
+ return true;
166
+ }
167
+
168
+ /**
169
+ * Parses native-JSONL runtime-observation text into RuntimeObservation
170
+ * DRAFTS — every field a RuntimeObservation record needs EXCEPT `id`,
171
+ * `matchedNodeIds`, `matchedEdgeIds`, `matchedFlowIds`, `matchMethod`,
172
+ * `matchConfidence`, which are minted/derived downstream and can never be
173
+ * supplied by the wire. `context` is
174
+ * `{version, adapter, source, environment, windowStart, windowEnd, importedAt, retention}`
175
+ * — every draft carries these verbatim, EXCEPT `environment`, which a
176
+ * per-line `environment` key overrides.
177
+ *
178
+ * Never throws. `text` must be a string and `context` a plain object, or
179
+ * this returns `{drafts: [], errors: [{line: 0, message: '...'}]}`
180
+ * immediately. Blank lines (and the trailing newline JSONL files
181
+ * ordinarily end with) are skipped silently — never reported as errors.
182
+ * A malformed line (invalid JSON, wrong top-level shape, an unapproved
183
+ * top-level key, a malformed `attributes`/`eventCountBand`/
184
+ * `firstObservedAt`/`lastObservedAt`) yields exactly ONE `{line, message}`
185
+ * error for that line (`line` 1-based) and is skipped — every OTHER line
186
+ * still parses, so an operator sees every problem in one pass rather than
187
+ * stopping at the first.
188
+ */
189
+ function parseNativeJsonlObservations(text, context) {
190
+ if (typeof text !== 'string' || !_isPlainObject(context)) {
191
+ return {
192
+ drafts: [],
193
+ errors: [{ line: 0, message: 'parseNativeJsonlObservations requires a string text and a plain-object context' }],
194
+ };
195
+ }
196
+
197
+ const {
198
+ version, adapter, source, environment: defaultEnvironment,
199
+ windowStart, windowEnd, importedAt, retention,
200
+ } = context;
201
+
202
+ const drafts = [];
203
+ const errors = [];
204
+
205
+ const lines = text.split(/\r?\n/);
206
+ for (let i = 0; i < lines.length; i++) {
207
+ const rawLine = lines[i];
208
+ if (rawLine.trim().length === 0) continue; // blank line, or the trailing newline's own empty tail
209
+ const line = i + 1;
210
+
211
+ let record;
212
+ try {
213
+ record = JSON.parse(rawLine);
214
+ } catch {
215
+ // M2 (final review): every OTHER rejection path in this module is
216
+ // key-only/value-free by design — V8's own JSON.parse error message
217
+ // quotes a snippet of the offending input (`e.message`), which would
218
+ // make this the sole value-echo channel in the whole command. Name
219
+ // only the line number, never the parse error's own text.
220
+ errors.push({ line, message: `invalid JSON on line ${line}` });
221
+ continue;
222
+ }
223
+
224
+ if (!_isPlainObject(record)) {
225
+ const gotType = record === null ? 'null' : Array.isArray(record) ? 'array' : typeof record;
226
+ errors.push({ line, message: `record must be a JSON object, got ${gotType}` });
227
+ continue;
228
+ }
229
+
230
+ const unknownKeys = Object.keys(record).filter((k) => !NATIVE_JSONL_RECORD_KEYS.includes(k));
231
+ if (unknownKeys.length > 0) {
232
+ errors.push({
233
+ line,
234
+ message: `unknown field(s) not permitted on the wire: ${unknownKeys.join(', ')} — native-JSONL records are closed-world (mirroring RuntimeObservation's own closed-world rule): only ${NATIVE_JSONL_RECORD_KEYS.join('/')} are accepted, and this rejects every one of id/matchedNodeIds/matchedEdgeIds/matchedFlowIds/matchMethod/matchConfidence too, since none are members of that allowlist`,
235
+ });
236
+ continue;
237
+ }
238
+
239
+ if (!_attributesShapeOk(record.attributes)) {
240
+ errors.push({
241
+ line,
242
+ message: 'attributes must be a plain object whose every value is a scalar (string/number/boolean) or an array of strings',
243
+ });
244
+ continue;
245
+ }
246
+
247
+ if (!_isNonEmptyString(record.eventCountBand)
248
+ || !_isNonEmptyString(record.firstObservedAt)
249
+ || !_isNonEmptyString(record.lastObservedAt)) {
250
+ errors.push({
251
+ line,
252
+ message: 'eventCountBand, firstObservedAt, and lastObservedAt must each be present and a non-empty string',
253
+ });
254
+ continue;
255
+ }
256
+
257
+ drafts.push({
258
+ version,
259
+ adapter,
260
+ source,
261
+ environment: 'environment' in record ? record.environment : defaultEnvironment,
262
+ windowStart,
263
+ windowEnd,
264
+ attributes: record.attributes,
265
+ eventCountBand: record.eventCountBand,
266
+ firstObservedAt: record.firstObservedAt,
267
+ lastObservedAt: record.lastObservedAt,
268
+ retention,
269
+ importedAt,
270
+ });
271
+ }
272
+
273
+ return { drafts, errors };
274
+ }
275
+
276
+ // The adapter registry — a frozen, module-level lookup. `adapterFor`
277
+ // returns `null` for anything unknown, NEVER a default: an unimplemented
278
+ // adapter name (e.g. `'otlp'`, deferred per the scoping doc's §4.3 ruling)
279
+ // must be rejected outright, not silently accepted on faith that it will
280
+ // someday exist.
281
+ const _ADAPTERS = Object.freeze({
282
+ 'native-jsonl': Object.freeze({ name: 'native-jsonl', parse: parseNativeJsonlObservations }),
283
+ });
284
+
285
+ /**
286
+ * `adapterFor(name) -> {name, parse} | null` — the registry lookup.
287
+ * `parse` has the `(text, context) -> {drafts, errors}` signature of
288
+ * `parseNativeJsonlObservations` above.
289
+ */
290
+ function adapterFor(name) {
291
+ if (typeof name !== 'string') return null;
292
+ return Object.prototype.hasOwnProperty.call(_ADAPTERS, name) ? _ADAPTERS[name] : null;
293
+ }
294
+
295
+
296
+ /***/ })
297
+
298
+ };
@@ -1,5 +1,5 @@
1
- export const id = 1;
2
- export const ids = [1];
1
+ export const id = 3001;
2
+ export const ids = [3001];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 3001:
@@ -71,7 +71,7 @@ const RELIABLE_N = 10;
71
71
 
72
72
  function _findFinding(scanRoot, findingId) {
73
73
  try {
74
- const raw = JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync((0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .statePath */ .BQ)(scanRoot, 'last-scan.json'), 'utf8'));
74
+ const raw = JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync((0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.statePath)(scanRoot, 'last-scan.json'), 'utf8'));
75
75
  const findings = Array.isArray(raw.findings) ? raw.findings : [];
76
76
  return findings.find(f => f && (f.id === findingId || f.stableId === findingId)) || null;
77
77
  } catch { return null; }
@@ -120,7 +120,7 @@ function recordCalibrationFeedback(scanRoot, { findingId, outcome, note } = {})
120
120
  if (!(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.stateWritesEnabled)()) return { ok: false, reason: 'state writes are disabled (--no-state)' };
121
121
  try {
122
122
  node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(dir, { recursive: true });
123
- node_fs__WEBPACK_IMPORTED_MODULE_0__.appendFileSync((0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .statePath */ .BQ)(scanRoot, CALIBRATION_FEEDBACK_FILE), JSON.stringify(record) + '\n', 'utf8');
123
+ node_fs__WEBPACK_IMPORTED_MODULE_0__.appendFileSync((0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.statePath)(scanRoot, CALIBRATION_FEEDBACK_FILE), JSON.stringify(record) + '\n', 'utf8');
124
124
  } catch (e) { return { ok: false, reason: e.message }; }
125
125
  return { ok: true, record };
126
126
  }
@@ -131,7 +131,7 @@ function recordCalibrationFeedback(scanRoot, { findingId, outcome, note } = {})
131
131
  */
132
132
  function loadCalibrationFeedback(scanRoot) {
133
133
  let fp;
134
- try { fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .statePath */ .BQ)(scanRoot, CALIBRATION_FEEDBACK_FILE); } catch { return []; }
134
+ try { fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.statePath)(scanRoot, CALIBRATION_FEEDBACK_FILE); } catch { return []; }
135
135
  let raw;
136
136
  try { raw = node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(fp, 'utf8'); } catch { return []; }
137
137
  const out = [];
@@ -1,5 +1,5 @@
1
- export const id = 117;
2
- export const ids = [117];
1
+ export const id = 3117;
2
+ export const ids = [3117];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 3117:
@@ -58,7 +58,7 @@ const SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'];
58
58
 
59
59
  function _readLastScan(scanRoot) {
60
60
  if (!scanRoot) return null;
61
- const fp = (0,_posture_state_dir_js__WEBPACK_IMPORTED_MODULE_2__/* .statePath */ .BQ)(scanRoot, 'last-scan.json');
61
+ const fp = (0,_posture_state_dir_js__WEBPACK_IMPORTED_MODULE_2__.statePath)(scanRoot, 'last-scan.json');
62
62
  if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(fp)) return null;
63
63
  try { return JSON.parse(node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(fp, 'utf8')); }
64
64
  catch { return null; }