@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
@@ -25,6 +25,62 @@ var nodeCrypto = require("node:crypto");
25
25
  var helpers = require("../helpers");
26
26
  var check = helpers.check;
27
27
  var b = require("../../");
28
+ var asn1 = require("../../lib/asn1-der");
29
+ var cms = require("../../lib/cms-codec");
30
+
31
+ // The S/MIME signer is pure-PQC (ML-DSA-65). Trust-chain validation in
32
+ // b.mail.crypto.smime.verify (since v0.13.42) binds the chain leaf to the
33
+ // key that actually verified the signature: it refuses unless a cert in
34
+ // SignedData.certificates carries that exact public key. b.mtlsCa issues
35
+ // classical (RSA/EC) leaf certs, whose key can never equal the ML-DSA
36
+ // signer key — so the chain leaf has to be an X.509 cert that embeds the
37
+ // ML-DSA-65 public key in its SubjectPublicKeyInfo. The framework has no
38
+ // ML-DSA X.509 issuer (ML-DSA in X.509 is still draft), so this builds a
39
+ // minimal RFC 5280 cert over the b.asn1Der writer + b.cms ML-DSA OID and
40
+ // signs the TBS with ML-DSA-65. node:crypto.X509Certificate parses it,
41
+ // exports the SPKI, and verifies the ML-DSA signature natively.
42
+ function _x509Name(cn) {
43
+ var atv = asn1.writeSequence([asn1.writeOid("2.5.4.3"), asn1.writeUtf8String(cn)]);
44
+ return asn1.writeSequence([asn1.writeSet([atv])]);
45
+ }
46
+ function _x509GeneralizedTime(d) {
47
+ function pad2(n) { return String(n).length >= 2 ? String(n) : "0" + n; }
48
+ var s = d.getUTCFullYear() +
49
+ pad2(d.getUTCMonth() + 1) + pad2(d.getUTCDate()) +
50
+ pad2(d.getUTCHours()) + pad2(d.getUTCMinutes()) + pad2(d.getUTCSeconds()) + "Z";
51
+ return asn1.writeNode(0x18, Buffer.from(s, "ascii")); // 0x18 = GeneralizedTime
52
+ }
53
+ function _buildMlDsaCert(opts) {
54
+ // opts: { subjectCn, subjectPubKey, issuerCn, issuerSecretKey, serial,
55
+ // notBefore, notAfter }. signatureAlgorithm == subject key alg
56
+ // (ML-DSA-65) for both self-signed (CA) and issued (leaf) shapes.
57
+ var algId = asn1.writeSequence([asn1.writeOid(cms.OID.mldsa65)]);
58
+ var spki = asn1.writeSequence([algId, asn1.writeBitString(Buffer.from(opts.subjectPubKey), 0)]);
59
+ var tbs = asn1.writeSequence([
60
+ asn1.writeContextExplicit(0, asn1.writeInteger(Buffer.from([2]))), // version v3
61
+ asn1.writeInteger(Buffer.from([opts.serial])), // serialNumber
62
+ algId, // signature AlgorithmIdentifier
63
+ _x509Name(opts.issuerCn), // issuer
64
+ asn1.writeSequence([_x509GeneralizedTime(opts.notBefore),
65
+ _x509GeneralizedTime(opts.notAfter)]), // validity
66
+ _x509Name(opts.subjectCn), // subject
67
+ spki, // SubjectPublicKeyInfo
68
+ ]);
69
+ var sig = b.pqcSoftware.ml_dsa_65.sign(new Uint8Array(tbs), opts.issuerSecretKey);
70
+ return asn1.writeSequence([tbs, algId, asn1.writeBitString(Buffer.from(sig), 0)]);
71
+ }
72
+ function _derToPem(der) {
73
+ // 64-char line wrap. A regex replace adds a trailing newline when the
74
+ // base64 length is an exact multiple of 64, which (combined with the
75
+ // closing newline) yields a blank line mid-block that OpenSSL's PEM
76
+ // reader treats as end-of-data — silently truncating the cert. Slice
77
+ // explicitly so every line is full except the last.
78
+ var b64 = Buffer.from(der).toString("base64");
79
+ var lines = [];
80
+ for (var i = 0; i < b64.length; i += 64) { lines.push(b64.slice(i, i + 64)); }
81
+ return "-----BEGIN CERTIFICATE-----\n" + lines.join("\n") +
82
+ "\n-----END CERTIFICATE-----\n";
83
+ }
28
84
 
