@blamejs/blamejs-shop 0.4.30 → 0.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/checkout.js +8 -0
  4. package/lib/order.js +71 -11
  5. package/lib/vendor/MANIFEST.json +392 -278
  6. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  7. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  8. package/lib/vendor/blamejs/.gitignore +6 -0
  9. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  10. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  11. package/lib/vendor/blamejs/README.md +8 -6
  12. package/lib/vendor/blamejs/SECURITY.md +19 -3
  13. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  14. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  15. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  16. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  17. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  18. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  19. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  20. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  21. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  25. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  26. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  27. package/lib/vendor/blamejs/index.js +4 -0
  28. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  30. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  31. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  32. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  33. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  34. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  35. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  36. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  37. package/lib/vendor/blamejs/lib/audit.js +259 -123
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  39. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  40. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  41. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  42. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  43. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  44. package/lib/vendor/blamejs/lib/cache.js +174 -105
  45. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  46. package/lib/vendor/blamejs/lib/cli.js +19 -14
  47. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  48. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  49. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  50. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  51. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  52. package/lib/vendor/blamejs/lib/consent.js +82 -29
  53. package/lib/vendor/blamejs/lib/constants.js +27 -11
  54. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  55. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  56. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  57. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  58. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  59. package/lib/vendor/blamejs/lib/db.js +249 -99
  60. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  61. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  62. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  63. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  64. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  65. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  66. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  67. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  68. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  69. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  70. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  71. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  72. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  73. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  74. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  75. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  76. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  77. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  78. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  79. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  80. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  81. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  82. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  83. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  84. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  85. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  86. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  87. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  88. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  89. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  90. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  91. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  92. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  93. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  94. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  95. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  96. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  98. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  99. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  100. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  101. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  102. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  103. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  104. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  106. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  107. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  108. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  109. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  110. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  111. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  112. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  113. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  114. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  115. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  116. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  117. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  118. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  119. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  120. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  121. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  122. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  123. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  124. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  125. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  126. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  128. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  129. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  132. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  134. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  136. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  137. package/lib/vendor/blamejs/lib/mail.js +8 -4
  138. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  139. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  140. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  141. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  142. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  143. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  144. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  145. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  146. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  147. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  148. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  149. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  151. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  152. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  153. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  154. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  155. package/lib/vendor/blamejs/lib/observability.js +124 -0
  156. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  157. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  158. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  159. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  160. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  161. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  162. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  163. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  164. package/lib/vendor/blamejs/lib/queue.js +7 -0
  165. package/lib/vendor/blamejs/lib/redact.js +68 -11
  166. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  167. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  168. package/lib/vendor/blamejs/lib/retention.js +101 -40
  169. package/lib/vendor/blamejs/lib/router.js +212 -5
  170. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  171. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  172. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  173. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  174. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  175. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  176. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  177. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  178. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  179. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  180. package/lib/vendor/blamejs/lib/session.js +175 -77
  181. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  182. package/lib/vendor/blamejs/lib/sse.js +26 -0
  183. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  184. package/lib/vendor/blamejs/lib/static.js +177 -34
  185. package/lib/vendor/blamejs/lib/subject.js +96 -49
  186. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  187. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  189. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  190. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  191. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  192. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  193. package/lib/vendor/blamejs/package.json +2 -2
  194. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  202. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  203. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  204. package/lib/vendor/blamejs/scripts/release.js +398 -38
  205. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  206. package/lib/vendor/blamejs/test/10-state.js +140 -14
  207. package/lib/vendor/blamejs/test/20-db.js +65 -2
  208. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  209. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  210. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  211. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  212. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  213. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  214. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  215. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  222. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  223. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  224. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  225. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  226. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  227. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  228. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  229. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  230. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  231. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  232. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  233. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  234. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  235. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  236. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  237. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  238. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  240. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  250. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  251. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  272. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  273. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  274. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  275. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  279. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  280. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  293. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  304. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  310. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  312. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  313. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  314. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  315. package/lib/vendor/blamejs/test/smoke.js +79 -21
  316. package/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  318. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  319. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  320. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  321. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  322. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  323. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  324. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  325. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  326. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  327. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  328. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  329. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  330. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  331. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  332. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  335. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  336. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  337. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  338. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -0,0 +1,353 @@
