@blamejs/blamejs-shop 0.4.30 → 0.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/checkout.js +8 -0
  4. package/lib/order.js +71 -11
  5. package/lib/vendor/MANIFEST.json +392 -278
  6. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  7. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  8. package/lib/vendor/blamejs/.gitignore +6 -0
  9. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  10. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  11. package/lib/vendor/blamejs/README.md +8 -6
  12. package/lib/vendor/blamejs/SECURITY.md +19 -3
  13. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  14. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  15. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  16. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  17. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  18. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  19. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  20. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  21. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  25. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  26. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  27. package/lib/vendor/blamejs/index.js +4 -0
  28. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  30. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  31. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  32. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  33. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  34. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  35. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  36. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  37. package/lib/vendor/blamejs/lib/audit.js +259 -123
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  39. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  40. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  41. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  42. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  43. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  44. package/lib/vendor/blamejs/lib/cache.js +174 -105
  45. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  46. package/lib/vendor/blamejs/lib/cli.js +19 -14
  47. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  48. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  49. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  50. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  51. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  52. package/lib/vendor/blamejs/lib/consent.js +82 -29
  53. package/lib/vendor/blamejs/lib/constants.js +27 -11
  54. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  55. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  56. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  57. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  58. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  59. package/lib/vendor/blamejs/lib/db.js +249 -99
  60. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  61. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  62. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  63. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  64. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  65. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  66. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  67. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  68. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  69. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  70. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  71. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  72. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  73. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  74. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  75. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  76. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  77. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  78. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  79. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  80. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  81. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  82. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  83. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  84. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  85. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  86. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  87. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  88. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  89. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  90. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  91. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  92. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  93. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  94. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  95. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  96. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  98. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  99. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  100. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  101. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  102. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  103. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  104. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  106. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  107. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  108. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  109. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  110. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  111. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  112. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  113. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  114. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  115. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  116. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  117. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  118. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  119. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  120. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  121. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  122. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  123. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  124. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  125. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  126. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  128. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  129. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  132. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  134. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  136. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  137. package/lib/vendor/blamejs/lib/mail.js +8 -4
  138. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  139. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  140. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  141. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  142. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  143. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  144. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  145. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  146. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  147. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  148. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  149. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  151. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  152. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  153. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  154. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  155. package/lib/vendor/blamejs/lib/observability.js +124 -0
  156. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  157. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  158. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  159. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  160. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  161. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  162. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  163. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  164. package/lib/vendor/blamejs/lib/queue.js +7 -0
  165. package/lib/vendor/blamejs/lib/redact.js +68 -11
  166. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  167. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  168. package/lib/vendor/blamejs/lib/retention.js +101 -40
  169. package/lib/vendor/blamejs/lib/router.js +212 -5
  170. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  171. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  172. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  173. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  174. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  175. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  176. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  177. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  178. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  179. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  180. package/lib/vendor/blamejs/lib/session.js +175 -77
  181. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  182. package/lib/vendor/blamejs/lib/sse.js +26 -0
  183. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  184. package/lib/vendor/blamejs/lib/static.js +177 -34
  185. package/lib/vendor/blamejs/lib/subject.js +96 -49
  186. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  187. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  189. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  190. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  191. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  192. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  193. package/lib/vendor/blamejs/package.json +2 -2
  194. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  202. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  203. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  204. package/lib/vendor/blamejs/scripts/release.js +398 -38
  205. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  206. package/lib/vendor/blamejs/test/10-state.js +140 -14
  207. package/lib/vendor/blamejs/test/20-db.js +65 -2
  208. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  209. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  210. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  211. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  212. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  213. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  214. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  215. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  222. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  223. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  224. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  225. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  226. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  227. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  228. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  229. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  230. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  231. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  232. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  233. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  234. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  235. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  236. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  237. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  238. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  240. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  250. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  251. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  272. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  273. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  274. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  275. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  279. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  280. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  293. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  304. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  310. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  312. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  313. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  314. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  315. package/lib/vendor/blamejs/test/smoke.js +79 -21
  316. package/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  318. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  319. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  320. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  321. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  322. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  323. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  324. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  325. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  326. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  327. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  328. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  329. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  330. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  331. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  332. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  335. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  336. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  337. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  338. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -245,6 +245,139 @@ async function run() {
245
245
  check("record: bad name dropped", ex3.bufferedCounters === 0);
246
246
  check("record: bad value dropped", ex3.bufferedObservations === 0);
247
247
  await ex3.close();
248
+
249
+ // ---- Telemetry-attribute redaction (CWE-532) ----
250
+ // Span/metric attribute VALUES are a first-class egress sink — a secret
251
+ // in an attribute must not reach the OTLP collector verbatim. Redaction
252
+ // is ON by default (composes b.redact via b.observability.getRedactor);
253
+ // benign attributes pass through unchanged.
254
+ await _testRedaction();
255
+
256
+ // setRedactor surface validation
257
+ check("setRedactor rejects non-function/non-null", (function () {
258
+ var t = null;
259
+ try { b.observability.setRedactor(42); } catch (e) { t = e; }
260
+ return t instanceof TypeError && /must be a function or null/.test(t.message);
261
+ })());
262
+ check("getRedactor returns a function", typeof b.observability.getRedactor() === "function");
263
+ }
264
+
265
+ function _findAttr(list, key) {
266
+ for (var i = 0; i < list.length; i++) if (list[i].key === key) return list[i];
267
+ return null;
268
+ }
269
+
270
+ async function _testRedaction() {
271
+ // Always restore the default redactor so this block can't pollute the
272
+ // shared b.observability singleton used by sibling tests.
273
+ try {
274
+ // Default-on: secret-shaped attrs scrubbed, benign attrs untouched —
275
+ // asserted on the real OTLP payload captured by the test exporter.
276
+ var captured = null;
277
+ var hc = b.testing.fakeHttpClient(function (req) {
278
+ captured = JSON.parse(req.body);
279
+ return { statusCode: 200, headers: {}, body: Buffer.from("") };
280
+ });
281
+ var ex = b.otelExport.create({
282
+ endpoint: "https://otel.example/v1/metrics",
283
+ serviceName: "wiki",
284
+ intervalMs: 0,
285
+ httpClient: hc,
286
+ });
287
+ ex.recordCounter("http.requests", 1, {
288
+ "http.route": "/checkout", // benign — passes through
289
+ "authorization": "Bearer eyJabc.eyJdef.sigsigsig", // sensitive field name
290
+ "card": "4111 1111 1111 1111", // credit-card value-shape
291
+ "status": 200, // benign number
292
+ });
293
+ await ex.flush();
294
+
295
+ var dp = captured.resourceMetrics[0].scopeMetrics[0].metrics
296
+ .find(function (m) { return m.name === "http.requests" && m.sum; })
297
+ .sum.dataPoints[0];
298
+ var attrs = dp.attributes;
299
+ check("redact: benign route attr passes through",
300
+ _findAttr(attrs, "http.route").value.stringValue === "/checkout");
301
+ check("redact: benign number attr passes through",
302
+ _findAttr(attrs, "status").value.intValue === "200");
303
+ check("redact: sensitive field-name attr redacted",
304
+ _findAttr(attrs, "authorization").value.stringValue === b.redact.MARKER);
305
+ check("redact: credit-card value-shape attr redacted",
306
+ _findAttr(attrs, "card").value.stringValue === "[REDACTED-CC]");
307
+ await ex.close();
308
+
309
+ // Resource attributes also flow through the redactor — a secret in a
310
+ // resource attribute (operator misconfiguration) is scrubbed too.
311
+ var capturedRes = null;
312
+ var hcRes = b.testing.fakeHttpClient(function (req) {
313
+ capturedRes = JSON.parse(req.body);
314
+ return { statusCode: 200, headers: {}, body: Buffer.from("") };
315
+ });
316
+ var exRes = b.otelExport.create({
317
+ endpoint: "https://otel.example/v1/metrics",
318
+ serviceName: "wiki",
319
+ intervalMs: 0,
320
+ httpClient: hcRes,
321
+ resourceAttributes: { "deployment.environment": "production", "api_key": "AKIAABCDEFGHIJKLMNOP" },
322
+ });
323
+ exRes.recordCounter("x", 1);
324
+ await exRes.flush();
325
+ var resAttrs = capturedRes.resourceMetrics[0].resource.attributes;
326
+ check("redact: benign resource attr passes through",
327
+ _findAttr(resAttrs, "deployment.environment").value.stringValue === "production");
328
+ check("redact: sensitive resource attr redacted",
329
+ _findAttr(resAttrs, "api_key").value.stringValue === b.redact.MARKER);
330
+ await exRes.close();
331
+
332
+ // Operator override via setRedactor — a stricter scrubber is honored
333
+ // without re-creating the exporter.
334
+ b.observability.setRedactor(function (value, key) {
335
+ if (key === "enduser.id") return "[CUSTOM]";
336
+ return b.redact.redact(value, { parentKey: key });
337
+ });
338
+ var enc = b.otelExport._attrsToOtlpForTest({ "enduser.id": "u-42", "http.route": "/p" });
339
+ check("redact: custom redactor applied",
340
+ _findAttr(enc, "enduser.id").value.stringValue === "[CUSTOM]");
341
+ check("redact: custom redactor leaves benign attr",
342
+ _findAttr(enc, "http.route").value.stringValue === "/p");
343
+
344
+ // A throwing redactor must DROP the attribute (fail toward dropping,
345
+ // not leaking) and must NOT crash the export.
346
+ b.observability.setRedactor(function () { throw new Error("redactor-boom"); });
347
+ var threw = null;
348
+ var encThrow;
349
+ try { encThrow = b.otelExport._attrsToOtlpForTest({ secret_token: "shhh", keep: "x" }); }
350
+ catch (e) { threw = e; }
351
+ check("redact: throwing redactor does not crash export", threw === null);
352
+ check("redact: throwing redactor drops all attrs (no leak)", encThrow.length === 0);
353
+
354
+ // A throwing redactor through the full flush path still ships an
355
+ // empty-attribute datapoint rather than the raw secret.
356
+ var capturedThrow = null;
357
+ var hcThrow = b.testing.fakeHttpClient(function (req) {
358
+ capturedThrow = JSON.parse(req.body);
359
+ return { statusCode: 200, headers: {}, body: Buffer.from("") };
360
+ });
361
+ var exThrow = b.otelExport.create({
362
+ endpoint: "https://otel.example/v1/metrics",
363
+ serviceName: "wiki",
364
+ intervalMs: 0,
365
+ httpClient: hcThrow,
366
+ });
367
+ exThrow.recordCounter("http.requests", 1, { secret_token: "shhh" });
368
+ await exThrow.flush();
369
+ var dpThrow = capturedThrow.resourceMetrics[0].scopeMetrics[0].metrics
370
+ .find(function (m) { return m.name === "http.requests" && m.sum; })
371
+ .sum.dataPoints[0];
372
+ check("redact: flush with throwing redactor drops the secret attr",
373
+ (dpThrow.attributes || []).length === 0);
374
+ var bodyStr = JSON.stringify(capturedThrow);
375
+ check("redact: secret never appears in exported payload",
376
+ bodyStr.indexOf("shhh") === -1);
377
+ await exThrow.close();
378
+ } finally {
379
+ b.observability.setRedactor(null); // restore default for sibling tests
380
+ }
248
381
  }