29
85
  async function run() {
30
86
  // ---- Spin up an isolated mTLS CA (caKeySealedMode=disabled keeps
@@ -117,21 +173,46 @@ async function run() {
117
173
  threw === "mail-crypto/smime/signature-mismatch");
118
174
 
119
175
  // ---- Trust-anchor chain validation — opts.trustAnchorCertsPem.
120
- // The CMS SignedData carries the leaf cert (we embedded it
121
- // via the encodeSignedData certificates field). With the CA
122
- // PEM as the trust anchor, verify walks leaf CA.
123
- //
124
- // For this composition to work we need to re-encode the
125
- // SignedData with the leaf cert in the certificates [0]
126
- // blockthe sign() path above only embedded it via the
127
- // SignerInfo's issuerAndSerialNumber pointer. Re-encode
128
- // manually here to exercise the chain path.
176
+ // verify() walks leaf CA against the operator's trust anchor
177
+ // AND binds the leaf to the key that verified the signature
178
+ // (since v0.13.42): the chain leaf must be the cert carrying
179
+ // signerPublicKey, else the chain-validated result would assert
180
+ // a cert↔signer binding the code never made. The signer is
181
+ // ML-DSA-65, so the chain leaf must embed that ML-DSA key in its
182
+ // SubjectPublicKeyInfobuild a real ML-DSA cert chain (CA
183
+ // leaf) carrying signerKp.publicKey, with the CA PEM as the
184
+ // trust anchor. The leaf goes into SignedData.certificates so
185
+ // verify() can locate + bind it.
186
+ var caKp = b.pqcSoftware.ml_dsa_65.keygen();
187
+ var nowD = new Date();
188
+ var notBefore = new Date(nowD.getTime() - 60 * 60 * 1000);
189
+ var notAfter = new Date(nowD.getTime() + 7 * 24 * 60 * 60 * 1000);
190
+ var caCertDer = _buildMlDsaCert({
191
+ subjectCn: "smime-pqc-ca.blamejs-test.example",
192
+ subjectPubKey: caKp.publicKey,
193
+ issuerCn: "smime-pqc-ca.blamejs-test.example",
194
+ issuerSecretKey: caKp.secretKey, // self-signed
195
+ serial: 1,
196
+ notBefore: notBefore,
197
+ notAfter: notAfter,
198
+ });
199
+ var pqcLeafCertDer = _buildMlDsaCert({
200
+ subjectCn: "smime-signer.blamejs-test.example",
201
+ subjectPubKey: signerKp.publicKey, // == the verified signer key
202
+ issuerCn: "smime-pqc-ca.blamejs-test.example",
203
+ issuerSecretKey: caKp.secretKey, // issued by the CA
204
+ serial: 2,
205
+ notBefore: notBefore,
206
+ notAfter: notAfter,
207
+ });
208
+ var caCertPem = _derToPem(caCertDer);
209
+
129
210
  var signedWithCerts = b.cms.encodeSignedData({
130
211
  encapContent: Buffer.from(message, "utf8"),
131
212
  digestAlg: "sha3-512",
132
- certificates: [leafCertDer],
213
+ certificates: [pqcLeafCertDer],
133
214
  signers: [{
134
- certificate: leafCertDer,
215
+ certificate: pqcLeafCertDer,
135
216
  secretKey: signerKp.secretKey,
136
217
  sigAlg: "ML-DSA-65",
137
218
  }],
@@ -140,30 +221,74 @@ async function run() {
140
221
  message: Buffer.from(message, "utf8"),
141
222
  signature: signedWithCerts,
142
223
  signerPublicKey: signerKp.publicKey,
143
- trustAnchorCertsPem: [caBundle.caCertPem],
224
+ trustAnchorCertsPem: [caCertPem],
144
225
  });
145
226
  check("smime.verify: chain validates against trust anchor",
146
227
  verifiedChain && verifiedChain.valid === true &&
147
228
  verifiedChain.chainVerified === true);
148
229
 
149
230
  // ---- Untrusted-chain refusal: supply an UNRELATED trust anchor.
150
- var unrelatedCa = b.mtlsCa.create({
151
- dataDir: fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-smime-other-")),
152
- caKeySealedMode: "disabled",
231
+ // A second, independent ML-DSA CA did not issue the leaf, so no
232
+ // chain link reaches it.
233
+ var otherCaKp = b.pqcSoftware.ml_dsa_65.keygen();
234
+ var unrelatedCaDer = _buildMlDsaCert({
235
+ subjectCn: "smime-pqc-other-ca.blamejs-test.example",
236
+ subjectPubKey: otherCaKp.publicKey,
237
+ issuerCn: "smime-pqc-other-ca.blamejs-test.example",
238
+ issuerSecretKey: otherCaKp.secretKey,
239
+ serial: 1,
240
+ notBefore: notBefore,
241
+ notAfter: notAfter,
153
242
  });
154
- var unrelatedBundle = await unrelatedCa.initCA();
155
243
  threw = null;
156
244
  try {
157
245
  b.mail.crypto.smime.verify({
158
246
  message: Buffer.from(message, "utf8"),
159
247
  signature: signedWithCerts,
160
248
  signerPublicKey: signerKp.publicKey,
161
- trustAnchorCertsPem: [unrelatedBundle.caCertPem],
249
+ trustAnchorCertsPem: [_derToPem(unrelatedCaDer)],
162
250
  });
163
251
  } catch (eC) { threw = eC.code; }
164
252
  check("smime.verify: refuses unrelated trust anchor",
165
253
  threw === "mail-crypto/smime/untrusted-chain");
166
254
 
255
+ // ---- Binding refusal: a validly-chained cert for a DIFFERENT key
256
+ // must NOT pass chain validation when the signature was verified
257
+ // under signerKp. Build a leaf carrying an UNRELATED ML-DSA key
258
+ // but properly issued by the trusted CA; verify() must refuse
259
+ // because no cert in the chain carries the verified signer key.
260
+ var strangerKp = b.pqcSoftware.ml_dsa_65.keygen();
261
+ var strangerLeafDer = _buildMlDsaCert({
262
+ subjectCn: "smime-stranger.blamejs-test.example",
263
+ subjectPubKey: strangerKp.publicKey,
264
+ issuerCn: "smime-pqc-ca.blamejs-test.example",
265
+ issuerSecretKey: caKp.secretKey,
266
+ serial: 3,
267
+ notBefore: notBefore,
268
+ notAfter: notAfter,
269
+ });
270
+ var signedWithStrangerCert = b.cms.encodeSignedData({
271
+ encapContent: Buffer.from(message, "utf8"),
272
+ digestAlg: "sha3-512",
273
+ certificates: [strangerLeafDer],
274
+ signers: [{
275
+ certificate: pqcLeafCertDer,
276
+ secretKey: signerKp.secretKey,
277
+ sigAlg: "ML-DSA-65",
278
+ }],
279
+ });
280
+ threw = null;
281
+ try {
282
+ b.mail.crypto.smime.verify({
283
+ message: Buffer.from(message, "utf8"),
284
+ signature: signedWithStrangerCert,
285
+ signerPublicKey: signerKp.publicKey,
286
+ trustAnchorCertsPem: [caCertPem],
287
+ });
288
+ } catch (eB) { threw = eB.code; }
289
+ check("smime.verify: refuses chain leaf bound to a different key",
290
+ threw === "mail-crypto/smime/signer-not-in-chain");
291
+
167
292
  // ---- X.509 sanity — confirm node:crypto can parse the leaf and
168
293
  // verify its issuer matches the CA subject.
169
294
  var leafX509 = new nodeCrypto.X509Certificate(leaf.cert);
@@ -58,33 +58,48 @@ async function run() {
58
58
  ],
59
59
  });
60
60
 
61
- // Wait until probes have fired across all three configured targets.
61
+ // start() registers every target in the status table synchronously,
62
+ // before any probe has run — so a bare `statuses().length >= 3` is
63
+ // satisfied while every entry is still in its initial state with no
64
+ // probe recorded. Wait until each target has actually completed a
65
+ // probe (lastProbeAt set) so the assertions below read real outcomes.
62
66
  var statuses = await helpers.waitUntil(function () {
63
67
  var s = b.network.heartbeat.statuses();
64
- var count = Array.isArray(s) ? s.length : Object.keys(s).length;
65
- return count >= 3 ? s : false;
66
- }, { label: "heartbeat: 3+ probe statuses available" });
68
+ var arr = Array.isArray(s) ? s : Object.keys(s).map(function (k) { return s[k]; });
69
+ if (arr.length < 3) return false;
70
+ return arr.every(function (e) { return e && e.lastProbeAt !== null; }) ? s : false;
71
+ }, { label: "heartbeat: all 3 targets completed a probe" });
67
72
  check("statuses: returns at least one entry",
68
73
  Array.isArray(statuses) ? statuses.length >= 3 : Object.keys(statuses).length >= 3);