1
+ "use strict";
2
+ /**
3
+ * Live test of b.frameworkSchema.ensureSchema against the docker MySQL
4
+ * container. ensureSchema materializes the framework's external-DB surface
5
+ * (audit / consent / checkpoints / tips / scheduler / rate-limit / pubsub /
6
+ * api-key / session / job / cache / seeder / break-glass tables + their
7
+ * indexes + the append-only WORM triggers). It was Postgres/SQLite-only
8
+ * until the MySQL DDL branch landed; this file proves the MySQL branch
9
+ * creates EVERY framework table on a real server AND that a row inserts +
10
+ * reads back through each, with the dialect-specific shapes exercised:
11
+ *
12
+ * - BIGINT for ms-epoch counters/timestamps (a 32-bit INT overflows
13
+ * Date.now()).
14
+ * - LONGBLOB for the binary nonce / signature columns.
15
+ * - VARCHAR(191) for every TEXT column in a PRIMARY KEY or index (MySQL
16
+ * refuses unbounded TEXT/BLOB in a key — the bug #97 surfaced).
17
+ * - BIGINT AUTO_INCREMENT PRIMARY KEY for the pubsub id.
18
+ * - the WORM triggers (SIGNAL SQLSTATE '45000') block DELETE/UPDATE on
19
+ * the append-only tables.
20
+ *
21
+ * The driver is the externalDb-shaped persistent docker-exec mysql client
22
+ * b.externalDb.init wraps; ensureSchema dispatches its DDL through it. A
23
+ * dedicated database (bjfs_test) keeps the run isolated.
24
+ *
25
+ * RUN: node scripts/test-integration.js --skip-service-check framework-schema-mysql
26
+ */
27
+ var execFileSync = require("node:child_process").execFileSync;
28
+ var helpers = require("../helpers");
29
+ var check = helpers.check;
30
+ var services = require("../helpers/services");
31
+ var b = require("../../");
32
+
33
+ var CONTAINER = "blamejs-test-mysql";
34
+ var DB_NAME = "bjfs_test";
35
+ // ANSI_QUOTES is NOT set: the framework's MySQL DDL emits backtick-quoted
36
+ // identifiers, which parse in either sql_mode — this proves the backtick
37
+ // path, not a double-quote-via-ANSI_QUOTES workaround.
38
+ var _results = [];
39
+ function soft(label, cond) {
40
+ _results.push({ label: label, ok: !!cond });
41
+ console.log((cond ? " ok " : " FAIL ") + label);
42
+ return !!cond;
43
+ }
44
+
45
+ // ---- one-shot docker-exec mysql ----
46
+ // SQL on stdin (never argv). Each call is a fresh connection — faithful to
47
+ // a pooled driver where each acquire is a clean session. stderr captured so
48
+ // a MySQL error surfaces with its 4-digit code.
49
+ function _mysqlExec(sql, opts) {
50
+ opts = opts || {};
51
+ var dbArgs = opts.noDb ? [] : [DB_NAME];
52
+ var args = ["exec", "-i", CONTAINER, "mysql", "-uroot", "-pblamejs_test_root",
53
+ "--batch", "--raw"].concat(dbArgs);
54
+ try {
55
+ var out = execFileSync("docker", args,
56
+ { input: sql + "\n", stdio: ["pipe", "pipe", "pipe"], maxBuffer: 64 * 1024 * 1024 });
57
+ return { ok: true, out: out.toString("utf8") };
58
+ } catch (e) {
59
+ var stderr = e.stderr ? e.stderr.toString("utf8") : "";
60
+ return { ok: false, out: (e.stdout ? e.stdout.toString("utf8") : ""), err: stderr || (e.message || String(e)) };
61
+ }
62
+ }
63
+
64
+ // One-shot for setup / out-of-band assertions; throws on error.
65
+ function _mysql(sql, opts) {
66
+ var r = _mysqlExec(sql, opts);
67
+ if (!r.ok) throw new Error("mysql setup failed for [" + sql.slice(0, 120) + "]: " + _clean(r.err));
68
+ return r.out;
69
+ }
70
+
71
+ function _clean(s) {
72
+ return String(s || "").split(/\r?\n/)
73
+ .filter(function (l) { return l && l.indexOf("World-writable") === -1 && l.indexOf("Using a password") === -1; })
74
+ .join(" ").slice(0, 220);
75
+ }
76
+
77
+ // externalDb-shaped driver over the one-shot exec. connect/close are no-ops
78
+ // (each query opens its own connection); query inlines `$N` / `?` params and
79
+ // returns { rows, rowCount }.
80
+ function _makeDockerMysqlDriver() {
81
+ return {
82
+ connect: function () { return Promise.resolve({}); },
83
+ query: function (_client, sql, params) {
84
+ var r = _mysqlExec(_bindParams(sql, params || []));
85
+ if (!r.ok) {
86
+ var em = /ERROR\s+(\d+)[^:]*:\s*(.*)/.exec(r.err);
87
+ var err = new Error("MySQL " + (em ? em[1] + ": " + em[2] : _clean(r.err)));
88
+ if (em) err.code = em[1];
89
+ return Promise.reject(err);
90
+ }
91
+ return Promise.resolve({ rows: _parseRows(r.out), rowCount: 0 });
92
+ },
93
+ close: function () { return Promise.resolve(); },
94
+ dialect: "mysql",
95
+ };
96
+ }
97
+
98
+ function _parseRows(out) {
99
+ var lines = out.split(/\r?\n/).filter(function (l) {
100
+ return l.length > 0 && l.indexOf("World-writable") === -1 && l.indexOf("Using a password") === -1;
101
+ });
102
+ if (lines.length === 0) return [];
103
+ var headers = lines[0].split("\t");
104
+ var rows = [];
105
+ for (var i = 1; i < lines.length; i++) {
106
+ var cells = lines[i].split("\t");
107
+ var row = {};
108
+ for (var c = 0; c < headers.length; c++) {
109
+ var cell = cells[c];
110
+ row[headers[c]] = (cell === "NULL" || cell === undefined) ? null : cell;
111
+ }
112
+ rows.push(row);
113
+ }
114
+ return rows;
115
+ }
116
+
117
+ function _bindParams(sql, params) {
118
+ var i = 0;
119
+ return sql.replace(/\$(\d+)|\?/g, function (m) {
120
+ var idx = m.charAt(0) === "$" ? Number(m.slice(1)) - 1 : i++;
121
+ var v = params[idx];
122
+ if (v === null || v === undefined) return "NULL";
123
+ if (Buffer.isBuffer(v)) return "0x" + (v.length ? v.toString("hex") : "00");
124
+ if (typeof v === "number") return String(v);
125
+ if (typeof v === "boolean") return v ? "1" : "0";
126
+ return "'" + String(v).replace(/\\/g, "\\\\").replace(/'/g, "''") + "'";
127
+ });
128
+ }
129
+
130
+ // Every framework table ensureSchema creates, with a minimal valid row to
131
+ // insert + read back so the per-table column shapes (BIGINT / LONGBLOB /
132
+ // VARCHAR-key) are exercised end-to-end. Buffers exercise LONGBLOB; large
133
+ // ms-epoch numbers exercise BIGINT (a 32-bit INT would overflow).
134
+ var BIG_MS = 1893456000000; // 2030-01-01, well beyond 32-bit INT range
135
+ var NONCE = Buffer.from("0123456789abcdef0123456789abcdef", "hex");
136
+ var FRAMEWORK_TABLES = [
137
+ "_blamejs_audit_log", "_blamejs_consent_log", "_blamejs_audit_checkpoints",
138
+ "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
139
+ "_blamejs_scheduler_ticks", "_blamejs_rate_limit_counters",
140
+ "_blamejs_pubsub_messages", "_blamejs_api_encrypt_nonces", "_blamejs_api_keys",
141
+ "_blamejs_sessions", "_blamejs_jobs", "_blamejs_cache", "_blamejs_cache_tags",
142
+ "_blamejs_seeders", "_blamejs_seeders_lock", "_blamejs_break_glass_policies",
143
+ "_blamejs_break_glass_grants",
144
+ ];
145
+
146
+ async function run() {
147
+ var mysqlSvc = await services.requireService("mysql");
148
+ if (!mysqlSvc.ok) throw new Error("mysql unreachable: " + mysqlSvc.reason);
149
+
150
+ _mysql("CREATE DATABASE IF NOT EXISTS " + DB_NAME + ";", { noDb: true });
151
+ _mysql(FRAMEWORK_TABLES.map(function (t) { return "DROP TABLE IF EXISTS `" + t + "`;"; }).join("\n"));
152
+
153
+ var driver = _makeDockerMysqlDriver();
154
+ b.externalDb._resetForTest();
155
+ b.externalDb.init({
156
+ backends: {
157
+ ops: { connect: driver.connect, query: driver.query, close: driver.close, dialect: "mysql" },
158
+ },
159
+ });
160
+
161
+ try {
162
+ // ---- ensureSchema creates EVERY framework table on real MySQL ----
163
+ var report = await b.frameworkSchema.ensureSchema({ externalDbBackend: "ops", dialect: "mysql" });
164
+ soft("ensureSchema(mysql) returned the created-table report",
165
+ report && Array.isArray(report.tables) && report.tables.length === FRAMEWORK_TABLES.length);
166
+
167
+ var present = _mysql(
168
+ "SELECT count(*) AS n FROM information_schema.tables WHERE table_schema='" + DB_NAME +
169
+ "' AND table_name LIKE '_blamejs_%';");
170
+ var createdCount = Number((_parseRows(present)[0] || {}).n);
171
+ soft("ensureSchema(mysql) materialized all " + FRAMEWORK_TABLES.length +
172
+ " framework tables on the server (got " + createdCount + ")",
173
+ createdCount === FRAMEWORK_TABLES.length);
174
+
175
+ // Confirm a representative key column is VARCHAR (NOT TEXT) — the bug
176
+ // #97 fix (MySQL refuses TEXT in a key). audit_log._id is the PK.
177
+ var colType = _mysql(
178
+ "SELECT DATA_TYPE AS dt FROM information_schema.columns WHERE table_schema='" + DB_NAME +
179
+ "' AND table_name='_blamejs_audit_log' AND column_name='_id';");
180
+ soft("ensureSchema(mysql): a PRIMARY-KEY TEXT column is VARCHAR, not TEXT (key-length fix)",
181
+ /varchar/i.test((_parseRows(colType)[0] || {}).dt || ""));
182
+ // ms-epoch column is BIGINT (not a 32-bit INT).
183
+ var intType = _mysql(
184
+ "SELECT DATA_TYPE AS dt FROM information_schema.columns WHERE table_schema='" + DB_NAME +
185
+ "' AND table_name='_blamejs_audit_log' AND column_name='recordedAt';");
186
+ soft("ensureSchema(mysql): a ms-epoch column is BIGINT (no 32-bit overflow)",
187
+ /bigint/i.test((_parseRows(intType)[0] || {}).dt || ""));
188
+
189
+ // ---- insert + read a row through each table ----
190
+ await _roundTripAuditLog();
191
+ await _roundTripConsentLog();
192
+ await _roundTripCheckpoints();
193
+ await _roundTripSingleRow("_blamejs_audit_tip", { scope: "audit", atMonotonicCounter: 1, rowHash: "h", signedAt: "now", fencingToken: 0 }, "scope", "audit");
194
+ await _roundTripSingleRow("_blamejs_consent_tip", { scope: "consent", atMonotonicCounter: 1, rowHash: "h", signedAt: "now", fencingToken: 0 }, "scope", "consent");
195
+ await _roundTripSingleRow("_blamejs_audit_purge_anchor", { scope: "audit", lastPurgedCounter: 1, lastPurgedRowHash: "h", archiveBundleId: "b1", purgedAt: BIG_MS }, "scope", "audit");
196
+ await _roundTripSingleRow("_blamejs_scheduler_ticks", { tickKey: "job:1", name: "job", scheduledAtUnix: BIG_MS, claimedAtUnix: BIG_MS, claimedBy: "node-1" }, "tickKey", "job:1");
197
+ await _roundTripSingleRow("_blamejs_rate_limit_counters", { key: "ip:1.2.3.4", windowStart: BIG_MS, count: 7 }, "key", "ip:1.2.3.4");
198
+ await _roundTripPubsub();
199
+ await _roundTripSingleRow("_blamejs_api_encrypt_nonces", { nonceHash: "nh-1", expireAt: BIG_MS }, "nonceHash", "nh-1");
200
+ await _roundTripApiKeys();
201
+ await _roundTripSessions();
202
+ await _roundTripJobs();
203
+ await _roundTripSingleRow("_blamejs_cache", { cacheKey: "ns:k1", valueJson: "{\"a\":1}", expiresAt: BIG_MS, updatedAt: BIG_MS }, "cacheKey", "ns:k1");
204
+ await _roundTripSingleRow("_blamejs_cache_tags", { cacheKey: "ns:k1", tag: "t1" }, "cacheKey", "ns:k1");
205
+ await _roundTripSingleRow("_blamejs_seeders", { env: "dev", name: "0001-seed", description: "d", appliedAt: "now", rerunnable: 0 }, "name", "0001-seed");
206
+ await _roundTripSingleRow("_blamejs_seeders_lock", { scope: "lock", lockedAt: BIG_MS, lockedBy: "node-1" }, "scope", "lock");
207
+ await _roundTripBreakGlassPolicies();
208
+ await _roundTripBreakGlassGrants();
209
+
210
+ // ---- WORM trigger blocks DELETE/UPDATE on an append-only table ----
211
+ await _wormBlocks();
212
+ } finally {
213
+ try { await b.externalDb.shutdown(); } catch (_e) {}
214
+ b.externalDb._resetForTest();
215
+ _mysql(FRAMEWORK_TABLES.map(function (t) { return "DROP TABLE IF EXISTS `" + t + "`;"; }).join("\n"));
216
+ }
217
+
218
+ var failed = _results.filter(function (r) { return !r.ok; });
219
+ console.log("\n[framework-schema-mysql] " + (_results.length - failed.length) + "/" +
220
+ _results.length + " checks passed");
221
+ if (failed.length) failed.forEach(function (r) { console.log(" - " + r.label); });
222
+ for (var i = 0; i < _results.length; i++) check(_results[i].label, _results[i].ok);
223
+ }
224
+
225
+ // Insert a row via externalDb then read it back; assert the key column
226
+ // round-trips. Generic single-PK helper.
227
+ async function _roundTripSingleRow(table, row, keyCol, keyVal) {
228
+ var cols = Object.keys(row);
229
+ var placeholders = cols.map(function () { return "?"; }).join(", ");
230
+ var quotedCols = cols.map(function (c) { return "`" + c + "`"; }).join(", ");
231
+ var params = cols.map(function (c) { return row[c]; });
232
+ await b.externalDb.query(
233
+ "INSERT INTO `" + table + "` (" + quotedCols + ") VALUES (" + placeholders + ")",
234
+ params, { backend: "ops", rowResidencyTag: "unrestricted" });
235
+ var res = await b.externalDb.query(
236
+ "SELECT `" + keyCol + "` AS k FROM `" + table + "` WHERE `" + keyCol + "` = ?",
237
+ [keyVal], { backend: "ops" });
238
+ soft(table + ": insert + read a row round-trips through real MySQL",
239
+ res && res.rows && res.rows.length === 1 && res.rows[0].k === keyVal);
240
+ }
241
+
242
+ async function _roundTripAuditLog() {
243
+ await b.externalDb.query(
244
+ "INSERT INTO `_blamejs_audit_log` (`_id`,`recordedAt`,`monotonicCounter`,`action`,`outcome`,`prevHash`,`rowHash`,`nonce`,`fencingToken`) " +
245
+ "VALUES (?,?,?,?,?,?,?,?,?)",
246
+ ["a-1", BIG_MS, 1, "login", "success", "p0", "r1", NONCE, 0],
247
+ { backend: "ops", rowResidencyTag: "unrestricted" });
248
+ var res = await b.externalDb.query(
249
+ "SELECT `_id` AS k, `recordedAt` AS ts FROM `_blamejs_audit_log` WHERE `_id` = ?",
250
+ ["a-1"], { backend: "ops" });
251
+ var row = res && res.rows && res.rows[0];
252
+ soft("_blamejs_audit_log: row round-trips (LONGBLOB nonce + BIGINT recordedAt)",
253
+ row && row.k === "a-1" && String(row.ts) === String(BIG_MS));
254
+ }
255
+
256
+ async function _roundTripConsentLog() {
257
+ await b.externalDb.query(
258
+ "INSERT INTO `_blamejs_consent_log` (`_id`,`recordedAt`,`monotonicCounter`,`subjectId`,`subjectIdHash`,`purpose`,`lawfulBasis`,`action`,`channel`,`prevHash`,`rowHash`,`nonce`,`fencingToken`) " +
259
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",
260
+ ["c-1", BIG_MS, 1, "subj", "subjHash", "marketing", "consent", "grant", "web", "p0", "r1", NONCE, 0],
261
+ { backend: "ops", rowResidencyTag: "unrestricted" });
262
+ var res = await b.externalDb.query("SELECT `_id` AS k FROM `_blamejs_consent_log` WHERE `_id` = ?", ["c-1"], { backend: "ops" });
263
+ soft("_blamejs_consent_log: row round-trips", res && res.rows && res.rows[0] && res.rows[0].k === "c-1");
264
+ }
265
+
266
+ async function _roundTripCheckpoints() {
267
+ await b.externalDb.query(
268
+ "INSERT INTO `_blamejs_audit_checkpoints` (`_id`,`createdAt`,`atMonotonicCounter`,`atRowHash`,`signature`,`publicKeyFingerprint`,`fencingToken`) VALUES (?,?,?,?,?,?,?)",
269
+ ["chk-1", BIG_MS, 5, "r5", NONCE, "fp-1", 0],
270
+ { backend: "ops", rowResidencyTag: "unrestricted" });
271
+ var res = await b.externalDb.query("SELECT `_id` AS k FROM `_blamejs_audit_checkpoints` WHERE `_id` = ?", ["chk-1"], { backend: "ops" });
272
+ soft("_blamejs_audit_checkpoints: row round-trips (LONGBLOB signature)", res && res.rows && res.rows[0] && res.rows[0].k === "chk-1");
273
+ }
274
+
275
+ async function _roundTripPubsub() {
276
+ // id is BIGINT AUTO_INCREMENT — omit it so the engine assigns one.
277
+ await b.externalDb.query(
278
+ "INSERT INTO `_blamejs_pubsub_messages` (`topic`,`payload`,`publishedAt`,`publishedBy`) VALUES (?,?,?,?)",
279
+ ["chan", "{\"x\":1}", BIG_MS, "node-1"], { backend: "ops", rowResidencyTag: "unrestricted" });
280
+ var res = await b.externalDb.query("SELECT `id` AS id FROM `_blamejs_pubsub_messages` WHERE `topic` = ?", ["chan"], { backend: "ops" });
281
+ soft("_blamejs_pubsub_messages: AUTO_INCREMENT id assigned + row round-trips",
282
+ res && res.rows && res.rows[0] && Number(res.rows[0].id) >= 1);
283
+ }
284
+
285
+ async function _roundTripApiKeys() {
286
+ await b.externalDb.query(
287
+ "INSERT INTO `_blamejs_api_keys` (`id`,`namespace`,`ownerId`,`ownerIdHash`,`secretHash`,`createdAt`,`prefix`) VALUES (?,?,?,?,?,?,?)",
288
+ ["ns:idhex", "ns", "owner", "ownerHash", "secretHash", BIG_MS, "pfx"],
289
+ { backend: "ops", rowResidencyTag: "unrestricted" });
290
+ var res = await b.externalDb.query("SELECT `id` AS k FROM `_blamejs_api_keys` WHERE `id` = ?", ["ns:idhex"], { backend: "ops" });
291
+ soft("_blamejs_api_keys: row round-trips", res && res.rows && res.rows[0] && res.rows[0].k === "ns:idhex");
292
+ }
293
+
294
+ async function _roundTripSessions() {
295
+ await b.externalDb.query(
296
+ "INSERT INTO `_blamejs_sessions` (`sidHash`,`userId`,`userIdHash`,`createdAt`,`expiresAt`,`lastActivity`) VALUES (?,?,?,?,?,?)",
297
+ ["sid-1", "uid-sealed", "uidHash", BIG_MS, BIG_MS, BIG_MS],
298
+ { backend: "ops", rowResidencyTag: "unrestricted" });
299
+ var res = await b.externalDb.query("SELECT `sidHash` AS k FROM `_blamejs_sessions` WHERE `sidHash` = ?", ["sid-1"], { backend: "ops" });
300
+ soft("_blamejs_sessions: row round-trips", res && res.rows && res.rows[0] && res.rows[0].k === "sid-1");
301
+ }
302
+
303
+ async function _roundTripJobs() {
304
+ await b.externalDb.query(
305
+ "INSERT INTO `_blamejs_jobs` (`_id`,`queueName`,`status`,`enqueuedAt`,`availableAt`) VALUES (?,?,?,?,?)",
306
+ ["job-1", "q1", "pending", BIG_MS, BIG_MS],
307
+ { backend: "ops", rowResidencyTag: "unrestricted" });
308
+ var res = await b.externalDb.query("SELECT `_id` AS k FROM `_blamejs_jobs` WHERE `_id` = ?", ["job-1"], { backend: "ops" });
309
+ soft("_blamejs_jobs: row round-trips", res && res.rows && res.rows[0] && res.rows[0].k === "job-1");
310
+ }
311
+
312
+ async function _roundTripBreakGlassPolicies() {
313
+ await b.externalDb.query(
314
+ "INSERT INTO `_blamejs_break_glass_policies` (`tableName`,`columnsJson`,`factorsJson`,`grantTtlMs`,`updatedAt`) VALUES (?,?,?,?,?)",
315
+ ["secret_table", "[\"ssn\"]", "[\"webauthn\"]", BIG_MS, BIG_MS],
316
+ { backend: "ops", rowResidencyTag: "unrestricted" });
317
+ var res = await b.externalDb.query("SELECT `tableName` AS k FROM `_blamejs_break_glass_policies` WHERE `tableName` = ?", ["secret_table"], { backend: "ops" });
318
+ soft("_blamejs_break_glass_policies: row round-trips", res && res.rows && res.rows[0] && res.rows[0].k === "secret_table");
319
+ }
320
+
321
+ async function _roundTripBreakGlassGrants() {
322
+ await b.externalDb.query(
323
+ "INSERT INTO `_blamejs_break_glass_grants` (`_id`,`issuedToActorId`,`issuedToActorHash`,`factorType`,`scopeTable`,`scopeColumnsJson`,`issuedAt`,`expiresAt`,`maxRowsPerGrant`) VALUES (?,?,?,?,?,?,?,?,?)",
324
+ ["grant-1", "actor", "actorHash", "webauthn", "secret_table", "[\"ssn\"]", BIG_MS, BIG_MS, 1],
325
+ { backend: "ops", rowResidencyTag: "unrestricted" });
326
+ var res = await b.externalDb.query("SELECT `_id` AS k FROM `_blamejs_break_glass_grants` WHERE `_id` = ?", ["grant-1"], { backend: "ops" });
327
+ soft("_blamejs_break_glass_grants: row round-trips", res && res.rows && res.rows[0] && res.rows[0].k === "grant-1");
328
+ }
329
+
330
+ // The append-only WORM triggers must block DELETE + UPDATE on the audit
331
+ // tables. ensureSchema installs them via SIGNAL SQLSTATE '45000'.
332
+ async function _wormBlocks() {
333
+ var delBlocked = false;
334
+ try {
335
+ await b.externalDb.query("DELETE FROM `_blamejs_audit_log` WHERE `_id` = ?", ["a-1"], { backend: "ops" });
336
+ } catch (_e) { delBlocked = true; }
337
+ soft("_blamejs_audit_log: WORM trigger blocks DELETE (append-only)", delBlocked);
338
+
339
+ var updBlocked = false;
340
+ try {
341
+ await b.externalDb.query("UPDATE `_blamejs_audit_log` SET `action` = ? WHERE `_id` = ?", ["tampered", "a-1"], { backend: "ops" });
342
+ } catch (_e) { updBlocked = true; }
343
+ soft("_blamejs_audit_log: WORM trigger blocks UPDATE (append-only)", updBlocked);
344
+ }
345
+
346
+ module.exports = { run: run };
347
+
348
+ if (require.main === module) {
349
+ run().then(
350
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
351
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
352
+ );
353
+ }
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ /**
3
+ * Live CloudWatch Logs sink test — exercises lib/log-stream-cloudwatch.js
4
+ * against LocalStack's CloudWatch Logs API (Logs_20140328) over TLS.
5
+ *
6
+ * What this proves (real, end-to-end):
7
+ * - The sink's autoCreate handshake issues CreateLogGroup ->
8
+ * CreateLogStream before the first PutLogEvents, and treats an
9
+ * already-existing group/stream as success.
10
+ * - The PutLogEvents wire shape is correct: X-Amz-Target
11
+ * Logs_20140328.PutLogEvents, Content-Type application/x-amz-json-1.1,
12
+ * a { logGroupName, logStreamName, logEvents:[{timestamp,message}] }
13
+ * body, events sorted ascending by timestamp.
14
+ * - The endpoint override (cfg.endpoint) is honoured — requests reach
15
+ * 127.0.0.1:4566, not logs.<region>.amazonaws.com.
16
+ * - The sequence-token handshake: the framework picks up
17
+ * nextSequenceToken from each PutLogEvents response and carries it
18
+ * forward (stats().sequenceToken advances).
19
+ * - close()/shutdown() drains buffered records to the wire — the
20
+ * "records queued just before shutdown reach the wire" contract
21
+ * b.logStream advertises.
22
+ *
23
+ * Read-back is a SigV4-signed GetLogEvents / DescribeLogStreams built
24
+ * with the framework's own signer (service "logs"), so the events the
25
+ * sink delivered are confirmed present in CloudWatch with the expected
26
+ * message content + ordering.
27
+ *
28
+ * Scope honesty — what this does NOT prove:
29
+ * LocalStack accepts the test credentials and does NOT verify the
30
+ * SigV4 signature. So this proves request SHAPE, the
31
+ * create-group -> create-stream -> put-events sequence, sequence-token
32
+ * handling, endpoint-override honouring, close-time drain, and
33
+ * read-back content/ordering — NOT signature correctness.
34
+ * (Signature correctness against a server that
35
+ * DOES verify SigV4 is covered by object-store-sigv4.test.js against
36
+ * MinIO.)
37
+ *
38
+ * No security bypass: TLS to LocalStack trusts the test CA via
39
+ * NODE_EXTRA_CA_CERTS (exported by scripts/test-integration.js).
40
+ * rejectUnauthorized stays on; the sink's allowInternal:true only
41
+ * permits the loopback host, it does not disable verification.
42
+ */
43
+ var nodeCrypto = require("node:crypto");
44
+ var helpers = require("../helpers");
45
+ var check = helpers.check;
46
+ var services = require("../helpers/services");
47
+
48
+ var cloudwatchProto = require("../../lib/log-stream-cloudwatch");
49
+ var sigv4 = require("../../lib/object-store/sigv4");
50
+ var httpClient = require("../../lib/http-client");
51
+ var safeUrl = require("../../lib/safe-url");
52
+
53
+ var REGION = "us-east-1";
54
+ var ACCESS = "test";
55
+ var SECRET = "test";
56
+
57
+ // ---- SigV4-signed CloudWatch Logs read-back helper ----
58
+ // Builds + signs a Logs_20140328 request with the framework's own
59
+ // signer (service "logs") and posts it through httpClient. Returns the
60
+ // parsed JSON body. Rejects (throws) on a non-2xx so the caller sees
61
+ // the AWS exception text.
62
+ function _logsCall(endpoint, target, payload) {
63
+ var body = Buffer.from(JSON.stringify(payload), "utf8");
64
+ var payloadHash = nodeCrypto.createHash("sha256").update(body).digest("hex");
65
+ var signed = sigv4.signRequest({
66
+ method: "POST",
67
+ url: endpoint,
68
+ headers: {
69
+ "Content-Type": "application/x-amz-json-1.1",
70
+ "X-Amz-Target": target,
71
+ },
72
+ payloadHash: payloadHash,
73
+ region: REGION,
74
+ service: "logs",
75
+ accessKeyId: ACCESS,
76
+ secretAccessKey: SECRET,
77
+ allowedProtocols: safeUrl.ALLOW_HTTP_TLS,
78
+ });
79
+ return httpClient.request({
80
+ method: "POST",
81
+ url: endpoint,
82
+ headers: signed.headers,
83
+ body: body,
84
+ allowInternal: true,
85
+ }).then(function (res) {
86
+ return JSON.parse(res.body.toString("utf8"));
87
+ });
88
+ }
89
+
90
+ function _readEvents(endpoint, logGroupName, logStreamName) {
91
+ return _logsCall(endpoint, "Logs_20140328.GetLogEvents", {
92
+ logGroupName: logGroupName,
93
+ logStreamName: logStreamName,
94
+ startFromHead: true,
95
+ }).then(function (parsed) {
96
+ return (parsed && parsed.events) || [];
97
+ });
98
+ }
99
+
100
+ async function run() {
101
+ var ls = await services.requireService("localstack");
102
+ if (!ls.ok) throw new Error("localstack unreachable: " + ls.reason);
103
+
104
+ var endpoint = services.URLS.localstack; // https://127.0.0.1:4566
105
+
106
+ // ---- 1) endpoint override is honoured ----
107
+ // _resolveEndpoint must reflect cfg.endpoint, not the AWS regional host.
108
+ var resolved = cloudwatchProto._resolveEndpoint({
109
+ endpoint: endpoint, region: REGION,
110
+ });
111
+ check("endpoint override honoured (not logs.<region>.amazonaws.com)",
112
+ resolved === endpoint.replace(/\/+$/, "") + "/" &&
113
+ resolved.indexOf("127.0.0.1:4566") !== -1);
114
+
115
+ // ---- 2) autoCreate is load-bearing: PutLogEvents to a never-created
116
+ // group/stream is a permanent ResourceNotFoundException. (Establishes
117
+ // that the create handshake below is doing real work, not a no-op.) ----
118
+ var stamp = Date.now() + "-" + Math.floor(Math.random() * 1e6);
119
+ var missingGroup = "blamejs-cw-missing-" + stamp;
120
+ var missingStream = "missing-stream-" + stamp;
121
+ var rnfErr = null;
122
+ try {
123
+ await _logsCall(endpoint, "Logs_20140328.PutLogEvents", {
124
+ logGroupName: missingGroup,
125
+ logStreamName: missingStream,
126
+ logEvents: [{ timestamp: Date.now(), message: "should-not-land" }],
127
+ });
128
+ } catch (e) { rnfErr = e; }
129
+ check("PutLogEvents to an uncreated group fails (ResourceNotFoundException) — autoCreate is load-bearing",
130
+ rnfErr && /ResourceNotFoundException/.test(String(rnfErr.message || "")));
131
+ check("classifier treats ResourceNotFoundException as permanent",
132
+ cloudwatchProto._isPermanentAwsError(new Error("ResourceNotFoundException: no such group")) === true);
133
+
134
+ // ---- 3) sink delivers events via autoCreate + close() drain + read-back ----
135
+ // This is the core proof: emit a few records (under batchSize so close()
136
+ // is the thing that has to drain them), close, then read them back out
137
+ // of CloudWatch. Records are pushed out of timestamp order to confirm
138
+ // the sink sorts ascending before PutLogEvents (AWS hard requirement).
139
+ var logGroupName = "blamejs-cw-test-" + stamp;
140
+ var logStreamName = "stream-" + stamp;
141
+
142
+ var drops = [];
143
+ var sink = cloudwatchProto.create({
144
+ region: REGION,
145
+ accessKeyId: ACCESS,
146
+ secretAccessKey: SECRET,
147
+ endpoint: endpoint,
148
+ logGroupName: logGroupName,
149
+ logStreamName: logStreamName,
150
+ autoCreate: true, // exercise CreateLogGroup -> CreateLogStream
151
+ allowInternal: true, // permit the loopback host (TLS stays verified)
152
+ allowedProtocols: safeUrl.ALLOW_HTTP_TLS,
153
+ batchSize: 10, // larger than the record count → close() drains
154
+ onDrop: function (d) { drops.push(d); },
155
+ });
156
+
157
+ var base = Date.now();
158
+ var messages = [
159
+ { ts: base + 30, message: "cw-event-three" },
160
+ { ts: base + 10, message: "cw-event-one" },
161
+ { ts: base + 20, message: "cw-event-two" },
162
+ ];
163
+ for (var i = 0; i < messages.length; i += 1) {
164
+ var rv = await sink.emit(messages[i]);
165
+ check("emit accepted record '" + messages[i].message + "'", rv && rv.accepted === true);
166
+ }
167
+ // close() MUST drain the buffered records to CloudWatch — this is the
168
+ // documented shutdown contract. (If close() flips closed=true before
169
+ // draining, _flush()'s `while (... && !closed)` loop strands them.)
170
+ await sink.close();
171
+
172
+ check("no drops during delivery", drops.length === 0);
173
+
174
+ // Read the events back out of CloudWatch — the real end-to-end proof.
175
+ var events = await helpers.waitUntil(async function () {
176
+ var ev = await _readEvents(endpoint, logGroupName, logStreamName);
177
+ return ev.length >= 3 ? ev : false;
178
+ }, { timeoutMs: 8000, label: "cloudwatch: GetLogEvents returns the 3 records close() should have drained" });
179
+
180
+ check("read-back: all three events present", events.length === 3);
181
+
182
+ var readMessages = events.map(function (e) { return e.message; });
183
+ check("read-back: 'cw-event-one' present", readMessages.indexOf("cw-event-one") !== -1);
184
+ check("read-back: 'cw-event-two' present", readMessages.indexOf("cw-event-two") !== -1);
185
+ check("read-back: 'cw-event-three' present", readMessages.indexOf("cw-event-three") !== -1);
186
+
187
+ // GetLogEvents with startFromHead returns events oldest-first. The
188
+ // sink sorts by timestamp ascending, so the read-back order must be
189
+ // one -> two -> three regardless of emit order.
190
+ check("read-back: events ordered ascending by timestamp (sink sorted them)",
191
+ readMessages[0] === "cw-event-one" &&
192
+ readMessages[1] === "cw-event-two" &&
193
+ readMessages[2] === "cw-event-three");
194
+
195
+ var st = sink.stats();
196
+ check("after delivery: nothing left queued", st.queued === 0);
197
+ check("sink picked up a sequenceToken from PutLogEvents response",
198
+ typeof st.sequenceToken === "string" && st.sequenceToken.length > 0);
199
+
200
+ // ---- 4) DescribeLogStreams confirms the stream the sink created ----
201
+ var describe = await _logsCall(endpoint, "Logs_20140328.DescribeLogStreams", {
202
+ logGroupName: logGroupName,
203
+ });
204
+ var streamNames = ((describe && describe.logStreams) || []).map(function (s) { return s.logStreamName; });
205
+ check("DescribeLogStreams: autoCreate created the stream",
206
+ streamNames.indexOf(logStreamName) !== -1);
207
+
208
+ // NOTE: a redaction-before-sink leg was intentionally not included. The
209
+ // CloudWatch sink serializes only record.message (record.meta is dropped),
210
+ // and log records are not redacted before egress, so neither a
211
+ // meta-redaction nor a meta-preservation guarantee holds for this sink —
212
+ // asserting one would be vacuous. That structured-field / DLP gap is tracked
213
+ // separately; this file proves the wire shape, autoCreate, sequence-token
214
+ // handling, close-time drain, and read-back.
215
+ }
216
+
217
+ module.exports = { run: run };
218
+
219
+ if (require.main === module) {
220
+ run().then(
221
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
222
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
223
+ );
224
+ }