@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,517 @@
1
+ "use strict";
2
+ /**
3
+ * Live test of the catalog claim that the tamper-evident, signed audit
4
+ * hash-chain "runs on the operator's external Postgres in cluster mode"
5
+ * (b.audit / b.clusterStorage / b.frameworkSchema). Driver: a docker-exec
6
+ * psql shim that replicates a real node-postgres driver's coercions
7
+ * EXACTLY — the point of the test:
8
+ *
9
+ * - unquoted camelCase columns come back LOWERCASED in the result keys
10
+ * (Postgres folds unquoted identifiers; node-postgres returns the
11
+ * server's reported names verbatim → `rowhash`, `prevhash`,
12
+ * `monotoniccounter`, …),
13
+ * - BIGINT (int8) comes back as a JS STRING (node-postgres default to
14
+ * avoid >2^53 precision loss),
15
+ * - BYTEA comes back as a Node Buffer.
16
+ *
17
+ * What this proves (or refutes), end-to-end against the live server:
18
+ *
19
+ * 1. frameworkSchema.ensureSchema creates _blamejs_audit_log + the
20
+ * append-only WORM triggers on real Postgres (the chain's home in
21
+ * cluster mode).
22
+ *
23
+ * 2. Build a KNOWN-VALID chain with the framework's OWN hash math
24
+ * (b.auditChain.computeRowHash), INSERT the rows into the live
25
+ * _blamejs_audit_log via the driver, then run the framework's own
26
+ * verifier (b.auditChain.verifyChain, the exact reader b.audit.verify
27
+ * uses) against the live table. A correct framework returns ok:true.
28
+ * THIS IS THE CORE PROOF and it asserts the CORRECT behavior so a
29
+ * regression / pre-existing gap surfaces as a failure.
30
+ *
31
+ * 3. The BIGINT→string + BYTEA→Buffer coercion of the hash-preimage
32
+ * columns (monotonicCounter, recordedAt, nonce) must not break a
33
+ * valid chain's verification.
34
+ *
35
+ * 4. TAMPER a hashed column directly via the driver → verify must
36
+ * report ok:false.
37
+ *
38
+ * 5. cluster.init leadership acquisition over the real Postgres lease
39
+ * provider — the gate every chain append passes through.
40
+ *
41
+ * MySQL note: frameworkSchema only emits DDL for postgres / sqlite
42
+ * (lib/framework-schema.js _types() throws on "mysql"; the module
43
+ * docstring states MySQL is not supported). There is no MySQL audit-chain
44
+ * path to exercise — the test asserts the framework refuses MySQL rather
45
+ * than fabricating a MySQL chain.
46
+ */
47
+
48
+ var spawn = require("node:child_process").spawn;
49
+ var execFileSync = require("node:child_process").execFileSync;
50
+ var helpers = require("../helpers");
51
+ var check = helpers.check;
52
+ var services = require("../helpers/services");
53
+ var b = require("../../");
54
+
55
+ var CONTAINER = "blamejs-test-postgres";
56
+ var NULL_SENTINEL = "__BJNULL__";
57
+ var PSQL_ARGS = "psql -U blamejs -d blamejs_test -A " +
58
+ "-v ON_ERROR_STOP=0 -P null=__BJNULL__ 2>&1";
59
+
60
+ // ---- one-shot psql (setup / teardown / out-of-band tamper + asserts) ----
61
+ function _psql(sql) {
62
+ var prelude = "\\pset fieldsep '\\t'\n";
63
+ var out = execFileSync(
64
+ "docker",
65
+ ["exec", "-i", CONTAINER, "sh", "-c",
66
+ "psql -U blamejs -d blamejs_test -qtA -P null=__BJNULL__ 2>&1"],
67
+ { input: prelude + sql + "\n", stdio: ["pipe", "pipe", "pipe"] }
68
+ ).toString("utf8");
69
+ if (/^ERROR:/m.test(out)) {
70
+ throw new Error("psql setup failed for [" + sql + "]:\n" + out);
71
+ }
72
+ return out;
73
+ }
74
+
75
+ // ---- persistent-session docker-exec psql driver (faithful to pg) ----
76
+ var _seq = 0;
77
+ function _makeDockerPgDriver() {
78
+ return {
79
+ connect: function () {
80
+ return new Promise(function (resolve, reject) {
81
+ var child = spawn(
82
+ "docker",
83
+ ["exec", "-i", CONTAINER, "sh", "-c",
84
+ PSQL_ARGS + " ; echo __BLAMEJS_PSQL_EXIT__"],
85
+ { stdio: ["pipe", "pipe", "pipe"] }
86
+ );
87
+ var client = { child: child, buf: "", pending: null, closed: false };
88
+ child.on("error", function (e) {
89
+ if (client.pending) { var p = client.pending; client.pending = null; p.reject(e); }
90
+ });
91
+ child.on("close", function () {
92
+ client.closed = true;
93
+ if (client.pending) {
94
+ var p = client.pending; client.pending = null;
95
+ p.reject(new Error("psql session closed mid-statement"));
96
+ }
97
+ });
98
+ child.stdout.on("data", function (chunk) {
99
+ client.buf += chunk.toString("utf8");
100
+ _drain(client);
101
+ });
102
+ var primeSentinel = "__BJ_PRIME__";
103
+ client.pending = {
104
+ sentinel: primeSentinel,
105
+ resolve: function () { resolve(client); },
106
+ reject: reject,
107
+ };
108
+ client.child.stdin.write(
109
+ "\\pset fieldsep '\\t'\n\\pset footer off\n\\set VERBOSITY verbose\n" +
110
+ "SET bytea_output = 'hex';\n" +
111
+ "\\echo " + primeSentinel + "\n");
112
+ });
113
+ },
114
+
115
+ query: function (client, sql, params) {
116
+ params = params || [];
117
+ var bound = _bindParams(sql, params);
118
+ var sentinel = "__BJ_EOR_" + (++_seq) + "__";
119
+ return new Promise(function (resolve, reject) {
120
+ if (client.closed) { reject(new Error("psql session is closed")); return; }
121
+ client.pending = { sentinel: sentinel, resolve: resolve, reject: reject };
122
+ client.child.stdin.write(bound + "\n;\n\\echo " + sentinel + "\n");
123
+ });
124
+ },
125
+
126
+ close: function (client) {
127
+ return new Promise(function (resolve) {
128
+ if (client.closed) { resolve(); return; }
129
+ try { client.child.stdin.end("\\q\n"); } catch (_e) { /* best effort */ }
130
+ var done = false;
131
+ client.child.on("close", function () { if (!done) { done = true; resolve(); } });
132
+ setTimeout(function () {
133
+ if (done) return;
134
+ done = true;
135
+ try { client.child.kill("SIGKILL"); } catch (_e) {}
136
+ resolve();
137
+ }, 2000);
138
+ });
139
+ },
140
+
141
+ dialect: "postgres",
142
+ };
143
+ }
144
+
145
+ function _drain(client) {
146
+ if (!client.pending) return;
147
+ var sentinel = client.pending.sentinel;
148
+ var marker = "\n" + sentinel + "\n";
149
+ var idx = client.buf.indexOf(marker);
150
+ var startAtZero = client.buf.indexOf(sentinel + "\n") === 0;
151
+ var block;
152
+ if (idx !== -1) {
153
+ block = client.buf.slice(0, idx);
154
+ client.buf = client.buf.slice(idx + marker.length);
155
+ } else if (startAtZero) {
156
+ block = "";
157
+ client.buf = client.buf.slice((sentinel + "\n").length);
158
+ } else {
159
+ return;
160
+ }
161
+ var p = client.pending;
162
+ client.pending = null;
163
+ var parsed;
164
+ try { parsed = _parseBlock(block); }
165
+ catch (e) { return p.reject(e); }
166
+ if (parsed.error) return p.reject(parsed.error);
167
+ p.resolve({ rows: parsed.rows, rowCount: parsed.rowCount });
168
+ }
169
+
170
+ // Inline params: Buffers as bytea hex literals (byte-faithful round-trip),
171
+ // numbers raw, everything else single-quote-escaped.
172
+ var BYTEA_LITERAL_PREFIX = "'" + "\\" + "x";
173
+ function _bindParams(sql, params) {
174
+ return sql.replace(/\$(\d+)/g, function (_m, n) {
175
+ var i = Number(n) - 1;
176
+ if (i < 0 || i >= params.length) {
177
+ throw new Error("placeholder $" + n + " has no matching param");
178
+ }
179
+ var v = params[i];
180
+ if (v === null || v === undefined) return "NULL";
181
+ if (Buffer.isBuffer(v)) return BYTEA_LITERAL_PREFIX + v.toString("hex") + "'::bytea";
182
+ if (typeof v === "number") return String(v);
183
+ if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
184
+ return "'" + String(v).replace(/'/g, "''") + "'";
185
+ });
186
+ }
187
+
188
+ var _CMD_TAG_RE = /^(INSERT|UPDATE|DELETE|MERGE|SELECT|COPY|MOVE)\b(?:\s+\d+)*\s*$/;
189
+ var _CTRL_TAG_RE = /^(BEGIN|COMMIT|ROLLBACK|SET|RESET|SAVEPOINT|RELEASE|START|CREATE|DROP|ALTER|GRANT|REVOKE|TRUNCATE|COMMENT|DO|CALL|VACUUM|ANALYZE|EXPLAIN|TABLE|SHOW|DISCARD)\b/;
190
+
191
+ // Columns the framework reads as Buffers (real pg returns bytea as Buffer).
192
+ var _BYTEA_COLUMNS = { nonce: true, signature: true };
193
+
194
+ function _parseBlock(block) {
195
+ var lines = block.split(/\r?\n/);
196
+ while (lines.length && lines[lines.length - 1] === "") lines.pop();
197
+
198
+ for (var i = 0; i < lines.length; i++) {
199
+ var em = /^ERROR:\s+([0-9A-Za-z]{5}):\s*(.*)$/.exec(lines[i]);
200
+ if (em) {
201
+ var err = new Error("Postgres " + em[1] + ": " + em[2]);
202
+ err.code = em[1];
203
+ return { error: err };
204
+ }
205
+ }
206
+
207
+ var affected = null;
208
+ var dataLines = [];
209
+ for (var j = 0; j < lines.length; j++) {
210
+ var ln = lines[j];
211
+ if (/^(NOTICE|WARNING|DETAIL|HINT|LINE|LOCATION|CONTEXT|STATEMENT):/.test(ln)) continue;
212
+ var tm = _CMD_TAG_RE.exec(ln);
213
+ if (tm) {
214
+ var nums = ln.trim().split(/\s+/).slice(1).map(Number);
215
+ if (nums.length) affected = nums[nums.length - 1];
216
+ continue;
217
+ }
218
+ if (_CTRL_TAG_RE.test(ln) && ln.indexOf("\t") === -1) continue;
219
+ dataLines.push(ln);
220
+ }
221
+
222
+ var rows = [];
223
+ if (dataLines.length >= 1) {
224
+ // dataLines[0] is the header row (column names AS POSTGRES REPORTS
225
+ // THEM — lowercase for unquoted identifiers). We deliberately keep
226
+ // them verbatim, exactly as node-postgres would key the row object.
227
+ var headers = dataLines[0].split("\t");
228
+ for (var k = 1; k < dataLines.length; k++) {
229
+ var cells = dataLines[k].split("\t");
230
+ var row = {};
231
+ for (var c = 0; c < headers.length; c++) {
232
+ var cell = cells[c];
233
+ var hdr = headers[c];
234
+ if (cell === NULL_SENTINEL || cell === undefined) { row[hdr] = null; continue; }
235
+ if (_BYTEA_COLUMNS[hdr] === true) {
236
+ var hex = cell.charAt(0) === "\\" && cell.charAt(1) === "x"
237
+ ? cell.slice(2) : cell;
238
+ row[hdr] = Buffer.from(hex, "hex");
239
+ } else {
240
+ // STRING — including BIGINT columns (node-postgres int8 default).
241
+ row[hdr] = cell;
242
+ }
243
+ }
244
+ rows.push(row);
245
+ }
246
+ }
247
+ var rowCount = (affected !== null) ? affected : rows.length;
248
+ return { rows: rows, rowCount: rowCount, error: null };
249
+ }
250
+
251
+ // Audit_log column set that ensureSchema creates (camelCase in DDL —
252
+ // Postgres folds the stored names to lowercase). We INSERT with these
253
+ // names quoted so the values land in the right physical columns; the
254
+ // READBACK is what surfaces the lowercase keys.
255
+ var AUDIT_COLS = [
256
+ "_id", "recordedAt", "monotonicCounter",
257
+ "actorUserId", "actorUserIdHash", "actorIp",
258
+ "actorUserAgent", "actorSessionId",
259
+ "action", "resourceKind", "resourceId", "resourceIdHash",
260
+ "outcome", "reason", "metadata", "requestId",
261
+ "prevHash", "rowHash", "nonce", "fencingToken",
262
+ ];
263
+ // Columns that feed the chain-hash preimage (must match what the
264
+ // framework's chain-writer hashes: every audit column except the chain
265
+ // bookkeeping prevHash/rowHash/nonce/fencingToken).
266
+ var HASHABLE_COLS = [
267
+ "_id", "recordedAt", "monotonicCounter",
268
+ "actorUserId", "actorUserIdHash", "actorIp",
269
+ "actorUserAgent", "actorSessionId",
270
+ "action", "resourceKind", "resourceId", "resourceIdHash",
271
+ "outcome", "reason", "metadata", "requestId",
272
+ ];
273
+
274
+ // Build the framework-faithful logical row + its rowHash, exactly as
275
+ // chain-writer would: materialize null for every hashable column so the
276
+ // canonicalizer sees the same key set at write- and verify-time, then
277
+ // computeRowHash(prevHash, hashableFields, nonce).
278
+ function _buildChainRow(driverClient, driver, counter, prevHash, logical) {
279
+ var crypto = require("../../lib/crypto");
280
+ var nonce = crypto.generateBytes(16);
281
+ var full = Object.assign({
282
+ _id: "row-" + counter,
283
+ recordedAt: 1700000000000 + counter,
284
+ monotonicCounter: counter,
285
+ }, logical);
286
+ // Hashable view: every hashable column present, null-filled.
287
+ var hashable = {};
288
+ for (var i = 0; i < HASHABLE_COLS.length; i++) {
289
+ var col = HASHABLE_COLS[i];
290
+ hashable[col] = (full[col] === undefined) ? null : full[col];
291
+ }
292
+ var rowHash = b.auditChain.computeRowHash(prevHash, hashable, nonce);
293
+ var rowForInsert = Object.assign({}, hashable, {
294
+ prevHash: prevHash, rowHash: rowHash, nonce: nonce, fencingToken: 0,
295
+ });
296
+ return { rowForInsert: rowForInsert, rowHash: rowHash };
297
+ }
298
+
299
+ // Insert a chain row using the EXACT SQL shape the framework's
300
+ // chain-writer emits: identifiers quoted via safeSql.quoteIdentifier
301
+ // (double-quoted, case-PRESERVING camelCase). This is what
302
+ // b.audit.record → chain-writer → clusterStorage actually runs against
303
+ // the external Postgres backend, so a failure here is the framework's
304
+ // real failure, not a test artifact.
305
+ var safeSql = require("../../lib/safe-sql");
306
+ async function _insertChainRow(driver, driverClient, rowForInsert) {
307
+ var quoted = AUDIT_COLS.map(function (c) { return safeSql.quoteIdentifier(c); }).join(", ");
308
+ var ph = AUDIT_COLS.map(function (_c, i) { return "$" + (i + 1); }).join(", ");
309
+ var vals = AUDIT_COLS.map(function (c) {
310
+ return rowForInsert[c] === undefined ? null : rowForInsert[c];
311
+ });
312
+ await driver.query(driverClient,
313
+ 'INSERT INTO ' + safeSql.quoteIdentifier("_blamejs_audit_log") +
314
+ ' (' + quoted + ') VALUES (' + ph + ')', vals);
315
+ }
316
+
317
+ async function run() {
318
+ var pg = await services.requireService("postgres");
319
+ if (!pg.ok) throw new Error("postgres unreachable: " + pg.reason);
320
+
321
+ var DROP_ALL = [
322
+ "_blamejs_audit_log", "_blamejs_consent_log", "_blamejs_audit_checkpoints",
323
+ "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
324
+ "_blamejs_scheduler_ticks", "_blamejs_rate_limit_counters",
325
+ "_blamejs_pubsub_messages", "_blamejs_api_encrypt_nonces", "_blamejs_api_keys",
326
+ "_blamejs_sessions", "_blamejs_jobs", "_blamejs_cache", "_blamejs_cache_tags",
327
+ "_blamejs_seeders", "_blamejs_seeders_lock", "_blamejs_break_glass_policies",
328
+ "_blamejs_break_glass_grants", "_blamejs_leader", "_blamejs_cluster_state",
329
+ ].map(function (t) { return "DROP TABLE IF EXISTS " + t + " CASCADE;"; }).join("\n");
330
+ _psql(DROP_ALL);
331
+
332
+ b.cluster._resetForTest();
333
+ b.audit._resetForTest();
334
+ b.externalDb._resetForTest();
335
+
336
+ var driver = _makeDockerPgDriver();
337
+ b.externalDb.init({
338
+ backends: {
339
+ ops: {
340
+ connect: driver.connect, query: driver.query, close: driver.close,
341
+ dialect: "postgres",
342
+ },
343
+ },
344
+ });
345
+
346
+ // ---- 1. framework audit schema on the live server ----
347
+ var report = await b.frameworkSchema.ensureSchema({
348
+ externalDbBackend: "ops",
349
+ dialect: "postgres",
350
+ });
351
+ check("ensureSchema created _blamejs_audit_log on real Postgres",
352
+ report.tables.indexOf("_blamejs_audit_log") !== -1);
353
+ var tblCheck = _psql(
354
+ "SELECT count(*) AS n FROM information_schema.tables " +
355
+ "WHERE table_name = '_blamejs_audit_log';");
356
+ check("_blamejs_audit_log table is present on the server", /\b1\b/.test(tblCheck.trim()));
357
+
358
+ // ---- 2. build a KNOWN-VALID chain with the framework's own hash math,
359
+ // INSERT it into the live table, verify with the framework's
360
+ // own verifier (b.auditChain.verifyChain → the reader
361
+ // b.audit.verify uses). A correct framework returns ok:true. ----
362
+ var driverClient = await driver.connect();
363
+
364
+ var logicalRows = [
365
+ { action: "system.boot", outcome: "success" },
366
+ { action: "auth.login.success", outcome: "success", actorUserId: "u-1", actorIp: "10.0.0.7" },
367
+ { action: "consent.granted", outcome: "success", actorUserId: "u-2",
368
+ resourceKind: "purpose", resourceId: "marketing", metadata: '{"region":"eu"}' },
369
+ { action: "system.shutdown", outcome: "success" },
370
+ ];
371
+ var prevHash = b.auditChain.ZERO_HASH;
372
+ var insertErr = null;
373
+ try {
374
+ for (var i = 0; i < logicalRows.length; i++) {
375
+ var built = _buildChainRow(driverClient, driver, i + 1, prevHash, logicalRows[i]);
376
+ await _insertChainRow(driver, driverClient, built.rowForInsert);
377
+ prevHash = built.rowHash;
378
+ }
379
+ } catch (e) { insertErr = e; }
380
+
381
+ // The framework's chain-writer INSERT must land rows in the external
382
+ // Postgres table. ensureSchema created the columns UNQUOTED (Postgres
383
+ // folds them to lowercase: recordedat / monotoniccounter / rowhash …)
384
+ // while chain-writer INSERTs into safeSql.quoteIdentifier()-quoted,
385
+ // case-PRESERVING camelCase columns ("recordedAt" …). On real Postgres
386
+ // those names don't match → the append fails.
387
+ check("framework chain-writer INSERT lands audit rows on real Postgres " +
388
+ "(the columns it writes must exist on the ensureSchema-created table)",
389
+ insertErr === null);
390
+ if (insertErr) {
391
+ check("WRITE-PATH DETAIL: " + ((insertErr && insertErr.message) || String(insertErr)) +
392
+ " — ensureSchema DDL creates UNQUOTED (lowercase-folded) columns " +
393
+ "but chain-writer INSERTs safeSql.quoteIdentifier-quoted camelCase " +
394
+ 'columns ("recordedAt"…); the audit chain cannot be written to ' +
395
+ "the operator's external Postgres", false);
396
+ }
397
+
398
+ var countOnServer = _psql("SELECT count(*) AS n FROM _blamejs_audit_log;");
399
+ check("known-valid chain rows are physically in _blamejs_audit_log",
400
+ new RegExp("\\b" + logicalRows.length + "\\b").test(countOnServer.trim()));
401
+
402
+ // The verifier the framework ships: walk the live chain and recompute.
403
+ // queryAll routes through the SAME driver the framework's clusterStorage
404
+ // uses, so the row objects are keyed exactly as node-postgres keys them.
405
+ async function liveQueryAll(sql, params) {
406
+ var r = await driver.query(driverClient, sql, params || []);
407
+ return r.rows;
408
+ }
409
+ var v1 = await b.auditChain.verifyChain(liveQueryAll, "_blamejs_audit_log", {});
410
+ check("audit chain verifies ok:true on real Postgres " +
411
+ "(a valid chain stored on the operator's external DB must verify)",
412
+ v1.ok === true);
413
+ check("verifyChain walked every stored row (rowsVerified === " + logicalRows.length + ")",
414
+ v1.ok === true && v1.rowsVerified === logicalRows.length);
415
+ if (!v1.ok) {
416
+ check("FALSE-TAMPER DETAIL: verifyChain reports '" + v1.reason +
417
+ "' at row " + v1.breakAt + " on an UNTAMPERED chain — " +
418
+ "expected=" + String(v1.expected).slice(0, 20) +
419
+ "… actual=" + String(v1.actual).slice(0, 20) + "…", false);
420
+ }
421
+
422
+ // ---- 3. coercion fidelity: confirm the readback IS real-pg-shaped
423
+ // (lowercase keys, BIGINT→string, BYTEA→Buffer). This is the
424
+ // shape the framework's reader must handle. ----
425
+ var sample = (await liveQueryAll(
426
+ 'SELECT * FROM _blamejs_audit_log ORDER BY "monotonicCounter" ASC LIMIT 1', []))[0];
427
+ var keys = sample ? Object.keys(sample) : [];
428
+ check("readback row carries the chain columns (some hash + nonce key present)",
429
+ keys.length >= 18);
430
+ check("BYTEA nonce coerced to a Buffer (real-pg shape)",
431
+ sample && Buffer.isBuffer(sample.nonce));
432
+ // The framework reader expects camelCase (row.rowHash / row.monotonicCounter);
433
+ // these assertions document what real pg actually returns.
434
+ var hasCamelRowHash = sample && typeof sample.rowHash === "string";
435
+ var hasLowerRowHash = sample && typeof sample.rowhash === "string";
436
+ check("readback exposes rowHash under the key the framework reader uses " +
437
+ "(row.rowHash) — NOT only the Postgres-folded lowercase key",
438
+ hasCamelRowHash === true);
439
+ if (!hasCamelRowHash && hasLowerRowHash) {
440
+ check("CASE-FOLD DETAIL: Postgres returns the column as 'rowhash' " +
441
+ "(lowercase) but verifyChain reads row.rowHash → undefined; " +
442
+ "monotonicCounter is keyed 'monotoniccounter' as " +
443
+ (typeof sample.monotoniccounter) + " value " +
444
+ JSON.stringify(sample.monotoniccounter), false);
445
+ }
446
+
447
+ // ---- 4. tamper a hashed column → verify must report ok:false ----
448
+ // Drop the WORM triggers (simulate a privileged DB-write attacker) then
449
+ // mutate the action of the row at counter 2.
450
+ _psql([
451
+ "DROP TRIGGER IF EXISTS no_update__blamejs_audit_log ON _blamejs_audit_log;",
452
+ "DROP TRIGGER IF EXISTS no_delete__blamejs_audit_log ON _blamejs_audit_log;",
453
+ ].join("\n"));
454
+ _psql("UPDATE _blamejs_audit_log SET action = 'auth.login.tampered' " +
455
+ 'WHERE "monotonicCounter" = 2;');
456
+ var vTampered = await b.auditChain.verifyChain(liveQueryAll, "_blamejs_audit_log", {});
457
+ check("verifyChain returns ok:false after a hashed column is tampered",
458
+ vTampered.ok === false);
459
+ // The tamper detection is only MEANINGFUL if verify passed on the clean
460
+ // chain (else ok:false is a false positive that happens to coincide).
461
+ check("tamper detection is meaningful (clean chain had verified ok:true)",
462
+ v1.ok === true && vTampered.ok === false);
463
+
464
+ // ---- 5. cluster leadership over the real Postgres lease provider ----
465
+ // Every chain append in cluster mode passes cluster.requireLeader().
466
+ // Confirm a single node can actually acquire leadership on real Postgres.
467
+ _psql(["DROP TABLE IF EXISTS _blamejs_leader CASCADE;",
468
+ "DROP TABLE IF EXISTS _blamejs_cluster_state CASCADE;"].join("\n"));
469
+ var clusterErr = null;
470
+ try {
471
+ await b.cluster.init({
472
+ nodeId: "audit-ext-node",
473
+ role: "leader",
474
+ externalDbBackend: "ops",
475
+ dialect: "postgres",
476
+ });
477
+ } catch (e) { clusterErr = e; }
478
+ check("cluster.init completed without throwing on real Postgres",
479
+ clusterErr === null);
480
+ check("cluster node acquired leadership on real Postgres " +
481
+ "(required for EVERY audit-chain append in cluster mode)",
482
+ clusterErr === null && b.cluster.isLeader() === true);
483
+ if (clusterErr === null && b.cluster.isLeader() !== true) {
484
+ var leaderRow = _psql(
485
+ 'SELECT "nodeId", "expiresAt" FROM _blamejs_leader WHERE scope=\'leader\';');
486
+ check("LEADERSHIP DETAIL: a leader row WAS written to the server [" +
487
+ leaderRow.trim() + "] but acquireLease returned no in-memory " +
488
+ "lease (provider read row.expiresAt/row.nodeId but the live " +
489
+ "row keys are lowercase expiresat/nodeid) → isLeader()=false → " +
490
+ "every audit append would throw NotLeaderError", false);
491
+ }
492
+
493
+ // ---- MySQL audit-chain coverage ----
494
+ // MySQL is a first-class audit-chain backend: the framework-schema
495
+ // reconciler emits MySQL DDL and the hash chain appends and verifies
496
+ // against it. The end-to-end proof (ensureSchema + audit.record →
497
+ // chain-writer._insertRow + audit.verify ok:true against a real MySQL
498
+ // server) lives in audit-stack-mysql.test.js. This Postgres-focused file
499
+ // does not re-probe MySQL through the Postgres "ops" connection.
500
+
501
+ // ---- teardown ----
502
+ try { await driver.close(driverClient); } catch (_e) {}
503
+ try { await b.cluster.shutdown(); } catch (_e) {}
504
+ await b.externalDb.shutdown();
505
+ b.cluster._resetForTest();
506
+ b.audit._resetForTest();
507
+ _psql(DROP_ALL);
508
+ }
509
+
510
+ module.exports = { run: run };
511
+
512
+ if (require.main === module) {
513
+ run().then(
514
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
515
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
516
+ );
517
+ }