@blamejs/blamejs-shop 0.4.31 → 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 (336) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +392 -278
  4. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  5. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  6. package/lib/vendor/blamejs/.gitignore +6 -0
  7. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  8. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  9. package/lib/vendor/blamejs/README.md +8 -6
  10. package/lib/vendor/blamejs/SECURITY.md +19 -3
  11. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  12. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  13. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  14. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  15. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  16. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  17. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  18. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  19. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  20. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  21. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  23. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  24. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  25. package/lib/vendor/blamejs/index.js +4 -0
  26. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  27. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  28. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  29. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  30. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  31. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  32. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  33. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  34. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  35. package/lib/vendor/blamejs/lib/audit.js +259 -123
  36. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  37. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  38. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  39. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  40. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  41. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  42. package/lib/vendor/blamejs/lib/cache.js +174 -105
  43. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  44. package/lib/vendor/blamejs/lib/cli.js +19 -14
  45. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  46. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  47. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  48. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  49. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  50. package/lib/vendor/blamejs/lib/consent.js +82 -29
  51. package/lib/vendor/blamejs/lib/constants.js +27 -11
  52. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  53. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  54. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  55. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  56. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  57. package/lib/vendor/blamejs/lib/db.js +249 -99
  58. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  59. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  60. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  61. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  62. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  63. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  64. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  65. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  66. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  67. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  68. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  69. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  70. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  71. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  72. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  73. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  74. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  75. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  76. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  77. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  78. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  79. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  80. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  81. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  82. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  83. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  84. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  85. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  86. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  87. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  88. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  89. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  90. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  91. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  92. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  93. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  94. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  95. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  96. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  97. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  98. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  99. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  100. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  101. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  102. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  103. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  104. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  106. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  107. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  108. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  109. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  110. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  111. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  112. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  113. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  114. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  115. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  116. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  117. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  118. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  119. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  120. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  121. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  123. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  124. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  125. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  126. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  128. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  129. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  131. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  132. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  133. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  134. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  135. package/lib/vendor/blamejs/lib/mail.js +8 -4
  136. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  137. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  138. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  139. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  140. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  141. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  142. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  143. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  144. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  145. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  146. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  147. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  148. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  149. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  150. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  151. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  152. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  153. package/lib/vendor/blamejs/lib/observability.js +124 -0
  154. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  155. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  156. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  157. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  158. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  159. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  160. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  161. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  162. package/lib/vendor/blamejs/lib/queue.js +7 -0
  163. package/lib/vendor/blamejs/lib/redact.js +68 -11
  164. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  165. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  166. package/lib/vendor/blamejs/lib/retention.js +101 -40
  167. package/lib/vendor/blamejs/lib/router.js +212 -5
  168. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  169. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  170. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  171. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  172. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  173. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  174. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  175. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  176. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  177. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  178. package/lib/vendor/blamejs/lib/session.js +175 -77
  179. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  180. package/lib/vendor/blamejs/lib/sse.js +26 -0
  181. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  182. package/lib/vendor/blamejs/lib/static.js +177 -34
  183. package/lib/vendor/blamejs/lib/subject.js +96 -49
  184. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  185. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  186. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  187. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  188. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  189. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  190. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  191. package/lib/vendor/blamejs/package.json +2 -2
  192. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  193. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  194. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  200. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  201. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  202. package/lib/vendor/blamejs/scripts/release.js +398 -38
  203. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  204. package/lib/vendor/blamejs/test/10-state.js +140 -14
  205. package/lib/vendor/blamejs/test/20-db.js +65 -2
  206. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  207. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  208. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  209. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  210. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  211. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  212. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  213. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  214. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  215. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  220. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  221. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  222. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  223. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  224. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  225. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  226. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  227. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  228. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  229. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  230. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  231. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  232. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  233. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  234. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  235. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  236. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  237. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  238. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  248. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  251. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  258. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  271. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  272. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  273. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  277. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  278. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  291. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  302. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  308. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  310. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  311. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  312. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  313. package/lib/vendor/blamejs/test/smoke.js +79 -21
  314. package/package.json +1 -1
  315. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  316. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  317. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  318. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  319. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  320. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  321. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  322. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  323. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  324. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  325. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  326. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  327. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  328. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  329. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  330. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  331. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  332. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  334. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  335. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  336. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -316,6 +316,33 @@ function create(opts) {
316
316
  return cur;
317
317
  }
318
318
 
319
+ // ---- Account authorization (RFC 8620 §3.6.1 accountNotFound) ------------
320
+ //
321
+ // The set of accountIds an actor may touch is whatever
322
+ // `opts.accountsFor(actor)` enumerates in its `accounts` map — the same
323
+ // source the session resource advertises. Resolving it ONCE per request
324
+ // and rejecting any client-supplied accountId outside that set is the
325
+ // cross-tenant authorization control: without it, a tenant's request can
326
+ // name another tenant's accountId and reach the operator's method/blob
327
+ // handler, which must then independently re-check or leak. The listener
328
+ // owns this gate so every account-scoped op (method dispatch + blob
329
+ // upload/download) is covered uniformly.
330
+ async function _permittedAccountIds(actor) {
331
+ var info = await opts.accountsFor(actor);
332
+ info = info || {};
333
+ var accounts = info.accounts || {};
334
+ // A Set of the accountIds the actor is enumerated for. An empty/garbage
335
+ // accounts map yields an empty set → every account-scoped reference is
336
+ // rejected (fail-closed), which is the correct posture for an actor the
337
+ // operator declined to grant any account.
338
+ var set = Object.create(null);
339
+ if (accounts && typeof accounts === "object") {
340
+ var ids = Object.keys(accounts);
341
+ for (var i = 0; i < ids.length; i += 1) set[ids[i]] = true;
342
+ }
343
+ return set;
344
+ }
345
+
319
346
  // ---- Dispatch ------------------------------------------------------------
320
347
  //
321
348
  // `dispatch(actor, body)` is the operator-callable form — accepts a
@@ -340,6 +367,20 @@ function create(opts) {
340
367
  return _refusalResponse(errType, (e && e.message) || "request refused");
341
368
  }
342
369
 
370
+ // Resolve the actor's permitted accountId set ONCE for the whole
371
+ // request (RFC 8620 §3.6.1). Every account-scoped method call is gated
372
+ // against it below, BEFORE the operator handler runs, so a client can't
373
+ // name another tenant's accountId and reach the backend.
374
+ var permittedAccounts;
375
+ try {
376
+ permittedAccounts = await _permittedAccountIds(actor);
377
+ } catch (e) {
378
+ _emit("mail.server.jmap.accounts_for_threw",
379
+ { error: (e && e.message) || String(e) }, "failure");
380
+ return _refusalResponse("urn:ietf:params:jmap:error:serverFail",
381
+ "account authorization unavailable");
382
+ }
383
+
343
384
  var methodResponses = [];
344
385
  var byClientId = Object.create(null);
345
386
  for (var i = 0; i < parsed.methodCalls.length; i += 1) {
@@ -361,6 +402,24 @@ function create(opts) {
361
402
  description: "Method '" + methodName + "' not implemented on this server" }, clientId]);
362
403
  continue;
363
404
  }