249
382
 
250
383
  module.exports = { run: run };
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ // The OTLP span exporter must run every attribute VALUE through the telemetry
3
+ // redactor before serialization. Telemetry is a first-class EGRESS sink — a
4
+ // span attribute holding a bearer token, password, or API key would otherwise
5
+ // be shipped verbatim onto the OTLP wire (CWE-532: insertion of sensitive
6
+ // information into an externally-shipped sink), reaching whatever collector the
7
+ // operator points at.
8
+ //
9
+ // Drives the real consumer path: create() an exporter with a capturing
10
+ // fetchImpl, queue a span (and a span EVENT) carrying sensitive attributes,
11
+ // flush, and inspect the outgoing body — for BOTH json and protobuf encodings.
12
+ // The default redactor (b.redact.redact) scrubs by sensitive field name.
13
+
14
+ var helpers = require("../helpers");
15
+ var b = helpers.b;
16
+ var check = helpers.check;
17
+
18
+ var otlp = require("../../lib/observability-otlp-exporter");
19
+
20
+ var SECRET_TOKEN = "Bearer eyJSECRETtokenABCdef.ghi.jkl";
21
+ var SECRET_PW = "hunter2-PLAINTEXT-PASSWORD";
22
+ var SECRET_API = "sk_live_PLAINTEXT_APIKEY_0001";
23
+ var CONTROL_VAL = "GET-control-value-keep-me";
24
+
25
+ function makeSpan() {
26
+ return {
27
+ traceId: "0123456789abcdef0123456789abcdef",
28
+ spanId: "0123456789abcdef",
29
+ parentSpanId: "",
30
+ name: "GET /x",
31
+ kind: "server",
32
+ startTimeUnixNano: "1700000000000000000",
33
+ endTimeUnixNano: "1700000000100000000",
34
+ attributes: {
35
+ "http.method": CONTROL_VAL, // non-sensitive control — must survive
36
+ "authorization": SECRET_TOKEN,
37
+ "password": SECRET_PW,
38
+ "api_key": SECRET_API,
39
+ },
40
+ events: [
41
+ { timeUnixNano: "1700000000050000000", name: "log",
42
+ attributes: { "password": SECRET_PW } },
43
+ ],
44
+ status: { code: 1, message: "" },
45
+ resource: { "service.name": "svc" },
46
+ };
47
+ }
48
+
49
+ async function captureBody(encoding) {
50
+ var captured = [];
51
+ var ex = otlp.create({
52
+ endpoint: "https://collector.invalid/v1/traces",
53
+ encoding: encoding,
54
+ batchSize: 100, // don't auto-flush; flush explicitly
55
+ audit: false,
56
+ fetchImpl: async function (url, init) {
57
+ captured.push(init && init.body);
58
+ return { ok: true, status: 200, text: async function () { return ""; } };
59
+ },
60
+ });
61
+ ex.queue(makeSpan());
62
+ await ex.flush();
63
+ await ex.shutdown();
64
+ var body = captured[0];
65
+ return Buffer.isBuffer(body) ? body.toString("latin1") : String(body);
66
+ }
67
+
68
+ async function run() {
69
+ b.observability.setRedactor(null); // default redactor active
70
+
71
+ // The shared primitive both exporters route through — assert it directly so
72
+ // the redaction contract is covered at the seam, not only end-to-end.
73
+ var ra = b.observability.redactAttrs({
74
+ "http.method": CONTROL_VAL, authorization: SECRET_TOKEN, password: SECRET_PW,
75
+ });
76
+ check("redactAttrs scrubs sensitive keys", ra.authorization === "[REDACTED]" && ra.password === "[REDACTED]");
77
+ check("redactAttrs keeps non-sensitive keys", ra["http.method"] === CONTROL_VAL);
78
+
79
+ var jsonWire = await captureBody("json");
80
+ check("json: bearer token redacted on the OTLP wire", jsonWire.indexOf(SECRET_TOKEN) === -1);
81
+ check("json: password redacted on the OTLP wire", jsonWire.indexOf(SECRET_PW) === -1);
82
+ check("json: api key redacted on the OTLP wire", jsonWire.indexOf(SECRET_API) === -1);
83
+ check("json: span-EVENT attribute password redacted", jsonWire.split(SECRET_PW).length === 1);
84
+ check("json: non-sensitive control attribute survives", jsonWire.indexOf(CONTROL_VAL) !== -1);
85
+
86
+ var protoWire = await captureBody("protobuf");
87
+ check("protobuf: bearer token redacted on the OTLP wire", protoWire.indexOf(SECRET_TOKEN) === -1);
88
+ check("protobuf: password redacted on the OTLP wire", protoWire.indexOf(SECRET_PW) === -1);
89
+ check("protobuf: api key redacted on the OTLP wire", protoWire.indexOf(SECRET_API) === -1);
90
+ check("protobuf: non-sensitive control attribute survives", protoWire.indexOf(CONTROL_VAL) !== -1);
91
+
92
+ b.observability.setRedactor(null); // restore default for other tests
93
+ process.stdout.write("OK — otlp attribute redaction tests\n");
94
+ }
95
+
96
+ run().then(function () {
97
+ process.exit(0);
98
+ }).catch(function (e) {
99
+ process.stderr.write((e && e.stack ? e.stack : String(e)) + "\n");
100
+ process.exit(1);
101
+ });
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ // #128: the outbox must reclaim a row stranded 'in-flight' by a crashed
3
+ // publisher. A claim flips status pending → in-flight and stamps claimed_at;
4
+ // the claim path then only SELECTs status='pending', so if the process dies
5
+ // between the claim and _markPublished/_markRetry/_markDead, the row sits
6
+ // in-flight forever — silently dropped, violating the at-least-once delivery
7
+ // the module header advertises (b.queue has a sweepExpired reaper; outbox had
8
+ // none). The fix reaps any in-flight row whose claim is older than the lease
9
+ // (or predates the claimed_at column) back to 'pending' at the top of every
10
+ // poll.
11
+ //
12
+ // Driven against a REAL node:sqlite backend (a faithful externalDb), so the
13
+ // claim / reap / publish SQL actually executes. RED on the buggy tree: the
14
+ // stranded row is never published. GREEN after the fix: the reaper returns it
15
+ // to the pending pool and it publishes on the next poll.
16
+
17
+ var { DatabaseSync } = require("node:sqlite");
18
+ var helpers = require("../helpers");
19
+ var b = helpers.b;
20
+ var check = helpers.check;
21
+ var C = b.constants;
22
+
23
+ // Minimal faithful externalDb over an in-memory node:sqlite db: implements
24
+ // query(sql, params) + transaction(fn) + dialect, converting JS Date params
25
+ // to ISO strings the way the framework's real sqlite provider does.
26
+ function _sqliteExternalDb() {
27
+ var db = new DatabaseSync(":memory:");
28
+ function _bind(params) {
29
+ return (params || []).map(function (v) {
30
+ if (v instanceof Date) return v.toISOString();
31
+ return v;
32
+ });
33
+ }
34
+ function _query(sqlText, params) {
35
+ var stmt = db.prepare(sqlText);
36
+ var args = _bind(params);
37
+ if (/^\s*select/i.test(sqlText)) {
38
+ return { rows: stmt.all.apply(stmt, args) };
39
+ }
40
+ var info = stmt.run.apply(stmt, args);
41
+ return { rows: [], changes: info.changes };
42
+ }
43
+ var xdb = {
44
+ dialect: "sqlite",
45
+ query: async function (s, p) { return _query(s, p); },
46
+ };
47
+ return {
48
+ dialect: "sqlite",
49
+ query: async function (s, p) { return _query(s, p); },
50
+ transaction: async function (fn) {
51
+ db.exec("BEGIN");
52
+ try { var r = await fn(xdb); db.exec("COMMIT"); return r; }
53
+ catch (e) { try { db.exec("ROLLBACK"); } catch (_e) {} throw e; }
54
+ },
55
+ _raw: db,
56
+ };
57
+ }
58
+
59
+ async function run() {
60
+ var xdb = _sqliteExternalDb();
61
+ var published = [];
62
+ var outbox = b.outbox.create({
63
+ externalDb: xdb,
64
+ table: "test_outbox",
65
+ publisher: async function (event) { published.push(event); },
66
+ pollIntervalMs: C.TIME.seconds(1),
67
+ claimReclaimMs: C.TIME.seconds(1), // short lease so a 10s-old claim is stale
68
+ audit: false,
69
+ });
70
+ await outbox.declareSchema();
71
+
72
+ // enqueue is transactional (the outbox pattern — written in the same txn as
73
+ // the domain row); wrap each in a transaction and hand it the txClient.
74
+ function _enqueue(event) {
75
+ return xdb.transaction(async function (tx) { await outbox.enqueue(event, tx); });
76
+ }
77
+
78
+ // ---- the crash: a row claimed (in-flight) but never published ----
79
+ await _enqueue({ topic: "orders", payload: { id: "o-1" } });
80
+ check("#128 the enqueued row starts pending", (await outbox.pendingCount()) === 1);
81
+
82
+ // Simulate a publisher that claimed the row then died: flip it to in-flight
83
+ // with a claim timestamp older than the lease.
84
+ var staleClaim = new Date(Date.now() - C.TIME.seconds(10)).toISOString();
85
+ xdb._raw.prepare(
86
+ "UPDATE \"test_outbox\" SET status = 'in-flight', claimed_at = ? WHERE topic = 'orders'"
87
+ ).run(staleClaim);
88
+ check("#128 the stranded row is no longer in the pending pool",
89
+ (await outbox.pendingCount()) === 0);
90
+ check("#128 nothing has been published yet", published.length === 0);
91
+
92
+ // ---- one poll: the reaper must reclaim + the row must publish ----
93
+ await outbox._processOnce();
94
+
95
+ check("#128 the stranded in-flight row is reclaimed and published",
96
+ published.length === 1 && published[0].topic === "orders");
97
+ check("#128 no row is left stranded in-flight",
98
+ Number(xdb._raw.prepare(
99
+ "SELECT COUNT(*) AS n FROM \"test_outbox\" WHERE status = 'in-flight'").get().n) === 0);
100
+ check("#128 the published row is marked published",
101
+ Number(xdb._raw.prepare(
102
+ "SELECT COUNT(*) AS n FROM \"test_outbox\" WHERE status = 'published'").get().n) === 1);
103
+ check("#128 deadCount stays 0 (the row was delivered, not dead-lettered)",
104
+ (await outbox.deadCount()) === 0);
105
+
106
+ // ---- a FRESH in-flight claim (within the lease) must NOT be reclaimed ----
107
+ await _enqueue({ topic: "fresh", payload: { id: "f-1" } });
108
+ xdb._raw.prepare(
109
+ "UPDATE \"test_outbox\" SET status = 'in-flight', claimed_at = ? WHERE topic = 'fresh'"
110
+ ).run(new Date().toISOString());
111
+ var publishedBefore = published.length;
112
+ await outbox._processOnce();
113
+ check("#128 a fresh in-flight claim (within the lease) is NOT reclaimed",
114
+ Number(xdb._raw.prepare(
115
+ "SELECT COUNT(*) AS n FROM \"test_outbox\" WHERE topic = 'fresh' AND status = 'in-flight'").get().n) === 1);
116
+ check("#128 the fresh in-flight row was not re-published",
117
+ published.length === publishedBefore);
118
+
119
+ // ---- a legacy in-flight row (NULL claimed_at) is reclaimed ----
120
+ await _enqueue({ topic: "legacy", payload: { id: "l-1" } });
121
+ xdb._raw.prepare(
122
+ "UPDATE \"test_outbox\" SET status = 'in-flight', claimed_at = NULL WHERE topic = 'legacy'"
123
+ ).run();
124
+ await outbox._processOnce();
125
+ check("#128 a legacy in-flight row (NULL claimed_at) is reclaimed and published",
126
+ published.some(function (e) { return e.topic === "legacy"; }));
127
+
128
+ await outbox.stop();
129
+ console.log("OK — outbox stale-in-flight reaper tests");
130
+ }
131
+
132
+ module.exports = { run: run };
133
+ if (require.main === module) {
134
+ run().then(function () { process.exit(0); })
135
+ .catch(function (err) { process.stderr.write(String(err && err.stack || err) + "\n"); process.exit(1); });
136
+ }
@@ -12,6 +12,9 @@ var EventEmitter = require("events");
12
12
  var helpers = require("../helpers");
13
13
  var b = helpers.b;
14
14
  var check = helpers.check;
15
+ // _contentType is the internal Content-Type parameter parser the
16
+ // middleware + standalone helpers share; exposed for tests.
17
+ var _contentType = require("../../lib/middleware/body-parser")._contentType;
15
18
 
16
19
  function _streamReq(opts) {
17
20
  opts = opts || {};
@@ -201,6 +204,83 @@ async function testMiddlewareAndStandaloneShareImpl() {
201
204
  JSON.stringify(standalone) === JSON.stringify(middlewareParsed));
202
205
  }
203
206
 
207
+ // ---- Prototype-pollution defense (CWE-915 / CWE-1321) ----
208
+ //
209
+ // Header/parameter/field names are request-controlled. The parsers build
210
+ // their maps from [key, value] pairs through Object.fromEntries instead
211
+ // of a computed-write (`target[key] = value`) sink, dropping the
212
+ // __proto__ / constructor / prototype names so a hostile name can never
213
+ // reach Object.prototype.
214
+
215
+ function testContentTypeIgnoresPoisonedParam() {
216
+ // A Content-Type parameter literally named `__proto__` must not pollute
217
+ // the prototype chain, and the legitimate boundary/charset must still
218
+ // parse to the same shape.
219
+ var ct = _contentType({
220
+ headers: {
221
+ "content-type":
222
+ 'multipart/form-data; boundary=----abc; __proto__=evil; charset=utf-8',
223
+ },
224
+ });
225
+ check("content-type: type parsed", ct.type === "multipart/form-data");
226
+ check("content-type: boundary parsed", ct.params.boundary === "----abc");
227
+ check("content-type: charset parsed", ct.params.charset === "utf-8");
228
+ check("content-type: __proto__ param dropped (no own prop)",
229
+ !Object.prototype.hasOwnProperty.call(ct.params, "__proto__"));
230
+ check("content-type: Object.prototype not polluted",
231
+ ({}).evil === undefined && Object.prototype.evil === undefined);
232
+ }
233
+
234
+ async function testMultipartRefusesPoisonedFieldName() {
235
+ // A multipart field whose Content-Disposition name is `__proto__` is
236
+ // refused at the parse boundary (400) and never reaches the field map.
237
+ var boundary = "----blamejstest" + Date.now();
238
+ var body = _multipartBody(boundary, [
239
+ { name: "__proto__", value: '{"polluted":true}' },
240
+ ]);
241
+ var req = _streamReq({
242
+ headers: {
243
+ "content-type": "multipart/form-data; boundary=" + boundary,
244
+ "content-length": String(Buffer.byteLength(body)),
245
+ },
246
+ body: body,
247
+ });
248
+ var threw = false;
249
+ try { await b.parsers.multipart(req, { maxBytes: b.constants.BYTES.mib(1), maxFiles: 5 }); }
250
+ catch (e) { threw = e.code === "body-parser/multipart-poisoned-field"; }
251
+ check("multipart: __proto__ field name refused with 400", threw);
252
+ check("multipart: Object.prototype not polluted by field name",
253
+ ({}).polluted === undefined && Object.prototype.polluted === undefined);
254
+ }
255
+
256
+ async function testMultipartRepeatedFieldShapeUnchanged() {
257
+ // Success path: repeated field name → array; single → scalar. The
258
+ // entries-merge accumulation must produce the same shape the prior
259
+ // computed-write accumulation did.
260
+ var boundary = "----blamejstest" + Date.now();
261
+ var body = _multipartBody(boundary, [
262
+ { name: "tag", value: "a" },
263
+ { name: "tag", value: "b" },
264
+ { name: "tag", value: "c" },
265
+ { name: "title", value: "solo" },
266
+ ]);
267
+ var req = _streamReq({
268
+ headers: {
269
+ "content-type": "multipart/form-data; boundary=" + boundary,
270
+ "content-length": String(Buffer.byteLength(body)),
271
+ },
272
+ body: body,
273
+ });
274
+ var result = await b.parsers.multipart(req, { maxBytes: b.constants.BYTES.mib(1), maxFiles: 5 });
275
+ check("multipart: repeated field collapses to array in order",
276
+ Array.isArray(result.fields.tag) &&
277
+ result.fields.tag.length === 3 &&
278
+ result.fields.tag[0] === "a" &&
279
+ result.fields.tag[1] === "b" &&
280
+ result.fields.tag[2] === "c");
281
+ check("multipart: single field stays scalar", result.fields.title === "solo");
282
+ }
283
+
204
284
  (async function run() {
205
285
  await testJsonParsesValidObject();
206
286
  await testJsonRefusesOverMaxBytes();
@@ -212,5 +292,8 @@ async function testMiddlewareAndStandaloneShareImpl() {
212
292
  await testMultipartEnforcesMaxFiles();
213
293
  await testMultipartRefusesBadOpts();
214
294
  await testMiddlewareAndStandaloneShareImpl();
295
+ testContentTypeIgnoresPoisonedParam();
296
+ await testMultipartRefusesPoisonedFieldName();
297
+ await testMultipartRepeatedFieldShapeUnchanged();
215
298
  console.log("OK — parsers-standalone tests");
216
299
  })().catch(function (e) { console.error(e); process.exit(1); });