@blamejs/blamejs-shop 0.4.30 → 0.4.32

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 (338) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/checkout.js +8 -0
  4. package/lib/order.js +71 -11
  5. package/lib/vendor/MANIFEST.json +392 -278
  6. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  7. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  8. package/lib/vendor/blamejs/.gitignore +6 -0
  9. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  10. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  11. package/lib/vendor/blamejs/README.md +8 -6
  12. package/lib/vendor/blamejs/SECURITY.md +19 -3
  13. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  14. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  15. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  16. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  17. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  18. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  19. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  20. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  21. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  25. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  26. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  27. package/lib/vendor/blamejs/index.js +4 -0
  28. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  30. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  31. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  32. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  33. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  34. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  35. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  36. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  37. package/lib/vendor/blamejs/lib/audit.js +259 -123
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  39. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  40. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  41. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  42. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  43. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  44. package/lib/vendor/blamejs/lib/cache.js +174 -105
  45. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  46. package/lib/vendor/blamejs/lib/cli.js +19 -14
  47. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  48. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  49. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  50. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  51. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  52. package/lib/vendor/blamejs/lib/consent.js +82 -29
  53. package/lib/vendor/blamejs/lib/constants.js +27 -11
  54. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  55. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  56. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  57. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  58. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  59. package/lib/vendor/blamejs/lib/db.js +249 -99
  60. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  61. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  62. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  63. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  64. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  65. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  66. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  67. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  68. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  69. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  70. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  71. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  72. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  73. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  74. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  75. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  76. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  77. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  78. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  79. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  80. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  81. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  82. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  83. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  84. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  85. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  86. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  87. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  88. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  89. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  90. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  91. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  92. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  93. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  94. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  95. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  96. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  98. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  99. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  100. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  101. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  102. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  103. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  104. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  106. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  107. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  108. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  109. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  110. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  111. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  112. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  113. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  114. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  115. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  116. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  117. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  118. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  119. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  120. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  121. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  122. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  123. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  124. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  125. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  126. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  128. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  129. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  132. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  134. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  136. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  137. package/lib/vendor/blamejs/lib/mail.js +8 -4
  138. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  139. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  140. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  141. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  142. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  143. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  144. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  145. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  146. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  147. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  148. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  149. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  151. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  152. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  153. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  154. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  155. package/lib/vendor/blamejs/lib/observability.js +124 -0
  156. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  157. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  158. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  159. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  160. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  161. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  162. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  163. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  164. package/lib/vendor/blamejs/lib/queue.js +7 -0
  165. package/lib/vendor/blamejs/lib/redact.js +68 -11
  166. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  167. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  168. package/lib/vendor/blamejs/lib/retention.js +101 -40
  169. package/lib/vendor/blamejs/lib/router.js +212 -5
  170. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  171. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  172. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  173. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  174. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  175. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  176. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  177. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  178. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  179. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  180. package/lib/vendor/blamejs/lib/session.js +175 -77
  181. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  182. package/lib/vendor/blamejs/lib/sse.js +26 -0
  183. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  184. package/lib/vendor/blamejs/lib/static.js +177 -34
  185. package/lib/vendor/blamejs/lib/subject.js +96 -49
  186. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  187. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  189. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  190. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  191. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  192. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  193. package/lib/vendor/blamejs/package.json +2 -2
  194. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  202. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  203. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  204. package/lib/vendor/blamejs/scripts/release.js +398 -38
  205. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  206. package/lib/vendor/blamejs/test/10-state.js +140 -14
  207. package/lib/vendor/blamejs/test/20-db.js +65 -2
  208. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  209. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  210. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  211. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  212. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  213. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  214. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  215. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  222. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  223. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  224. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  225. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  226. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  227. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  228. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  229. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  230. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  231. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  232. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  233. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  234. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  235. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  236. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  237. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  238. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  240. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  250. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  251. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  272. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  273. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  274. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  275. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  279. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  280. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  293. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  304. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  310. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  312. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  313. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  314. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  315. package/lib/vendor/blamejs/test/smoke.js +79 -21
  316. package/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  318. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  319. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  320. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  321. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  322. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  323. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  324. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  325. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  326. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  327. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  328. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  329. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  330. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  331. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  332. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  335. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  336. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  337. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  338. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ /**
3
+ * Live b.sql sqlite-FTS5 + catalog/pragma test against a real node:sqlite
4
+ * DatabaseSync handle (no docker - sqlite is the built-in dialect).
5
+ *
6
+ * Exercises the sqlite-only builders the mail store + the at-rest key-
7
+ * rotation pipeline drive, end to end against a live engine so the emitted
8
+ * SQL is proven to PARSE + RUN + return the right rows, not just match a
9
+ * string shape:
10
+ *
11
+ * 1. createVirtualTable -> CREATE VIRTUAL TABLE ... USING fts5(...) runs;
12
+ * whereMatch -> `<fts> MATCH ?` returns exactly the rows whose tokens
13
+ * match, with the query string bound (never interpolated).
14
+ * 2. whereInJsonEach -> `<col> IN (SELECT value FROM json_each(?))`
15
+ * unrolls a JSON-array string bind to a membership filter.
16
+ * 3. The catalog sub-API (listTables / tableExists / tableInfo /
17
+ * sampleRandom / changes) + pragma (journal_mode / synchronous /
18
+ * wal_checkpoint) emit statements the engine accepts, returning the
19
+ * real catalog metadata.
20
+ * 4. A bound MATCH operand carrying SQL metacharacters stays a literal
21
+ * FTS query term - it cannot break out of the placeholder.
22
+ */
23
+
24
+ var { DatabaseSync } = require("node:sqlite");
25
+ var helpers = require("../helpers");
26
+ var check = helpers.check;
27
+ var b = require("../../");
28
+
29
+ function _all(db, built) {
30
+ var st = db.prepare(built.sql);
31
+ return built.params.length > 0 ? st.all.apply(st, built.params) : st.all();
32
+ }
33
+ function _get(db, built) {
34
+ var st = db.prepare(built.sql);
35
+ return built.params.length > 0 ? st.get.apply(st, built.params) : st.get();
36
+ }
37
+ function _run(db, built) {
38
+ var st = db.prepare(built.sql);
39
+ return built.params.length > 0 ? st.run.apply(st, built.params) : st.run();
40
+ }
41
+
42
+ async function run() {
43
+ var sql = b.sql;
44
+ var db = new DatabaseSync(":memory:");
45
+ try {
46
+ // ---- 1. FTS5 virtual table + MATCH ----
47
+ _run(db, sql.createVirtualTable("mail_fts", {
48
+ columns: [{ name: "objectid", unindexed: true }, "subject_toks", "body_toks"],
49
+ tokenize: "unicode61 remove_diacritics 2",
50
+ quoteName: true,
51
+ }));
52
+ check("createVirtualTable: CREATE VIRTUAL TABLE USING fts5 runs", true);
53
+
54
+ function ins(oid, subj, body) {
55
+ _run(db, sql.insert("mail_fts", { quoteName: true })
56
+ .columns(["objectid", "subject_toks", "body_toks"])
57
+ .values({ objectid: oid, subject_toks: subj, body_toks: body }).toSql());
58
+ }
59
+ ins("m1", "alpha bravo", "charlie delta");
60
+ ins("m2", "bravo", "echo");
61
+ ins("m3", "zulu", "delta foxtrot");
62
+
63
+ // `<fts> MATCH ?` inside the IN-subquery shape the mail store uses -
64
+ // bind the query string, never interpolate.
65
+ var matchSub = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
66
+ .columns(["objectid"]).whereMatch("mail_fts", "bravo").toSql();
67
+ var bravoRows = _all(db, matchSub).map(function (r) { return r.objectid; }).sort();
68
+ check("whereMatch 'bravo' returns m1 + m2 (token in subject of both)",
69
+ bravoRows.length === 2 && bravoRows[0] === "m1" && bravoRows[1] === "m2");
70
+
71
+ var deltaSub = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
72
+ .columns(["objectid"]).whereMatch("mail_fts", "delta").toSql();
73
+ var deltaRows = _all(db, deltaSub).map(function (r) { return r.objectid; }).sort();
74
+ check("whereMatch 'delta' returns m1 + m3 (token in body of both)",
75
+ deltaRows.length === 2 && deltaRows[0] === "m1" && deltaRows[1] === "m3");
76
+
77
+ // The MATCH operand binds: a query carrying a token that does not exist
78
+ // returns nothing (and a metacharacter-laden operand stays a literal
79
+ // FTS term, never a statement break - the engine parses it as a query).
80
+ var noneSub = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
81
+ .columns(["objectid"]).whereMatch("mail_fts", "nonexistenttoken").toSql();
82
+ check("whereMatch unknown token returns no rows", _all(db, noneSub).length === 0);
83
+
84
+ // ---- 2. json_each membership ----
85
+ db.prepare('CREATE TABLE "msgs" ("objectid" TEXT, "folder_id" INTEGER)').run();
86
+ db.prepare('INSERT INTO "msgs" VALUES (?,?),(?,?),(?,?)')
87
+ .run("m1", 1, "m2", 1, "m3", 2);
88
+ var jeBuilt = sql.select("msgs", { dialect: "sqlite", quoteName: true })
89
+ .columns(["objectid", "folder_id"])
90
+ .where("folder_id", 1)
91
+ .whereInJsonEach("objectid", JSON.stringify(["m1", "m3"]))
92
+ .toSql();
93
+ var jeRows = _all(db, jeBuilt).map(function (r) { return r.objectid; });
94
+ check("whereInJsonEach: folder=1 AND objectid IN json_each(['m1','m3']) -> only m1",
95
+ jeRows.length === 1 && jeRows[0] === "m1");
96
+
97
+ // ---- 3. catalog sub-API ----
98
+ var tables = _all(db, sql.catalog.listTables()).map(function (r) { return r.name; });
99
+ check("catalog.listTables lists the user tables (msgs present, no sqlite_ internal)",
100
+ tables.indexOf("msgs") !== -1 && tables.every(function (n) { return n.indexOf("sqlite_") !== 0; }));
101
+ check("catalog.tableExists true for a real table",
102
+ !!_get(db, sql.catalog.tableExists("msgs")));
103
+ check("catalog.tableExists false for a missing table",
104
+ !_get(db, sql.catalog.tableExists("no_such_table")));
105
+ var info = _all(db, sql.catalog.tableInfo("msgs")).map(function (c) { return c.name; }).sort();
106
+ check("catalog.tableInfo returns the column names",
107
+ info.length === 2 && info[0] === "folder_id" && info[1] === "objectid");
108
+ var sample = _all(db, sql.catalog.sampleRandom("msgs", ["objectid"], { limit: 2 }));
109
+ check("catalog.sampleRandom ORDER BY RANDOM LIMIT ? returns <= limit rows",
110
+ sample.length <= 2 && sample.length >= 1);
111
+
112
+ // catalog.changes reports the row count of the last write on this conn.
113
+ db.prepare('UPDATE "msgs" SET "folder_id" = 9 WHERE "folder_id" = 2').run();
114
+ var changed = _get(db, sql.catalog.changes());
115
+ check("catalog.changes reports last-write rowcount", changed && changed.c === 1);
116
+
117
+ // ---- 4. pragma sub-API ----
118
+ var jm = _get(db, sql.pragma("journal_mode", "WAL"));
119
+ check("pragma journal_mode=WAL runs (returns a mode row)", !!jm);
120
+ _run(db, sql.pragma("synchronous", "NORMAL"));
121
+ check("pragma synchronous=NORMAL runs", true);
122
+ _run(db, sql.pragma("wal_checkpoint", "TRUNCATE"));
123
+ check("pragma wal_checkpoint(TRUNCATE) runs", true);
124
+
125
+ // ---- 5. metacharacter operand stays bound (no breakout) ----
126
+ // A would-be-injection MATCH operand is a literal FTS query term: the
127
+ // FTS5 parser treats it as a (possibly zero-match) query, never a
128
+ // statement. The row count is whatever matches; the point is the
129
+ // statement does not error out / stack a second statement.
130
+ var safeMatch = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
131
+ .columns(["objectid"]).whereMatch("mail_fts", "alpha").toSql();
132
+ var injBuilt = { sql: safeMatch.sql, params: ['alpha"; DROP TABLE "msgs'] };
133
+ var injErr = null;
134
+ try { _all(db, injBuilt); } catch (e) { injErr = e; }
135
+ var msgsStill = !!_get(db, sql.catalog.tableExists("msgs"));
136
+ check("bound MATCH operand with metacharacters does not drop a table",
137
+ msgsStill);
138
+ // The metachar query either matches nothing or errors as a malformed
139
+ // FTS expression - either way "msgs" survived (no statement breakout).
140
+ check("metachar MATCH operand stayed a single bound statement",
141
+ injErr === null || msgsStill);
142
+ } finally {
143
+ db.close();
144
+ }
145
+ }
146
+
147
+ module.exports = { run: run };
148
+
149
+ if (require.main === module) {
150
+ run().then(
151
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
152
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
153
+ );
154
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Live proof of the outbound-TLS classical-downgrade audit. When an outbound
4
+ * connection negotiates classical X25519 (the peer offers no ML-KEM hybrid),
5
+ * the framework emits a `tls.classical_downgrade` audit event; when it
6
+ * negotiates a hybrid, it does not. Azurite (its OpenSSL has no ML-KEM)
7
+ * forces the classical fallback; MinIO-tls (OpenSSL 3.5) negotiates the
8
+ * hybrid. Runs over TLS with the test CA (NODE_EXTRA_CA_CERTS), no bypass.
9
+ */
10
+ var helpers = require("../helpers");
11
+ var b = helpers.b;
12
+ var check = helpers.check;
13
+ var services = require("../helpers/services");
14
+ var httpClient = require("../../lib/http-client");
15
+ var setupTestDb = require("../helpers/db").setupTestDb;
16
+ var teardownTestDb = require("../helpers/db").teardownTestDb;
17
+ var fs = require("node:fs"), os = require("node:os"), path = require("node:path");
18
+
19
+ async function downgradeRows(sinceMs) {
20
+ await b.audit.flush();
21
+ var rows = await b.audit.query({ action: "tls.classical_downgrade", from: sinceMs - 1000, limit: 100 });
22
+ return (rows || []).map(function (r) {
23
+ var md = r.metadata;
24
+ if (typeof md === "string") { try { md = JSON.parse(md); } catch (_e) { md = {}; } }
25
+ return md || {};
26
+ });
27
+ }
28
+
29
+ async function run() {
30
+ var azu = await services.requireService("azurite");
31
+ if (!azu.ok) throw new Error("azurite unreachable: " + azu.reason);
32
+ var mio = await services.requireService("minioTls");
33
+ if (!mio.ok) throw new Error("minio-tls unreachable: " + mio.reason);
34
+
35
+ var dir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-tlsdown-"));
36
+ try {
37
+ await setupTestDb(dir, []);
38
+
39
+ // Classical peer (Azurite — no ML-KEM hybrid). The HTTP response is
40
+ // irrelevant (an unauthenticated GET may 400); the downgrade audit fires
41
+ // on the TLS handshake regardless.
42
+ var t0 = Date.now();
43
+ try { await httpClient.request({ url: "https://127.0.0.1:10000/", method: "GET", allowInternal: true }); } catch (_e) {}
44
+ var afterAzu = await downgradeRows(t0);
45
+ var azuHit = afterAzu.filter(function (m) { return String(m.port) === "10000"; });
46
+ check("classical peer (Azurite) emitted a tls.classical_downgrade audit", azuHit.length >= 1);
47
+ check("downgrade audit names the classical group + host",
48
+ azuHit.some(function (m) { return m.group === "X25519" && m.host === "127.0.0.1"; }));
49
+
50
+ // PQC peer (MinIO-tls — negotiates the ML-KEM hybrid). No downgrade for it.
51
+ var t1 = Date.now();
52
+ try { await httpClient.request({ url: "https://127.0.0.1:9443/", method: "GET", allowInternal: true }); } catch (_e) {}
53
+ var afterMio = await downgradeRows(t1);
54
+ var mioHit = afterMio.filter(function (m) { return String(m.port) === "9443"; });
55
+ check("PQC peer (MinIO-tls) emitted NO downgrade audit (hybrid negotiated)", mioHit.length === 0);
56
+
57
+ await teardownTestDb(dir);
58
+ } finally {
59
+ try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_e) {}
60
+ }
61
+ console.log("OK — " + helpers.getChecks() + " checks passed");
62
+ }
63
+
64
+ module.exports = { run: run };
65
+
66
+ if (require.main === module) {
67
+ run().then(
68
+ function () { process.exit(0); },
69
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
70
+ );
71
+ }
@@ -3,6 +3,15 @@
3
3
  var helpers = require("../helpers");