405
+ // Cross-tenant gate (RFC 8620 §3.6.1): if the call names an accountId,
406
+ // it MUST be one the actor is enumerated for. Rejected BEFORE the
407
+ // operator handler runs so a forged/foreign accountId never reaches
408
+ // the backend. Calls without an accountId (account-agnostic methods)
409
+ // pass through unchanged.
410
+ if (resolvedArgs && typeof resolvedArgs === "object" &&
411
+ resolvedArgs.accountId !== undefined && resolvedArgs.accountId !== null) {
412
+ var callAccountId = resolvedArgs.accountId;
413
+ if (typeof callAccountId !== "string" || !permittedAccounts[callAccountId]) {
414
+ _emit("mail.server.jmap.account_not_found",
415
+ { method: methodName, accountId: typeof callAccountId === "string" ? callAccountId : null,
416
+ clientId: clientId }, "denied");
417
+ methodResponses.push(["error",
418
+ { type: "urn:ietf:params:jmap:error:accountNotFound",
419
+ description: "accountId is not accessible to this actor" }, clientId]);
420
+ continue;
421
+ }
422
+ }
364
423
  if (!_legacyDeprecationEmitted && registry.source(methodName) === "builtin") {
365
424
  _legacyDeprecationEmitted = true;
366
425
  _emit("mail.server.jmap.methods_opt_deprecated",
@@ -813,6 +872,40 @@ function create(opts) {
813
872
  if (refused) return;
814
873
  var bytes = collector.result();
815
874
  Promise.resolve()
875
+ // Cross-tenant gate (RFC 8620 §3.6.1): the accountId in the upload
876
+ // URL must be one the actor is enumerated for, else accountNotFound
877
+ // — the foreign accountId never reaches uploadBlob.
878
+ .then(function () { return _permittedAccountIds(actor); })
879
+ .then(function (permitted) {
880
+ if (!permitted[accountId]) {
881
+ _emit("mail.server.jmap.account_not_found",
882
+ { op: "upload", accountId: accountId }, "denied");
883
+ res.statusCode = 404;
884
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
885
+ res.end(JSON.stringify({
886
+ type: "urn:ietf:params:jmap:error:accountNotFound",
887
+ description: "accountId is not accessible to this actor",
888
+ }));
889
+ return;
890
+ }
891
+ return _completeUpload(bytes);
892
+ })
893
+ .catch(function (err) {
894
+ _emit("mail.server.jmap.upload_threw",
895
+ { accountId: accountId, error: (err && err.message) || String(err) }, "failure");
896
+ if (!res.headersSent) {
897
+ res.statusCode = 500;
898
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
899
+ res.end(JSON.stringify({
900
+ type: "urn:ietf:params:jmap:error:serverFail",
901
+ description: "Upload failed",
902
+ }));
903
+ }
904
+ });
905
+ });
906
+
907
+ function _completeUpload(bytes) {
908
+ return Promise.resolve()
816
909
  .then(function () { return opts.mailStore.uploadBlob(actor, accountId, contentType, bytes); })
817
910
  .then(function (meta) {
818
911
  if (!meta || typeof meta !== "object" || typeof meta.blobId !== "string") {
@@ -827,18 +920,10 @@ function create(opts) {
827
920
  type: meta.type || contentType,
828
921
  size: typeof meta.size === "number" ? meta.size : bytes.length,
829
922
  }));
830
- })
831
- .catch(function (err) {
832
- _emit("mail.server.jmap.upload_threw",
833
- { accountId: accountId, error: (err && err.message) || String(err) }, "failure");
834
- res.statusCode = 500;
835
- res.setHeader("Content-Type", "application/json; charset=utf-8");
836
- res.end(JSON.stringify({
837
- type: "urn:ietf:params:jmap:error:serverFail",
838
- description: "Upload failed",
839
- }));
840
923
  });
841
- });
924
+ // Errors from uploadBlob propagate to the req.on("end") chain's
925
+ // .catch (single serverFail responder, headersSent-guarded).
926
+ }
842
927
  req.on("error", function () {
843
928
  if (!refused) {
844
929
  refused = true;
@@ -944,9 +1029,29 @@ function create(opts) {
944
1029
  }));
945
1030
  return;
946
1031
  }
1032
+ var downloadDenied = false;
947
1033
  Promise.resolve()