69
74
 
75
+ // Assert the reported `state` field directly. Matching a keyword
76
+ // against JSON.stringify(status) is meaningless here — the status
77
+ // object carries `name` ("caddy-up" / "caddy-down"), so the blob
78
+ // always contains "up"/"down" regardless of the real probe outcome.
70
79
  var caddyUp = b.network.heartbeat.status("caddy-up");
71
80
  check("caddy-up: status object returned",
72
81
  typeof caddyUp === "object" && caddyUp !== null);
73
- check("caddy-up: marked as up/healthy",
74
- /up|healthy|ok|success/i.test(JSON.stringify(caddyUp)));
82
+ check("caddy-up: marked as healthy (200 from /healthz)",
83
+ caddyUp.state === "healthy");
75
84
 
76
85
  var caddyDown = b.network.heartbeat.status("caddy-down");
77
86
  check("caddy-down: status object returned",
78
87
  typeof caddyDown === "object" && caddyDown !== null);
79
- check("caddy-down: marked as down/failure",
80
- /down|fail|error|unhealthy/i.test(JSON.stringify(caddyDown)));
88
+ check("caddy-down: marked as down (connection refused)",
89
+ caddyDown.state === "down");
81
90
 
82
91
  var squidTcp = b.network.heartbeat.status("squid-tcp");
