@blamejs/blamejs-shop 0.5.12 → 0.5.13

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 (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -0,0 +1,1181 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * b.network.smtp.policy — coverage for the input-validation, option-default,
6
+ * error-handling, and pure-logic branches that smtp-policy.test.js leaves
7
+ * uncovered.
8
+ *
9
+ * Everything here is in-memory: DNS is driven through the `dnsLookup` opt,
10
+ * HTTPS submission through an operator-supplied `httpClient` fake, and the
11
+ * receive-side `parseReport` runs on Buffers built in-process. No branch
12
+ * needs a live network or DNS backend (those belong to the integration
13
+ * suite). The uncovered surface is: MTA-STS parse rejects (empty / bad-mode /
14
+ * non-string), matchMx defensive returns, mtaSts.fetch precondition + domain
15
+ * guard, dane.tlsa / recordShape guards + every RFC 6698 label, verifyChain
16
+ * PKIX-opt-in + unsupported-usage + SHA-512 + SPKI-no-bytes paths, tlsRpt
17
+ * recordShape type guards + policy defaults, fetchPolicy rua-required +
18
+ * no-record returns, submit scheme dispatch + failure branches, and the
19
+ * entire tlsRpt.parseReport receive-side parser.
20
+ */
21
+
22
+ var helpers = require("../helpers");
23
+ var b = helpers.b;
24
+ var check = helpers.check;
25
+
26
+ var nodeCrypto = require("crypto");
27
+ var zlib = require("zlib");
28
+ var nodeDns = require("node:dns");
29
+ var C = require("../../lib/constants");
30
+ var asn1 = require("../../lib/asn1-der");
31
+ var httpClientMod = require("../../lib/http-client");
32
+
33
+ // ---- small local helpers -------------------------------------------------
34
+
35
+ function throwsWithCode(fn, codeRe) {
36
+ var threw = null;
37
+ try { fn(); } catch (e) { threw = e; }
38
+ return threw !== null && codeRe.test(threw.code || "");
39
+ }
40
+
41
+ async function asyncThrowsWithCode(fn, codeRe) {
42
+ var threw = null;
43
+ try { await fn(); } catch (e) { threw = e; }
44
+ return threw !== null && codeRe.test(threw.code || "");
45
+ }
46
+
47
+ // mtaSts.fetch uses the framework httpClient() singleton directly (no
48
+ // opts.httpClient seam like tlsRpt.submit has), so the successful-fetch
49
+ // path is driven by swapping the singleton's `.request` for a responder
50
+ // and restoring it in finally. The layer-0 runner forks one process per
51
+ // file, so this patch never leaks across test files. `dnsLookup` still
52
+ // drives the _mta-sts TXT precondition lookup as the operator seam.
53
+ async function withFakeHttpRequest(responder, fn) {
54
+ var orig = httpClientMod.request;
55
+ httpClientMod.request = responder;
56
+ try { return await fn(); }
57
+ finally { httpClientMod.request = orig; }
58
+ }
59
+
60
+ // dane.tlsa reads node:dns.promises.resolveTlsa (captured once at module
61
+ // load as a stable object reference). Swapping the method on that same
62
+ // object injects the TLSA answer without a live DNS TYPE-52 query.
63
+ async function withFakeResolveTlsa(impl, fn) {
64
+ var orig = nodeDns.promises.resolveTlsa;
65
+ nodeDns.promises.resolveTlsa = impl;
66
+ try { return await fn(); }
67
+ finally { nodeDns.promises.resolveTlsa = orig; }
68
+ }
69
+
70
+ // Minimal-but-parseable X.509 DER for the DANE-TA chain-order checks.
71
+ // verifyChain extracts the TA cert's Subject and the child cert's Issuer
72
+ // via asn1-der and requires TA.subject === child.issuer (RFC 7672
73
+ // §3.1.1). A real peerCertificate chain is always DER; these fixtures let
74
+ // the ASN.1 walk succeed so the ordered-match and mismatch branches run.
75
+ function _derName(label) {
76
+ return asn1.writeSequence([ asn1.writeNode(asn1.TAG.PRINTABLE_STRING, Buffer.from(label, "ascii")) ]);
77
+ }
78
+ // Shared SubjectPublicKeyInfo fixture — embedded verbatim in every
79
+ // _derCert, so a selector=1 (SPKI) TLSA match can be built against its
80
+ // exact bytes (readNode's .raw slices these back out byte-identically).
81
+ var _SPKI_DER = asn1.writeSequence([
82
+ asn1.writeSequence([ asn1.writeOid("1.2.840.10045.2.1"), asn1.writeOid("1.2.840.10045.3.1.7") ]),
83
+ asn1.writeNode(asn1.TAG.BIT_STRING, Buffer.from([0x00, 0x04, 0x01, 0x02, 0x03, 0x04])),
84
+ ]);
85
+ function _derCert(issuerName, subjectName) {
86
+ var sigAlg = asn1.writeSequence([ asn1.writeOid("1.2.840.113549.1.1.11"), asn1.writeNull() ]);
87
+ var validity = asn1.writeSequence([
88
+ asn1.writeNode(asn1.TAG.UTC_TIME, Buffer.from("260101000000Z")),
89
+ asn1.writeNode(asn1.TAG.UTC_TIME, Buffer.from("270101000000Z")),
90
+ ]);
91
+ var spki = _SPKI_DER;
92
+ var tbs = asn1.writeSequence([
93
+ asn1.writeContextExplicit(0, asn1.writeInteger(Buffer.from([0x02]))), // [0] version
94
+ asn1.writeInteger(Buffer.from([0x01])), // serialNumber
95
+ sigAlg, // signature
96
+ issuerName, // issuer
97
+ validity, // validity
98
+ subjectName, // subject
99
+ spki, // subjectPublicKeyInfo
100
+ ]);
101
+ return asn1.writeSequence([ tbs, sigAlg, asn1.writeNode(asn1.TAG.BIT_STRING, Buffer.from([0x00, 0xaa])) ]);
102
+ }
103
+
104
+ // ---- MTA-STS parse (mtaSts.parsePolicy) ----------------------------------
105
+
106
+ function testParseStsEmptyAndNonString() {
107
+ check("parsePolicy: empty text → mta-sts-empty",
108
+ throwsWithCode(function () { b.network.smtp.mtaSts.parsePolicy(""); }, /mta-sts-empty/));
109
+ check("parsePolicy: non-string → mta-sts-empty",
110
+ throwsWithCode(function () { b.network.smtp.mtaSts.parsePolicy(null); }, /mta-sts-empty/));
111
+ check("parsePolicy: number → mta-sts-empty",
112
+ throwsWithCode(function () { b.network.smtp.mtaSts.parsePolicy(42); }, /mta-sts-empty/));
113
+ }
114
+
115
+ function testParseStsBadMode() {
116
+ check("parsePolicy: unknown mode → mta-sts-bad-mode",
117
+ throwsWithCode(function () {
118
+ b.network.smtp.mtaSts.parsePolicy("version: STSv1\nmode: bogus\n");
119
+ }, /mta-sts-bad-mode/));
120
+ // A version-only policy (no mode line) leaves mode null → bad-mode.
121
+ check("parsePolicy: missing mode → mta-sts-bad-mode",
122
+ throwsWithCode(function () {
123
+ b.network.smtp.mtaSts.parsePolicy("version: STSv1\nmax_age: 100\n");
124
+ }, /mta-sts-bad-mode/));
125
+ }
126
+
127
+ function testParseStsBadVersion() {
128
+ // A syntactically valid policy whose version token is not STSv1 is
129
+ // refused before the mode check (RFC 8461 §3.1 — version MUST be STSv1).
130
+ check("parsePolicy: version STSv2 → mta-sts-bad-version",
131
+ throwsWithCode(function () {
132
+ b.network.smtp.mtaSts.parsePolicy("version: STSv2\nmode: enforce\n");
133
+ }, /mta-sts-bad-version/));
134
+ // Absent version line leaves version null → bad-version (not bad-mode).
135
+ check("parsePolicy: missing version → mta-sts-bad-version",
136
+ throwsWithCode(function () {
137
+ b.network.smtp.mtaSts.parsePolicy("mode: enforce\nmax_age: 100\n");
138
+ }, /mta-sts-bad-version/));
139
+ }
140
+
141
+ function testParseStsModeVariantsAndMaxAge() {
142
+ var testing = b.network.smtp.mtaSts.parsePolicy("version: STSv1\nmode: testing\n");
143
+ check("parsePolicy: testing mode accepted", testing.mode === "testing");
144
+
145
+ var none = b.network.smtp.mtaSts.parsePolicy("version: STSv1\nmode: none\n");
146
+ check("parsePolicy: none mode accepted", none.mode === "none");
147
+
148
+ // mode is lowercased on parse.
149
+ var upper = b.network.smtp.mtaSts.parsePolicy("version: STSv1\nmode: ENFORCE\n");
150
+ check("parsePolicy: mode is case-normalized to lowercase", upper.mode === "enforce");
151
+
152
+ // mx hosts are lowercased and collected in order (repeats preserved).
153
+ var multi = b.network.smtp.mtaSts.parsePolicy(
154
+ "version: STSv1\nmode: enforce\nmx: MX1.Example.COM\nmx: mx2.example.com\n");
155
+ check("parsePolicy: mx hosts lowercased + ordered",
156
+ multi.mx.length === 2 && multi.mx[0] === "mx1.example.com" && multi.mx[1] === "mx2.example.com");
157
+
158
+ // With no max_age line the field stays null (falls back to the default TTL
159
+ // inside fetch; parse itself just records absence).
160
+ check("parsePolicy: absent max_age stays null", multi.max_age === null);
161
+ }
162
+
163
+ // ---- MTA-STS MX match (mtaSts.matchMx) — defensive returns ----------------
164
+
165
+ function testMatchMxDefensiveReturns() {
166
+ check("matchMx: non-string mxHost → false",
167
+ b.network.smtp.mtaSts.matchMx(123, ["mx.example.com"]) === false);
168
+ check("matchMx: non-array mxList → false",
169
+ b.network.smtp.mtaSts.matchMx("mx.example.com", "mx.example.com") === false);
170
+ check("matchMx: null mxList → false",
171
+ b.network.smtp.mtaSts.matchMx("mx.example.com", null) === false);
172
+ }
173
+
174
+ function testMatchMxCaseAndDotEdges() {
175
+ // Case-insensitive exact match.
176
+ check("matchMx: exact match is case-insensitive",
177
+ b.network.smtp.mtaSts.matchMx("MX1.EXAMPLE.COM", ["mx1.example.com"]) === true);
178
+ // A single-label host (no dot) cannot satisfy a wildcard entry.
179
+ check("matchMx: dotless host vs wildcard → false",
180
+ b.network.smtp.mtaSts.matchMx("localhost", ["*.example.com"]) === false);
181
+ // A bare "*." entry is too short to be a wildcard and never matches.
182
+ check("matchMx: bare '*.' entry never matches",
183
+ b.network.smtp.mtaSts.matchMx("a.example.com", ["*."]) === false);
184
+ // A non-matching-suffix wildcard → false.
185
+ check("matchMx: wildcard suffix must match",
186
+ b.network.smtp.mtaSts.matchMx("mx1.other.com", ["*.example.com"]) === false);
187
+ // A single-label wildcard that DOES match the host's suffix → true.
188
+ check("matchMx: single-label wildcard matches a subdomain",
189
+ b.network.smtp.mtaSts.matchMx("mx1.example.com", ["*.example.com"]) === true);
190
+ // A wildcard entry preceding an exact entry: the exact host still matches.
191
+ check("matchMx: exact host matches even when a wildcard precedes it",
192
+ b.network.smtp.mtaSts.matchMx("mail.example.com", ["*.other.com", "mail.example.com"]) === true);
193
+ }
194
+
195
+ // ---- MTA-STS fetch (mtaSts.fetch) — precondition + domain guard -----------
196
+
197
+ async function testMtaStsFetchDomainGuard() {
198
+ check("mtaSts.fetch: non-string domain → bad-domain",
199
+ await asyncThrowsWithCode(function () { return b.network.smtp.mtaSts.fetch(123); }, /bad-domain/));
200
+ check("mtaSts.fetch: empty domain → bad-domain",
201
+ await asyncThrowsWithCode(function () { return b.network.smtp.mtaSts.fetch(""); }, /bad-domain/));
202
+ }
203
+
204
+ async function testMtaStsFetchNoTxtRecord() {
205
+ // A domain whose _mta-sts TXT does not carry v=STSv1 has no rotation
206
+ // signal → fetch refuses to pull the HTTPS policy (RFC 8461 §3.1) and
207
+ // returns null WITHOUT touching the network.
208
+ var dnsLookup = async function () { return [["some-unrelated-txt-value"]]; };
209
+ var rv = await b.network.smtp.mtaSts.fetch("example.com", { dnsLookup: dnsLookup });
210
+ check("mtaSts.fetch: TXT without v=STSv1 → null", rv === null);
211
+ }
212
+
213
+ async function testMtaStsFetchTxtAbsent() {
214
+ // ENOTFOUND from the resolver → safeResolveTxt returns null → fetch null.
215
+ var dnsLookup = async function () { var e = new Error("nx"); e.code = "ENOTFOUND"; throw e; };
216
+ var rv = await b.network.smtp.mtaSts.fetch("no-such.example.com", { dnsLookup: dnsLookup });
217
+ check("mtaSts.fetch: absent _mta-sts TXT → null", rv === null);
218
+ }
219
+
220
+ async function testMtaStsFetchTxtHardLookupFailure() {
221
+ // A hard resolver failure (not ENOTFOUND/ENODATA) on the _mta-sts TXT
222
+ // lookup surfaces a structured SmtpPolicyError — a spoofable/absent TXT
223
+ // is null, but a genuine resolver fault is an error, not silent success.
224
+ var dnsLookup = async function () { var e = new Error("servfail"); e.code = "ESERVFAIL"; throw e; };
225
+ check("mtaSts.fetch: hard TXT resolver failure → mta-sts-txt-lookup-failed",
226
+ await asyncThrowsWithCode(function () {
227
+ return b.network.smtp.mtaSts.fetch("servfail.example.com", { dnsLookup: dnsLookup });
228
+ }, /mta-sts-txt-lookup-failed/));
229
+ }
230
+
231
+ // ---- DANE tlsa (dane.tlsa) — domain guard ---------------------------------
232
+
233
+ async function testDaneTlsaDomainGuard() {
234
+ check("dane.tlsa: non-string domain → bad-domain",
235
+ await asyncThrowsWithCode(function () { return b.network.smtp.dane.tlsa(42); }, /bad-domain/));
236
+ check("dane.tlsa: empty domain → bad-domain",
237
+ await asyncThrowsWithCode(function () { return b.network.smtp.dane.tlsa(""); }, /bad-domain/));
238
+ }
239
+
240
+ // ---- DANE recordShape (dane.recordShape) — guard + every label -----------
241
+
242
+ function testDaneRecordShapeGuard() {
243
+ check("dane.recordShape: non-object → dane-bad-record",
244
+ throwsWithCode(function () { b.network.smtp.dane.recordShape(null); }, /dane-bad-record/));
245
+ check("dane.recordShape: string → dane-bad-record",
246
+ throwsWithCode(function () { b.network.smtp.dane.recordShape("x"); }, /dane-bad-record/));
247
+ }
248
+
249
+ function testDaneRecordShapeAllLabels() {
250
+ var pkixTa = b.network.smtp.dane.recordShape({ usage: 0, selector: 0, mtype: 0, dataHex: "aa" });
251
+ check("recordShape: usage 0 / selector 0 / mtype 0 → PKIX-TA / Cert / Full",
252
+ pkixTa.usageLabel === "PKIX-TA" && pkixTa.selectorLabel === "Cert" && pkixTa.mtypeLabel === "Full");
253
+
254
+ var pkixEe = b.network.smtp.dane.recordShape({ usage: 1, selector: 1, mtype: 2, dataHex: "bb" });
255
+ check("recordShape: usage 1 / selector 1 / mtype 2 → PKIX-EE / SPKI / SHA-512",
256
+ pkixEe.usageLabel === "PKIX-EE" && pkixEe.selectorLabel === "SPKI" && pkixEe.mtypeLabel === "SHA-512");
257
+
258
+ var daneTa = b.network.smtp.dane.recordShape({ usage: 2, selector: 0, mtype: 1, dataHex: "cc" });
259
+ check("recordShape: usage 2 → DANE-TA", daneTa.usageLabel === "DANE-TA");
260
+
261
+ var unknown = b.network.smtp.dane.recordShape({ usage: 9, selector: 5, mtype: 7, dataHex: "dd" });
262
+ check("recordShape: out-of-range codes → unknown labels",
263
+ unknown.usageLabel === "unknown" && unknown.selectorLabel === "unknown" && unknown.mtypeLabel === "unknown");
264
+
265
+ // The raw fields pass through unchanged.
266
+ check("recordShape: raw fields pass through",
267
+ daneTa.usage === 2 && daneTa.selector === 0 && daneTa.mtype === 1 && daneTa.dataHex === "cc");
268
+
269
+ // usage 3 → DANE-EE (the last labeled arm before "unknown").
270
+ var daneEe = b.network.smtp.dane.recordShape({ usage: 3, selector: 1, mtype: 1, dataHex: "ee" });
271
+ check("recordShape: usage 3 → DANE-EE", daneEe.usageLabel === "DANE-EE");
272
+ }
273
+
274
+ // ---- DANE verifyChain (dane.verifyChain) — uncovered branches ------------
275
+
276
+ function testVerifyChainPkixOptIn() {
277
+ var leaf = Buffer.from("leaf-der-bytes", "utf8");
278
+ var ca = Buffer.from("ca-der-bytes", "utf8");
279
+
280
+ // PKIX-EE (usage 1) with allowPkixModes → matches leaf, flags pkixPathRequired.
281
+ var eeRec = { usage: 1, selector: 0, mtype: 0, dataHex: leaf.toString("hex") };
282
+ var eeRv = b.network.smtp.dane.verifyChain([leaf, ca], [eeRec], { allowPkixModes: true });
283
+ check("verifyChain: PKIX-EE opt-in matches leaf with pkixPathRequired",
284
+ eeRv.ok === true && eeRv.matches[0].usage === "PKIX-EE" &&
285
+ eeRv.matches[0].certIndex === 0 && eeRv.matches[0].pkixPathRequired === true);
286
+
287
+ // PKIX-TA (usage 0) with allowPkixModes → matches a non-leaf cert.
288
+ var taRec = { usage: 0, selector: 0, mtype: 0, dataHex: ca.toString("hex") };
289
+ var taRv = b.network.smtp.dane.verifyChain([leaf, ca], [taRec], { allowPkixModes: true });
290
+ check("verifyChain: PKIX-TA opt-in matches trust-anchor cert with pkixPathRequired",
291
+ taRv.ok === true && taRv.matches[0].usage === "PKIX-TA" &&
292
+ taRv.matches[0].certIndex === 1 && taRv.matches[0].pkixPathRequired === true);
293
+ }
294
+
295
+ function testVerifyChainUnsupportedUsage() {
296
+ var leaf = Buffer.from("leaf", "utf8");
297
+ var rec = { usage: 7, selector: 0, mtype: 0, dataHex: "00" }; // out-of-range usage
298
+ var rv = b.network.smtp.dane.verifyChain([leaf], [rec]);
299
+ check("verifyChain: unsupported usage → ok=false + unsupported-usage error",
300
+ rv.ok === false && rv.matches.length === 0 &&
301
+ rv.errors[0] && rv.errors[0].reason === "unsupported-usage" && rv.errors[0].usage === 7);
302
+ }
303
+
304
+ function testVerifyChainDaneEeSha512() {
305
+ var leaf = Buffer.from("leaf-bytes-for-sha512", "utf8");
306
+ var sha512Hex = nodeCrypto.createHash("sha512").update(leaf).digest("hex");
307
+ var rec = { usage: 3, selector: 0, mtype: 2, dataHex: sha512Hex };
308
+ var rv = b.network.smtp.dane.verifyChain([leaf], [rec]);
309
+ check("verifyChain: DANE-EE / Cert / SHA-512 matches via hash",
310
+ rv.ok === true && rv.matches[0].usage === "DANE-EE" && rv.matches[0].mtype === "SHA-512");
311
+ }
312
+
313
+ function testVerifyChainSpkiSelectorNoBytes() {
314
+ // selector=1 (SPKI) on a non-DER buffer → SPKI extraction returns null →
315
+ // no match (the `if (!bytes) return null` branch in _matchTlsaAgainstCert).
316
+ var fake = Buffer.from("definitely not DER", "utf8");
317
+ var rec = { usage: 3, selector: 1, mtype: 0, dataHex: fake.toString("hex") };
318
+ var rv = b.network.smtp.dane.verifyChain([fake], [rec]);
319
+ check("verifyChain: SPKI selector on non-DER cert → no match",
320
+ rv.ok === false && rv.matches.length === 0);
321
+ }
322
+
323
+ // ---- TLS-RPT recordShape (tlsRpt.recordShape) — type guards + defaults ----
324
+
325
+ function testRecordShapeTypeGuards() {
326
+ // Called with no opts at all → defaults to {} → the organization guard
327
+ // fires (proving the opts-default path, not a TypeError on undefined).
328
+ check("recordShape: no opts → tls-rpt-bad-organization",
329
+ throwsWithCode(function () { b.network.smtp.tlsRpt.recordShape(); }, /tls-rpt-bad-organization/));
330
+ check("recordShape: non-string organization → tls-rpt-bad-organization",
331
+ throwsWithCode(function () {
332
+ b.network.smtp.tlsRpt.recordShape({ organization: 123, policies: [] });
333
+ }, /tls-rpt-bad-organization/));
334
+ check("recordShape: non-array policies → tls-rpt-bad-policies",
335
+ throwsWithCode(function () {
336
+ b.network.smtp.tlsRpt.recordShape({ organization: "example.com", policies: "nope" });
337
+ }, /tls-rpt-bad-policies/));
338
+ }
339
+
340
+ function testRecordShapePolicyDefaults() {
341
+ var rpt = b.network.smtp.tlsRpt.recordShape({
342
+ organization: "example.com",
343
+ policies: [{ domain: "example.com" }], // everything else defaulted
344
+ });
345
+ var pol = rpt.policies[0];
346
+ check("recordShape: policy-type defaults to 'sts'", pol.policy["policy-type"] === "sts");
347
+ check("recordShape: policy-string defaults to []",
348
+ Array.isArray(pol.policy["policy-string"]) && pol.policy["policy-string"].length === 0);
349
+ check("recordShape: mx-host defaults to []",
350
+ Array.isArray(pol.policy["mx-host"]) && pol.policy["mx-host"].length === 0);
351
+ check("recordShape: session counts default to 0",
352
+ pol.summary["total-successful-session-count"] === 0 &&
353
+ pol.summary["total-failure-session-count"] === 0);
354
+ check("recordShape: failure-details defaults to []",
355
+ Array.isArray(pol["failure-details"]) && pol["failure-details"].length === 0);
356
+ // A generated report-id + a default date-range are always present.
357
+ check("recordShape: auto report-id present",
358
+ typeof rpt["report-id"] === "string" && rpt["report-id"].length > 0);
359
+ check("recordShape: default date-range present",
360
+ typeof rpt["date-range"]["start-datetime"] === "string" &&
361
+ typeof rpt["date-range"]["end-datetime"] === "string");
362
+ check("recordShape: contact-info defaults to null", rpt["contact-info"] === null);
363
+ }
364
+
365
+ // ---- TLS-RPT fetchPolicy (tlsRpt.fetchPolicy) — guard + no-record returns --
366
+
367
+ async function testFetchPolicyDomainGuard() {
368
+ check("fetchPolicy: non-string domain → tls-rpt-bad-domain",
369
+ await asyncThrowsWithCode(function () { return b.network.smtp.tlsRpt.fetchPolicy(42); }, /tls-rpt-bad-domain/));
370
+ }
371
+
372
+ async function testFetchPolicyRuaRequired() {
373
+ // A v=TLSRPTv1 record with no rua= is malformed and MUST be ignored.
374
+ var dnsLookup = async function () { return [["v=TLSRPTv1;"]]; };
375
+ var rv = await b.network.smtp.tlsRpt.fetchPolicy("example.com", { dnsLookup: dnsLookup });
376
+ check("fetchPolicy: v=TLSRPTv1 without rua → null", rv === null);
377
+ }
378
+
379
+ async function testFetchPolicyNoMatchingRecord() {
380
+ // No record begins with v=TLSRPTv1 → null.
381
+ var dnsLookup = async function () { return [["v=spf1 -all"]]; };
382
+ var rv = await b.network.smtp.tlsRpt.fetchPolicy("example.com", { dnsLookup: dnsLookup });
383
+ check("fetchPolicy: no v=TLSRPTv1 record → null", rv === null);
384
+ }
385
+
386
+ async function testFetchPolicyHardLookupFailure() {
387
+ // A hard resolver failure on the _smtp._tls TXT lookup surfaces a
388
+ // structured SmtpPolicyError (absence is null; a fault is an error).
389
+ var dnsLookup = async function () { var e = new Error("servfail"); e.code = "ESERVFAIL"; throw e; };
390
+ check("fetchPolicy: hard TXT resolver failure → tls-rpt-lookup-failed",
391
+ await asyncThrowsWithCode(function () {
392
+ return b.network.smtp.tlsRpt.fetchPolicy("servfail.example.com", { dnsLookup: dnsLookup });
393
+ }, /tls-rpt-lookup-failed/));
394
+ }
395
+
396
+ async function testFetchPolicyNoTxtAtAll() {
397
+ // safeResolveTxt returns null on ENODATA → fetchPolicy null.
398
+ var dnsLookup = async function () { var e = new Error("nodata"); e.code = "ENODATA"; throw e; };
399
+ var rv = await b.network.smtp.tlsRpt.fetchPolicy("bare.example.com", { dnsLookup: dnsLookup });
400
+ check("fetchPolicy: no TXT record at all → null", rv === null);
401
+ }
402
+
403
+ async function testFetchPolicyTrimsAndSplitsRua() {
404
+ var dnsLookup = async function () {
405
+ return [["v=TLSRPTv1; rua=https://a.example.com/r , mailto:tls@example.com "]];
406
+ };
407
+ var rv = await b.network.smtp.tlsRpt.fetchPolicy("example.com", { dnsLookup: dnsLookup });
408
+ check("fetchPolicy: comma-split rua entries are trimmed",
409
+ rv && rv.rua.length === 2 &&
410
+ rv.rua[0] === "https://a.example.com/r" && rv.rua[1] === "mailto:tls@example.com");
411
+ }
412
+
413
+ async function testFetchPolicyStringRecordAmongNonMatching() {
414
+ // A plain-string TXT record (not the array-of-chunks shape) is read
415
+ // directly, and a preceding non-TLSRPT record is skipped before the
416
+ // matching one is chosen.
417
+ var dnsLookup = async function () {
418
+ return ["v=spf1 -all", "v=TLSRPTv1; rua=https://reports.example.com/r"];
419
+ };
420
+ var rv = await b.network.smtp.tlsRpt.fetchPolicy("example.com", { dnsLookup: dnsLookup });
421
+ check("fetchPolicy: string record chosen past a non-matching record",
422
+ rv && rv.rua.length === 1 && rv.rua[0] === "https://reports.example.com/r");
423
+ }
424
+
425
+ // ---- TLS-RPT submit (tlsRpt.submit) — dispatch + failure branches ----------
426
+
427
+ async function testSubmitRejectsNonObjectReport() {
428
+ check("submit: non-object report → tls-rpt-bad-report",
429
+ await asyncThrowsWithCode(function () {
430
+ return b.network.smtp.tlsRpt.submit("not-a-report", { rua: ["https://x.example/r"] });
431
+ }, /tls-rpt-bad-report/));
432
+ }
433
+
434
+ async function testSubmitHttpsNon2xx() {
435
+ // The framework httpClient resolves { statusCode, headers, body } — the
436
+ // fake mirrors that real contract so this branch exercises the shape the
437
+ // production path actually returns.
438
+ var fakeHttp = { request: async function () { return { statusCode: 500, body: Buffer.from("") }; } };
439
+ var rv = await b.network.smtp.tlsRpt.submit(
440
+ { "organization-name": "example.com", "report-id": "r1" },
441
+ { rua: ["https://reports.example.com/submit"], httpClient: fakeHttp });
442
+ var e = rv.results[0];
443
+ check("submit: https non-2xx → ok=false with HTTP-status error",
444
+ e.kind === "https" && e.ok === false && e.error === "HTTP 500");
445
+ }
446
+
447
+ async function testSubmitHttpsSuccess2xx() {
448
+ // A successful submission MUST be reported ok=true. The framework
449
+ // httpClient resolves { statusCode, headers, body } (see mtaSts.fetch,
450
+ // which reads res.statusCode); a submit path that reads a non-existent
451
+ // `status` field would mark every real 2xx POST as a failure.
452
+ var fakeHttp = { request: async function () { return { statusCode: 200, headers: {}, body: Buffer.from("") }; } };
453
+ var rv = await b.network.smtp.tlsRpt.submit(
454
+ { "organization-name": "example.com", "report-id": "r1" },
455
+ { rua: ["https://reports.example.com/submit"], httpClient: fakeHttp });
456
+ var e = rv.results[0];
457
+ check("submit: https 2xx → ok=true, status=200, no error",
458
+ e.kind === "https" && e.ok === true && e.status === 200 && e.error === null);
459
+ }
460
+
461
+ async function testSubmitHttpsThrows() {
462
+ var fakeHttp = { request: async function () { throw new Error("connreset"); } };
463
+ var rv = await b.network.smtp.tlsRpt.submit(
464
+ { "organization-name": "example.com" },
465
+ { rua: ["https://reports.example.com/submit"], httpClient: fakeHttp });
466
+ var e = rv.results[0];
467
+ check("submit: https request throw is caught into entry.error",
468
+ e.ok === false && /connreset/.test(e.error || ""));
469
+ }
470
+
471
+ async function testSubmitHttpsThrowsNonError() {
472
+ // An error with an empty (falsy) message is still captured into
473
+ // entry.error via the String(e) fallback rather than surfacing as
474
+ // "undefined".
475
+ var fakeHttp = { request: async function () { throw new Error(""); } };
476
+ var rv = await b.network.smtp.tlsRpt.submit(
477
+ { "organization-name": "example.com" },
478
+ { rua: ["https://reports.example.com/submit"], httpClient: fakeHttp });
479
+ var e = rv.results[0];
480
+ check("submit: message-less throw captured via String(e)",
481
+ e.ok === false && e.error === "Error");
482
+ }
483
+
484
+ async function testSubmitInvalidMailtoAddr() {
485
+ var rv = await b.network.smtp.tlsRpt.submit(
486
+ { "organization-name": "example.com" },
487
+ { rua: ["mailto:not a valid address"] });
488
+ var e = rv.results[0];
489
+ check("submit: invalid mailto addr-spec → refused, not forwarded",
490
+ e.ok === false && /not a valid RFC 5322 addr-spec/.test(e.error || "") && !e.mailto);
491
+ }
492
+
493
+ async function testSubmitUnsupportedScheme() {
494
+ var rv = await b.network.smtp.tlsRpt.submit(
495
+ { "organization-name": "example.com" },
496
+ { rua: ["ftp://reports.example.com/r"] });
497
+ var e = rv.results[0];
498
+ check("submit: unsupported rua scheme → error names the scheme",
499
+ e.ok === false && /unsupported rua URI scheme: ftp/.test(e.error || ""));
500
+ }
501
+
502
+ async function testSubmitValidMailtoBody() {
503
+ var report = b.network.smtp.tlsRpt.recordShape({
504
+ organization: "example.com",
505
+ reportId: "rpt-777",
506
+ policies: [{ type: "sts", domain: "example.com" }],
507
+ });
508
+ var rv = await b.network.smtp.tlsRpt.submit(report, { rua: ["mailto:tls@example.com"] });
509
+ var e = rv.results[0];
510
+ check("submit: valid mailto → prepared gzip body + subject with Report-ID",
511
+ e.kind === "mailto" && e.ok === true &&
512
+ Buffer.isBuffer(e.mailto.body) && e.mailto.body[0] === 0x1f && e.mailto.body[1] === 0x8b &&
513
+ e.mailto.to === "tls@example.com" &&
514
+ e.mailto.subject.indexOf("rpt-777") !== -1);
515
+ }
516
+
517
+ // ---- TLS-RPT parseReport (tlsRpt.parseReport) — receive-side parser -------
518
+
519
+ function _validReport() {
520
+ return {
521
+ "organization-name": "reporter.example",
522
+ "date-range": { "start-datetime": "2026-01-01T00:00:00Z", "end-datetime": "2026-01-02T00:00:00Z" },
523
+ "report-id": "report-abc-123",
524
+ "contact-info": "tls-reports@reporter.example",
525
+ "policies": [
526
+ { summary: { "total-successful-session-count": 10, "total-failure-session-count": 3 } },
527
+ { summary: { "total-successful-session-count": 5, "total-failure-session-count": 1 } },
528
+ ],
529
+ };
530
+ }
531
+
532
+ function testParseReportBadInput() {
533
+ check("parseReport: null body → tls-rpt-bad-input",
534
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(null); }, /tls-rpt-bad-input/));
535
+ check("parseReport: undefined body → tls-rpt-bad-input",
536
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(undefined); }, /tls-rpt-bad-input/));
537
+ check("parseReport: number body → tls-rpt-bad-input",
538
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(12345); }, /tls-rpt-bad-input/));
539
+ }
540
+
541
+ function testParseReportBadJsonAndShape() {
542
+ check("parseReport: malformed JSON → tls-rpt-bad-json",
543
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport("{not json"); }, /tls-rpt-bad-json/));
544
+ check("parseReport: scalar JSON (number) → tls-rpt-bad-shape",
545
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport("123"); }, /tls-rpt-bad-shape/));
546
+ check("parseReport: JSON null → tls-rpt-bad-shape",
547
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport("null"); }, /tls-rpt-bad-shape/));
548
+ }
549
+
550
+ function testParseReportMissingRequiredField() {
551
+ var r = _validReport();
552
+ delete r["report-id"];
553
+ check("parseReport: missing required field → tls-rpt-missing-field",
554
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(JSON.stringify(r)); }, /tls-rpt-missing-field/));
555
+ }
556
+
557
+ function testParseReportBadDateRange() {
558
+ var r = _validReport();
559
+ r["date-range"] = { "start-datetime": 1234, "end-datetime": "2026-01-02T00:00:00Z" };
560
+ check("parseReport: non-string date-range field → tls-rpt-bad-date-range",
561
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(JSON.stringify(r)); }, /tls-rpt-bad-date-range/));
562
+ }
563
+
564
+ function testParseReportPoliciesNotArray() {
565
+ var r = _validReport();
566
+ r.policies = { "0": {} };
567
+ check("parseReport: policies not an array → tls-rpt-bad-policies",
568
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(JSON.stringify(r)); }, /tls-rpt-bad-policies/));
569
+ }
570
+
571
+ function testParseReportTooManyPolicies() {
572
+ var r = _validReport();
573
+ r.policies = [];
574
+ for (var i = 0; i < 1025; i += 1) r.policies.push({ summary: {} }); // cap is 1024
575
+ check("parseReport: > 1024 policies → tls-rpt-too-many-policies",
576
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(JSON.stringify(r)); }, /tls-rpt-too-many-policies/));
577
+ }
578
+
579
+ function testParseReportTooLarge() {
580
+ // A body larger than the 8 MiB cap is refused before any parse/decompress.
581
+ var big = Buffer.alloc(C.BYTES.mib(8) + 1, 0x20); // spaces, not gzip magic
582
+ check("parseReport: over-cap body → tls-rpt-too-large",
583
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(big); }, /tls-rpt-too-large/));
584
+ }
585
+
586
+ function testParseReportHappyPathAggregates() {
587
+ var parsed = b.network.smtp.tlsRpt.parseReport(JSON.stringify(_validReport()));
588
+ check("parseReport: organization surfaced", parsed.organization === "reporter.example");
589
+ check("parseReport: report-id surfaced", parsed.reportId === "report-abc-123");
590
+ check("parseReport: contact surfaced", parsed.contact === "tls-reports@reporter.example");
591
+ check("parseReport: date-range surfaced",
592
+ parsed.dateRange.start === "2026-01-01T00:00:00Z" && parsed.dateRange.end === "2026-01-02T00:00:00Z");
593
+ check("parseReport: success/failure counts aggregated across policies",
594
+ parsed.totals.successful === 15 && parsed.totals.failure === 4);
595
+ check("parseReport: raw report echoed", parsed.raw && parsed.raw["report-id"] === "report-abc-123");
596
+ }
597
+
598
+ function testParseReportContactOptional() {
599
+ var r = _validReport();
600
+ delete r["contact-info"];
601
+ var parsed = b.network.smtp.tlsRpt.parseReport(JSON.stringify(r));
602
+ check("parseReport: absent contact-info → null", parsed.contact === null);
603
+ }
604
+
605
+ function testParseReportNonFiniteCountsSkipped() {
606
+ var r = _validReport();
607
+ r.policies = [
608
+ { summary: { "total-successful-session-count": "not-a-number", "total-failure-session-count": 2 } },
609
+ { summary: { "total-successful-session-count": 4, "total-failure-session-count": null } },
610
+ { /* no summary at all */ },
611
+ ];
612
+ var parsed = b.network.smtp.tlsRpt.parseReport(JSON.stringify(r));
613
+ check("parseReport: non-numeric counts ignored in aggregation",
614
+ parsed.totals.successful === 4 && parsed.totals.failure === 2);
615
+ }
616
+
617
+ function testParseReportGzipMagicSniff() {
618
+ var gz = zlib.gzipSync(Buffer.from(JSON.stringify(_validReport()), "utf8"));
619
+ var parsed = b.network.smtp.tlsRpt.parseReport(gz); // no contentType — sniffed by magic
620
+ check("parseReport: gzip body auto-detected by magic bytes",
621
+ parsed.organization === "reporter.example" && parsed.totals.successful === 15);
622
+ }
623
+
624
+ function testParseReportGzipViaContentType() {
625
+ var gz = zlib.gzipSync(Buffer.from(JSON.stringify(_validReport()), "utf8"));
626
+ var parsed = b.network.smtp.tlsRpt.parseReport(gz, { contentType: "application/tlsrpt+gzip" });
627
+ check("parseReport: gzip body decompressed via contentType hint",
628
+ parsed.reportId === "report-abc-123");
629
+ }
630
+
631
+ function testParseReportGunzipFailure() {
632
+ // gzip magic bytes but a truncated/garbage deflate stream → gunzip throws.
633
+ var bad = Buffer.from([0x1f, 0x8b, 0x08, 0x00, 0xde, 0xad, 0xbe, 0xef]);
634
+ check("parseReport: corrupt gzip → tls-rpt-gunzip-failed",
635
+ throwsWithCode(function () { b.network.smtp.tlsRpt.parseReport(bad); }, /tls-rpt-gunzip-failed/));
636
+ }
637
+
638
+ // ---- MTA-STS fetch (mtaSts.fetch) — HTTPS-fetch success + cache-TTL clamp -
639
+
640
+ var _STS_ENFORCE = "version: STSv1\nmode: enforce\nmx: MX1.Example.COM\nmx: mx2.example.com\n";
641
+
642
+ async function testMtaStsFetchSuccessAndMaxAgeClamp() {
643
+ // A published _mta-sts TXT (v=STSv1 with an id) satisfies the RFC 8461
644
+ // §3.1 precondition, so fetch pulls + parses the HTTPS policy and caches
645
+ // it. max_age within the [1h, ~1y] window is honored verbatim as the
646
+ // cache TTL.
647
+ var body = _STS_ENFORCE + "max_age: 604800\n"; // 7 days, in-window
648
+ var rv = await withFakeHttpRequest(
649
+ async function () { return { statusCode: 200, headers: {}, body: Buffer.from(body, "utf8") }; },
650
+ function () {
651
+ return b.network.smtp.mtaSts.fetch("within.example", {
652
+ dnsLookup: async function () { return [["v=STSv1; id=WITHIN01"]]; },
653
+ });
654
+ });
655
+ check("mtaSts.fetch: enforce policy fetched + parsed",
656
+ rv && rv.mode === "enforce" && rv.version === "STSv1");
657
+ check("mtaSts.fetch: mx hosts lowercased from HTTPS body",
658
+ rv.mx.length === 2 && rv.mx[0] === "mx1.example.com");
659
+ check("mtaSts.fetch: policy id carried from the _mta-sts TXT", rv.id === "WITHIN01");
660
+ check("mtaSts.fetch: fetchedAt stamped", typeof rv.fetchedAt === "number" && rv.fetchedAt > 0);
661
+ check("mtaSts.fetch: in-window max_age honored as cache TTL",
662
+ rv._cacheTtlMs === 604800 * C.TIME.seconds(1));
663
+ }
664
+
665
+ async function testMtaStsFetchMaxAgeCeilingClamp() {
666
+ // max_age above the RFC 8461 §3.2 ceiling (~1 year) clamps to the ceiling.
667
+ var body = _STS_ENFORCE + "max_age: 999999999\n";
668
+ var rv = await withFakeHttpRequest(
669
+ async function () { return { statusCode: 200, headers: {}, body: Buffer.from(body, "utf8") }; },
670
+ function () {
671
+ return b.network.smtp.mtaSts.fetch("ceil.example", {
672
+ dnsLookup: async function () { return [["v=STSv1; id=CEIL01"]]; },
673
+ });
674
+ });
675
+ check("mtaSts.fetch: over-ceiling max_age clamps to ~1y", rv._cacheTtlMs === C.TIME.weeks(52));
676
+ }
677
+
678
+ async function testMtaStsFetchMaxAgeAbsentUsesDefault() {
679
+ // No max_age line → parsed.max_age null → default framework TTL (60 min).
680
+ var rv = await withFakeHttpRequest(
681
+ async function () { return { statusCode: 200, headers: {}, body: Buffer.from(_STS_ENFORCE, "utf8") }; },
682
+ function () {
683
+ return b.network.smtp.mtaSts.fetch("noage.example", {
684
+ dnsLookup: async function () { return [["v=STSv1;"]]; }, // no id= → policy id null
685
+ });
686
+ });
687
+ check("mtaSts.fetch: absent max_age → default cache TTL", rv._cacheTtlMs === C.TIME.minutes(60));
688
+ check("mtaSts.fetch: TXT without id= → policy id null", rv.id === null);
689
+ }
690
+
691
+ async function testMtaStsFetchTxtRecordShapes() {
692
+ // _fetchStsTxt tolerates a mixed TXT answer: a non-string chunk is
693
+ // skipped, and a plain-string record (not the array-of-chunks shape) is
694
+ // read directly. The id= token is extracted from whichever record
695
+ // carries v=STSv1.
696
+ var rv = await withFakeHttpRequest(
697
+ async function () { return { statusCode: 200, headers: {}, body: Buffer.from(_STS_ENFORCE + "max_age: 86400\n", "utf8") }; },
698
+ function () {
699
+ return b.network.smtp.mtaSts.fetch("mixed.example", {
700
+ dnsLookup: async function () { return [12345, "v=STSv1; id=MIXED42"]; }, // non-string then plain string
701
+ });
702
+ });
703
+ check("mtaSts.fetch: mixed TXT (non-string skipped, string record read) → id extracted",
704
+ rv && rv.id === "MIXED42" && rv.mode === "enforce");
705
+ }
706
+
707
+ async function testMtaStsFetch404ReturnsNull() {
708
+ // A 404 at the well-known path means "no policy published" → null,
709
+ // NOT an error (RFC 8461 opportunistic behavior).
710
+ var rv = await withFakeHttpRequest(
711
+ async function () { return { statusCode: 404, headers: {}, body: Buffer.from("") }; },
712
+ function () {
713
+ return b.network.smtp.mtaSts.fetch("gone.example", {
714
+ dnsLookup: async function () { return [["v=STSv1; id=GONE01"]]; },
715
+ });
716
+ });
717
+ check("mtaSts.fetch: HTTPS 404 → null (no policy)", rv === null);
718
+ }
719
+
720
+ async function testMtaStsFetchNon2xxThrows() {
721
+ // A non-404 non-2xx (e.g. 500) is a hard fetch failure and surfaces a
722
+ // structured SmtpPolicyError.
723
+ var threw = await asyncThrowsWithCode(function () {
724
+ return withFakeHttpRequest(
725
+ async function () { return { statusCode: 500, headers: {}, body: Buffer.from("") }; },
726
+ function () {
727
+ return b.network.smtp.mtaSts.fetch("err5.example", {
728
+ dnsLookup: async function () { return [["v=STSv1; id=ERR501"]]; },
729
+ });
730
+ });
731
+ }, /mta-sts-fetch-failed/);
732
+ check("mtaSts.fetch: 5xx → mta-sts-fetch-failed", threw);
733
+ }
734
+
735
+ async function testMtaStsFetchHttpThrowIsOpportunisticNull() {
736
+ // A network / TLS error from the httpClient on an un-cached first fetch
737
+ // yields "no enforceable policy" → null (documented TOFU fallback).
738
+ var rv = await withFakeHttpRequest(
739
+ async function () { throw new Error("ECONNRESET at policy endpoint"); },
740
+ function () {
741
+ return b.network.smtp.mtaSts.fetch("reset.example", {
742
+ dnsLookup: async function () { return [["v=STSv1; id=RESET01"]]; },
743
+ });
744
+ });
745
+ check("mtaSts.fetch: httpClient throw → opportunistic null", rv === null);
746
+ }
747
+
748
+ // ---- DANE tlsa (dane.tlsa) — resolveTlsa dispatch + DNSSEC gate -----------
749
+
750
+ function _tlsaRec(usage, selector, match, data) {
751
+ return { certUsage: usage, selector: selector, match: match, data: data };
752
+ }
753
+
754
+ async function testDaneTlsaMapsRecordsWhenDnssecAsserted() {
755
+ // With opts.dnssecValidated:true the raw node:dns TLSA rows are
756
+ // normalized to { usage, selector, mtype, dataHex }. Buffer data is
757
+ // hex-encoded; a non-Buffer data field is stringified.
758
+ var rv = await withFakeResolveTlsa(
759
+ async function () {
760
+ return [
761
+ _tlsaRec(3, 1, 1, Buffer.from([0xab, 0xcd])),
762
+ _tlsaRec(2, 0, 1, "deadbeef"),
763
+ ];
764
+ },
765
+ function () { return b.network.smtp.dane.tlsa("example.com", 25, { dnssecValidated: true }); });
766
+ check("dane.tlsa: DNSSEC-asserted → records normalized",
767
+ rv.length === 2 && rv[0].usage === 3 && rv[0].selector === 1 && rv[0].mtype === 1);
768
+ check("dane.tlsa: Buffer data hex-encoded", rv[0].dataHex === "abcd");
769
+ check("dane.tlsa: non-Buffer data stringified", rv[1].dataHex === "deadbeef");
770
+ }
771
+
772
+ async function testDaneTlsaDefaultPortWhenOmitted() {
773
+ // Port omitted → defaults to 25 (the qname is _25._tcp.<domain>); the
774
+ // lookup still succeeds through the same DNSSEC-asserted path.
775
+ var seenQname = null;
776
+ var rv = await withFakeResolveTlsa(
777
+ async function (qname) { seenQname = qname; return [_tlsaRec(3, 0, 1, Buffer.from([0x01]))]; },
778
+ function () { return b.network.smtp.dane.tlsa("mail.example.com", undefined, { dnssecValidated: true }); });
779
+ check("dane.tlsa: omitted port defaults to 25 in the qname",
780
+ seenQname === "_25._tcp.mail.example.com" && rv.length === 1);
781
+ }
782
+
783
+ async function testDaneTlsaRefusesWithoutDnssec() {
784
+ // The default (no opts.dnssecValidated) REFUSES to use TLSA records —
785
+ // RFC 7672 §1.3 fail-closed: unvalidated records MUST NOT be used.
786
+ var threw = await asyncThrowsWithCode(function () {
787
+ return withFakeResolveTlsa(
788
+ async function () { return [_tlsaRec(3, 0, 1, Buffer.from([0x01]))]; },
789
+ function () { return b.network.smtp.dane.tlsa("example.com", 25); });
790
+ }, /dane-no-dnssec/);
791
+ check("dane.tlsa: no dnssecValidated → dane-no-dnssec (fail-closed)", threw);
792
+ }
793
+
794
+ async function testDaneTlsaEmptyOnNxAndNoData() {
795
+ // ENOTFOUND / ENODATA are "domain publishes no TLSA" → empty array, not
796
+ // an error (and the DNSSEC gate is never reached because there are no
797
+ // records to use).
798
+ var nx = await withFakeResolveTlsa(
799
+ async function () { var e = new Error("nx"); e.code = "ENOTFOUND"; throw e; },
800
+ function () { return b.network.smtp.dane.tlsa("nx.example.com", 25, { dnssecValidated: true }); });
801
+ check("dane.tlsa: ENOTFOUND → []", Array.isArray(nx) && nx.length === 0);
802
+
803
+ var nd = await withFakeResolveTlsa(
804
+ async function () { var e = new Error("nodata"); e.code = "ENODATA"; throw e; },
805
+ function () { return b.network.smtp.dane.tlsa("nd.example.com", 25, { dnssecValidated: true }); });
806
+ check("dane.tlsa: ENODATA → []", Array.isArray(nd) && nd.length === 0);
807
+ }
808
+
809
+ async function testDaneTlsaLookupFailure() {
810
+ // A non-NX resolver error (SERVFAIL, timeout) is surfaced as a
811
+ // structured lookup failure.
812
+ var threw = await asyncThrowsWithCode(function () {
813
+ return withFakeResolveTlsa(
814
+ async function () { var e = new Error("SERVFAIL"); e.code = "ESERVFAIL"; throw e; },
815
+ function () { return b.network.smtp.dane.tlsa("srvfail.example.com", 25, { dnssecValidated: true }); });
816
+ }, /dane-lookup-failed/);
817
+ check("dane.tlsa: resolver SERVFAIL → dane-lookup-failed", threw);
818
+
819
+ // A resolver error with an empty (falsy) message still yields a
820
+ // structured failure — the detail falls back to String(e).
821
+ var threwNoMsg = await asyncThrowsWithCode(function () {
822
+ return withFakeResolveTlsa(
823
+ async function () { var e = new Error(""); e.code = "EWEIRD"; throw e; }, // falsy .message
824
+ function () { return b.network.smtp.dane.tlsa("weird.example.com", 25, { dnssecValidated: true }); });
825
+ }, /dane-lookup-failed/);
826
+ check("dane.tlsa: message-less resolver error → dane-lookup-failed", threwNoMsg);
827
+ }
828
+
829
+ async function testDaneTlsaNullRecordsYieldEmpty() {
830
+ // A resolver that resolves null (rather than an array) still produces a
831
+ // safe empty result after the DNSSEC gate.
832
+ var rv = await withFakeResolveTlsa(
833
+ async function () { return null; },
834
+ function () { return b.network.smtp.dane.tlsa("nullrecs.example.com", 25, { dnssecValidated: true }); });
835
+ check("dane.tlsa: null resolver result → []", Array.isArray(rv) && rv.length === 0);
836
+ }
837
+
838
+ async function testDaneTlsaUnavailableRuntime() {
839
+ // On a runtime without node:dns.resolveTlsa the primitive refuses
840
+ // rather than silently degrading.
841
+ var threw = await asyncThrowsWithCode(function () {
842
+ return withFakeResolveTlsa(undefined, function () {
843
+ return b.network.smtp.dane.tlsa("example.com", 25, { dnssecValidated: true });
844
+ });
845
+ }, /dane-unavailable/);
846
+ check("dane.tlsa: resolveTlsa missing → dane-unavailable", threw);
847
+ }
848
+
849
+ // ---- DANE verifyChain (dane.verifyChain) — input guards + DANE-TA chain ---
850
+
851
+ function testVerifyChainInputGuards() {
852
+ check("verifyChain: empty chain → dane-bad-chain",
853
+ throwsWithCode(function () { b.network.smtp.dane.verifyChain([], []); }, /dane-bad-chain/));
854
+ check("verifyChain: non-array chain → dane-bad-chain",
855
+ throwsWithCode(function () { b.network.smtp.dane.verifyChain("nope", []); }, /dane-bad-chain/));
856
+ check("verifyChain: non-Buffer chain entry → dane-bad-chain",
857
+ throwsWithCode(function () { b.network.smtp.dane.verifyChain(["not-a-buffer"], []); }, /dane-bad-chain/));
858
+ check("verifyChain: non-array tlsaRecords → dane-bad-tlsa",
859
+ throwsWithCode(function () { b.network.smtp.dane.verifyChain([Buffer.from("x")], "nope"); }, /dane-bad-tlsa/));
860
+ }
861
+
862
+ function testVerifyChainDaneEeSha256() {
863
+ // DANE-EE / Cert / SHA-256 — the mtype=1 hash branch against the leaf.
864
+ var leaf = Buffer.from("leaf-bytes-for-sha256", "utf8");
865
+ var sha256Hex = nodeCrypto.createHash("sha256").update(leaf).digest("hex");
866
+ var rv = b.network.smtp.dane.verifyChain([leaf], [{ usage: 3, selector: 0, mtype: 1, dataHex: sha256Hex }]);
867
+ check("verifyChain: DANE-EE / Cert / SHA-256 matches via hash",
868
+ rv.ok === true && rv.matches[0].usage === "DANE-EE" && rv.matches[0].mtype === "SHA-256");
869
+ }
870
+
871
+ function testVerifyChainDaneEeFullNoMatchAndBadDataHex() {
872
+ var leaf = Buffer.from("leaf", "utf8");
873
+ // mtype=0 (Full) with the wrong bytes → no match, ok=false.
874
+ var wrong = b.network.smtp.dane.verifyChain([leaf], [{ usage: 3, selector: 0, mtype: 0, dataHex: "00" }]);
875
+ check("verifyChain: DANE-EE Full wrong bytes → no match", wrong.ok === false && wrong.matches.length === 0);
876
+ // Non-string dataHex is coerced to empty → cannot match.
877
+ var noHex = b.network.smtp.dane.verifyChain([leaf], [{ usage: 3, selector: 0, mtype: 0, dataHex: null }]);
878
+ check("verifyChain: non-string dataHex → no match", noHex.ok === false && noHex.matches.length === 0);
879
+ }
880
+
881
+ function testVerifyChainPkixModesRejectedByDefault() {
882
+ // usage 0/1 WITHOUT opts.allowPkixModes → structured pkix-modes-not-allowed
883
+ // error, ok=false (RFC 7672 §3.1.1 — SMTP DANE honors only DANE-TA/EE).
884
+ var fake = Buffer.from("anything", "utf8");
885
+ var rvEe = b.network.smtp.dane.verifyChain([fake], [{ usage: 1, selector: 0, mtype: 1, dataHex: "abc" }]);
886
+ check("verifyChain: PKIX-EE without opt-in → pkix-modes-not-allowed",
887
+ rvEe.ok === false && rvEe.errors[0] && rvEe.errors[0].reason === "pkix-modes-not-allowed");
888
+ var rvTa = b.network.smtp.dane.verifyChain([fake], [{ usage: 0, selector: 0, mtype: 1, dataHex: "abc" }]);
889
+ check("verifyChain: PKIX-TA without opt-in → pkix-modes-not-allowed",
890
+ rvTa.ok === false && rvTa.errors[0] && rvTa.errors[0].reason === "pkix-modes-not-allowed");
891
+ }
892
+
893
+ function testVerifyChainDaneTaSyntheticUnverified() {
894
+ // usage=2 against non-DER buffers: the TLSA hash-matches the non-leaf
895
+ // cert, but the ASN.1 chain-order extraction fails, so the match is
896
+ // accepted-but-flagged chainOrderUnverified (synthetic/test inputs only).
897
+ var leaf = Buffer.from("leaf-synthetic", "utf8");
898
+ var ca = Buffer.from("ca-synthetic", "utf8");
899
+ var caSha = nodeCrypto.createHash("sha256").update(ca).digest("hex");
900
+ var rv = b.network.smtp.dane.verifyChain([leaf, ca], [{ usage: 2, selector: 0, mtype: 1, dataHex: caSha }]);
901
+ check("verifyChain: DANE-TA on non-DER buffers → match flagged chainOrderUnverified",
902
+ rv.ok === true && rv.matches[0].usage === "DANE-TA" &&
903
+ rv.matches[0].certIndex === 1 && rv.matches[0].chainOrderUnverified === true);
904
+ }
905
+
906
+ function testVerifyChainDaneTaChainOrderVerified() {
907
+ // Real DER: the matched DANE-TA cert's Subject equals the leaf's Issuer,
908
+ // so the RFC 7672 §3.1.1 chain-order check passes and the match is NOT
909
+ // flagged unverified.
910
+ var caName = _derName("Test Root CA");
911
+ var leafName = _derName("leaf.example.com");
912
+ var leaf = _derCert(caName, leafName); // issuer=CA, subject=leaf
913
+ var ta = _derCert(caName, caName); // self-issued root
914
+ var taSha = nodeCrypto.createHash("sha256").update(ta).digest("hex");
915
+ var rv = b.network.smtp.dane.verifyChain([leaf, ta], [{ usage: 2, selector: 0, mtype: 1, dataHex: taSha }]);
916
+ check("verifyChain: DANE-TA ordered chain → verified match",
917
+ rv.ok === true && rv.matches.length === 1 &&
918
+ rv.matches[0].usage === "DANE-TA" && rv.matches[0].certIndex === 1 &&
919
+ rv.matches[0].chainOrderUnverified === undefined);
920
+ }
921
+
922
+ function testVerifyChainDaneTaChainOrderMismatch() {
923
+ // Real DER where the hash-matching cert's Subject does NOT equal the
924
+ // leaf's Issuer: the match is refused and a chain-order-mismatch error
925
+ // is recorded (a cert that merely hash-matches is not accepted as the
926
+ // trust anchor unless it is actually the parent).
927
+ var caName = _derName("Real Issuer CA");
928
+ var leafName = _derName("leaf.example.com");
929
+ var otherName = _derName("Unrelated Subject");
930
+ var leaf = _derCert(caName, leafName); // leaf.issuer = caName
931
+ var rogue = _derCert(caName, otherName); // subject != caName
932
+ var rogueSha = nodeCrypto.createHash("sha256").update(rogue).digest("hex");
933
+ var rv = b.network.smtp.dane.verifyChain([leaf, rogue], [{ usage: 2, selector: 0, mtype: 1, dataHex: rogueSha }]);
934
+ check("verifyChain: DANE-TA out-of-order chain → refused with chain-order-mismatch",
935
+ rv.ok === false && rv.matches.length === 0 &&
936
+ rv.errors[0] && rv.errors[0].reason === "dane-ta-chain-order-mismatch");
937
+ }
938
+
939
+ function testVerifyChainDaneTaSkipsNonMatchingCert() {
940
+ // A three-cert chain where the TLSA record matches only the last cert:
941
+ // the non-matching intermediate is skipped and the loop continues up the
942
+ // chain until the trust anchor matches.
943
+ var leaf = Buffer.from("leaf-3chain", "utf8");
944
+ var inter = Buffer.from("intermediate-3chain", "utf8");
945
+ var ta = Buffer.from("trust-anchor-3chain", "utf8");
946
+ var taSha = nodeCrypto.createHash("sha256").update(ta).digest("hex");
947
+ var rv = b.network.smtp.dane.verifyChain([leaf, inter, ta], [{ usage: 2, selector: 0, mtype: 1, dataHex: taSha }]);
948
+ check("verifyChain: DANE-TA skips non-matching intermediate, matches anchor",
949
+ rv.ok === true && rv.matches[0].usage === "DANE-TA" && rv.matches[0].certIndex === 2);
950
+ }
951
+
952
+ function testVerifyChainSpkiSelectorRealDer() {
953
+ // selector=1 (SPKI) against a REAL DER leaf: the SubjectPublicKeyInfo is
954
+ // extracted from tbsCertificate and matched. Full (mtype 0) compares the
955
+ // SPKI bytes verbatim; the DER embeds _SPKI_DER, so its hex is the
956
+ // association data.
957
+ var leaf = _derCert(_derName("Issuer"), _derName("leaf.example.com"));
958
+ var full = b.network.smtp.dane.verifyChain([leaf],
959
+ [{ usage: 3, selector: 1, mtype: 0, dataHex: _SPKI_DER.toString("hex") }]);
960
+ check("verifyChain: DANE-EE / SPKI / Full matches extracted SubjectPublicKeyInfo",
961
+ full.ok === true && full.matches[0].usage === "DANE-EE" && full.matches[0].mtype === "Full");
962
+
963
+ // SHA-256 over the same SPKI bytes → hash match.
964
+ var spkiSha = nodeCrypto.createHash("sha256").update(_SPKI_DER).digest("hex");
965
+ var hashed = b.network.smtp.dane.verifyChain([leaf],
966
+ [{ usage: 3, selector: 1, mtype: 1, dataHex: spkiSha }]);
967
+ check("verifyChain: DANE-EE / SPKI / SHA-256 matches SPKI digest",
968
+ hashed.ok === true && hashed.matches[0].mtype === "SHA-256");
969
+ }
970
+
971
+ function testVerifyChainSelectorAndMtypeFallthroughs() {
972
+ var leaf = _derCert(_derName("Issuer"), _derName("leaf.example.com"));
973
+ // selector=1 mtype=1 with the WRONG digest → SPKI extracted but no match.
974
+ var wrongSha = b.network.smtp.dane.verifyChain([leaf],
975
+ [{ usage: 3, selector: 1, mtype: 1, dataHex: "00".repeat(32) }]);
976
+ check("verifyChain: SPKI SHA-256 wrong digest → no match",
977
+ wrongSha.ok === false && wrongSha.matches.length === 0);
978
+ // selector=1 mtype=2 (SHA-512) wrong digest → no match (exercises the
979
+ // SHA-512 branch's non-match arm).
980
+ var wrong512 = b.network.smtp.dane.verifyChain([leaf],
981
+ [{ usage: 3, selector: 1, mtype: 2, dataHex: "00".repeat(64) }]);
982
+ check("verifyChain: SPKI SHA-512 wrong digest → no match",
983
+ wrong512.ok === false && wrong512.matches.length === 0);
984
+ // selector=2 is neither Cert(0) nor SPKI(1) → _selectorBytes returns
985
+ // null → the record cannot match.
986
+ var badSelector = b.network.smtp.dane.verifyChain([leaf],
987
+ [{ usage: 3, selector: 2, mtype: 0, dataHex: "aa" }]);
988
+ check("verifyChain: unknown selector → no bytes → no match",
989
+ badSelector.ok === false && badSelector.matches.length === 0);
990
+ // mtype=9 is not a defined matching type → falls through to no match.
991
+ var badMtype = b.network.smtp.dane.verifyChain([leaf],
992
+ [{ usage: 3, selector: 0, mtype: 9, dataHex: "aa" }]);
993
+ check("verifyChain: unknown mtype → no match", badMtype.ok === false && badMtype.matches.length === 0);
994
+ }
995
+
996
+ function testVerifyChainMalformedDerFailsClosed() {
997
+ // A hostile / malformed peer cert must never crash the DANE verifier and
998
+ // must never yield a spuriously-verified match from unparseable ASN.1.
999
+ // These fixtures drive the structural guard arms in the cert-field
1000
+ // extractors (non-SEQUENCE top, short TBSCertificate, non-SEQUENCE tbs,
1001
+ // wrong-typed SubjectPublicKeyInfo slot) — every one returns null so the
1002
+ // verdict stays fail-closed.
1003
+ var sigAlg = asn1.writeSequence([ asn1.writeOid("1.2.840.113549.1.1.11"), asn1.writeNull() ]);
1004
+ var bit = asn1.writeNode(asn1.TAG.BIT_STRING, Buffer.from([0x00, 0xaa]));
1005
+ var name = _derName("x");
1006
+ var validity = asn1.writeSequence([
1007
+ asn1.writeNode(asn1.TAG.UTC_TIME, Buffer.from("260101000000Z")),
1008
+ asn1.writeNode(asn1.TAG.UTC_TIME, Buffer.from("270101000000Z")),
1009
+ ]);
1010
+
1011
+ // (a) valid DER whose top node is an INTEGER, not a SEQUENCE.
1012
+ var intCert = asn1.writeInteger(Buffer.from([0x2a]));
1013
+ // (b) SEQUENCE whose tbsCertificate SEQUENCE holds too few fields.
1014
+ var shortTbs = asn1.writeSequence([
1015
+ asn1.writeSequence([ asn1.writeInteger(Buffer.from([1])), asn1.writeInteger(Buffer.from([2])) ]),
1016
+ sigAlg, bit,
1017
+ ]);
1018
+ // (c) SEQUENCE whose first child (the tbs slot) is an INTEGER.
1019
+ var nonSeqTbs = asn1.writeSequence([ asn1.writeInteger(Buffer.from([1])), sigAlg, bit ]);
1020
+ // (d) well-formed field layout but the SubjectPublicKeyInfo slot is an
1021
+ // INTEGER instead of a SEQUENCE.
1022
+ var wrongSpki = asn1.writeSequence([
1023
+ asn1.writeSequence([
1024
+ asn1.writeContextExplicit(0, asn1.writeInteger(Buffer.from([2]))),
1025
+ asn1.writeInteger(Buffer.from([1])), sigAlg, name, validity, name,
1026
+ asn1.writeInteger(Buffer.from([7])), // SPKI slot: INTEGER, not SEQUENCE
1027
+ ]),
1028
+ sigAlg, bit,
1029
+ ]);
1030
+
1031
+ // (e) SEQUENCE with an empty value → zero children.
1032
+ var emptySeq = asn1.writeSequence([]);
1033
+ // (f) SEQUENCE whose value is a truncated inner tag → readSequence throws.
1034
+ var truncatedSeq = asn1.writeNode(asn1.TAG.SEQUENCE | 0x20, Buffer.from([0x30]));
1035
+ // (g) SEQUENCE whose tbs child is itself a SEQUENCE with a truncated
1036
+ // value → the inner readSequence(tbs.value) throws.
1037
+ var truncatedTbs = asn1.writeSequence([
1038
+ asn1.writeNode(asn1.TAG.SEQUENCE | 0x20, Buffer.from([0x30])), sigAlg, bit,
1039
+ ]);
1040
+
1041
+ var mangled = [intCert, shortTbs, nonSeqTbs, wrongSpki, emptySeq, truncatedSeq, truncatedTbs];
1042
+ for (var i = 0; i < mangled.length; i += 1) {
1043
+ var cert = mangled[i];
1044
+ var sha = nodeCrypto.createHash("sha256").update(cert).digest("hex");
1045
+ var noThrowTa = true, taRv = null;
1046
+ try { taRv = b.network.smtp.dane.verifyChain([cert, cert], [{ usage: 2, selector: 0, mtype: 1, dataHex: sha }]); }
1047
+ catch (_e) { noThrowTa = false; }
1048
+ check("verifyChain: malformed cert #" + i + " DANE-TA does not throw", noThrowTa && taRv !== null);
1049
+
1050
+ var noThrowEe = true, eeRv = null;
1051
+ try { eeRv = b.network.smtp.dane.verifyChain([cert], [{ usage: 3, selector: 1, mtype: 0, dataHex: "aa" }]); }
1052
+ catch (_e) { noThrowEe = false; }
1053
+ check("verifyChain: malformed cert #" + i + " SPKI selector fails closed (no match, no throw)",
1054
+ noThrowEe && eeRv !== null && eeRv.ok === false && eeRv.matches.length === 0);
1055
+ }
1056
+ }
1057
+
1058
+ // ---- TLS-RPT submit (tlsRpt.submit) — rua guard ---------------------------
1059
+
1060
+ async function testSubmitRuaGuard() {
1061
+ check("submit: empty rua array → tls-rpt-bad-rua",
1062
+ await asyncThrowsWithCode(function () {
1063
+ return b.network.smtp.tlsRpt.submit({ "organization-name": "example.com" }, { rua: [] });
1064
+ }, /tls-rpt-bad-rua/));
1065
+ check("submit: missing rua (non-array) → tls-rpt-bad-rua",
1066
+ await asyncThrowsWithCode(function () {
1067
+ return b.network.smtp.tlsRpt.submit({ "organization-name": "example.com" }, {});
1068
+ }, /tls-rpt-bad-rua/));
1069
+ // Called with no opts at all → defaults to {} → the same rua guard fires.
1070
+ check("submit: no opts → tls-rpt-bad-rua",
1071
+ await asyncThrowsWithCode(function () {
1072
+ return b.network.smtp.tlsRpt.submit({ "organization-name": "example.com" });
1073
+ }, /tls-rpt-bad-rua/));
1074
+ }
1075
+
1076
+ async function testSubmitMailtoSubjectFallbacks() {
1077
+ // A mailto submission for a report missing organization-name / report-id
1078
+ // still produces a subject; the missing fields fall back to empty
1079
+ // strings rather than "undefined".
1080
+ var rv = await b.network.smtp.tlsRpt.submit({}, { rua: ["mailto:tls@example.com"] });
1081
+ var e = rv.results[0];
1082
+ check("submit: mailto with bare report → prepared body, empty-string subject fields",
1083
+ e.kind === "mailto" && e.ok === true && Buffer.isBuffer(e.mailto.body) &&
1084
+ e.mailto.subject.indexOf("undefined") === -1 &&
1085
+ e.mailto.subject.indexOf("Report-ID: <>") !== -1);
1086
+ }
1087
+
1088
+ // ---- runner --------------------------------------------------------------
1089
+
1090
+ async function run() {
1091
+ testParseStsEmptyAndNonString();
1092
+ testParseStsBadMode();
1093
+ testParseStsBadVersion();
1094
+ testParseStsModeVariantsAndMaxAge();
1095
+
1096
+ testMatchMxDefensiveReturns();
1097
+ testMatchMxCaseAndDotEdges();
1098
+
1099
+ await testMtaStsFetchDomainGuard();
1100
+ await testMtaStsFetchNoTxtRecord();
1101
+ await testMtaStsFetchTxtAbsent();
1102
+ await testMtaStsFetchSuccessAndMaxAgeClamp();
1103
+ await testMtaStsFetchMaxAgeCeilingClamp();
1104
+ await testMtaStsFetchMaxAgeAbsentUsesDefault();
1105
+ await testMtaStsFetchTxtRecordShapes();
1106
+ await testMtaStsFetch404ReturnsNull();
1107
+ await testMtaStsFetchNon2xxThrows();
1108
+ await testMtaStsFetchHttpThrowIsOpportunisticNull();
1109
+ await testMtaStsFetchTxtHardLookupFailure();
1110
+
1111
+ await testDaneTlsaDomainGuard();
1112
+ await testDaneTlsaMapsRecordsWhenDnssecAsserted();
1113
+ await testDaneTlsaDefaultPortWhenOmitted();
1114
+ await testDaneTlsaRefusesWithoutDnssec();
1115
+ await testDaneTlsaEmptyOnNxAndNoData();
1116
+ await testDaneTlsaLookupFailure();
1117
+ await testDaneTlsaNullRecordsYieldEmpty();
1118
+ await testDaneTlsaUnavailableRuntime();
1119
+
1120
+ testDaneRecordShapeGuard();
1121
+ testDaneRecordShapeAllLabels();
1122
+
1123
+ testVerifyChainInputGuards();
1124
+ testVerifyChainPkixOptIn();
1125
+ testVerifyChainPkixModesRejectedByDefault();
1126
+ testVerifyChainUnsupportedUsage();
1127
+ testVerifyChainDaneEeSha256();
1128
+ testVerifyChainDaneEeSha512();
1129
+ testVerifyChainDaneEeFullNoMatchAndBadDataHex();
1130
+ testVerifyChainSpkiSelectorNoBytes();
1131
+ testVerifyChainDaneTaSyntheticUnverified();
1132
+ testVerifyChainDaneTaChainOrderVerified();
1133
+ testVerifyChainDaneTaChainOrderMismatch();
1134
+ testVerifyChainDaneTaSkipsNonMatchingCert();
1135
+ testVerifyChainSpkiSelectorRealDer();
1136
+ testVerifyChainSelectorAndMtypeFallthroughs();
1137
+ testVerifyChainMalformedDerFailsClosed();
1138
+
1139
+ testRecordShapeTypeGuards();
1140
+ testRecordShapePolicyDefaults();
1141
+
1142
+ await testFetchPolicyDomainGuard();
1143
+ await testFetchPolicyRuaRequired();
1144
+ await testFetchPolicyNoMatchingRecord();
1145
+ await testFetchPolicyHardLookupFailure();
1146
+ await testFetchPolicyNoTxtAtAll();
1147
+ await testFetchPolicyTrimsAndSplitsRua();
1148
+ await testFetchPolicyStringRecordAmongNonMatching();
1149
+
1150
+ await testSubmitRejectsNonObjectReport();
1151
+ await testSubmitHttpsNon2xx();
1152
+ await testSubmitHttpsSuccess2xx();
1153
+ await testSubmitHttpsThrows();
1154
+ await testSubmitHttpsThrowsNonError();
1155
+ await testSubmitInvalidMailtoAddr();
1156
+ await testSubmitUnsupportedScheme();
1157
+ await testSubmitValidMailtoBody();
1158
+ await testSubmitRuaGuard();
1159
+ await testSubmitMailtoSubjectFallbacks();
1160
+
1161
+ testParseReportBadInput();
1162
+ testParseReportBadJsonAndShape();
1163
+ testParseReportMissingRequiredField();
1164
+ testParseReportBadDateRange();
1165
+ testParseReportPoliciesNotArray();
1166
+ testParseReportTooManyPolicies();
1167
+ testParseReportTooLarge();
1168
+ testParseReportHappyPathAggregates();
1169
+ testParseReportContactOptional();
1170
+ testParseReportNonFiniteCountsSkipped();
1171
+ testParseReportGzipMagicSniff();
1172
+ testParseReportGzipViaContentType();
1173
+ testParseReportGunzipFailure();
1174
+ }
1175
+
1176
+ module.exports = { run: run };
1177
+
1178
+ if (require.main === module) {
1179
+ run().then(function () { console.log("OK"); })
1180
+ .catch(function (e) { console.error(e.stack || e); process.exit(1); });
1181
+ }