948
- .then(function () { return opts.mailStore.downloadBlob(actor, accountId, blobId); })
1034
+ // Cross-tenant gate (RFC 8620 §3.6.1): the accountId in the download
1035
+ // URL must be one the actor is enumerated for, else accountNotFound —
1036
+ // the foreign accountId never reaches downloadBlob.
1037
+ .then(function () { return _permittedAccountIds(actor); })
1038
+ .then(function (permitted) {
1039
+ if (!permitted[accountId]) {
1040
+ downloadDenied = true;
1041
+ _emit("mail.server.jmap.account_not_found",
1042
+ { op: "download", accountId: accountId, blobId: blobId }, "denied");
1043
+ res.statusCode = 404;
1044
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
1045
+ res.end(JSON.stringify({
1046
+ type: "urn:ietf:params:jmap:error:accountNotFound",
1047
+ description: "accountId is not accessible to this actor",
1048
+ }));
1049
+ return undefined;
1050
+ }
1051
+ return opts.mailStore.downloadBlob(actor, accountId, blobId);
1052
+ })
949
1053
  .then(function (result) {
1054
+ if (downloadDenied) return;
950
1055
  if (!result || (typeof result !== "object" && !Buffer.isBuffer(result))) {
951
1056
  res.statusCode = 404;
952
1057
  res.setHeader("Content-Type", "application/json; charset=utf-8");
@@ -73,6 +73,8 @@
73
73
  * - `mail.server.mx.rbl_refused` — connecting IP on a DNS blocklist (zones)
74
74
  * - `mail.server.mx.greylist_deferred` — (ip, from, rcpt) first-seen 450 deferral
75
75
  * - `mail.server.mx.data_refused` — refusal reason + SMTP code (5xx vs 4xx)
76
+ * - `mail.server.mx.envelope_verdict` — DATA-phase SPF/DKIM/DMARC results + action (accept / quarantine / reject / defer) + gate mode
77
+ * - `mail.server.mx.envelope_error` — DATA-phase authentication pipeline failure or timeout (disposition follows onTemperror)
76
78
  * - `mail.server.mx.delivered` — agent.handoff ack
77
79
  * - `mail.server.mx.tls_handshake_failed` — handshake error
78
80
  * - `mail.server.mx.smtp_smuggling_detected` — CRLF.CRLF injection class
@@ -111,13 +113,20 @@
111
113
  * (connecting-IP DNS blocklist, evaluated once per connection) and
112
114
  * `opts.greylist` ((ip, from, rcpt) first-seen deferral) evaluate at
113
115
  * RCPT TO and surface their verdicts on the `rcpt_to` event. The
114
- * message-authentication gates (`b.guardEnvelope` SPF/DKIM/DMARC
115
- * alignment) require the inbound SPF + DKIM verification results as
116
- * inputs; that inbound-auth pipeline composes `b.mail.spf` +
117
- * `b.mail.dmarc` + DKIM verification and lands as a follow-up, at
118
- * which point the DATA-phase envelope/DMARC gate wires in. Until
119
- * then operators run those checks on the delivered message via the
120
- * agent handoff.
116
+ * message-authentication gate (`opts.guardEnvelope`) runs at DATA
117
+ * completion through `b.mail.inbound.verify` SPF (RFC 7208) on the
118
+ * envelope identity, DKIM (RFC 6376) on the message bytes, DMARC
119
+ * (RFC 7489) policy + alignment on the From-header domain and in
120
+ * enforce mode refuses before the agent handoff: 550 5.7.26
121
+ * (RFC 7372) when the sender's published policy says reject, 550
122
+ * 5.7.1 on the RFC 7489 §6.6.1 multi-From spoofing shape, 451 4.7.0
123
+ * on DNS temperror or pipeline timeout (operator-tunable via
124
+ * `onTemperror` / `timeoutMs`). Accepted messages carry the verdict
125
+ * to the agent handoff as `auth` and gain the receiver's RFC 8601
126
+ * Authentication-Results header — any sender-attached header forging
127
+ * this receiver's authserv-id is stripped first (§5) — so downstream
128
+ * consumers act on authenticated results instead of re-verifying;
129
+ * monitor mode annotates without refusing.
121
130
  *
122
131
  * @card
123
132
  * Inbound SMTP / MX listener. RFC 5321 state machine with SMTP-
@@ -144,6 +153,12 @@ var mailServerTls = require("./mail-server-tls");
144
153
  var { defineClass } = require("./framework-error");
145
154
 
146
155
  var audit = lazyRequire(function () { return require("./audit"); });
156
+ // Lazy like the sibling host primitives' guard loads — the inbound
157
+ // authentication pipeline (and the DKIM verifier whose range
158
+ // constants the boot validation mirrors) only loads when an operator
159
+ // wires opts.guardEnvelope.
160
+ var mailAuth = lazyRequire(function () { return require("./mail-auth"); });
161
+ var dkim = lazyRequire(function () { return require("./mail-dkim"); });
147
162
 
148
163
  var MailServerMxError = defineClass("MailServerMxError", { alwaysPermanent: true });
149
164
 
@@ -178,6 +193,59 @@ var RE_MAIL_FROM = /^MAIL\s+FROM:\s*<([^>]*)>(?:\s+(.*))?$/i;
178
193
  var RE_RCPT_TO = /^RCPT\s+TO:\s*<([^>]+)>(?:\s+.*)?$/i;
179
194
  var RE_SIZE = /SIZE=(\d+)/i;
180
195
 
196
+ // Map the b.mail.inbound.verify verdict to the DATA-phase gate action.
197
+ // The sender's published DMARC policy drives it (RFC 7489 §6.3 p= /
198
+ // §6.6.2 disposition): reject → refuse at the wire; quarantine →
199
+ // deliver annotated (an MX cannot spam-folder — the downstream agent
200
+ // owns disposition); none / pass → accept. DNS temperror defers or
201
+ // accepts per the operator's onTemperror choice. permerror carries a
202
+ // reject recommendation only for the multi-From spoofing shape
203
+ // (RFC 7489 §6.6.1), set by the pipeline itself.
204
+ function _envelopeActionFor(inbound, gate) {
205
+ var dmarc = inbound.dmarc || {};
206
+ if (dmarc.result === "temperror") {
207
+ return gate.onTemperror === "accept" ? "accept" : "defer";
208
+ }
209
+ if (dmarc.recommendedAction === "reject") return "reject";
210
+ if (dmarc.recommendedAction === "quarantine") return "quarantine";
211
+ return "accept";
212
+ }
213
+
214
+ // RFC 8601 §5 — an MTA adding its own Authentication-Results header
215
+ // MUST first remove any existing instance claiming its authserv-id: a
216
+ // sender can pre-attach a forged header carrying the receiver's name
217
+ // ("Authentication-Results: mx.example.com; dmarc=pass") and downstream
218
+ // consumers that trust the receiver's A-R header would read the forged
219
+ // verdict instead of the computed one. Headers naming OTHER
220
+ // authserv-ids are prior-hop information and stay. Operates on the
221
+ // header block only — the block is decoded as latin1 (byte-preserving
222
+ // round-trip) and the body bytes are never decoded at all, so 8-bit
223
+ // content is untouched.
224
+ function _stripForgedAuthResults(messageBuf, authservId) {
225
+ if (!authservId) return messageBuf;
226
+ var sepIdx = messageBuf.indexOf("\r\n\r\n");
227
+ var headerEnd = sepIdx === -1 ? messageBuf.length : sepIdx + 2;
228
+ var head = messageBuf.slice(0, headerEnd).toString("latin1");
229
+ var rest = messageBuf.slice(headerEnd);
230
+ if (head.toLowerCase().indexOf("authentication-results:") === -1) return messageBuf;
231
+ var lines = head.split("\r\n");
232
+ var out = [];
233
+ var skipping = false;
234
+ var prefix = "authentication-results:";
235
+ var wantId = authservId.toLowerCase();
236
+ for (var i = 0; i < lines.length; i += 1) {
237
+ var line = lines[i];
238
+ if (skipping && (line.charAt(0) === " " || line.charAt(0) === "\t")) continue; // folded continuation
239
+ skipping = false;
240
+ if (line.slice(0, prefix.length).toLowerCase() === prefix) {
241
+ var idTok = line.slice(prefix.length).trim().split(/[;\s]/)[0].toLowerCase();
242
+ if (idTok === wantId) { skipping = true; continue; }
243
+ }
244
+ out.push(line);
245
+ }
246
+ return Buffer.concat([Buffer.from(out.join("\r\n"), "latin1"), rest]);
247
+ }
248
+
181
249
  /**
182
250
  * @primitive b.mail.server.mx.create
183
251
  * @signature b.mail.server.mx.create(opts)
@@ -202,6 +270,16 @@ var RE_SIZE = /SIZE=(\d+)/i;
202
270
  * maxRcptsPerMessage: number, // default 100 — per RFC 5321 §4.5.3.1.8
203
271
  * idleTimeoutMs: number, // default 5 minutes — RFC 5321 §4.5.3.2.7
204
272
  * profile: "strict" | "balanced" | "permissive", // gate posture cascade
273
+ * guardEnvelope: true | { // optional gate — DATA-phase SPF/DKIM/DMARC via b.mail.inbound.verify
274
+ * mode?: "enforce" | "monitor", // default: enforce (monitor when profile is permissive)
275
+ * onTemperror?: "defer" | "accept", // DNS temperror disposition; default "defer" (451 4.7.5)
276
+ * authservId?: string, // RFC 8601 authserv-id; default localDomains[0]
277
+ * dnsLookup?: function, // async (qname, type) override for SPF/DKIM/DMARC lookups
278
+ * maxSignatures?: number, // DKIM verify cap (1-16)
279
+ * clockSkewMs?: number, // DKIM timestamp skew tolerance
280
+ * minRsaBits?: number, // DKIM minimum RSA key size
281
+ * timeoutMs?: number, // pipeline wall-clock ceiling; default 20s (timeout → temperror disposition)
282
+ * },
205
283
  *
206
284
  * @example
207
285
  * var tls = b.network.tls.context({ cert: certPem, key: keyPem });
@@ -269,6 +347,92 @@ function create(opts) {
269
347
  rateLimit = mailServerRateLimit.create(opts.rateLimit || {});
270
348
  }
271
349
 
350
+ // DATA-phase message-authentication gate. `guardEnvelope: true`
351
+ // gates with defaults; an object tunes it. Like the sibling gates
352
+ // (helo / rbl / greylist) the phase is skipped when the operator
353
+ // doesn't wire it — the gate needs live DNS to evaluate the
354
+ // sender's published policy, which closed-network deployments may
355
+ // not have.
356
+ var envelopeGate = null;
357
+ if (opts.guardEnvelope !== undefined && opts.guardEnvelope !== false) {
358
+ if (opts.guardEnvelope !== true &&
359
+ (typeof opts.guardEnvelope !== "object" || opts.guardEnvelope === null ||
360
+ Array.isArray(opts.guardEnvelope))) {
361
+ throw new MailServerMxError("mail-server-mx/bad-opts",
362
+ "mail.server.mx.create: guardEnvelope must be true, false, or a config object");
363
+ }
364
+ var ge = opts.guardEnvelope === true ? {} : opts.guardEnvelope;
365
+ validateOpts(ge, ["mode", "onTemperror", "authservId", "dnsLookup",
366
+ "maxSignatures", "clockSkewMs", "minRsaBits", "timeoutMs"],
367
+ "mail.server.mx.guardEnvelope");
368
+ var geMode = (ge.mode === undefined || ge.mode === null)
369
+ ? (profile === "permissive" ? "monitor" : "enforce")
370
+ : ge.mode;
371
+ if (geMode !== "enforce" && geMode !== "monitor") {
372
+ throw new MailServerMxError("mail-server-mx/bad-opts",
373
+ "mail.server.mx.create: guardEnvelope.mode must be 'enforce' or 'monitor'");
374
+ }
375
+ var geOnTemperror = (ge.onTemperror === undefined || ge.onTemperror === null)
376
+ ? "defer" : ge.onTemperror;
377
+ if (geOnTemperror !== "defer" && geOnTemperror !== "accept") {
378
+ throw new MailServerMxError("mail-server-mx/bad-opts",
379
+ "mail.server.mx.create: guardEnvelope.onTemperror must be 'defer' or 'accept'");
380
+ }
381
+ if (ge.authservId !== undefined && ge.authservId !== null) {
382
+ validateOpts.requireNonEmptyString(ge.authservId,
383
+ "mail.server.mx.create: guardEnvelope.authservId",
384
+ MailServerMxError, "mail-server-mx/bad-opts");
385
+ }
386
+ if (ge.dnsLookup !== undefined && ge.dnsLookup !== null &&
387
+ typeof ge.dnsLookup !== "function") {
388
+ throw new MailServerMxError("mail-server-mx/bad-opts",
389
+ "mail.server.mx.create: guardEnvelope.dnsLookup must be a function");
390
+ }
391
+ // DKIM bounds caught at boot, not at the first DATA — mirroring
392
+ // the exact ranges b.mail.dkim.verify enforces per call, so an
393
+ // operator typo fails startup instead of turning every live
394
+ // message into an envelope_error + temperror disposition.
395
+ numericBounds.requireAllPositiveFiniteIntIfPresent(ge,
396
+ ["maxSignatures", "clockSkewMs", "minRsaBits", "timeoutMs"],
397
+ "mail.server.mx.guardEnvelope.", MailServerMxError, "mail-server-mx/bad-bound");
398
+ if (ge.maxSignatures !== undefined && ge.maxSignatures !== null &&
399
+ ge.maxSignatures > dkim().DKIM_MAX_SIGNATURES_PER_MESSAGE_CEILING) {
400
+ throw new MailServerMxError("mail-server-mx/bad-bound",
401
+ "mail.server.mx.create: guardEnvelope.maxSignatures " + ge.maxSignatures +
402
+ " exceeds the DKIM verifier ceiling " +
403
+ dkim().DKIM_MAX_SIGNATURES_PER_MESSAGE_CEILING +
404
+ " (RFC 6376 §6.1 fan-out DoS bound)");
405
+ }
406
+ if (ge.clockSkewMs !== undefined && ge.clockSkewMs !== null &&
407
+ ge.clockSkewMs > dkim().DKIM_CLOCK_SKEW_MS_MAX) {
408
+ throw new MailServerMxError("mail-server-mx/bad-bound",
409
+ "mail.server.mx.create: guardEnvelope.clockSkewMs " + ge.clockSkewMs +
410
+ " exceeds the DKIM verifier ceiling " + dkim().DKIM_CLOCK_SKEW_MS_MAX +
411
+ " (RFC 6376 §3.5 back-dating replay defense)");
412
+ }
413
+ envelopeGate = Object.freeze({
414
+ mode: geMode,
415
+ onTemperror: geOnTemperror,
416
+ // RFC 8601 authserv-id — the receiver's own name on the
417
+ // Authentication-Results header. Defaults to the first local
418
+ // domain; with neither, the header is skipped (the verdict
419
+ // still reaches the agent handoff).
420
+ authservId: ge.authservId || localDomains[0] || null,
421
+ dnsLookup: ge.dnsLookup || undefined,
422
+ maxSignatures: ge.maxSignatures,
423
+ clockSkewMs: ge.clockSkewMs,
424
+ minRsaBits: ge.minRsaBits,
425
+ // Wall-clock ceiling for the whole pipeline (SPF include chains
426
+ // + per-signature DKIM key fetches + DMARC policy walk). A
427
+ // message stuffed with signatures pointing at slow resolvers
428
+ // must not pin the connection slot — on timeout the message
429
+ // takes the temperror disposition (defer / accept per
430
+ // onTemperror).
431
+ timeoutMs: (ge.timeoutMs === undefined || ge.timeoutMs === null)
432
+ ? C.TIME.seconds(20) : ge.timeoutMs,
433
+ });
434
+ }
435
+
272
436
  // Default-on operator-supplied-domain hardening. opts.localDomains
273
437
  // and the HELO / MAIL FROM / RCPT TO domain validations all route
274
438
  // through `b.guardDomain` for IDN homograph / Punycode-spoof defense
@@ -885,6 +1049,110 @@ function create(opts) {
885
1049
  return;
886
1050
  }
887
1051
  }
1052
+ // DATA-phase message authentication (opts.guardEnvelope) — SPF /
1053
+ // DKIM / DMARC through b.mail.inbound.verify, refusing before the
1054
+ // agent handoff so a policy-failing message never reaches storage.
1055
+ var inboundAuth = null;
1056
+ if (envelopeGate) {
1057
+ var inboundVerdict = null;
1058
+ try {
1059
+ // Wall-clock ceiling around the whole pipeline — a message
1060
+ // stuffed with signatures pointing at slow resolvers must
1061
+ // not pin the connection slot. Timeout surfaces as
1062
+ // SafeAsyncError(async/timeout) into the catch below.
1063
+ inboundVerdict = await safeAsync.withTimeout(
1064
+ mailAuth().inbound.verify({
1065
+ ip: state.remoteAddress,
1066
+ helo: state.helo || undefined,
1067
+ mailFrom: state.mailFrom || undefined,
1068
+ message: dedotted,
1069
+ dnsLookup: envelopeGate.dnsLookup,
1070
+ maxSignatures: envelopeGate.maxSignatures,
1071
+ clockSkewMs: envelopeGate.clockSkewMs,
1072
+ minRsaBits: envelopeGate.minRsaBits,
1073
+ authservId: envelopeGate.authservId || undefined,
1074
+ }),
1075
+ envelopeGate.timeoutMs,
1076
+ { name: "mail.server.mx.guardEnvelope" });
1077
+ } catch (err) {
1078
+ // Pipeline infrastructure failure or wall-clock timeout (not
1079
+ // an authentication verdict). Same disposition as a DNS
1080
+ // temperror: defer so the sender retries, or accept
1081
+ // unauthenticated when the operator chose availability via
1082
+ // onTemperror.
1083
+ _emit("mail.server.mx.envelope_error", {
1084
+ connectionId: state.id,
1085
+ mailFrom: state.mailFrom,
1086
+ error: (err && err.message) || String(err),
1087
+ }, "failure");
1088
+ if (envelopeGate.mode === "enforce" && envelopeGate.onTemperror === "defer") {
1089
+ _writeReply(socket, REPLY_451_LOCAL_ERROR,
1090
+ "4.7.0 Message authentication could not be completed; try again later");
1091
+ _resetTransaction(state);
1092
+ return;
1093
+ }
1094
+ }
1095
+ if (inboundVerdict) {
1096
+ var envAction = _envelopeActionFor(inboundVerdict, envelopeGate);
1097
+ var dkimSummary = inboundVerdict.dkim.some(function (d) { return d.result === "pass"; })
1098
+ ? "pass"
1099
+ : (inboundVerdict.dkim[0] ? inboundVerdict.dkim[0].result : "none");
1100
+ _emit("mail.server.mx.envelope_verdict", {
1101
+ connectionId: state.id,
1102
+ mailFrom: state.mailFrom,
1103
+ fromDomain: inboundVerdict.from.domain,
1104
+ spf: inboundVerdict.spf.result,
1105
+ dkim: dkimSummary,
1106
+ dmarc: inboundVerdict.dmarc.result,
1107
+ action: envAction,
1108
+ mode: envelopeGate.mode,
1109
+ }, (envAction === "reject" || envAction === "defer") ? "denied" : "success");
1110
+ if (envelopeGate.mode === "enforce" && envAction === "reject") {
1111
+ // RFC 7372 §3.2 — 5.7.26 ("multiple authentication checks
1112
+ // failed") for a DMARC evaluation that failed; the
1113
+ // multi-From / unparsable-author permerror shape is a
1114
+ // message-acceptability refusal and keeps the generic
1115
+ // 5.7.1.
1116
+ var enhanced = inboundVerdict.dmarc.result === "fail" ? "5.7.26" : "5.7.1";
1117
+ _writeReply(socket, REPLY_550_MAILBOX_UNAVAIL,
1118
+ enhanced + " Message refused by sender authentication policy (DMARC " +
1119
+ inboundVerdict.dmarc.result + "; SPF " + inboundVerdict.spf.result +
1120
+ ", DKIM " + dkimSummary + ")");
1121
+ _resetTransaction(state);
1122
+ return;
1123
+ }
1124
+ if (envelopeGate.mode === "enforce" && envAction === "defer") {
1125
+ _writeReply(socket, REPLY_451_LOCAL_ERROR,
1126
+ "4.7.0 Sender authentication temporarily unavailable (DNS); try again later");
1127
+ _resetTransaction(state);
1128
+ return;
1129
+ }
1130
+ // Accept / quarantine / monitor mode: the verdict rides to
1131
+ // the agent handoff as `auth`, and the receiver's RFC 8601
1132
+ // Authentication-Results header is prepended so downstream
1133
+ // consumers (spam-foldering quarantined mail included) act
1134
+ // on authenticated results instead of re-verifying.
1135
+ if (inboundVerdict.authResults) {
1136
+ // RFC 8601 §5 — strip any sender-attached A-R header
1137
+ // claiming this receiver's authserv-id before prepending
1138
+ // the computed one (forged-verdict shadowing defense).
1139
+ dedotted = _stripForgedAuthResults(dedotted, envelopeGate.authservId);
1140
+ dedotted = Buffer.concat([
1141
+ Buffer.from(inboundVerdict.authResults + "\r\n", "utf8"),
1142
+ dedotted,
1143
+ ]);
1144
+ }
1145
+ inboundAuth = {
1146
+ spf: inboundVerdict.spf,
1147
+ dkim: inboundVerdict.dkim,
1148
+ dmarc: inboundVerdict.dmarc,
1149
+ from: inboundVerdict.from,
1150
+ action: envAction,
1151
+ mode: envelopeGate.mode,
1152
+ quarantine: envAction === "quarantine",
1153
+ };
1154
+ }
1155
+ }
888
1156
  // operator-supplied agent handoff — when wired, persist via
889
1157
  // agent + write the 250 reply. When not wired, accept-and-drop
890
1158
  // (audit-only mode useful for staging deployments).
@@ -897,6 +1165,7 @@ function create(opts) {
897
1165
  remote: { address: state.remoteAddress, port: state.remotePort },
898
1166
  tls: state.tls,
899
1167
  helo: state.helo,
1168
+ auth: inboundAuth,
900
1169
  connectionId: state.id,
901
1170
  }).then(function (ack) {
902
1171
  _emit("mail.server.mx.delivered",
@@ -70,6 +70,7 @@
70
70
  var { defineClass } = require("./framework-error");
71
71
  var lazyRequire = require("./lazy-require");
72
72
  var validateOpts = require("./validate-opts");
73
+ var gateContract = require("./gate-contract");
73
74
 
74
75
  var audit = lazyRequire(function () { return require("./audit"); });
75
76
 
@@ -90,12 +91,7 @@ var PROFILES = Object.freeze({
90
91
  permissive: { threshold: 10.0, maxReasons: MAX_REASONS, maxReasonBytes: MAX_REASON_BYTES },
91
92
  });
92
93
 
93
- var COMPLIANCE_POSTURES = Object.freeze({
94
- hipaa: "strict",
95
- "pci-dss": "strict",
96
- gdpr: "strict",
97
- soc2: "strict",
98
- });
94
+ var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
99
95
 
100
96
  /**
101
97
  * @primitive b.mail.spamScore.create