@blamejs/blamejs-shop 0.4.31 → 0.4.33

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 (343) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/vendor/MANIFEST.json +400 -282
  5. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  6. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  7. package/lib/vendor/blamejs/.gitignore +6 -0
  8. package/lib/vendor/blamejs/CHANGELOG.md +28 -0
  9. package/lib/vendor/blamejs/MIGRATING.md +55 -0
  10. package/lib/vendor/blamejs/README.md +8 -6
  11. package/lib/vendor/blamejs/SECURITY.md +19 -3
  12. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  13. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  14. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  15. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  16. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  17. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  18. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  19. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  20. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  21. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  24. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  25. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  26. package/lib/vendor/blamejs/index.js +4 -0
  27. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  28. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  29. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  30. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  31. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  32. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  33. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  34. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  35. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  36. package/lib/vendor/blamejs/lib/audit.js +259 -123
  37. package/lib/vendor/blamejs/lib/auth/elevation-grant.js +6 -2
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +66 -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 +36 -7
  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 +210 -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/credential-hash.js +9 -0
  55. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  56. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  57. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  58. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  59. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  60. package/lib/vendor/blamejs/lib/db.js +249 -99
  61. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  62. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  63. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  64. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  65. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  66. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  67. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  68. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  69. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  70. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  71. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  72. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  73. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  74. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  75. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  76. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  77. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  78. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  79. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  80. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  81. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  82. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  83. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  84. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  85. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  86. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  87. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  88. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  89. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  90. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  91. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  92. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  93. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  94. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  95. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  96. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  98. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  99. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  100. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  101. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  102. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  105. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  106. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  107. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  108. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  109. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  110. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  111. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  112. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  113. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  114. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  115. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  116. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  117. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  118. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  119. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  120. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  121. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  122. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  123. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  124. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  125. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  126. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  128. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  129. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  131. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  132. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  134. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  136. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  137. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  138. package/lib/vendor/blamejs/lib/mail.js +8 -4
  139. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  140. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  141. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  142. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  143. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  144. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  145. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  146. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  147. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  148. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  149. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  151. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  152. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  153. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  154. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  155. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  156. package/lib/vendor/blamejs/lib/observability.js +124 -0
  157. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  158. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  159. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  160. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  161. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  162. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  163. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  164. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  165. package/lib/vendor/blamejs/lib/queue.js +7 -0
  166. package/lib/vendor/blamejs/lib/redact.js +68 -11
  167. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  168. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  169. package/lib/vendor/blamejs/lib/retention.js +117 -42
  170. package/lib/vendor/blamejs/lib/router.js +212 -5
  171. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  172. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  173. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  174. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  175. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  176. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  177. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  178. package/lib/vendor/blamejs/lib/scheduler.js +47 -12
  179. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  180. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  181. package/lib/vendor/blamejs/lib/session.js +175 -77
  182. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  183. package/lib/vendor/blamejs/lib/sse.js +26 -0
  184. package/lib/vendor/blamejs/lib/ssrf-guard.js +169 -4
  185. package/lib/vendor/blamejs/lib/static.js +177 -34
  186. package/lib/vendor/blamejs/lib/subject.js +96 -49
  187. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  189. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  190. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  191. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  192. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  193. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  194. package/lib/vendor/blamejs/package.json +2 -2
  195. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  202. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  203. package/lib/vendor/blamejs/release-notes/v0.15.7.json +43 -0
  204. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  205. package/lib/vendor/blamejs/scripts/gen-migrating.js +67 -0
  206. package/lib/vendor/blamejs/scripts/release.js +398 -38
  207. package/lib/vendor/blamejs/test/00-primitives.js +168 -0
  208. package/lib/vendor/blamejs/test/10-state.js +140 -14
  209. package/lib/vendor/blamejs/test/20-db.js +65 -2
  210. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  211. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  212. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  213. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  214. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  215. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  216. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  217. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  222. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  223. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  224. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  225. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  226. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  227. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  228. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  229. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  230. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  231. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  232. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  233. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  234. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  235. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  236. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  237. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  238. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  239. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  240. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  242. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  251. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  252. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1196 -14
  253. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +18 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  259. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  267. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  275. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  276. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  277. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  278. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  282. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  283. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  286. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  287. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  288. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  296. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +59 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +362 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-watchdog-stale-settle.test.js +71 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  309. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  315. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  317. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  318. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  319. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  320. package/lib/vendor/blamejs/test/smoke.js +79 -21
  321. package/package.json +2 -2
  322. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  323. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  324. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  325. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  326. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  327. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  328. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  329. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  330. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  331. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  332. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  333. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  335. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  336. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  337. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  338. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  339. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  340. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  341. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  342. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  343. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -0,0 +1,429 @@