83
92
  check("squid-tcp: TCP target probe returned status",
84
93
  typeof squidTcp === "object" && squidTcp !== null);
85
- check("squid-tcp: marked as up (port is open)",
86
- /up|healthy|ok|success/i.test(JSON.stringify(squidTcp)));
94
+ check("squid-tcp: marked as healthy (port 3128 open)",
95
+ squidTcp.state === "healthy");
87
96
 
97
+ // caddy-down probes a dead port and crosses healthy → down on its
98
+ // first failing probe (threshold 1), which fires onStateChange. Poll
99
+ // rather than read synchronously — the transition lands on the probe
100
+ // callback, which may settle a tick after lastProbeAt is recorded.
101
+ await helpers.waitUntil(function () { return stateChanges.length >= 1; },
102
+ { label: "heartbeat: onStateChange fired for at least one target" });
88
103
  check("onStateChange: fired for at least one target",
89
104
  stateChanges.length >= 1);
90
105
 
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /**
3
+ * Live Azure Blob (Shared Key) round-trip against the Azurite emulator in
4
+ * docker-compose.test.yml, over TLS with the test CA (NODE_EXTRA_CA_CERTS set
5
+ * by scripts/test-integration.js — no rejectUnauthorized:false).
6
+ *
7
+ * Azurite is PATH-STYLE: the account is the first URL path segment
8
+ * (https://127.0.0.1:10000/devstoreaccount1/<container>/<blob>), unlike
9
+ * production Azure's host-based <account>.blob.core.windows.net. A successful
10
+ * authenticated round-trip is itself the proof that the Shared-Key canonical
11
+ * resource carries the account exactly once — a doubled account (the prior
12
+ * behavior) returns 403 AuthenticationFailed and put() would throw. Also a
13
+ * deterministic buildStringToSign check that path-style does not double it.
14
+ */
15
+ var helpers = require("../helpers");
16
+ var check = helpers.check;
17
+ var services = require("../helpers/services");
18
+ var b = require("../../");
19
+ var azureBlob = require("../../lib/object-store/azure-blob");
20
+
21
+ // Azurite's well-known emulator account + key (public, documented).
22
+ var ENDPOINT = "https://127.0.0.1:10000";
23
+ var ACCOUNT = "devstoreaccount1";
24
+ var KEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
25
+
26
+ async function run() {
27
+ var az = await services.requireService("azurite");
28
+ if (!az.ok) throw new Error("azurite unreachable: " + az.reason);
29
+
30
+ // --- deterministic: canonical resource is "/" + account + the request's
31
+ // absolute path. For a PATH-STYLE URL (account already the first path
32
+ // segment, as with Azurite) that yields the account twice — the form a
33
+ // path-style server expects (verified live below). For a HOST-BASED URL
34
+ // (account only in the host) it appears once. ---
35
+ var HDRS = { "x-ms-date": "Mon, 01 Jan 2024 00:00:00 GMT", "x-ms-version": azureBlob.DEFAULT_API_VERSION };
36
+ var stsPath = azureBlob.buildStringToSign({
37
+ method: "GET", accountName: ACCOUNT,
38
+ url: new URL(ENDPOINT + "/" + ACCOUNT + "/c1/blob.txt"), headers: HDRS,
39
+ });
40
+ check("path-style canonical resource is the doubled-account form a path-style server expects",
41
+ stsPath.indexOf("/" + ACCOUNT + "/" + ACCOUNT + "/c1/blob.txt") !== -1);
42
+ var stsHost = azureBlob.buildStringToSign({
43
+ method: "GET", accountName: ACCOUNT,
44
+ url: new URL("https://" + ACCOUNT + ".blob.core.windows.net/c1/blob.txt"), headers: HDRS,
45
+ });
46
+ check("host-based canonical resource carries the account exactly once",
47
+ stsHost.indexOf("/" + ACCOUNT + "/c1/blob.txt") !== -1 &&
48
+ stsHost.indexOf("/" + ACCOUNT + "/" + ACCOUNT + "/") === -1);
49
+
50
+ var container = "blamejs-az-" + process.pid;
51
+ var commonCfg = {
52
+ protocol: "azure-blob", accountName: ACCOUNT, accountKey: KEY,
53
+ endpoint: ENDPOINT, allowInternal: true,
54
+ pathStyle: true, // Azurite addresses the account as the first path segment
55
+ };
56
+
57
+ // --- container lifecycle (path-style auto-detected from the IP host) ---
58
+ var ops = b.objectStore.bucketOps.create(commonCfg);
59
+ await ops.create(container);
60
+ check("createContainer accepted (signature verified by Azurite)", true);
61
+ var containers = await ops.list();
62
+ check("listContainers includes the new container",
63
+ containers.some(function (c) { return c.name === container; }));
64
+
65
+ // --- blob round-trip ---
66
+ var be = b.objectStore.buildBackend(Object.assign({ container: container }, commonCfg));
67
+ var key = "folder/object.bin";
68
+ var payload = Buffer.from("azure-roundtrip-" + process.pid + "-" + "Z".repeat(64), "utf8");
69
+
70
+ var putRes = await be.put(key, payload, { contentType: "application/octet-stream" });
71
+ check("put returns the byte length", putRes.size === payload.length);
72
+
73
+ var got = await be.get(key);
74
+ check("get returns byte-identical content", Buffer.isBuffer(got) && Buffer.compare(got, payload) === 0);
75
+
76
+ var h = await be.head(key);
77
+ check("head reports the correct size", h.size === payload.length);
78
+
79
+ var listed = await be.list("");
80
+ check("list surfaces the uploaded key",
81
+ listed.items.some(function (it) { return it.key === key; }));
82
+
83
+ var deleted = await be.delete(key);
84
+ check("delete returns true for an existing blob", deleted === true);
85
+
86
+ var afterDelete = await be.list("");
87
+ check("list no longer surfaces the deleted key",
88
+ !afterDelete.items.some(function (it) { return it.key === key; }));
89
+
90
+ await ops.delete(container);
91
+ check("deleteContainer accepted", true);
92
+ }
93
+
94
+ module.exports = { run: run };
95
+
96
+ if (require.main === module) {
97
+ run().then(
98
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
99
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
100
+ );
101
+ }
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ /**
3
+ * Live GCS object-store round-trip against the docker-compose fake-gcs
4
+ * fixture (fsouza/fake-gcs-server, TLS-terminated with the test CA).
5
+ *
6
+ * What this proves: the framework's GCS JSON-API client
7
+ * (lib/object-store/gcs.js) marshals create-bucket / upload / download /
8
+ * list / head / delete onto the real GCS wire shape, routes them to a
9
+ * configurable endpoint, parses the real JSON responses, and round-trips
10
+ * bytes unchanged — over TLS, trusting the test CA with no
11
+ * rejectUnauthorized override anywhere.
12
+ *
13
+ * The OAuth2 hop. The framework ALWAYS exchanges the service-account
14
+ * RSA-SHA256-signed JWT for an access token before any storage call
15
+ * (gcs.js _ensureToken). fake-gcs has no token endpoint (POST /token →
16
+ * 404), so it cannot be targeted on its own — the client would fail at
17
+ * AUTH_FAILED before reaching the storage API. The framework exposes
18
+ * `config.tokenEndpoint` to point the OAuth2 leg elsewhere; this test
19
+ * stands up a tiny in-process HTTPS token issuer using the test CA's
20
+ * own gcs.crt / gcs.key (valid for 127.0.0.1, CA-signed, so the
21
+ * framework's http-client trusts it via NODE_EXTRA_CA_CERTS — no
22
+ * bypass). The framework's real OAuth2 wire exchange (JWT assertion
23
+ * POST, x-www-form-urlencoded, parse access_token) runs end-to-end over
24
+ * TLS against that issuer; every storage call then carries the issued
25
+ * bearer to fake-gcs.
26
+ *
27
+ * Honest scope — what is NOT proven here:
28
+ * - fake-gcs does NOT verify the bearer token or any signature; the
29
+ * in-test issuer does NOT verify the JWT assertion. So this is a
30
+ * wire / URL / JSON-marshalling / TLS-trust / endpoint-routing /
31
+ * OAuth2-exchange-shape proof, NOT a token- or signature-CORRECTNESS
32
+ * proof (RSA-SHA256 JWT signing + V4 presign signing stay covered by
33
+ * unit vectors in the layer-0 suite).
34
+ * - bucket DELETE: real GCS returns 204; fake-gcs returns 200 on an
35
+ * existing bucket (an emulator quirk). The framework correctly
36
+ * accepts 204 / 404 and refuses the unexpected 200, so we assert the
37
+ * correct delete-missing path (404 → false) against fake-gcs and
38
+ * leave the created bucket for the container reset to sweep rather
39
+ * than assert against the emulator's non-spec status.
40
+ */
41
+ var fs = require("node:fs");
42
+ var os = require("node:os");
43
+ var path = require("node:path");
44
+ var https = require("node:https");
45
+ var nodeCrypto = require("node:crypto");
46
+ var child = require("node:child_process");
47
+ var helpers = require("../helpers");
48
+ var check = helpers.check;
49
+ var services = require("../helpers/services");
50
+ var b = require("../../");
51
+
52
+ // A service account whose RSA keypair is generated fresh per run — the
53
+ // JWT signing path in gcs.js is exercised for real even though neither
54
+ // the local issuer nor fake-gcs verifies the assertion.
55
+ function _serviceAccount() {
56
+ var pair = nodeCrypto.generateKeyPairSync("rsa", {
57
+ modulusLength: 2048,
58
+ publicKeyEncoding: { type: "spki", format: "pem" },
59
+ privateKeyEncoding: { type: "pkcs8", format: "pem" },
60
+ });
61
+ return {
62
+ type: "service_account",
63
+ project_id: "blamejs-emu-project",
64
+ client_email: "emu-sa@blamejs-emu-project.iam.gserviceaccount.com",
65
+ private_key: pair.privateKey,
66
+ private_key_id: "emu-key-001",
67
+ };
68
+ }
69
+
70
+ // Copy a file out of the certs volume into the host tmpdir via a running
71
+ // container (dev tooling — same mechanism services.exportCaCert uses).
72
+ function _exportCert(name, dest) {
73
+ return new Promise(function (resolve, reject) {
74
+ var p = child.spawn("docker", ["cp", "blamejs-test-gcs:/certs/" + name, dest], {
75
+ stdio: ["ignore", "pipe", "pipe"],
76
+ });
77
+ var err = "";
78
+ p.stderr.on("data", function (d) { err += d.toString(); });
79
+ p.on("close", function (code) {
80
+ if (code !== 0) return reject(new Error("docker cp " + name + " failed (exit " + code + "): " + err.trim()));
81
+ resolve(dest);
82
+ });
83
+ p.on("error", reject);
84
+ });
85
+ }
86
+
87
+ // In-process HTTPS token issuer using the CA-signed gcs cert (valid for
88
+ // 127.0.0.1). Returns { url, hits(), close() }. The framework's
89
+ // http-client trusts it via NODE_EXTRA_CA_CERTS; no rejectUnauthorized
90
+ // override is set anywhere.
91
+ async function _startTokenIssuer() {
92
+ var tmp = os.tmpdir();
93
+ var crtPath = path.join(tmp, "blamejs-gcs-issuer.crt");
94
+ var keyPath = path.join(tmp, "blamejs-gcs-issuer.key");
95
+ await _exportCert("gcs.crt", crtPath);
96
+ await _exportCert("gcs.key", keyPath);
97
+ var hits = 0;
98
+ var lastAssertionSeen = false;
99
+ var srv = https.createServer({
100
+ cert: fs.readFileSync(crtPath),
101
+ key: fs.readFileSync(keyPath),
102
+ }, function (req, res) {
103
+ var chunks = [];
104
+ req.on("data", function (c) { chunks.push(c); });
105
+ req.on("end", function () {
106
+ var body = Buffer.concat(chunks).toString("utf8");
107
+ // Confirm the framework actually sent the JWT-bearer assertion the
108
+ // real OAuth2 service-account flow requires.
109
+ if (/grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer/.test(body) &&
110
+ /assertion=/.test(body)) {
111
+ lastAssertionSeen = true;
112
+ }
113
+ hits++;
114
+ res.statusCode = 200;
115
+ res.setHeader("Content-Type", "application/json");
116
+ res.end(JSON.stringify({ access_token: "emu-access-token", expires_in: 3600 }));
117
+ });
118
+ });
119
+ await new Promise(function (resolve) { srv.listen(0, "127.0.0.1", resolve); });
120
+ var port = srv.address().port;
121
+ return {
122
+ url: "https://127.0.0.1:" + port + "/token",
123
+ hits: function () { return hits; },
124
+ sawJwtAssertion: function () { return lastAssertionSeen; },
125
+ close: function () { return new Promise(function (r) { srv.close(r); }); },
126
+ };
127
+ }
128
+
129
+ async function _runRoundTrip(issuer) {
130
+ var sa = _serviceAccount();
131
+ var endpoint = services.URLS.gcs; // https://127.0.0.1:4443
132
+ var bucket = "blamejs-gcs-live-" + Date.now();
133
+ var common = {
134
+ serviceAccount: sa,
135
+ endpoint: endpoint,
136
+ tokenEndpoint: issuer.url,
137
+ allowInternal: true,
138
+ timeoutMs: 8000,
139
+ };
140
+
141
+ // ---- bucket create ----
142
+ var ops = b.objectStore.bucketOps.create(Object.assign({
143
+ protocol: "gcs",
144
+ projectId: sa.project_id,
145
+ }, common));
146
+ var created = await ops.create(bucket, { location: "US" });
147
+ check("bucketOps.create returns the bucket name", created.name === bucket);
148
+ check("OAuth2 token exchange happened before the storage call",
149
+ issuer.hits() >= 1);
150
+ check("framework sent the JWT-bearer assertion on the OAuth2 leg",
151
+ issuer.sawJwtAssertion() === true);
152
+
153
+ // ---- backend put / get / list / head / delete ----
154
+ var backend = b.objectStore.buildBackend(Object.assign({
155
+ name: "gcs-live",
156
+ protocol: "gcs",
157
+ bucket: bucket,
158
+ classifications: ["operational"],
159
+ residencyTag: "unrestricted",
160
+ }, common));
161
+
162
+ var key = "obj-" + Math.floor(Math.random() * 1e6) + ".bin";
163
+ var payload = nodeCrypto.randomBytes(4096);
164
+
165
+ var putRv = await backend.put(key, payload, { contentType: "application/octet-stream" });
166
+ check("put: returned a size", putRv && putRv.size === payload.length);
167
+
168
+ var got = await backend.get(key);
169
+ var gotBuf = Buffer.isBuffer(got) ? got : (got && got.body);
170
+ check("get: bytes round-trip exactly (byte-identical)",
171
+ Buffer.isBuffer(gotBuf) && Buffer.compare(gotBuf, payload) === 0);
172
+
173
+ var listing = await backend.list("obj-");
174
+ check("list: returns { items } shape",
175
+ listing && Array.isArray(listing.items));
176
+ check("list: surfaces the just-put object key",
177
+ listing.items.some(function (it) { return it.key === key; }));
178
+ check("list: item size matches the payload length",
179
+ listing.items.some(function (it) { return it.key === key && it.size === payload.length; }));
180
+
181
+ var emptyListing = await backend.list("does-not-exist-prefix-");
182
+ check("list: non-matching prefix returns empty items",
183
+ emptyListing && Array.isArray(emptyListing.items) && emptyListing.items.length === 0);
184
+
185
+ var meta = await backend.head(key);
186
+ check("head: size matches the payload length", meta && meta.size === payload.length);
187
+
188
+ var del = await backend.delete(key);
189
+ check("delete: returned true", del === true);
190
+
191
+ var afterDelete = await backend.list("obj-");
192
+ check("list after delete: object is gone",
193
+ !afterDelete.items.some(function (it) { return it.key === key; }));
194
+
195
+ // get on the deleted key surfaces a 404 — the framework rejects with
196
+ // an ObjectStoreError carrying statusCode 404 (not a silent empty).
197
+ var notFound = null;
198
+ try { await backend.get(key); } catch (e) { notFound = e; }
199
+ check("get on deleted key throws (404 surfaced, not swallowed)",
200
+ notFound && (notFound.statusCode === 404 ||
201
+ /404|not.?found/i.test(String(notFound.message || notFound.code || ""))));
202
+
203
+ // ---- bucket delete-missing path (correct against fake-gcs: 404 → false) ----
204
+ var delMissing = await ops.delete("blamejs-gcs-never-existed-" + Date.now());
205
+ check("bucketOps.delete on a missing bucket returns false (404 path)",
206
+ delMissing === false);
207
+
208
+ // Best-effort cleanup of the created bucket. Real GCS returns 204 on
209
+ // bucket DELETE; fake-gcs returns 200 (an emulator quirk the framework
210
+ // correctly refuses as UNEXPECTED_STATUS), so this throw is expected
211
+ // against the emulator and is NOT a framework defect. The bucket name
212
+ // carries Date.now() so re-runs don't collide; the container reset
213
+ // sweeps it.
214
+ try { await ops.delete(bucket); } catch (_e) { /* fake-gcs 200-on-delete quirk */ }
215
+ }
216
+
217
+ async function run() {
218
+ var svc = await services.requireService("gcs");
219
+ if (!svc.ok) throw new Error("fake-gcs unreachable: " + svc.reason);
220
+ // exportCaCert is what the runner already relies on for NODE_EXTRA_CA_CERTS;
221
+ // calling it keeps this test self-contained if run directly.
222
+ await services.exportCaCert();
223
+
224
+ var issuer = await _startTokenIssuer();
225
+ try {
226
+ await _runRoundTrip(issuer);
227
+ } finally {
228
+ await issuer.close();
229
+ }
230
+ }
231
+
232
+ module.exports = { run: run };
233
+
234
+ if (require.main === module) {
235
+ run().then(
236
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
237
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
238
+ );
239
+ }