@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,307 @@
1
+ export const id = 3180;
2
+ export const ids = [3180];
3
+ export const modules = {
4
+
5
+ /***/ 3180:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+
9
+ // EXPORTS
10
+ __webpack_require__.d(__webpack_exports__, {
11
+ generateHtmlReport: () => (/* binding */ generateHtmlReport)
12
+ });
13
+
14
+ // EXTERNAL MODULE: external "node:fs"
15
+ var external_node_fs_ = __webpack_require__(3024);
16
+ // EXTERNAL MODULE: external "node:path"
17
+ var external_node_path_ = __webpack_require__(6760);
18
+ // EXTERNAL MODULE: external "node:url"
19
+ var external_node_url_ = __webpack_require__(3136);
20
+ ;// CONCATENATED MODULE: ./scripts/bundle-frontend.mjs
21
+ // bundle-frontend.mjs — Milestone 4, sub-project Self-contained HTML
22
+ // report. A minimal, hand-rolled ES-module bundler, deliberately NOT a
23
+ // general one — see this sub-project's own scoping doc for why a real
24
+ // bundler dependency (esbuild etc.) was considered and NOT chosen:
25
+ // frontend/src/'s real module graph (confirmed by a full-tree grep before
26
+ // this file was written) uses ONLY named imports/exports, no default
27
+ // exports, no `export *`, no namespace or side-effect-only imports. This
28
+ // bundler supports exactly that subset and throws a clear error on
29
+ // anything else, rather than silently mishandling an unsupported form.
30
+ //
31
+ // Algorithm: parse each file's own import specifiers + exported top-level
32
+ // names via regex (safe here because the supported subset's syntax is
33
+ // simple and unambiguous — a full parser is not needed for this bounded,
34
+ // fully-enumerated 21-file input); topologically order every reachable
35
+ // module; wrap EVERY NON-ENTRY module in its own IIFE (this is what
36
+ // prevents two dependency files' same-named PRIVATE top-level bindings
37
+ // from colliding when concatenated — a real risk with naive flat
38
+ // concatenation, proven by this file's own test suite); each module's
39
+ // IIFE destructures its own imports from its dependencies' already-
40
+ // evaluated namespace objects (`const { a, b } = __NS_shared;`) and
41
+ // returns its own exports as a plain object.
42
+ //
43
+ // The ENTRY module is deliberately NOT wrapped in an IIFE: its body is
44
+ // emitted directly at the top level of the output (after its own
45
+ // destructured imports), so its top-level declarations — functions the
46
+ // caller needs to invoke directly, e.g. `bootstrap()` in a `<script>`
47
+ // tag, or (as this file's own tests require) a bare exported name called
48
+ // straight off the bundled output — become real top-level bindings
49
+ // rather than being trapped inside a closure whose return value is
50
+ // discarded. Wrapping the entry in an IIFE too (as an earlier draft of
51
+ // this algorithm did) type-checks and looks symmetrical, but it is a
52
+ // correctness bug: it makes every exported name of the entry module
53
+ // unreachable from outside the bundle, which is never what a bundle's
54
+ // caller wants. Only the entry is unwrapped — every other module is
55
+ // still fully IIFE-isolated, so the collision guarantee above is
56
+ // unaffected (there is exactly one unwrapped scope per bundle, by
57
+ // construction, since the entry is the unique DFS root and cannot be
58
+ // re-entered — a cycle back to it is rejected below as a circular
59
+ // import).
60
+
61
+
62
+
63
+
64
+ const IMPORT_RE = /import\s*\{([\s\S]*?)\}\s*from\s*['"](\.[^'"]+)['"];?/g;
65
+ const UNSUPPORTED_IMPORT_RE = /^import\s+(?!\{)/m;
66
+ const EXPORT_STAR_RE = /^export\s*\*/m;
67
+ const EXPORT_DEFAULT_RE = /^export\s+default\b/m;
68
+ // Three more real, unsupported forms — added after the final whole-branch
69
+ // review found each builds with NO error (`EXPORT_NAMED_RE` below requires
70
+ // `function`/`class`/`const`/`let`/`var` immediately after `export `, so
71
+ // `export async function` matches none of these guards OR the named-export
72
+ // extractor, and is silently dropped as neither a caught error nor a real
73
+ // export) and only fails later as a page-load SyntaxError, blanking the
74
+ // whole page with no visible error — `export async function` already
75
+ // exists in the real tree today (frontend/src/lib/api-client.js), outside
76
+ // today's bundled entry point's own reachable graph only by luck.
77
+ const EXPORT_ASYNC_RE = /^export\s+async\s+function/m;
78
+ const EXPORT_LIST_RE = /^export\s*\{/m;
79
+ const IMPORT_RENAME_RE = /\bas\b/;
80
+ const EXPORT_NAMED_RE = /^export\s+(?:function\*?|class|const|let|var)\s+([A-Za-z0-9_$]+)/gm;
81
+
82
+ function _nsName(absPath, seen) {
83
+ // A stable, collision-free JS identifier per module, derived from its
84
+ // path. seen is a Map<absPath, name> shared across the whole bundle run.
85
+ if (seen.has(absPath)) return seen.get(absPath);
86
+ const base = absPath.replace(/[^A-Za-z0-9_$]/g, '_');
87
+ const name = `__NS_${base}`;
88
+ seen.set(absPath, name);
89
+ return name;
90
+ }
91
+
92
+ function _parseModule(absPath) {
93
+ const src = external_node_fs_.readFileSync(absPath, 'utf8');
94
+ if (UNSUPPORTED_IMPORT_RE.test(src) || EXPORT_STAR_RE.test(src) || EXPORT_DEFAULT_RE.test(src) || EXPORT_ASYNC_RE.test(src) || EXPORT_LIST_RE.test(src)) {
95
+ throw new Error(`bundleFrontendModules: unsupported import/export form in ${absPath} — only named imports/exports are supported (no default/namespace/side-effect imports, no export */export default/export {}-list/export async function)`);
96
+ }
97
+ const imports = [];
98
+ let m;
99
+ IMPORT_RE.lastIndex = 0;
100
+ while ((m = IMPORT_RE.exec(src))) {
101
+ if (IMPORT_RENAME_RE.test(m[1])) {
102
+ throw new Error(`bundleFrontendModules: unsupported \`import { x as y }\` rename in ${absPath} — only bare named imports are supported`);
103
+ }
104
+ const names = m[1].split(',').map((s) => s.trim()).filter(Boolean);
105
+ const resolved = external_node_path_.resolve(external_node_path_.dirname(absPath), m[2]);
106
+ imports.push({ names, resolved });
107
+ }
108
+ const exportNames = [];
109
+ EXPORT_NAMED_RE.lastIndex = 0;
110
+ while ((m = EXPORT_NAMED_RE.exec(src))) exportNames.push(m[1]);
111
+ // Strip import lines entirely; strip the leading `export ` keyword from
112
+ // each exported declaration (the declaration itself — function/const/
113
+ // class — is kept verbatim, so the body is otherwise untouched).
114
+ const body = src
115
+ .replace(IMPORT_RE, '')
116
+ .replace(/^export\s+(?=(?:function\*?|class|const|let|var)\s)/gm, '');
117
+ return { absPath, body, imports, exportNames };
118
+ }
119
+
120
+ function bundleFrontendModules(entryAbsPath) {
121
+ const nsNames = new Map();
122
+ const parsed = new Map(); // absPath -> parsed module
123
+ const order = []; // topological, dependency-first
124
+ const visiting = new Set();
125
+
126
+ function visit(absPath) {
127
+ // `visiting` (currently-on-the-DFS-stack) must be checked BEFORE
128
+ // `parsed` (fully-resolved, safe to skip) — found by this task's own
129
+ // review: the original ordering set `parsed` before recursing into a
130
+ // module's own imports, so a cycle back to an ancestor hit the
131
+ // `parsed.has()` check first and returned silently, making the
132
+ // `visiting`-based throw below unreachable for ANY cycle. Reproduced
133
+ // live: a real entry<->b.js cycle built successfully at bundle time
134
+ // and only failed later, as a confusing `ReferenceError` (TDZ) when
135
+ // the broken output was executed, instead of this function's own
136
+ // clear build-time error.
137
+ if (visiting.has(absPath)) {
138
+ throw new Error(`bundleFrontendModules: circular import detected at ${absPath} — this bundler does not support cycles`);
139
+ }
140
+ if (parsed.has(absPath)) return;
141
+ visiting.add(absPath);
142
+ const mod = _parseModule(absPath);
143
+ parsed.set(absPath, mod);
144
+ for (const imp of mod.imports) visit(imp.resolved);
145
+ visiting.delete(absPath);
146
+ order.push(absPath);
147
+ }
148
+ visit(entryAbsPath);
149
+
150
+ const chunks = [];
151
+ for (const absPath of order) {
152
+ const mod = parsed.get(absPath);
153
+ const destructures = mod.imports
154
+ .map((imp) => ` const { ${imp.names.join(', ')} } = ${_nsName(imp.resolved, nsNames)};`)
155
+ .join('\n');
156
+
157
+ if (absPath === entryAbsPath) {
158
+ // Entry: emit unwrapped at top level so its declarations become
159
+ // real top-level bindings the caller can invoke — see the header
160
+ // comment for why this must not be an IIFE like every other module.
161
+ chunks.push(`${destructures}\n${mod.body}`);
162
+ continue;
163
+ }
164
+
165
+ const ns = _nsName(absPath, nsNames);
166
+ const returnObj = mod.exportNames.length ? ` return { ${mod.exportNames.join(', ')} };` : ' return {};';
167
+ chunks.push(`const ${ns} = (function() {\n${destructures}\n${mod.body}\n${returnObj}\n})();`);
168
+ }
169
+ const bundled = chunks.join('\n\n');
170
+
171
+ // Real gap found by the final whole-branch review, live-reproduced: the
172
+ // UNSUPPORTED_IMPORT_RE/EXPORT_STAR_RE/EXPORT_DEFAULT_RE guards above
173
+ // only cover THREE specific unsupported forms — real ES syntax this
174
+ // bundler doesn't handle (`export async function`, `export { g };`
175
+ // re-export lists, `import { h as hh }` renames) builds with NO error
176
+ // and only fails later, as a page-load-time SyntaxError that silently
177
+ // blanks the whole page (export-entry.js's own showError() never runs,
178
+ // since the entire inline <script> fails to parse before any of its
179
+ // code executes) — directly contradicting this file's own documented
180
+ // "throws a clear error on anything else" promise. `export async
181
+ // function` already exists in the real tree today
182
+ // (frontend/src/lib/api-client.js) — outside today's bundled entry
183
+ // point's own reachable graph only by luck. Rather than enumerating
184
+ // every unsupported form by name (the exact approach that missed these
185
+ // three), validate the FINAL bundle is syntactically valid JS before
186
+ // returning it — this converts any parse failure, including forms not
187
+ // yet imagined, into a clear build-time error. `new Function` compiles
188
+ // without executing (measured ~1ms on the real ~131KB bundle — cheap).
189
+ try {
190
+ // eslint-disable-next-line no-new-func
191
+ new Function(bundled);
192
+ } catch (e) {
193
+ throw new Error(`bundleFrontendModules: the assembled bundle is not valid JavaScript (${e.message}) — one of the ${order.length} modules likely uses an ES form this bundler doesn't support (only named imports/exports, no async/generator export shorthand ambiguity, no \`export { x };\` lists, no \`import { x as y }\` renames)`);
194
+ }
195
+ return bundled;
196
+ }
197
+
198
+ // EXTERNAL MODULE: ./src/lineage/export-json.js
199
+ var export_json = __webpack_require__(859);
200
+ ;// CONCATENATED MODULE: ./scripts/generate-html-report.mjs
201
+ // generate-html-report.mjs — Milestone 4, sub-project Self-contained
202
+ // HTML report. Assembles ONE offline-safe HTML document: inline CSS,
203
+ // one bundled inline <script> (Task 1's bundler over Task 2's
204
+ // export-entry.js), and the graph embedded via exportGraphJSON
205
+ // (redacted by default) as a global the bundled script reads.
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+ const HERE = external_node_path_.dirname((0,external_node_url_.fileURLToPath)(import.meta.url));
214
+ const FRONTEND_ROOT = external_node_path_.resolve(HERE, '../../frontend');
215
+ const STYLES_DIR = external_node_path_.join(FRONTEND_ROOT, 'styles');
216
+ const ENTRY_PATH = external_node_path_.join(FRONTEND_ROOT, 'src', 'export-entry.js');
217
+
218
+ // NOT alphabetical — confirmed this session by reading the real
219
+ // frontend/index.html directly: its own <link> order is
220
+ // tokens.css, shell.css, architecture-view.css, inspector.css,
221
+ // privacy-view.css, trace-view.css, filter-rail.css, inventory-view.css,
222
+ // query-bar.css. `tokens.css` first is load-bearing (CSS custom
223
+ // properties the other 8 files consume via `var(--...)` — an alphabetical
224
+ // sort would put it 8th, after 7 files that reference undefined custom
225
+ // properties on first paint). Matching real cascade order avoids a real
226
+ // specificity/undefined-custom-property regression alphabetical sorting
227
+ // would introduce silently. Re-confirmed against the real index.html
228
+ // directly at implementation time (unchanged from the task-3 brief's own
229
+ // citation).
230
+ const CSS_LOAD_ORDER = [
231
+ 'tokens.css', 'shell.css', 'architecture-view.css', 'inspector.css',
232
+ 'privacy-view.css', 'trace-view.css', 'filter-rail.css',
233
+ 'inventory-view.css', 'query-bar.css',
234
+ ];
235
+
236
+ function _inlineCss() {
237
+ const onDisk = new Set(external_node_fs_.readdirSync(STYLES_DIR).filter((f) => f.endsWith('.css')));
238
+ const missing = CSS_LOAD_ORDER.filter((f) => !onDisk.has(f));
239
+ if (missing.length) throw new Error(`generate-html-report: CSS_LOAD_ORDER names files not found in ${STYLES_DIR}: ${missing.join(', ')} — frontend/index.html's own <link> list may have changed; re-sync CSS_LOAD_ORDER with it`);
240
+ const extra = [...onDisk].filter((f) => !CSS_LOAD_ORDER.includes(f));
241
+ if (extra.length) throw new Error(`generate-html-report: real CSS files not in CSS_LOAD_ORDER: ${extra.join(', ')} — a new stylesheet was added to frontend/styles/ without updating this list's load order`);
242
+ return CSS_LOAD_ORDER.map((f) => external_node_fs_.readFileSync(external_node_path_.join(STYLES_DIR, f), 'utf8')).join('\n');
243
+ }
244
+
245
+ function generateHtmlReport(graph, opts = {}) {
246
+ const exported = (0,export_json.exportGraphJSON)(graph, opts);
247
+ const css = _inlineCss();
248
+ const bundledJs = bundleFrontendModules(ENTRY_PATH);
249
+ // Escape `<` so scanned-source-derived content (a node/flow/data-element
250
+ // label — none of which _redactGraph covers, since labels aren't a
251
+ // secret-shaped surface, but CAN carry arbitrary scanned identifier
252
+ // text) can never contain a literal `</script>` that breaks out of this
253
+ // inline data script and injects a second one. Same mitigation, same
254
+ // reasoning, as the existing SAST/SCA HTML report's own precedent
255
+ // (scanner/src/report/index.js's toHTML) — found missing here and
256
+ // fixed by this sub-project's own final task review, which reproduced
257
+ // the injection live before this fix landed.
258
+ const envelopeJson = JSON.stringify(exported).replace(/</g, '\\u003c');
259
+ return `<!DOCTYPE html>
260
+ <html lang="en" data-theme="dark">
261
+ <head>
262
+ <meta charset="UTF-8" />
263
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
264
+ <title>Data Flow Explorer — self-contained report</title>
265
+ <style>
266
+ ${css}
267
+ </style>
268
+ </head>
269
+ <body>
270
+ <div id="app-root"></div>
271
+ <script>
272
+ // The full exportGraphJSON envelope (digest/scope/coverage/limitations/
273
+ // confidential + the redacted graph body) is embedded whole here, under
274
+ // its own name, so this report carries the same tamper-evident/disclosure
275
+ // metadata the JSON exporter produces (PRD §17.5) — never dropped just
276
+ // because this is an HTML report rather than a .json file.
277
+ //
278
+ // __AGENTIC_SECURITY_EXPORTED_GRAPH__ is then bound to the envelope's own
279
+ // \`.graph\` body, NOT the envelope itself — this is a deliberate,
280
+ // necessary departure from an earlier draft of this generator (which
281
+ // assigned the whole envelope directly to that name). frontend/src/
282
+ // export-entry.js (Task 2, already shipped and covered by its own golden
283
+ // DOM-equivalence test, test/bundle-frontend-golden.test.js) reads this
284
+ // EXACT global and passes it straight through to bootstrap(rootEl, graph)
285
+ // -> mountShell(rootEl, graph)/computeFilterFacets(graph), both of which
286
+ // expect a real DataFlowGraph v1 document (top-level nodes/edges/flows/...),
287
+ // never the exportGraphJSON envelope shape (which nests the graph one
288
+ // level down, under .graph, alongside digest/scope/confidential). Handing
289
+ // bootstrap() the envelope instead of the graph would silently break real
290
+ // rendering — exactly what this sub-project's own real-Chrome acceptance
291
+ // proof (task-3 brief, Step 5) exists to catch. Confirmed against
292
+ // export-entry.js's and Task 2's golden test's real source before this
293
+ // generator was written, not assumed.
294
+ window.__AGENTIC_SECURITY_EXPORT_ENVELOPE__ = ${envelopeJson};
295
+ window.__AGENTIC_SECURITY_EXPORTED_GRAPH__ = window.__AGENTIC_SECURITY_EXPORT_ENVELOPE__.graph;
296
+ </script>
297
+ <script>
298
+ ${bundledJs}
299
+ </script>
300
+ </body>
301
+ </html>`;
302
+ }
303
+
304
+
305
+ /***/ })
306
+
307
+ };
@@ -0,0 +1,117 @@
1
+ export const id = 3276;
2
+ export const ids = [3276];
3
+ export const modules = {
4
+
5
+ /***/ 3276:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
+ /* harmony export */ validateScenario: () => (/* binding */ validateScenario)
10
+ /* harmony export */ });
11
+ /* unused harmony exports SCENARIO_VERSION, SCENARIO_OPERATION_KINDS, SCENARIO_OPERATION_REQUIRED_FIELDS */
12
+ // scenario.js — M5 deliverable #3a (FR-502 §10.10, DFG-0xx): the
13
+ // Scenario extension contract — a hypothetical set of graph overrides,
14
+ // NOT a DataFlowGraph v1 entity, mirrors recipient-profile.js's own
15
+ // contract shape exactly (structural-only {valid, errors} validator,
16
+ // zero graph access, per-field evidence typing for the fields a
17
+ // Scenario actually overrides).
18
+ //
19
+ // See docs/superpowers/plans/2026-09-02-data-flow-explorer-m5-whatif-simulator-scoping.md
20
+ // for the full design reasoning, including why EVIDENCE_GRADES gained
21
+ // 'assumed' instead of reusing 'declared', and why this module's own
22
+ // operations catalog excludes synthetic node/edge insertion (deferred).
23
+
24
+ const SCENARIO_VERSION = '1.0.0';
25
+
26
+ // The 6 in-scope hypothetical-change kinds (FR-502's own 7, minus the
27
+ // deferred synthetic-insertion category). Each operation names its
28
+ // target canonical id(s) plus the override value(s); scenario-engine.js
29
+ // is the only consumer that interprets `kind`.
30
+ const SCENARIO_OPERATION_KINDS = Object.freeze([
31
+ 'require_transit_protection',
32
+ 'apply_handling',
33
+ 'remove_entity',
34
+ 'replace_recipient_fact',
35
+ 'change_storage_fact',
36
+ 'change_governance_fact',
37
+ ]);
38
+
39
+ // Per-operation-kind required fields, beyond the universal `kind`. Kept
40
+ // as data (not inline in validateScenario) for the same reason
41
+ // SCENARIO_OPERATION_KINDS above is — a single source of truth a table
42
+ // can be checked against — though scenario-engine.js does not currently
43
+ // import this table itself; it only mentions it in a prose comment on
44
+ // its own _applyReplaceRecipientFact.
45
+ const SCENARIO_OPERATION_REQUIRED_FIELDS = Object.freeze({
46
+ require_transit_protection: ['targetEdgeId'],
47
+ apply_handling: ['targetEdgeId', 'handling'],
48
+ remove_entity: ['targetNodeId'],
49
+ replace_recipient_fact: ['targetNodeId', 'field', 'value'],
50
+ change_storage_fact: ['targetNodeId', 'field', 'value'],
51
+ change_governance_fact: ['targetFlowId', 'field', 'value'],
52
+ });
53
+
54
+ function _isNonEmptyString(v) { return typeof v === 'string' && v.length > 0; }
55
+ function _isPlainObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }
56
+ function _isStringArray(v) { return Array.isArray(v) && v.every((x) => typeof x === 'string'); }
57
+
58
+ /**
59
+ * Structural validation only — mirrors validateRecipientProfile's own
60
+ * {valid, errors} shape and "never throws" contract. Does not check
61
+ * that targetEdgeId/targetNodeId/targetFlowId actually exist in any
62
+ * real graph — that is scenario-engine.js's job at apply time, since
63
+ * this module has zero graph access by design.
64
+ */
65
+ function validateScenario(record) {
66
+ const errors = [];
67
+ const err = (p, message) => errors.push({ path: p, message });
68
+ if (!record || typeof record !== 'object' || Array.isArray(record)) {
69
+ err('$', 'Scenario record must be an object');
70
+ return { valid: false, errors };
71
+ }
72
+ if (!_isNonEmptyString(record.id) || !record.id.startsWith('scenario:')) {
73
+ err('$.id', 'id is required and must start with "scenario:"');
74
+ }
75
+ if (!_isNonEmptyString(record.version)) err('$.version', 'version is required');
76
+ if (!_isNonEmptyString(record.baseGraphId)) err('$.baseGraphId', 'baseGraphId is required');
77
+ if (!_isNonEmptyString(record.baseGraphDigest)) err('$.baseGraphDigest', 'baseGraphDigest is required');
78
+ if (!_isNonEmptyString(record.author)) err('$.author', 'author is required');
79
+ if (!_isNonEmptyString(record.createdAt)) err('$.createdAt', 'createdAt is required');
80
+ if (record.expiration !== null && record.expiration !== undefined && !_isNonEmptyString(record.expiration)) {
81
+ err('$.expiration', 'expiration must be a string or null');
82
+ }
83
+ if (!_isStringArray(record.assumptions ?? [])) err('$.assumptions', 'assumptions must be an array of strings');
84
+ if (!_isStringArray(record.verificationRequirements ?? [])) {
85
+ err('$.verificationRequirements', 'verificationRequirements must be an array of strings');
86
+ }
87
+ if (!Array.isArray(record.operations) || record.operations.length === 0) {
88
+ err('$.operations', 'operations is required and must be a non-empty array');
89
+ } else {
90
+ record.operations.forEach((op, i) => {
91
+ const p = `$.operations[${i}]`;
92
+ if (!_isPlainObject(op)) { err(p, 'each operation must be an object'); return; }
93
+ if (!SCENARIO_OPERATION_KINDS.includes(op.kind)) {
94
+ err(`${p}.kind`, `unrecognized operation kind "${op.kind}" — must be one of ${SCENARIO_OPERATION_KINDS.join('|')}`);
95
+ return;
96
+ }
97
+ for (const field of SCENARIO_OPERATION_REQUIRED_FIELDS[op.kind]) {
98
+ if (op[field] === undefined || op[field] === null || op[field] === '') {
99
+ err(`${p}.${field}`, `operation of kind "${op.kind}" requires "${field}"`);
100
+ }
101
+ }
102
+ });
103
+ }
104
+ // simulatedDelta is populated by scenario-engine.js after apply, never
105
+ // by a caller constructing the pre-apply record — null is the only
106
+ // valid pre-apply value, an object (scenario-diff.js's own shape) the
107
+ // only valid post-apply value.
108
+ if (record.simulatedDelta !== null && record.simulatedDelta !== undefined && !_isPlainObject(record.simulatedDelta)) {
109
+ err('$.simulatedDelta', 'simulatedDelta must be null (before apply) or an object (after apply)');
110
+ }
111
+ return { valid: errors.length === 0, errors };
112
+ }
113
+
114
+
115
+ /***/ })
116
+
117
+ };
@@ -1,5 +1,5 @@
1
- export const id = 415;
2
- export const ids = [415];
1
+ export const id = 3415;
2
+ export const ids = [3415];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 3415:
@@ -1,5 +1,5 @@
1
- export const id = 499;
2
- export const ids = [499];
1
+ export const id = 3499;
2
+ export const ids = [3499];
3
3
  export const modules = {
4
4
 
5
5
  /***/ 3499: