@blamejs/blamejs-shop 0.4.31 → 0.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +392 -278
  4. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  5. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  6. package/lib/vendor/blamejs/.gitignore +6 -0
  7. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  8. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  9. package/lib/vendor/blamejs/README.md +8 -6
  10. package/lib/vendor/blamejs/SECURITY.md +19 -3
  11. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  12. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  13. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  14. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  15. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  16. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  17. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  18. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  19. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  20. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  21. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  23. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  24. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  25. package/lib/vendor/blamejs/index.js +4 -0
  26. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  27. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  28. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  29. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  30. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  31. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  32. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  33. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  34. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  35. package/lib/vendor/blamejs/lib/audit.js +259 -123
  36. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  37. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  38. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  39. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  40. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  41. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  42. package/lib/vendor/blamejs/lib/cache.js +174 -105
  43. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  44. package/lib/vendor/blamejs/lib/cli.js +19 -14
  45. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  46. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  47. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  48. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  49. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  50. package/lib/vendor/blamejs/lib/consent.js +82 -29
  51. package/lib/vendor/blamejs/lib/constants.js +27 -11
  52. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  53. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  54. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  55. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  56. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  57. package/lib/vendor/blamejs/lib/db.js +249 -99
  58. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  59. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  60. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  61. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  62. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  63. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  64. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  65. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  66. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  67. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  68. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  69. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  70. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  71. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  72. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  73. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  74. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  75. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  76. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  77. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  78. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  79. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  80. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  81. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  82. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  83. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  84. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  85. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  86. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  87. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  88. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  89. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  90. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  91. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  92. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  93. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  94. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  95. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  96. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  97. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  98. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  99. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  100. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  101. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  102. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  103. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  104. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  106. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  107. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  108. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  109. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  110. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  111. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  112. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  113. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  114. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  115. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  116. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  117. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  118. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  119. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  120. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  121. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  123. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  124. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  125. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  126. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  128. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  129. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  131. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  132. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  133. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  134. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  135. package/lib/vendor/blamejs/lib/mail.js +8 -4
  136. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  137. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  138. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  139. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  140. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  141. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  142. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  143. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  144. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  145. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  146. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  147. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  148. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  149. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  150. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  151. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  152. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  153. package/lib/vendor/blamejs/lib/observability.js +124 -0
  154. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  155. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  156. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  157. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  158. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  159. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  160. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  161. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  162. package/lib/vendor/blamejs/lib/queue.js +7 -0
  163. package/lib/vendor/blamejs/lib/redact.js +68 -11
  164. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  165. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  166. package/lib/vendor/blamejs/lib/retention.js +101 -40
  167. package/lib/vendor/blamejs/lib/router.js +212 -5
  168. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  169. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  170. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  171. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  172. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  173. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  174. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  175. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  176. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  177. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  178. package/lib/vendor/blamejs/lib/session.js +175 -77
  179. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  180. package/lib/vendor/blamejs/lib/sse.js +26 -0
  181. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  182. package/lib/vendor/blamejs/lib/static.js +177 -34
  183. package/lib/vendor/blamejs/lib/subject.js +96 -49
  184. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  185. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  186. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  187. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  188. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  189. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  190. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  191. package/lib/vendor/blamejs/package.json +2 -2
  192. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  193. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  194. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  200. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  201. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  202. package/lib/vendor/blamejs/scripts/release.js +398 -38
  203. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  204. package/lib/vendor/blamejs/test/10-state.js +140 -14
  205. package/lib/vendor/blamejs/test/20-db.js +65 -2
  206. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  207. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  208. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  209. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  210. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  211. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  212. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  213. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  214. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  215. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  220. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  221. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  222. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  223. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  224. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  225. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  226. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  227. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  228. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  229. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  230. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  231. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  232. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  233. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  234. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  235. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  236. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  237. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  238. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  248. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  251. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  258. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  271. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  272. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  273. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  277. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  278. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  291. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  302. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  308. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  310. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  311. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  312. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  313. package/lib/vendor/blamejs/test/smoke.js +79 -21
  314. package/package.json +1 -1
  315. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  316. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  317. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  318. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  319. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  320. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  321. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  322. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  323. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  324. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  325. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  326. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  327. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  328. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  329. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  330. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  331. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  332. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  334. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  335. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  336. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -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
+ }