1
+ "use strict";
2
+ /**
3
+ * b.auth.passkey — REAL WebAuthn signature verification.
4
+ *
5
+ * The companion suite (passkey.test.js) stubs the vendored verifier via a
6
+ * require-cache override, so the actual attestation / assertion signature
7
+ * verification never executes there — a forged-assertion-accepted
8
+ * regression would pass that suite green. This suite closes that gap: it
9
+ * drives verifyRegistration + verifyAuthentication through the vendored
10
+ * verifier UNTOUCHED, with genuine WebAuthn material produced by a
11
+ * software authenticator built on Node's crypto.
12
+ *
13
+ * The software authenticator mints a real EC P-256 keypair, builds a
14
+ * spec-shaped attestationObject ("none" fmt) + authenticatorData +
15
+ * clientDataJSON, and signs `authenticatorData || SHA-256(clientDataJSON)`
16
+ * with ECDSA/SHA-256 in DER form exactly as a hardware authenticator
17
+ * does. The vendor's real ECDSA path (DER unwrap to raw r||s, COSE key
18
+ * decode, WebCrypto subtle.verify) runs against this material.
19
+ *
20
+ * Load-bearing assertions: a genuine attestation/assertion VERIFIES, and
21
+ * every tamper — flipped signature byte, wrong challenge, wrong origin,
22
+ * wrong RP ID, mutated authenticatorData, a different signing key against
23
+ * the victim's stored public key — is REJECTED (either verified:false or
24
+ * a thrown binding error). The forged-key + tampered-signature cases are
25
+ * the phishing-resistance proof: they only hold if the cryptographic
26
+ * verification actually ran.
27
+ */
28
+
29
+ var crypto = require("crypto");
30
+ var helpers = require("../helpers");
31
+ var b = helpers.b;
32
+ var check = helpers.check;
33
+
34
+ var passkey = b.auth.passkey;
35
+
36
+ var RP_ID = "example.test";
37
+ var ORIGIN = "https://example.test";
38
+
39
+ // ---- byte helpers ----
40
+
41
+ function b64url(buf) { return Buffer.from(buf).toString("base64url"); }
42
+ function sha256(buf) { return crypto.createHash("sha256").update(buf).digest(); }
43
+
44
+ // ---- minimal deterministic CBOR encoder (ints / neg-ints / bytes / text
45
+ // / maps) — only the subset COSE keys + the "none" attestationObject need.
46
+ // Not a general CBOR library; just enough to feed the real verifier.
47
+
48
+ function cborHead(major, n) {
49
+ if (n < 24) return Buffer.from([(major << 5) | n]);
50
+ if (n < 256) return Buffer.from([(major << 5) | 24, n]);
51
+ if (n < 65536) return Buffer.from([(major << 5) | 25, (n >> 8) & 0xff, n & 0xff]);
52
+ return Buffer.from([(major << 5) | 26,
53
+ (n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff]);
54
+ }
55
+ function cborInt(n) { return n >= 0 ? cborHead(0, n) : cborHead(1, -n - 1); }
56
+ function cborBytes(buf){ return Buffer.concat([cborHead(2, buf.length), buf]); }
57
+ function cborText(s) { var bb = Buffer.from(s, "utf8"); return Buffer.concat([cborHead(3, bb.length), bb]); }
58
+ function cborMap(pairs){
59
+ var parts = [cborHead(5, pairs.length)];
60
+ for (var i = 0; i < pairs.length; i++) { parts.push(pairs[i][0], pairs[i][1]); }
61
+ return Buffer.concat(parts);
62
+ }
63
+
64
+ // COSE_Key for an EC2 P-256 / ES256 public key, derived from the real
65
+ // JWK export of the Node KeyObject. { 1:2, 3:-7, -1:1, -2:x, -3:y }.
66
+ function coseEC2PublicKey(publicKey) {
67
+ var jwk = publicKey.export({ format: "jwk" });
68
+ var x = Buffer.from(jwk.x, "base64url");
69
+ var y = Buffer.from(jwk.y, "base64url");
70
+ return cborMap([
71
+ [cborInt(1), cborInt(2)], // kty: EC2
72
+ [cborInt(3), cborInt(-7)], // alg: ES256
73
+ [cborInt(-1), cborInt(1)], // crv: P-256
74
+ [cborInt(-2), cborBytes(x)], // x
75
+ [cborInt(-3), cborBytes(y)], // y
76
+ ]);
77
+ }
78
+
79
+ // authenticatorData = rpIdHash(32) || flags(1) || signCount(4) [|| attestedCredentialData]
80
+ function buildAuthData(rpId, flags, signCount, attestedCredData) {
81
+ var rpIdHash = sha256(Buffer.from(rpId, "utf8"));
82
+ var f = Buffer.from([flags & 0xff]);
83
+ var c = Buffer.alloc(4); c.writeUInt32BE(signCount >>> 0, 0);
84
+ return attestedCredData
85
+ ? Buffer.concat([rpIdHash, f, c, attestedCredData])
86
+ : Buffer.concat([rpIdHash, f, c]);
87
+ }
88
+
89
+ // attestedCredentialData = aaguid(16) || credIdLen(2) || credId || COSE pubkey
90
+ function buildAttestedCredData(aaguid, credId, cosePub) {
91
+ var len = Buffer.alloc(2); len.writeUInt16BE(credId.length, 0);
92
+ return Buffer.concat([aaguid, len, credId, cosePub]);
93
+ }
94
+
95
+ // ECDSA/SHA-256 over `data`, DER-encoded — the wire shape a real
96
+ // WebAuthn authenticator emits (the vendor unwraps DER to raw r||s).
97
+ function signDER(privateKey, data) {
98
+ return crypto.sign("sha256", data, { key: privateKey, dsaEncoding: "der" });
99
+ }
100
+
101
+ // authData flag bits: UP 0x01, UV 0x04, AT 0x40.
102
+ var FLAG_UP = 0x01, FLAG_UV = 0x04, FLAG_AT = 0x40;
103
+
104
+ // Build a fresh genuine credential + its registration response bound to a
105
+ // given challenge. Returns the keypair, credId, COSE pubkey, and the
106
+ // PublicKeyCredential-shaped registration response.
107
+ function makeRegistration(challenge) {
108
+ var kp = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
109
+ var cose = coseEC2PublicKey(kp.publicKey);
110
+ var credId = crypto.randomBytes(32);
111
+ var aaguid = Buffer.alloc(16, 0);
112
+
113
+ var authData = buildAuthData(RP_ID, FLAG_UP | FLAG_UV | FLAG_AT, 0,
114
+ buildAttestedCredData(aaguid, credId, cose));
115
+ var attObj = cborMap([
116
+ [cborText("fmt"), cborText("none")],
117
+ [cborText("attStmt"), cborMap([])],
118
+ [cborText("authData"), cborBytes(authData)],
119
+ ]);
120
+ var clientData = Buffer.from(JSON.stringify({
121
+ type: "webauthn.create", challenge: challenge, origin: ORIGIN, crossOrigin: false,
122
+ }), "utf8");
123
+
124
+ return {
125
+ keyPair: kp,
126
+ credId: credId,
127
+ response: {
128
+ id: b64url(credId),
129
+ rawId: b64url(credId),
130
+ type: "public-key",
131
+ response: {
132
+ clientDataJSON: b64url(clientData),
133
+ attestationObject: b64url(attObj),
134
+ },
135
+ clientExtensionResults: {},
136
+ },
137
+ };
138
+ }
139
+
140
+ // Build a genuine authentication assertion for a stored credential, signed
141
+ // by `signingKey` (which is the real key for the genuine case, or an
142
+ // attacker key for the forged case). signCount controls counter advance.
143
+ function makeAssertion(signingKey, credId, challenge, signCount) {
144
+ var authData = buildAuthData(RP_ID, FLAG_UP | FLAG_UV, signCount, null);
145
+ var clientData = Buffer.from(JSON.stringify({
146
+ type: "webauthn.get", challenge: challenge, origin: ORIGIN, crossOrigin: false,
147
+ }), "utf8");
148
+ var signed = Buffer.concat([authData, sha256(clientData)]);
149
+ var sig = signDER(signingKey, signed);
150
+ return {
151
+ authData: authData,
152
+ clientData: clientData,
153
+ signed: signed,
154
+ sig: sig,
155
+ response: {
156
+ id: b64url(credId),
157
+ rawId: b64url(credId),
158
+ type: "public-key",
159
+ response: {
160
+ clientDataJSON: b64url(clientData),
161
+ authenticatorData: b64url(authData),
162
+ signature: b64url(sig),
163
+ },
164
+ clientExtensionResults: {},
165
+ },
166
+ };
167
+ }
168
+
169
+ // Read the stored public key off a registration result across
170
+ // vendor-version field shapes (credential.publicKey | credentialPublicKey).
171
+ function storedPublicKey(regResult) {
172
+ var ri = (regResult && regResult.registrationInfo) || {};
173
+ if (ri.credential && ri.credential.publicKey) return ri.credential.publicKey;
174
+ return ri.credentialPublicKey;
175
+ }
176
+
177
+ // Verify and normalize the outcome to { ok, threw, code }. The verifier
178
+ // rejects either by returning verified:false OR by throwing a binding
179
+ // error (wrong challenge / origin / RP ID); both are "rejected".
180
+ async function authOutcome(args) {
181
+ try {
182
+ var rv = await passkey.verifyAuthentication(args);
183
+ return { ok: rv && rv.verified === true, threw: false, rv: rv };
184
+ } catch (e) {
185
+ return { ok: false, threw: true, code: e.code || e.message };
186
+ }
187
+ }
188
+ async function regOutcome(args) {
189
+ try {
190
+ var rv = await passkey.verifyRegistration(args);
191
+ return { ok: rv && rv.verified === true, threw: false, rv: rv };
192
+ } catch (e) {
193
+ return { ok: false, threw: true, code: e.code || e.message };
194
+ }
195
+ }
196
+
197
+ // ---- Registration: genuine attestation verifies; tampers rejected ----
198
+
199
+ async function testRegistrationGenuineAndTampered() {
200
+ // Mint the challenge through the real generateRegistrationOptions path.
201
+ var regOpts = await passkey.startRegistration({ rpName: "Example", rpId: RP_ID, userName: "alice" });
202
+ var challenge = regOpts.challenge;
203
+ check("startRegistration returns a base64url challenge",
204
+ typeof challenge === "string" && helpers.b.safeBuffer.BASE64URL_RE.test(challenge));
205
+
206
+ var reg = makeRegistration(challenge);
207
+
208
+ // Genuine attestation — the real verifier must accept it.
209
+ var good = await regOutcome({
210
+ response: reg.response,
211
+ expectedChallenge: challenge,
212
+ expectedOrigin: ORIGIN,
213
+ expectedRPID: RP_ID,
214
+ });
215
+ check("genuine registration verifies (real attestation path)", good.ok === true);
216
+ var pub = storedPublicKey(good.rv);
217
+ check("registration surfaces a COSE public key to persist",
218
+ Buffer.isBuffer(pub) || pub instanceof Uint8Array);
219
+ check("registration BE/BS flags map (single-device, not backed up)",
220
+ good.rv.backupEligible === false && good.rv.backupState === false);
221
+
222
+ // Wrong expected challenge — clientDataJSON's challenge no longer matches.
223
+ var badChallenge = await regOutcome({
224
+ response: reg.response,
225
+ expectedChallenge: b64url(crypto.randomBytes(32)),
226
+ expectedOrigin: ORIGIN,
227
+ expectedRPID: RP_ID,
228
+ });
229
+ check("registration with wrong expectedChallenge is rejected", badChallenge.ok === false);
230
+
231
+ // Wrong expected origin.
232
+ var badOrigin = await regOutcome({
233
+ response: reg.response,
234
+ expectedChallenge: challenge,
235
+ expectedOrigin: "https://evil.test",
236
+ expectedRPID: RP_ID,
237
+ });
238
+ check("registration with wrong expectedOrigin is rejected", badOrigin.ok === false);
239
+
240
+ // Wrong expected RP ID — the rpIdHash inside authData won't match.
241
+ var badRpId = await regOutcome({
242
+ response: reg.response,
243
+ expectedChallenge: challenge,
244
+ expectedOrigin: ORIGIN,
245
+ expectedRPID: "evil.test",
246
+ });
247
+ check("registration with wrong expectedRPID is rejected", badRpId.ok === false);
248
+
249
+ // Substituted clientDataJSON challenge — re-encode the client data with
250
+ // a different challenge than the server expects. The verifier compares
251
+ // the challenge embedded in clientDataJSON against expectedChallenge, so
252
+ // a credential captured for one ceremony can't be replayed into another.
253
+ // (fmt:"none" carries no attestation signature, so attestationObject-byte
254
+ // integrity is out of scope by spec — clientData binding is what guards
255
+ // the registration ceremony.)
256
+ var swapped = JSON.parse(JSON.stringify(reg.response));
257
+ var otherChallenge = b64url(crypto.randomBytes(32));
258
+ swapped.response.clientDataJSON = b64url(Buffer.from(JSON.stringify({
259
+ type: "webauthn.create", challenge: otherChallenge, origin: ORIGIN, crossOrigin: false,
260
+ }), "utf8"));
261
+ var badClientData = await regOutcome({
262
+ response: swapped,
263
+ expectedChallenge: challenge, // server still expects the original
264
+ expectedOrigin: ORIGIN,
265
+ expectedRPID: RP_ID,
266
+ });
267
+ check("registration with a substituted clientDataJSON challenge is rejected",
268
+ badClientData.ok === false);
269
+ }
270
+
271
+ // ---- Authentication: genuine assertion verifies; tampers rejected ----
272
+
273
+ async function testAuthenticationGenuineAndTampered() {
274
+ // Register a real credential first so we have a genuine stored pubkey.
275
+ var regOpts = await passkey.startRegistration({ rpName: "Example", rpId: RP_ID, userName: "bob" });
276
+ var reg = makeRegistration(regOpts.challenge);
277
+ var regRes = await regOutcome({
278
+ response: reg.response,
279
+ expectedChallenge: regOpts.challenge,
280
+ expectedOrigin: ORIGIN,
281
+ expectedRPID: RP_ID,
282
+ });
283
+ check("setup: credential registers", regRes.ok === true);
284
+ var storedPub = storedPublicKey(regRes.rv);
285
+
286
+ // Mint an authentication challenge via the real options path.
287
+ var authOpts = await passkey.startAuthentication({ rpId: RP_ID });
288
+ var challenge = authOpts.challenge;
289
+
290
+ var credential = function () {
291
+ return { id: b64url(reg.credId), publicKey: storedPub, counter: 0 };
292
+ };
293
+
294
+ // Genuine assertion signed with the real private key — must verify, and
295
+ // the signature counter must advance (clone-detection material).
296
+ var assertion = makeAssertion(reg.keyPair.privateKey, reg.credId, challenge, 7);
297
+ var good = await authOutcome({
298
+ response: assertion.response,
299
+ expectedChallenge: challenge,
300
+ expectedOrigin: ORIGIN,
301
+ expectedRPID: RP_ID,
302
+ credential: credential(),
303
+ });
304
+ check("genuine assertion verifies (real ECDSA signature path)", good.ok === true);
305
+ check("genuine assertion advances the signature counter",
306
+ good.rv.authenticationInfo && good.rv.authenticationInfo.newCounter === 7);
307
+
308
+ // --- THE LOAD-BEARING TAMPER CASES ---
309
+
310
+ // 1. Flipped signature byte — the cryptographic core must reject it.
311
+ var flipped = JSON.parse(JSON.stringify(assertion.response));
312
+ var sigBuf = Buffer.from(flipped.response.signature, "base64url");
313
+ sigBuf[sigBuf.length - 1] ^= 0x01;
314
+ flipped.response.signature = b64url(sigBuf);
315
+ var t1 = await authOutcome({
316
+ response: flipped,
317
+ expectedChallenge: challenge,
318
+ expectedOrigin: ORIGIN,
319
+ expectedRPID: RP_ID,
320
+ credential: credential(),
321
+ });
322
+ check("tampered signature (1 byte flipped) is REJECTED", t1.ok === false);
323
+ check("tampered signature rejection comes from verification, not a throw",
324
+ t1.threw === false && t1.rv.verified === false);
325
+
326
+ // 2. Wrong expected challenge — replay/binding defense.
327
+ var t2 = await authOutcome({
328
+ response: assertion.response,
329
+ expectedChallenge: b64url(crypto.randomBytes(32)),
330
+ expectedOrigin: ORIGIN,
331
+ expectedRPID: RP_ID,
332
+ credential: credential(),
333
+ });
334
+ check("assertion with wrong expectedChallenge is REJECTED", t2.ok === false);
335
+
336
+ // 3. Wrong expected origin — phishing-resistance binding.
337
+ var t3 = await authOutcome({
338
+ response: assertion.response,
339
+ expectedChallenge: challenge,
340
+ expectedOrigin: "https://evil.test",
341
+ expectedRPID: RP_ID,
342
+ credential: credential(),
343
+ });
344
+ check("assertion with wrong expectedOrigin is REJECTED (phishing-resistance)", t3.ok === false);
345
+
346
+ // 4. Wrong expected RP ID — rpIdHash binding.
347
+ var t4 = await authOutcome({
348
+ response: assertion.response,
349
+ expectedChallenge: challenge,
350
+ expectedOrigin: ORIGIN,
351
+ expectedRPID: "evil.test",
352
+ credential: credential(),
353
+ });
354
+ check("assertion with wrong expectedRPID is REJECTED", t4.ok === false);
355
+
356
+ // 5. Mutated authenticatorData — the signature covers authData, so a
357
+ // flipped counter byte must break verification.
358
+ var mutAd = JSON.parse(JSON.stringify(assertion.response));
359
+ var adBuf = Buffer.from(mutAd.response.authenticatorData, "base64url");
360
+ adBuf[adBuf.length - 1] ^= 0xff;
361
+ mutAd.response.authenticatorData = b64url(adBuf);
362
+ var t5 = await authOutcome({
363
+ response: mutAd,
364
+ expectedChallenge: challenge,
365
+ expectedOrigin: ORIGIN,
366
+ expectedRPID: RP_ID,
367
+ credential: credential(),
368
+ });
369
+ check("assertion with mutated authenticatorData is REJECTED", t5.ok === false);
370
+
371
+ // 6. FORGED KEY — an attacker signs with their own private key but
372
+ // presents the victim's stored public key. Only a real signature
373
+ // check rejects this; a stubbed verifier would accept it.
374
+ var attacker = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
375
+ var forged = makeAssertion(attacker.privateKey, reg.credId, challenge, 7);
376
+ var t6 = await authOutcome({
377
+ response: forged.response,
378
+ expectedChallenge: challenge,
379
+ expectedOrigin: ORIGIN,
380
+ expectedRPID: RP_ID,
381
+ credential: credential(),
382
+ });
383
+ check("FORGED assertion (attacker key vs victim pubkey) is REJECTED", t6.ok === false);
384
+ check("forged-key rejection comes from signature verification, not a throw",
385
+ t6.threw === false && t6.rv.verified === false);
386
+
387
+ // 7. Sanity: the same forged assertion, verified against the ATTACKER's
388
+ // own public key, DOES verify — proving the forged case above fails
389
+ // specifically because the key doesn't match, not for an unrelated
390
+ // reason (the test is exercising the real verification, not a no-op).
391
+ var attackerCose = coseEC2PublicKey(attacker.publicKey);
392
+ var attackerReg = makeRegistration(regOpts.challenge);
393
+ // build a stored-pubkey for the attacker by registering it
394
+ var attReg = await regOutcome({
395
+ response: attackerReg.response,
396
+ expectedChallenge: regOpts.challenge,
397
+ expectedOrigin: ORIGIN,
398
+ expectedRPID: RP_ID,
399
+ });
400
+ // Re-sign with the attacker's actual registered key for an apples-to-apples check.
401
+ var attChallengeOpts = await passkey.startAuthentication({ rpId: RP_ID });
402
+ var attAssertion = makeAssertion(attackerReg.keyPair.privateKey, attackerReg.credId,
403
+ attChallengeOpts.challenge, 3);
404
+ var attGood = await authOutcome({
405
+ response: attAssertion.response,
406
+ expectedChallenge: attChallengeOpts.challenge,
407
+ expectedOrigin: ORIGIN,
408
+ expectedRPID: RP_ID,
409
+ credential: { id: b64url(attackerReg.credId), publicKey: storedPublicKey(attReg.rv), counter: 0 },
410
+ });
411
+ check("control: a genuine assertion under its OWN key verifies (proves the verifier isn't a no-op)",
412
+ attGood.ok === true);
413
+ // Reference the encoded attacker COSE key so lint sees it consumed.
414
+ check("attacker COSE key encodes to bytes", Buffer.isBuffer(attackerCose) && attackerCose.length > 0);
415
+ }
416
+
417
+ // ---- run ----
418
+
419
+ async function run() {
420
+ await testRegistrationGenuineAndTampered();
421
+ await testAuthenticationGenuineAndTampered();
422
+ }
423
+
424
+ module.exports = { run: run };
425
+
426
+ if (require.main === module) {
427
+ run().then(function () { console.log("OK", helpers.getChecks(), "checks"); })
428
+ .catch(function (e) { console.error(e.stack || e); process.exit(1); });
429
+ }
@@ -2,11 +2,11 @@
2
2
  /**
3
3
  * b.pqcAgent — ecdhCurve negotiation surface.
4
4
  *
5
- * Covers the framework-default PQC-hybrid preference (now a 3-entry
6
- * list including SecP256r1MLKEM768), the narrowing path (subset of
7
- * the default), and the operator-supplied-group escape hatch
8
- * (allowOperatorGroups: true) including the audit emit on accepted
9
- * non-default groups.
5
+ * Covers the framework-default outbound group preference (the three
6
+ * ML-KEM hybrids plus the trailing classical X25519 fallback for peers
7
+ * that support no hybrid), the narrowing path (subset of the default),
8
+ * and the operator-supplied-group escape hatch (allowOperatorGroups:
9
+ * true) including the audit emit on accepted non-default groups.
10
10
  *
11
11
  * Run standalone: `node test/layer-0-primitives/pqc-agent-curve.test.js`
12
12
  * Or via smoke: `node test/smoke.js`
@@ -35,6 +35,11 @@ async function testDefaultGroupList() {
35
35
  check("default ecdhCurve preserves preference order",
36
36
  ec.indexOf("SecP384r1MLKEM1024") < ec.indexOf("X25519MLKEM768") &&
37
37
  ec.indexOf("X25519MLKEM768") < ec.indexOf("SecP256r1MLKEM768"));
38
+ // The classical X25519 fallback is the LAST group — hybrids are always
39
+ // preferred; classical is only negotiated when the peer offers no hybrid.
40
+ var groups = ec.split(":");
41
+ check("default ecdhCurve ends with the classical X25519 fallback",
42
+ groups[groups.length - 1] === "X25519");
38
43
  agent.destroy();
39
44
  }
40
45
 
@@ -55,7 +60,10 @@ function testNarrowToFrameworkSubset() {
55
60
  function testRefuseUnknownGroupByDefault() {
56
61
  var threw = false;
57
62
  try {
58
- b.pqcAgent.create({ ecdhCurve: "X25519" });
63
+ // secp256r1 (classical P-256) is a KNOWN_TLS_GROUPS entry but NOT in the
64
+ // framework outbound preference (the hybrids + the X25519 fallback), so
65
+ // it's refused without allowOperatorGroups.
66
+ b.pqcAgent.create({ ecdhCurve: "secp256r1" });
59
67
  } catch (e) {
60
68
  threw = e instanceof TypeError &&
61
69
  e.message.indexOf("not in the framework PQC-hybrid") !== -1 &&
@@ -86,12 +94,14 @@ async function testAllowOperatorGroupsAuditEmit() {
86
94
  var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-pqcagent-"));
87
95
  try {
88
96
  await setupTestDb(tmpDir);
97
+ // secp256r1 (classical P-256) is outside the framework preference, so it
98
+ // exercises the operator-group escape hatch + the acceptance audit.
89
99
  var agent = b.pqcAgent.create({
90
- ecdhCurve: "X25519",
100
+ ecdhCurve: "secp256r1",
91
101
  allowOperatorGroups: true,
92
102
  });
93
- check("X25519 accepted under allowOperatorGroups",
94
- agent.options.ecdhCurve === "X25519");
103
+ check("secp256r1 accepted under allowOperatorGroups",
104
+ agent.options.ecdhCurve === "secp256r1");
95
105
  agent.destroy();
96
106
 
97
107
  await b.audit.flush();
@@ -99,8 +109,8 @@ async function testAllowOperatorGroupsAuditEmit() {
99
109
  check("audit row written for operator-group acceptance", rows.length >= 1);
100
110
  var meta = typeof rows[0].metadata === "string"
101
111
  ? JSON.parse(rows[0].metadata) : rows[0].metadata;
102
- check("audit metadata carries group=X25519", meta.group === "X25519");
103
- check("audit metadata carries ecdhCurve", meta.ecdhCurve === "X25519");
112
+ check("audit metadata carries group=secp256r1", meta.group === "secp256r1");
113
+ check("audit metadata carries ecdhCurve", meta.ecdhCurve === "secp256r1");
104
114
  } finally {
105
115
  await teardownTestDb(tmpDir);
106
116
  }
@@ -292,6 +292,45 @@ async function testFlowSecondPassTargetsCustomTable() {
292
292
  }
293
293
  }
294
294
 
295
+ // ---- Self-registration: seal at rest without db.init ----
296
+
297
+ // A standalone redis/sqs queue node may never run db.init in-process, so
298
+ // the _blamejs_jobs sealed-column declaration would be absent and
299
+ // cryptoField.sealRow would silently pass the payload through in cleartext.
300
+ // queue.init must self-register the seal table so payloads seal regardless.
301
+ async function testSealRegistersWithoutDbInit() {
302
+ var tmpDir = _tmp();
303
+ await setupTestDb(tmpDir);
304
+ try {
305
+ // Simulate a process where db.init never registered _blamejs_jobs with
306
+ // cryptoField — clear the registry, then confirm it is genuinely gone.
307
+ b.cryptoField.clearForTest();
308
+ check("self-register precondition: _blamejs_jobs schema cleared",
309
+ b.cryptoField.getSchema("_blamejs_jobs") === null);
310
+
311
+ // queue.init must self-register the seal table.
312
+ b.queue.init({ backends: { primary: { protocol: "local" } } });
313
+ check("self-register: queue.init re-registered _blamejs_jobs seal map",
314
+ b.cryptoField.getSchema("_blamejs_jobs") !== null);
315
+
316
+ await b.queue.enqueue("seal-q", { secret: "ssn-7777", token: "bearer-abc" });
317
+
318
+ // Read the RAW payload column. b.db.from("_blamejs_jobs") would auto-
319
+ // UNSEAL (it's a registered table), masking the at-rest state — so use
320
+ // a raw prepared SELECT to inspect the bytes actually on disk.
321
+ var raw = b.db.prepare("SELECT payload FROM _blamejs_jobs WHERE queueName = ?").all("seal-q");
322
+ check("self-register: a row exists", raw.length === 1);
323
+ var stored = String(raw[0].payload || "");
324
+ check("self-register: payload sealed at rest (no plaintext secret)",
325
+ stored.length > 0 && stored.indexOf("ssn-7777") === -1 && stored.indexOf("bearer-abc") === -1);
326
+ check("self-register: payload carries the vault seal prefix",
327
+ stored.indexOf("vault:") === 0);
328
+ } finally {
329
+ try { await b.queue.shutdown({ timeoutMs: 500 }); } catch (_e) {}
330
+ await teardownTestDb(tmpDir);
331
+ }
332
+ }
333
+
295
334
  async function run() {
296
335
  await testDefaultConfigUsesFrameworkJobsTable();
297
336
  await testCustomTableRoutesRowsThere();
@@ -300,6 +339,7 @@ async function run() {
300
339
  await testSchemaQualifierIsQuoted();
301
340
  await testRejectsUnsafeTableAndSchemaAndHandle();
302
341
  await testFlowSecondPassTargetsCustomTable();
342
+ await testSealRegistersWithoutDbInit();
303
343
  }
304
344
 
305
345
  module.exports = { run: run };
@@ -219,6 +219,85 @@ async function testIdempotentInstall() {
219
219
  h1.uninstall();
220
220
  }
221
221
 
222
+ // Bug A — installForPosture is NOT auto-called by b.compliance.set; the
223
+ // install tracking + the boot warning replace the false advertisement.
224
+ function testIsOutboundDlpInstalledSurface() {
225
+ b.redact._resetForTest();
226
+ check("b.redact.isOutboundDlpInstalled is a function",
227
+ typeof b.redact.isOutboundDlpInstalled === "function");
228
+ check("isOutboundDlpInstalled false before any install",
229
+ b.redact.isOutboundDlpInstalled() === false);
230
+ var http = _fakeHttpClient();
231
+ var dlp = b.redact.installForPosture("hipaa", { httpClient: http });
232
+ check("isOutboundDlpInstalled true after installForPosture",
233
+ b.redact.isOutboundDlpInstalled() === true);
234
+ dlp.uninstall();
235
+ check("isOutboundDlpInstalled false after uninstall",
236
+ b.redact.isOutboundDlpInstalled() === false);
237
+ }
238
+
239
+ function testComplianceSetWarnsWhenDlpUnwired() {
240
+ b.compliance._resetForTest();
241
+ b.redact._resetForTest();
242
+ var captured = [];
243
+ var origAudit = b.audit.safeEmit;
244
+ b.audit.safeEmit = function (e) { captured.push(e); };
245
+ try {
246
+ b.compliance.set("hipaa");
247
+ } finally {
248
+ b.audit.safeEmit = origAudit;
249
+ }
250
+ var warns = captured.filter(function (e) {
251
+ return e.action === "compliance.posture.outbound_dlp_unwired";
252
+ });
253
+ check("compliance.set('hipaa') warns when no outbound DLP wired",
254
+ warns.length === 1 && warns[0].outcome === "warning" && warns[0].metadata.posture === "hipaa");
255
+ b.compliance._resetForTest();
256
+ }
257
+
258
+ function testComplianceSetNoWarnWhenDlpWired() {
259
+ b.compliance._resetForTest();
260
+ b.redact._resetForTest();
261
+ // Wire DLP first, then pin the posture — set() must NOT warn.
262
+ var http = _fakeHttpClient();
263
+ var dlp = b.redact.installForPosture("pci-dss", { httpClient: http });
264
+ var captured = [];
265
+ var origAudit = b.audit.safeEmit;
266
+ b.audit.safeEmit = function (e) { captured.push(e); };
267
+ try {
268
+ b.compliance.set("pci-dss");
269
+ } finally {
270
+ b.audit.safeEmit = origAudit;
271
+ }
272
+ var warns = captured.filter(function (e) {
273
+ return e.action === "compliance.posture.outbound_dlp_unwired";
274
+ });
275
+ check("compliance.set('pci-dss') does not warn when DLP wired",
276
+ warns.length === 0);
277
+ dlp.uninstall();
278
+ b.compliance._resetForTest();
279
+ }
280
+
281
+ function testComplianceSetNoWarnForNonDlpPosture() {
282
+ b.compliance._resetForTest();
283
+ b.redact._resetForTest();
284
+ var captured = [];
285
+ var origAudit = b.audit.safeEmit;
286
+ b.audit.safeEmit = function (e) { captured.push(e); };
287
+ try {
288
+ // sox is regulated but has no outbound-DLP classifier preset.
289
+ b.compliance.set("sox");
290
+ } finally {
291
+ b.audit.safeEmit = origAudit;
292
+ }
293
+ var warns = captured.filter(function (e) {
294
+ return e.action === "compliance.posture.outbound_dlp_unwired";
295
+ });
296
+ check("compliance.set('sox') (non-DLP-floor posture) does not warn",
297
+ warns.length === 0);
298
+ b.compliance._resetForTest();
299
+ }
300
+
222
301
  async function run() {
223
302
  testSurface();
224
303
  testClassifierRejectsBadOpts();
@@ -232,6 +311,10 @@ async function run() {
232
311
  await testInstallWebhook();
233
312
  await testPostureWiring();
234
313
  await testIdempotentInstall();
314
+ testIsOutboundDlpInstalledSurface();
315
+ testComplianceSetWarnsWhenDlpUnwired();
316
+ testComplianceSetNoWarnWhenDlpWired();
317
+ testComplianceSetNoWarnForNonDlpPosture();
235
318
  }
236
319
 
237
320
  if (require.main === module) {