4
4
  var b = helpers.b;
5
5
  var check = helpers.check;
6
+ var fs = helpers.fs;
7
+ var os = helpers.os;
8
+ var path = helpers.path;
9
+
10
+ // The shape-only tests below run single-process with no vault, so they
11
+ // pass requireMac:false (the documented escape hatch). The keyed-MAC
12
+ // envelope authentication (M6) is exercised against a real vault in the
13
+ // testEnvelopeMac* tests at the bottom of this file.
14
+ function _tmp() { return fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-evbus-")); }
6
15
 
7
16
  function _fakePubsub() {
8
17
  var subs = new Map();
@@ -43,7 +52,7 @@ function testSurface() {
43
52
  }
44
53
 
45
54
  async function testRegisterPublishSubscribe() {
46
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
55
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
47
56
  bus.registerTopic("mail.scan.malware-detected", {
48
57
  schema: { source: "string", confidence: "number" },
49
58
  });
@@ -58,7 +67,7 @@ async function testRegisterPublishSubscribe() {
58
67
  }
59
68
 
60
69
  async function testUnknownTopic() {
61
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
70
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
62
71
  await expectRejection("publish refuses unknown topic",
63
72
  bus.publish("mail.unknown.event", {}),
64
73
  "agent-event-bus/unknown-topic");
@@ -68,7 +77,7 @@ async function testUnknownTopic() {
68
77
  }
69
78
 
70
79
  async function testDuplicateTopic() {
71
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
80
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
72
81
  bus.registerTopic("mail.a.b", { schema: { x: "string" } });
73
82
  var threw = null;
74
83
  try { bus.registerTopic("mail.a.b", { schema: { x: "string" } }); }
@@ -78,7 +87,7 @@ async function testDuplicateTopic() {
78
87
  }
79
88
 
80
89
  async function testBadTopicShape() {
81
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
90
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
82
91
  var threw = null;
83
92
  try { bus.registerTopic("malware", { schema: { x: "string" } }); }
84
93
  catch (e) { threw = e; }
@@ -87,7 +96,7 @@ async function testBadTopicShape() {
87
96
  }
88
97
 
89
98
  async function testSchemaValidation() {
90
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
99
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
91
100
  bus.registerTopic("mail.scan.detected", {
92
101
  schema: { source: "string", confidence: "number" },
93
102
  });
@@ -113,7 +122,7 @@ async function testPermissions() {
113
122
  },
114
123
  auditFailures: false, auditSuccess: false,
115
124
  });
116
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), permissions: perms });
125
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), permissions: perms, requireMac: false });
117
126
  bus.registerTopic("mail.scan.detected", {
118
127
  schema: { source: "string" },
119
128
  permissions: { publish: ["mail-scan:write"], subscribe: ["mail-mx:write"] },
@@ -134,7 +143,7 @@ async function testPermissions() {
134
143
  }
135
144
 
136
145
  async function testTenantScope() {
137
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
146
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
138
147
  bus.registerTopic("mail.tenant.event", {
139
148
  schema: { source: "string" },
140
149
  tenantScope: true,
@@ -156,7 +165,7 @@ async function testTenantScope() {
156
165
  }
157
166
 
158
167
  async function testTenantScopeRefusesSubscriberWithoutTenantId() {
159
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
168
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
160
169
  bus.registerTopic("mail.scoped.event", {
161
170
  schema: { source: "string" },
162
171
  tenantScope: true,
@@ -172,7 +181,7 @@ async function testTenantScopeRefusesSubscriberWithoutTenantId() {
172
181
  }
173
182
 
174
183
  async function testAsyncHandlerErrors() {
175
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
184
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
176
185
  bus.registerTopic("mail.async.event", { schema: { x: "string" } });
177
186
  var crashed = false;
178
187
  var origHandler = process.listeners("unhandledRejection").slice();
@@ -196,7 +205,7 @@ async function testRefusesBadOpts() {
196
205
  }
197
206
 
198
207
  async function testListTopics() {
199
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
208
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
200
209
  bus.registerTopic("mail.a.b", { schema: { x: "string" }, posture: "soc2" });
201
210
  bus.registerTopic("mail.c.d", { schema: { y: "number" } });
202
211
  var list = bus.listTopics({});
@@ -208,7 +217,7 @@ async function testPublishRefusesUntenantedOnTenantTopic() {
208
217
  // SUBSTRATE-6 — tenant-scoped topic refuses publish without
209
218
  // actor.tenantId so the durable bus never accumulates untenanted
210
219
  // entries that get filtered out at subscribe-time.
211
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
220
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
212
221
  bus.registerTopic("mail.scan.malware", {
213
222
  schema: { source: "string" }, tenantScope: true,
214
223
  });
@@ -226,7 +235,7 @@ async function testPublishRefusesUntenantedOnTenantTopic() {
226
235
  async function testUnregisterTopic() {
227
236
  // SUBSTRATE-22 / BUG-12 — unregisterTopic exists; the kind filter
228
237
  // matches because register captures the kind.
229
- var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
238
+ var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
230
239
  bus.registerTopic("mail.scan.A", { schema: { x: "string" } });
231
240
  bus.registerTopic("mail.scan.B", { schema: { y: "number" } });
232
241
  bus.registerTopic("ai.classify.C", { schema: { z: "boolean" } });
@@ -242,6 +251,154 @@ async function testUnregisterTopic() {
242
251
  check("SUBSTRATE-22: re-register after unregister", bus.listTopics({}).length === 3);
243
252
  }
244
253
 
254
+ // ---- M6 — keyed-MAC envelope authentication (real vault) ----
255
+ //
256
+ // A pubsub-write attacker can set _tenantId to a victim's tenant + a
257
+ // schema-valid payload and forge a cross-tenant event; the tenant/schema
258
+ // checks prove SHAPE, not authenticity. The keyed MAC over the envelope's
259
+ // authority-bearing fields, verified at the consumer BEFORE the tenant
260
+ // check, refuses the forgery and any in-flight tamper. requireMac is on
261
+ // by default; these tests use the default with a real vault.
262
+
263
+ // A pubsub that captures the published envelope AND exposes the
264
+ // subscriber handler, so a test can deliver an arbitrary (forged /
265
+ // tampered) envelope directly to the consumer — exactly a pubsub-write
266
+ // attacker's capability.
267
+ function _capturingPubsub() {
268
+ var handlers = new Map();
269
+ var published = [];
270
+ return {
271
+ publish: async function (channel, envelope) {
272
+ published.push({ channel: channel, envelope: envelope });
273
+ (handlers.get(channel) || []).forEach(function (h) { h(envelope, { source: "fake" }); });
274
+ },
275
+ subscribe: async function (channel, handler) {
276
+ var list = handlers.get(channel) || [];
277
+ list.push(handler);
278
+ handlers.set(channel, list);
279
+ return function () {};
280
+ },
281
+ unsubscribe: function () {},
282
+ // Test affordance: deliver an attacker-controlled envelope straight to
283
+ // the consumer, bypassing publish() (the bus's own MAC mint).
284
+ _deliver: function (channel, envelope) {
285
+ (handlers.get(channel) || []).forEach(function (h) { h(envelope, { source: "attacker" }); });
286
+ },
287
+ _lastEnvelope: function () { return published.length ? published[published.length - 1].envelope : null; },
288
+ };
289
+ }
290
+
291
+ async function testEnvelopeMacForgedRefused() {
292
+ var tmpDir = _tmp();
293
+ await helpers.setupVaultOnly(tmpDir);
294
+ try {
295
+ var pubsub = _capturingPubsub();
296
+ var bus = b.agent.eventBus.create({ pubsub: pubsub }); // requireMac default ON
297
+ bus.registerTopic("mail.tenant.event", { schema: { source: "string" }, tenantScope: true });
298
+ var received = [];
299
+ await bus.subscribe("mail.tenant.event", function (p) { received.push(p); }, {
300
+ actor: { id: "victim", tenantId: "globex" },
301
+ });
302
+ // Attacker forges an envelope: victim's tenant, schema-valid payload,
303
+ // NO valid MAC. Delivered straight onto the bus (pubsub-write access).
304
+ pubsub._deliver("mail.tenant.event", {
305
+ _topic: "mail.tenant.event",
306
+ _posture: undefined,
307
+ _tenantId: "globex", // victim's tenant — forged
308
+ _publishedAt: Date.now(),
309
+ payload: { source: "attacker-injected" },
310
+ _mac: "AAAA", // bogus MAC
311
+ });
312
+ await helpers.passiveObserve(25, "M6: forged envelope must NOT be delivered");
313
+ check("forged cross-tenant envelope refused at consumer (MAC invalid)", received.length === 0);
314
+ } finally {
315
+ helpers.teardownVaultOnly(tmpDir);
316
+ }
317
+ }
318
+
319
+ async function testEnvelopeMacHonestDelivered() {
320
+ var tmpDir = _tmp();
321
+ await helpers.setupVaultOnly(tmpDir);
322
+ try {
323
+ var pubsub = _capturingPubsub();
324
+ var bus = b.agent.eventBus.create({ pubsub: pubsub });
325
+ bus.registerTopic("mail.tenant.event", { schema: { source: "string" }, tenantScope: true });
326
+ var received = [];
327
+ await bus.subscribe("mail.tenant.event", function (p) { received.push(p); }, {
328
+ actor: { id: "u-acme", tenantId: "acme" },
329
+ });
330
+ // Honest publish through the bus — it mints a valid MAC.
331
+ await bus.publish("mail.tenant.event", { source: "legit" }, {
332
+ actor: { id: "p1", tenantId: "acme" },
333
+ });
334
+ await helpers.waitUntil(function () { return received.length >= 1; }, {
335
+ timeoutMs: 5000, label: "M6: honestly-published event delivered",
336
+ });
337
+ check("honestly-published event delivered (valid MAC)", received.length === 1);
338
+ check("honest event payload intact", received[0].source === "legit");
339
+ } finally {
340
+ helpers.teardownVaultOnly(tmpDir);
341
+ }
342
+ }
343
+
344
+ async function testEnvelopeMacTamperFails() {
345
+ var tmpDir = _tmp();
346
+ await helpers.setupVaultOnly(tmpDir);
347
+ try {
348
+ var pubsub = _capturingPubsub();
349
+ var bus = b.agent.eventBus.create({ pubsub: pubsub });
350
+ bus.registerTopic("mail.scan.event", { schema: { source: "string" }, posture: "soc2" });
351
+ var receivedTopic = [];
352
+ await bus.subscribe("mail.scan.event", function (p) { receivedTopic.push(p); });
353
+
354
+ // Capture a genuine envelope, then tamper each authority field and
355
+ // re-deliver — every tamper must fail the MAC.
356
+ await bus.publish("mail.scan.event", { source: "ok" }, { actor: { id: "p1" } });
357
+ await helpers.waitUntil(function () { return receivedTopic.length >= 1; }, {
358
+ timeoutMs: 5000, label: "M6: baseline honest delivery",
359
+ });
360
+ var genuine = pubsub._lastEnvelope();
361
+ check("baseline honest envelope carries a MAC", typeof genuine._mac === "string" && genuine._mac.length > 0);
362
+
363
+ function _clone(env) { return JSON.parse(JSON.stringify(env)); }
364
+
365
+ // Tamper _posture (posture downgrade attempt).
366
+ var gotPosture = [];
367
+ await bus.subscribe("mail.scan.event", function (p) { gotPosture.push(p); });
368
+ var tPosture = _clone(genuine); tPosture._posture = "none"; tPosture.payload = { source: "ok" };
369
+ pubsub._deliver("mail.scan.event", tPosture);
370
+
371
+ // Tamper _topic.
372
+ var tTopic = _clone(genuine); tTopic._topic = "mail.scan.event"; tTopic.payload = { source: "ok" };
373
+ tTopic._tenantId = "injected"; // change a signed field
374
+ pubsub._deliver("mail.scan.event", tTopic);
375
+
376
+ // Tamper payload.
377
+ var tPayload = _clone(genuine); tPayload.payload = { source: "tampered" };
378
+ pubsub._deliver("mail.scan.event", tPayload);
379
+
380
+ await helpers.passiveObserve(40, "M6: tampered envelopes must NOT reach the second subscriber");
381
+ check("tampered _posture / _tenantId / payload all fail the MAC (none delivered)",
382
+ gotPosture.length === 0);
383
+ } finally {
384
+ helpers.teardownVaultOnly(tmpDir);
385
+ }
386
+ }
387
+
388
+ async function testEnvelopeMacPublishFailsClosedWithoutVault() {
389
+ // requireMac default ON + no vault → publish refuses (fail-closed)
390
+ // rather than emitting an unauthenticatable envelope.
391
+ b.vault._resetForTest();
392
+ if (b.agent.postureChain && b.agent.postureChain._resetForTest) b.agent.postureChain._resetForTest();
393
+ var bus = b.agent.eventBus.create({ pubsub: _capturingPubsub() });
394
+ bus.registerTopic("mail.scan.noVault", { schema: { source: "string" } });
395
+ var threw = null;
396
+ try { await bus.publish("mail.scan.noVault", { source: "x" }, { actor: { id: "p1" } }); }
397
+ catch (e) { threw = e; }
398
+ check("publish fails closed when no MAC key (requireMac default)",
399
+ threw && (threw.code || "").indexOf("agent-event-bus/envelope-mac-unavailable") !== -1);
400
+ }
401
+
245
402
  async function run() {
246
403
  testSurface();
247
404
  await testRegisterPublishSubscribe();
@@ -257,6 +414,12 @@ async function run() {
257
414
  await testRefusesBadOpts();
258
415
  await testListTopics();
259
416
  await testUnregisterTopic();
417
+ // M6 — keyed-MAC envelope authentication (real vault). The no-vault
418
+ // fail-closed test runs LAST (it tears the vault down).
419
+ await testEnvelopeMacForgedRefused();
420
+ await testEnvelopeMacHonestDelivered();
421
+ await testEnvelopeMacTamperFails();
422
+ await testEnvelopeMacPublishFailsClosedWithoutVault();
260
423
  }
261
424
 
262
425
  module.exports = { run: run };