@blamejs/blamejs-shop 0.4.69 → 0.4.71

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 (299) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/admin.js +8 -6
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/security-middleware.js +65 -23
  5. package/lib/shipping-insurance.js +29 -4
  6. package/lib/sms-dispatcher.js +17 -4
  7. package/lib/storefront.js +10 -7
  8. package/lib/vendor/MANIFEST.json +319 -267
  9. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  10. package/lib/vendor/blamejs/api-snapshot.json +58 -5
  11. package/lib/vendor/blamejs/examples/wiki/README.md +1 -1
  12. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +9 -8
  13. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +10 -9
  14. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +4 -3
  15. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +33 -17
  16. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +7 -10
  17. package/lib/vendor/blamejs/examples/wiki/server.js +5 -4
  18. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +5 -0
  19. package/lib/vendor/blamejs/lib/a2a-tasks.js +38 -6
  20. package/lib/vendor/blamejs/lib/agent-event-bus.js +13 -0
  21. package/lib/vendor/blamejs/lib/agent-idempotency.js +5 -1
  22. package/lib/vendor/blamejs/lib/agent-snapshot.js +32 -2
  23. package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +2 -1
  24. package/lib/vendor/blamejs/lib/ai-content-detect.js +1 -3
  25. package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +1 -1
  26. package/lib/vendor/blamejs/lib/ai-model-manifest.js +1 -1
  27. package/lib/vendor/blamejs/lib/ai-output.js +16 -7
  28. package/lib/vendor/blamejs/lib/api-snapshot.js +4 -1
  29. package/lib/vendor/blamejs/lib/app-shutdown.js +7 -1
  30. package/lib/vendor/blamejs/lib/archive-gz.js +9 -0
  31. package/lib/vendor/blamejs/lib/archive-read.js +9 -7
  32. package/lib/vendor/blamejs/lib/archive-tar-read.js +51 -8
  33. package/lib/vendor/blamejs/lib/archive.js +4 -2
  34. package/lib/vendor/blamejs/lib/asn1-der.js +70 -22
  35. package/lib/vendor/blamejs/lib/atomic-file.js +204 -2
  36. package/lib/vendor/blamejs/lib/audit-chain.js +54 -5
  37. package/lib/vendor/blamejs/lib/audit-daily-review.js +12 -2
  38. package/lib/vendor/blamejs/lib/audit-sign.js +2 -1
  39. package/lib/vendor/blamejs/lib/audit-tools.js +108 -23
  40. package/lib/vendor/blamejs/lib/audit.js +7 -2
  41. package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -2
  42. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +1 -1
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +43 -4
  44. package/lib/vendor/blamejs/lib/auth/dpop.js +6 -1
  45. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +5 -1
  46. package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
  47. package/lib/vendor/blamejs/lib/auth/lockout.js +18 -2
  48. package/lib/vendor/blamejs/lib/auth/passkey.js +1 -1
  49. package/lib/vendor/blamejs/lib/auth/password.js +1 -1
  50. package/lib/vendor/blamejs/lib/auth/saml.js +33 -13
  51. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +24 -4
  52. package/lib/vendor/blamejs/lib/auth/status-list.js +14 -2
  53. package/lib/vendor/blamejs/lib/auth/step-up.js +9 -1
  54. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +21 -2
  55. package/lib/vendor/blamejs/lib/backup/bundle.js +7 -2
  56. package/lib/vendor/blamejs/lib/backup/crypto.js +23 -8
  57. package/lib/vendor/blamejs/lib/backup/index.js +41 -20
  58. package/lib/vendor/blamejs/lib/backup/manifest.js +7 -1
  59. package/lib/vendor/blamejs/lib/break-glass.js +41 -22
  60. package/lib/vendor/blamejs/lib/cbor.js +34 -11
  61. package/lib/vendor/blamejs/lib/cdn-cache-control.js +7 -3
  62. package/lib/vendor/blamejs/lib/cert.js +5 -3
  63. package/lib/vendor/blamejs/lib/cli.js +5 -1
  64. package/lib/vendor/blamejs/lib/cloud-events.js +3 -2
  65. package/lib/vendor/blamejs/lib/cluster-storage.js +7 -3
  66. package/lib/vendor/blamejs/lib/codepoint-class.js +17 -0
  67. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -1
  68. package/lib/vendor/blamejs/lib/compliance-sanctions.js +9 -7
  69. package/lib/vendor/blamejs/lib/compliance.js +1 -1
  70. package/lib/vendor/blamejs/lib/config-drift.js +22 -8
  71. package/lib/vendor/blamejs/lib/content-credentials.js +11 -8
  72. package/lib/vendor/blamejs/lib/content-digest.js +11 -4
  73. package/lib/vendor/blamejs/lib/cookies.js +10 -2
  74. package/lib/vendor/blamejs/lib/cose.js +20 -0
  75. package/lib/vendor/blamejs/lib/crdt.js +2 -1
  76. package/lib/vendor/blamejs/lib/crypto-field.js +29 -23
  77. package/lib/vendor/blamejs/lib/crypto.js +18 -4
  78. package/lib/vendor/blamejs/lib/csp.js +4 -0
  79. package/lib/vendor/blamejs/lib/daemon.js +4 -1
  80. package/lib/vendor/blamejs/lib/data-act.js +27 -4
  81. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +14 -6
  82. package/lib/vendor/blamejs/lib/db-query.js +69 -9
  83. package/lib/vendor/blamejs/lib/db.js +32 -15
  84. package/lib/vendor/blamejs/lib/dora.js +43 -13
  85. package/lib/vendor/blamejs/lib/dr-runbook.js +1 -1
  86. package/lib/vendor/blamejs/lib/dsa.js +2 -1
  87. package/lib/vendor/blamejs/lib/dsr.js +22 -8
  88. package/lib/vendor/blamejs/lib/early-hints.js +19 -0
  89. package/lib/vendor/blamejs/lib/eat.js +5 -1
  90. package/lib/vendor/blamejs/lib/external-db.js +60 -4
  91. package/lib/vendor/blamejs/lib/fda-21cfr11.js +30 -5
  92. package/lib/vendor/blamejs/lib/flag-providers.js +6 -2
  93. package/lib/vendor/blamejs/lib/forms.js +1 -1
  94. package/lib/vendor/blamejs/lib/gate-contract.js +46 -5
  95. package/lib/vendor/blamejs/lib/gdpr-ropa.js +18 -9
  96. package/lib/vendor/blamejs/lib/graphql-federation.js +17 -4
  97. package/lib/vendor/blamejs/lib/guard-all.js +2 -2
  98. package/lib/vendor/blamejs/lib/guard-dsn.js +1 -1
  99. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  100. package/lib/vendor/blamejs/lib/guard-html.js +9 -11
  101. package/lib/vendor/blamejs/lib/guard-imap-command.js +1 -1
  102. package/lib/vendor/blamejs/lib/guard-jmap.js +1 -1
  103. package/lib/vendor/blamejs/lib/guard-json.js +14 -6
  104. package/lib/vendor/blamejs/lib/guard-mail-move.js +1 -1
  105. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +1 -1
  106. package/lib/vendor/blamejs/lib/guard-pop3-command.js +1 -1
  107. package/lib/vendor/blamejs/lib/guard-smtp-command.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-svg.js +8 -9
  109. package/lib/vendor/blamejs/lib/html-balance.js +7 -3
  110. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +33 -12
  111. package/lib/vendor/blamejs/lib/http-client.js +225 -53
  112. package/lib/vendor/blamejs/lib/iab-tcf.js +3 -2
  113. package/lib/vendor/blamejs/lib/importmap-integrity.js +41 -1
  114. package/lib/vendor/blamejs/lib/incident-report.js +9 -6
  115. package/lib/vendor/blamejs/lib/json-patch.js +1 -1
  116. package/lib/vendor/blamejs/lib/json-path.js +24 -3
  117. package/lib/vendor/blamejs/lib/jtd.js +2 -2
  118. package/lib/vendor/blamejs/lib/legal-hold.js +24 -8
  119. package/lib/vendor/blamejs/lib/log.js +2 -2
  120. package/lib/vendor/blamejs/lib/mail-agent.js +2 -2
  121. package/lib/vendor/blamejs/lib/mail-arf.js +1 -1
  122. package/lib/vendor/blamejs/lib/mail-auth.js +3 -3
  123. package/lib/vendor/blamejs/lib/mail-bimi.js +16 -16
  124. package/lib/vendor/blamejs/lib/mail-bounce.js +3 -3
  125. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +71 -6
  126. package/lib/vendor/blamejs/lib/mail-deploy.js +9 -5
  127. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -4
  128. package/lib/vendor/blamejs/lib/mail-helo.js +2 -4
  129. package/lib/vendor/blamejs/lib/mail-journal.js +11 -8
  130. package/lib/vendor/blamejs/lib/mail-mdn.js +8 -4
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -4
  132. package/lib/vendor/blamejs/lib/mail-scan.js +3 -5
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +4 -1
  134. package/lib/vendor/blamejs/lib/mail-server-registry.js +1 -1
  135. package/lib/vendor/blamejs/lib/mail-server-tls.js +9 -2
  136. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -4
  137. package/lib/vendor/blamejs/lib/mail-store-fts.js +1 -1
  138. package/lib/vendor/blamejs/lib/mail.js +22 -2
  139. package/lib/vendor/blamejs/lib/markup-tokenizer.js +24 -0
  140. package/lib/vendor/blamejs/lib/mcp.js +6 -4
  141. package/lib/vendor/blamejs/lib/mdoc.js +26 -3
  142. package/lib/vendor/blamejs/lib/metrics.js +14 -3
  143. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +2 -2
  144. package/lib/vendor/blamejs/lib/middleware/body-parser.js +10 -4
  145. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +26 -18
  146. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +5 -1
  147. package/lib/vendor/blamejs/lib/middleware/compression.js +9 -0
  148. package/lib/vendor/blamejs/lib/middleware/cors.js +32 -23
  149. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +60 -21
  150. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -4
  151. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +28 -4
  152. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +61 -30
  153. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +25 -16
  154. package/lib/vendor/blamejs/lib/middleware/scim-server.js +2 -1
  155. package/lib/vendor/blamejs/lib/middleware/security-headers.js +24 -6
  156. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +6 -3
  157. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +2 -2
  158. package/lib/vendor/blamejs/lib/money.js +1 -1
  159. package/lib/vendor/blamejs/lib/mtls-ca.js +10 -6
  160. package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
  161. package/lib/vendor/blamejs/lib/network-dns.js +9 -2
  162. package/lib/vendor/blamejs/lib/network-dnssec.js +2 -1
  163. package/lib/vendor/blamejs/lib/network-smtp-policy.js +23 -5
  164. package/lib/vendor/blamejs/lib/network-tls.js +27 -5
  165. package/lib/vendor/blamejs/lib/network-tsig.js +2 -2
  166. package/lib/vendor/blamejs/lib/nis2-report.js +1 -1
  167. package/lib/vendor/blamejs/lib/nist-crosswalk.js +1 -1
  168. package/lib/vendor/blamejs/lib/ntp-check.js +28 -0
  169. package/lib/vendor/blamejs/lib/numeric-bounds.js +9 -0
  170. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -2
  171. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +4 -2
  172. package/lib/vendor/blamejs/lib/object-store/gcs.js +6 -4
  173. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -2
  174. package/lib/vendor/blamejs/lib/object-store/http-request.js +30 -1
  175. package/lib/vendor/blamejs/lib/object-store/local.js +37 -17
  176. package/lib/vendor/blamejs/lib/object-store/sigv4.js +1 -2
  177. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +20 -4
  178. package/lib/vendor/blamejs/lib/outbox.js +11 -4
  179. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +1 -1
  180. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +21 -3
  181. package/lib/vendor/blamejs/lib/queue-local.js +10 -3
  182. package/lib/vendor/blamejs/lib/redact.js +7 -3
  183. package/lib/vendor/blamejs/lib/request-helpers.js +201 -23
  184. package/lib/vendor/blamejs/lib/resource-access-lock.js +3 -3
  185. package/lib/vendor/blamejs/lib/restore-bundle.js +46 -18
  186. package/lib/vendor/blamejs/lib/restore-rollback.js +10 -4
  187. package/lib/vendor/blamejs/lib/restore.js +19 -0
  188. package/lib/vendor/blamejs/lib/retention.js +20 -4
  189. package/lib/vendor/blamejs/lib/router.js +17 -4
  190. package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
  191. package/lib/vendor/blamejs/lib/safe-icap.js +1 -1
  192. package/lib/vendor/blamejs/lib/safe-json.js +44 -0
  193. package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
  194. package/lib/vendor/blamejs/lib/safe-vcard.js +1 -1
  195. package/lib/vendor/blamejs/lib/sandbox-worker.js +6 -0
  196. package/lib/vendor/blamejs/lib/sandbox.js +1 -1
  197. package/lib/vendor/blamejs/lib/scheduler.js +17 -1
  198. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +16 -0
  199. package/lib/vendor/blamejs/lib/session.js +27 -3
  200. package/lib/vendor/blamejs/lib/sql.js +3 -3
  201. package/lib/vendor/blamejs/lib/static.js +65 -13
  202. package/lib/vendor/blamejs/lib/template.js +7 -5
  203. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -19
  204. package/lib/vendor/blamejs/lib/tsa.js +5 -2
  205. package/lib/vendor/blamejs/lib/vault/index.js +5 -0
  206. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +22 -26
  207. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +8 -3
  208. package/lib/vendor/blamejs/lib/vault/rotate.js +13 -18
  209. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +4 -1
  210. package/lib/vendor/blamejs/lib/vc.js +1 -1
  211. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +10 -10
  212. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +23 -10
  213. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5498 -5494
  214. package/lib/vendor/blamejs/lib/webhook.js +16 -1
  215. package/lib/vendor/blamejs/lib/websocket.js +1 -1
  216. package/lib/vendor/blamejs/lib/worm.js +1 -1
  217. package/lib/vendor/blamejs/lib/ws-client.js +57 -46
  218. package/lib/vendor/blamejs/lib/x509-chain.js +44 -0
  219. package/lib/vendor/blamejs/package.json +1 -1
  220. package/lib/vendor/blamejs/release-notes/v0.15.14.json +122 -0
  221. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +119 -4
  222. package/lib/vendor/blamejs/test/00-primitives.js +5 -1
  223. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +18 -4
  224. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +42 -0
  225. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +36 -0
  226. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  227. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +47 -0
  228. package/lib/vendor/blamejs/test/layer-0-primitives/archive-gz.test.js +24 -0
  229. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-hardening.test.js +160 -0
  230. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +45 -0
  231. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +30 -0
  232. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +79 -0
  233. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-excl.test.js +132 -0
  234. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-stream.test.js +181 -0
  235. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-corrupted-anchor.test.js +65 -0
  236. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-incremental-verify.test.js +83 -0
  237. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +48 -1
  238. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +13 -3
  239. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +122 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +37 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +5 -3
  242. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +21 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +73 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +17 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +62 -3
  246. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +12 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-storage.test.js +40 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +146 -5
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +14 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/compression-range.test.js +115 -0
  251. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +17 -5
  252. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +27 -5
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +83 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +58 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +30 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +74 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +20 -6
  258. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-alg-kty.test.js +64 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +32 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +43 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +30 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +34 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +12 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +72 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +88 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +25 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +28 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +20 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/mail-header-injection.test.js +58 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +63 -9
  272. package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +41 -14
  273. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +61 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/object-store-range-header.test.js +51 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +35 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/output-header-hardening.test.js +102 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +191 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/proto-shadow-allowlist.test.js +120 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +75 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +128 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/restore-blob-remap.test.js +128 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/retention-sweep-termination.test.js +104 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/router-body-validation.test.js +98 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json-stringify-for-script.test.js +43 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +48 -5
  286. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +23 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +54 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +24 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +42 -1
  290. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +7 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/template-escape-html.test.js +43 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +15 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/vault-default-store.test.js +48 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-currency-classify.test.js +77 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +50 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +22 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/x509-chain-ca-enforcement.test.js +149 -0
  298. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +34 -0
  299. package/package.json +1 -1
@@ -57,7 +57,7 @@ var { generateToken, generateBytes, encryptPacked, decryptPacked, sha3Hash } = r
57
57
  var cryptoField = require("./crypto-field");
58
58
  var dbDeclareRowPolicy = require("./db-declare-row-policy");
59
59
  var dbDeclareView = require("./db-declare-view");
60
- var { Query, _isRawWriteToResidencyTable, _assertRawWriteResidency } = require("./db-query");
60
+ var { Query, _isRawWriteToResidencyTable, _assertRawWriteResidency, _stripLeadingSqlComments } = require("./db-query");
61
61
  var dbSchema = require("./db-schema");
62
62
  var { defineClass } = require("./framework-error");
63
63
  var frameworkFiles = require("./framework-files");
@@ -748,7 +748,7 @@ function loadOrCreateDbKey(dataDirPath, keyPathOverride) {
748
748
  var keyPath = keyPathOverride || nodePath.join(dataDirPath, frameworkFiles.fileName("dbKeyEnc"));
749
749
  var aad = _dbKeyAad(dataDirPath, keyPath);
750
750
  if (nodeFs.existsSync(keyPath)) {
751
- var sealed = atomicFile.readSync(keyPath, { encoding: "utf8" }).trim();
751
+ var sealed = atomicFile.readSync(keyPath, { encoding: "utf8", maxBytes: C.BYTES.kib(64) }).trim();
752
752
  var b64;
753
753
  // isAadSealed is checked FIRST and is load-bearing: AAD_PREFIX
754
754
  // ("vault.aad:") is NOT a prefix of VAULT_PREFIX ("vault:"), so a
@@ -811,7 +811,10 @@ function decryptToTmp() {
811
811
  try { nodeFs.unlinkSync(dbPath + "-shm"); } catch (_e) { /* may not exist */ }
812
812
  }
813
813
  }
814
- var packed = nodeFs.readFileSync(encPath);
814
+ // Cap + fd-bound db.enc read at db.init. NO refuseSymlink: the data dir may be
815
+ // a symlink-mounted volume (k8s PVC). db.enc is AEAD-verified downstream, so
816
+ // the cap is the OOM-before-cap defense (was an uncapped read).
817
+ var packed = atomicFile.fdSafeReadSync(encPath, { maxBytes: C.BYTES.gib(2) });
815
818
  if (packed.length < 26) return; // too short to be a valid envelope
816
819
  // AAD binds the envelope to this deployment's data dir so two
817
820
  // installs sharing the same operator passphrase can't swap each
@@ -890,11 +893,27 @@ function _probeStorageHeadroom() {
890
893
  // DELETE, PRAGMA, and DDL pass through ungated. Called once in init() after
891
894
  // schema setup so init's own writes are never gated (writesRefused is false
892
895
  // until the first probe anyway).
896
+ // A growth write for the storage-low gate: INSERT/UPDATE/REPLACE at the head
897
+ // AFTER stripping leading comments, OR a writable-CTE / EXPLAIN-prefixed write
898
+ // (`WITH c AS (...) INSERT INTO t ...`) whose effective verb places rows. The
899
+ // leading-keyword-only test missed both a `/* x */ INSERT` and a WITH-prefixed
900
+ // growth write, letting them proceed into a near-full tmpfs (the ENOSPC the gate
901
+ // exists to prevent). Matches write SYNTAX (INTO / UPDATE..SET) so a WITH..SELECT
902
+ // carrying the word "insert" in a value is not refused.
903
+ function _isGrowthWrite(sql) {
904
+ if (typeof sql !== "string") return false;
905
+ var s = _stripLeadingSqlComments(sql);
906
+ if (/^\s*(?:INSERT|UPDATE|REPLACE)\b/i.test(s)) return true;
907
+ if (/^\s*(?:WITH|EXPLAIN)\b/i.test(s) &&
908
+ /\b(?:(?:INSERT|REPLACE|MERGE)\s+(?:OR\s+[A-Za-z]+\s+)?INTO|UPDATE\s+[\w".`]+\s+SET)\b/i.test(s)) return true;
909
+ return false;
910
+ }
911
+
893
912
  function _installWriteGate() {
894
913
  var rawPrepare = database.prepare.bind(database);
895
914
  database.prepare = function (sql) {
896
915
  var stmt = rawPrepare(sql);
897
- if (/^\s*(?:INSERT|UPDATE|REPLACE)\b/i.test(sql)) {
916
+ if (_isGrowthWrite(sql)) {
898
917
  var rawRun = stmt.run.bind(stmt);
899
918
  stmt.run = function () {
900
919
  if (writesRefused) {
@@ -915,7 +934,7 @@ function encryptToDisk() {
915
934
  // Force WAL checkpoint so the .db file holds all committed transactions.
916
935
  try { runSql(database, "PRAGMA wal_checkpoint(TRUNCATE)"); } catch (_e) { /* best effort */ }
917
936
  if (!nodeFs.existsSync(dbPath)) return;
918
- atomicFile.writeSync(encPath, encryptPacked(nodeFs.readFileSync(dbPath), encKey, _dbEncAad(dataDir)));
937
+ atomicFile.writeSync(encPath, encryptPacked(atomicFile.fdSafeReadSync(dbPath, { maxBytes: C.BYTES.gib(2) }), encKey, _dbEncAad(dataDir)));
919
938
  }
920
939
 
921
940
  /**
@@ -952,7 +971,7 @@ function snapshot() {
952
971
  throw _dbErr("db/snapshot-no-source",
953
972
  "snapshot: plaintext DB at " + dbPath + " is missing — did init complete?");
954
973
  }
955
- var plain = nodeFs.readFileSync(dbPath);
974
+ var plain = atomicFile.fdSafeReadSync(dbPath, { maxBytes: C.BYTES.gib(2) });
956
975
  if (!encPath || !encKey) {
957
976
  // atRest: 'plain' — return the raw bytes. Operators wanting an
958
977
  // encrypted snapshot under plain mode wrap with their own
@@ -2611,14 +2630,12 @@ function declareRequireDualControl(args) {
2611
2630
  }
2612
2631
  var m = args.m === undefined ? 2 : args.m;
2613
2632
  var n = args.n === undefined ? Math.max(2, m) : args.n;
2614
- if (typeof m !== "number" || !isFinite(m) || m < 2 || Math.floor(m) !== m) {
2615
- throw new DbError("db/dual-control-bad-quorum",
2616
- "declareRequireDualControl: m must be an integer >= 2");
2617
- }
2618
- if (typeof n !== "number" || !isFinite(n) || n < m || Math.floor(n) !== n) {
2619
- throw new DbError("db/dual-control-bad-quorum",
2620
- "declareRequireDualControl: n must be an integer >= m");
2621
- }
2633
+ // m >= 2, n >= m, both integers via numericBounds (matches db.js's existing
2634
+ // inline numeric-bounds usage; throws DbError("db/dual-control-bad-quorum")).
2635
+ require("./numeric-bounds").requirePositiveFiniteInt(m,
2636
+ "declareRequireDualControl: m", DbError, "db/dual-control-bad-quorum", { min: 2 });
2637
+ require("./numeric-bounds").requirePositiveFiniteInt(n,
2638
+ "declareRequireDualControl: n", DbError, "db/dual-control-bad-quorum", { min: m });
2622
2639
  if (args.posture !== undefined && args.posture !== null &&
2623
2640
  (typeof args.posture !== "string" || args.posture.length === 0)) {
2624
2641
  throw new DbError("db/dual-control-bad-posture",
@@ -2785,7 +2802,7 @@ function _checkRollback(dataDirPath) {
2785
2802
  }
2786
2803
  var tip;
2787
2804
  try {
2788
- tip = safeJson.parse(atomicFile.readSync(tipPath), { schema: AUDIT_TIP_SCHEMA });
2805
+ tip = safeJson.parse(atomicFile.readSync(tipPath, { maxBytes: C.BYTES.kib(64) }), { schema: AUDIT_TIP_SCHEMA });
2789
2806
  } catch (e) {
2790
2807
  throw _dbErr("db/audit-tip-unreadable",
2791
2808
  "FATAL: audit.tip unreadable or schema-invalid at " + tipPath + " — " + e.message +
@@ -62,12 +62,19 @@ var SIGNIFICANT_INCIDENT_THRESHOLDS = Object.freeze({
62
62
  durationCriticalProcessMs: C.TIME.hours(2), // 2h
63
63
  });
64
64
 
65
- // Article 19 initial report deadline: 24h from "first awareness".
66
- // Article 19(4) intermediate update: within 72h of initial.
67
- // Article 19(6) final report: within 1 month of initial.
68
- var INITIAL_REPORT_DEADLINE_MS = C.TIME.hours(24);
69
- var INTERMEDIATE_REPORT_DEADLINE_MS = C.TIME.hours(72);
70
- var FINAL_REPORT_DEADLINE_MS = C.TIME.days(30);
65
+ // DORA major-incident reporting timeline (Art. 19 + RTS (EU) 2024/1772 Art. 5):
66
+ // - Initial notification: as early as possible and WITHIN 4 HOURS of
67
+ // classifying the incident as major (the outer bound is 24h from first
68
+ // awareness). classify() returns mustReportInitialByMs as a duration FROM
69
+ // classification, so the operative window encoded here is 4h — the
70
+ // 24h-from-awareness outer bound is enforced separately via
71
+ // INITIAL_REPORT_OUTER_DEADLINE_MS below.
72
+ // - Intermediate update: within 72h of the INITIAL notification's submission.
73
+ // - Final report: within 1 month of the intermediate report's submission.
74
+ var INITIAL_REPORT_DEADLINE_MS = C.TIME.hours(4);
75
+ var INITIAL_REPORT_OUTER_DEADLINE_MS = C.TIME.hours(24);
76
+ var INTERMEDIATE_REPORT_DEADLINE_MS = C.TIME.hours(72);
77
+ var FINAL_REPORT_DEADLINE_MS = C.TIME.days(30);
71
78
 
72
79
  // Adjacent-regulation incident-reporting deadlines — operators wiring
73
80
  // NIS2 / CRA / HIPAA breach notification reach for these constants
@@ -124,14 +131,26 @@ function _classifyImpl(input) {
124
131
  reasons.push("severity-high");
125
132
  }
126
133
 
127
- // 2. Affected clients (absolute).
134
+ // 2. Affected clients absolute count OR share of the client base. The
135
+ // percentile thresholds (RTS 2024/1772 Art. 1(1)(a): >10% major, ESA-
136
+ // guideline 1% significant) were declared but never evaluated, so a
137
+ // large-share-but-small-absolute incident (e.g. 16% of a 50k client base)
138
+ // under-classified. Operators pass clientBase (total clients) to enable
139
+ // the percentage criterion; absolute-only behavior is unchanged when it
140
+ // is omitted.
128
141
  if (typeof input.affectedClients === "number" && input.affectedClients > 0) {
129
- if (input.affectedClients >= MAJOR_INCIDENT_THRESHOLDS.affectedClientsAbsolute) {
142
+ var clientBase = (typeof input.clientBase === "number" && input.clientBase > 0) ? input.clientBase : null;
143
+ var clientPct = clientBase ? (input.affectedClients / clientBase) : 0;
144
+ var majorByClients = input.affectedClients >= MAJOR_INCIDENT_THRESHOLDS.affectedClientsAbsolute ||
145
+ (clientBase !== null && clientPct >= MAJOR_INCIDENT_THRESHOLDS.affectedClientsPercentile);
146
+ var significantByClients = input.affectedClients >= SIGNIFICANT_INCIDENT_THRESHOLDS.affectedClientsAbsolute ||
147
+ (clientBase !== null && clientPct >= SIGNIFICANT_INCIDENT_THRESHOLDS.affectedClientsPercentile);
148
+ if (majorByClients) {
130
149
  hitsMajor += 1;
131
- reasons.push("clients-major-absolute");
132
- } else if (input.affectedClients >= SIGNIFICANT_INCIDENT_THRESHOLDS.affectedClientsAbsolute) {
150
+ reasons.push("clients-major");
151
+ } else if (significantByClients) {
133
152
  hitsSignificant += 1;
134
- reasons.push("clients-significant-absolute");
153
+ reasons.push("clients-significant");
135
154
  }
136
155
  }
137
156
 
@@ -188,7 +207,11 @@ function _classifyImpl(input) {
188
207
  return {
189
208
  classification: classification,
190
209
  mustReport: mustReport,
210
+ // Operative initial-notification window: 4h from this classification.
191
211
  mustReportInitialByMs: mustReport ? INITIAL_REPORT_DEADLINE_MS : null,
212
+ // Outer bound: no later than 24h from first awareness — surfaced so an
213
+ // operator scheduling from `detectedAt` can enforce min(class+4h, aware+24h).
214
+ mustReportInitialOuterByMs: mustReport ? INITIAL_REPORT_OUTER_DEADLINE_MS : null,
192
215
  reasons: reasons,
193
216
  };
194
217
  }
@@ -343,10 +366,16 @@ function create(opts) {
343
366
  // Article 19 deadline — operator-side scheduler uses this.
344
367
  nextStageDueAt: null,
345
368
  };
369
+ // Anchor each downstream deadline on the SUBMISSION time of the report
370
+ // being filed (record.reportedAt), not on detectedAt: the intermediate is
371
+ // due 72h after the initial is *submitted*, and the final one month after
372
+ // the intermediate is *submitted* (DORA RTS 2024/1772 reporting timeline).
373
+ // Anchoring on detectedAt understates the deadline whenever a report is
374
+ // filed later than detection.
346
375
  if (input.stage === "initial") {
347
- record.nextStageDueAt = input.detectedAt + INTERMEDIATE_REPORT_DEADLINE_MS;
376
+ record.nextStageDueAt = record.reportedAt + INTERMEDIATE_REPORT_DEADLINE_MS;
348
377
  } else if (input.stage === "intermediate") {
349
- record.nextStageDueAt = input.detectedAt + FINAL_REPORT_DEADLINE_MS;
378
+ record.nextStageDueAt = record.reportedAt + FINAL_REPORT_DEADLINE_MS;
350
379
  }
351
380
  _emit("dora.incident.reported", {
352
381
  metadata: {
@@ -396,6 +425,7 @@ module.exports = {
396
425
  MAJOR_INCIDENT_THRESHOLDS: MAJOR_INCIDENT_THRESHOLDS,
397
426
  SIGNIFICANT_INCIDENT_THRESHOLDS: SIGNIFICANT_INCIDENT_THRESHOLDS,
398
427
  INITIAL_REPORT_DEADLINE_MS: INITIAL_REPORT_DEADLINE_MS,
428
+ INITIAL_REPORT_OUTER_DEADLINE_MS: INITIAL_REPORT_OUTER_DEADLINE_MS,
399
429
  INTERMEDIATE_REPORT_DEADLINE_MS: INTERMEDIATE_REPORT_DEADLINE_MS,
400
430
  FINAL_REPORT_DEADLINE_MS: FINAL_REPORT_DEADLINE_MS,
401
431
  DEADLINES_NIS2: DEADLINES_NIS2,
@@ -275,7 +275,7 @@ async function emit(opts) {
275
275
  "drRunbook.emit: outDir", DrRunbookError, "dr-runbook/no-outdir");
276
276
  validateOpts.requireNonEmptyString(opts.posture,
277
277
  "drRunbook.emit: posture", DrRunbookError, "dr-runbook/no-posture");
278
- if (!POSTURE_BLOCKS[opts.posture]) {
278
+ if (!Object.prototype.hasOwnProperty.call(POSTURE_BLOCKS, opts.posture)) {
279
279
  throw new DrRunbookError("dr-runbook/unknown-posture",
280
280
  "drRunbook.emit: posture '" + opts.posture + "' not in supported list (" +
281
281
  Object.keys(POSTURE_BLOCKS).join(", ") + ")");
@@ -36,6 +36,7 @@
36
36
 
37
37
  var validateOpts = require("./validate-opts");
38
38
  var lazyRequire = require("./lazy-require");
39
+ var numericBounds = require("./numeric-bounds");
39
40
  var C = require("./constants");
40
41
  var { DsaError } = require("./framework-error");
41
42
 
@@ -414,7 +415,7 @@ function transparencyReport(opts) {
414
415
  METRIC_FIELDS.forEach(function (field) {
415
416
  var v = supplied[field];
416
417
  if (v === undefined || v === null) { metrics[field] = 0; return; }
417
- if (typeof v !== "number" || !isFinite(v) || v < 0 || Math.floor(v) !== v) {
418
+ if (!numericBounds.isNonNegativeFiniteInt(v)) {
418
419
  throw new DsaError("dsa/bad-metric-value",
419
420
  "b.dsa.transparencyReport: metrics." + field +
420
421
  " must be a non-negative integer, got " +
@@ -210,7 +210,7 @@ var POSTURE_DEADLINE_MS = Object.freeze({
210
210
  // + extension). Read-only at module scope.
211
211
  function _deadlineForPosture(posture) {
212
212
  if (typeof posture !== "string") return POSTURE_DEADLINE_MS["default"];
213
- return POSTURE_DEADLINE_MS[posture] || POSTURE_DEADLINE_MS["default"];
213
+ return Object.prototype.hasOwnProperty.call(POSTURE_DEADLINE_MS, posture) ? POSTURE_DEADLINE_MS[posture] : POSTURE_DEADLINE_MS["default"];
214
214
  }
215
215
 
216
216
  function _now() { return Date.now(); }
@@ -1198,12 +1198,26 @@ function dbTicketStore(opts) {
1198
1198
  SUBJECT_FILTER_SPEC.forEach(function (spec) {
1199
1199
  var supplied = filter.subject[spec.key];
1200
1200
  if (!supplied) return;
1201
- var column = vaulted ? spec.hashCol : spec.plainCol;
1202
- var match = vaulted
1203
- ? (function () { var d = cryptoField().computeDerived(DSR_SEAL_TABLE, spec.sealField, supplied); return d ? d.value : null; })()
1204
- : supplied;
1205
- conds.push(column + " = " + spec.param);
1206
- params[spec.param] = match;
1201
+ if (!vaulted) {
1202
+ conds.push(spec.plainCol + " = " + spec.param);
1203
+ params[spec.param] = supplied;
1204
+ return;
1205
+ }
1206
+ // Vaulted: match BOTH the active keyed-MAC digest AND the legacy
1207
+ // salted-sha3 digest via the dual-read, so a ticket written before the
1208
+ // keyed-MAC default flip is still FOUND. A single-value equality on the
1209
+ // keyed-MAC digest silently skips those pre-flip rows, so an Art.17
1210
+ // erasure purge (list-by-subject → delete) would leave the subject's
1211
+ // legacy-hashed PII-bearing tickets behind. Mirrors subject.eraseHard.
1212
+ var cand = cryptoField().lookupHashCandidates(DSR_SEAL_TABLE, spec.sealField, supplied);
1213
+ var values = cand && cand.values ? cand.values : [];
1214
+ if (values.length === 0) return;
1215
+ var placeholders = values.map(function (v, i) {
1216
+ var p = spec.param + "_" + i;
1217
+ params[p] = v;
1218
+ return p;
1219
+ });
1220
+ conds.push(spec.hashCol + " IN (" + placeholders.join(", ") + ")");
1207
1221
  });
1208
1222
  }
1209
1223
 
@@ -1455,7 +1469,7 @@ var STATE_RULES = Object.freeze({
1455
1469
  function stateRules(state) {
1456
1470
  if (typeof state !== "string" || state.length === 0) return null;
1457
1471
  // Direct posture-name lookup first
1458
- if (STATE_RULES[state]) return Object.assign({}, STATE_RULES[state]);
1472
+ if (Object.prototype.hasOwnProperty.call(STATE_RULES, state)) return Object.assign({}, STATE_RULES[state]);
1459
1473
  // 2-letter state abbreviation lookup (case-insensitive)
1460
1474
  var u = state.toUpperCase();
1461
1475
  var keys = Object.keys(STATE_RULES);
@@ -170,6 +170,13 @@ function send(res, opts) {
170
170
  throw new EarlyHintsError("early-hints/bad-header-value",
171
171
  "earlyHints.send: header '" + name + "' must be a string or string[]", true);
172
172
  }
173
+ var vals = Array.isArray(canonical[name]) ? canonical[name] : [canonical[name]];
174
+ for (var vi = 0; vi < vals.length; vi += 1) {
175
+ if (typeof vals[vi] === "string" && _hasHeaderInjection(vals[vi])) {
176
+ throw new EarlyHintsError("early-hints/bad-header-value",
177
+ "earlyHints.send: header '" + name + "' value contains a CR/LF/NUL header-injection character", true);
178
+ }
179
+ }
173
180
  headers[name] = canonical[name];
174
181
  }
175
182
 
@@ -182,9 +189,21 @@ function send(res, opts) {
182
189
  }
183
190
  }
184
191
 
192
+ // A header value reaching res.writeEarlyHints must carry no CR/LF/NUL — those
193
+ // split the interim response into attacker-chosen headers. Node rejects them
194
+ // too, but screen defensively (matching the cookies / security-headers
195
+ // boundary) so the framework surfaces a typed error, not a raw Node throw.
196
+ function _hasHeaderInjection(s) {
197
+ return s.indexOf("\r") !== -1 || s.indexOf("\n") !== -1 || s.indexOf("\0") !== -1;
198
+ }
199
+
185
200
  function _validateLink(linkValue, idx) {
186
201
  validateOpts.requireNonEmptyString(linkValue, "earlyHints.send.link[" + idx + "]",
187
202
  EarlyHintsError, "early-hints/bad-link");
203
+ if (_hasHeaderInjection(linkValue)) {
204
+ throw new EarlyHintsError("early-hints/bad-link",
205
+ "link[" + idx + "] contains a CR/LF/NUL header-injection character");
206
+ }
188
207
  if (linkValue.length > LINK_MAX_BYTES) {
189
208
  throw new EarlyHintsError("early-hints/bad-link",
190
209
  "link[" + idx + "] exceeds " + LINK_MAX_BYTES + " bytes");
@@ -205,7 +205,11 @@ async function verify(eat, opts) {
205
205
  // Debug status — refuse a token that can't prove debug is disabled.
206
206
  if (opts.requireDebugDisabled === true) {
207
207
  var ds = raw.get(EAT.dbgstat);
208
- if (typeof ds !== "number" || ds < DBGSTAT.disabled) {
208
+ // Accept ONLY a defined disabled enum value (1..4). `ds < disabled` alone
209
+ // let any out-of-range value >= 1 (5, 99, non-integers) pass as "disabled"
210
+ // — a fail-open on an undefined dbgstat (RFC 9711 §3.3 defines 0..4 only).
211
+ if (typeof ds !== "number" || !Number.isInteger(ds) ||
212
+ ds < DBGSTAT.disabled || ds > DBGSTAT["disabled-fully-and-permanently"]) {
209
213
  throw new EatError("eat/debug-not-disabled",
210
214
  "eat.verify: requireDebugDisabled — dbgstat is " +
211
215
  (ds === undefined ? "absent" : (DBGSTAT_BY_VALUE[ds] || ds)) + ", not a disabled state");
@@ -339,6 +339,50 @@ function _classifyStatement(sql) {
339
339
  return _STATEMENT_CLASS_MAP[kw] || "OTHER";
340
340
  }
341
341
 
342
+ // True when a top-level (paren-depth 0, outside any string / comment / quoted-
343
+ // identifier / dollar-quoted span) RETURNING keyword is present — a DML
344
+ // statement with RETURNING yields rows to the caller. Quote-aware so the literal
345
+ // word inside a value ('see RETURNING docs') is not mistaken for a clause, and
346
+ // depth-aware so a RETURNING buried in a CTE / subquery paren does not count for
347
+ // the OUTER statement. Reuses the shared opaque-span scanner; single linear pass.
348
+ function _hasTopLevelReturning(sql) {
349
+ var n = sql.length, i = 0, depth = 0;
350
+ while (i < n) {
351
+ var skipped = _skipOpaqueSpan(sql, i);
352
+ if (skipped === -1) return false; // unterminated span — nothing top-level beyond
353
+ if (skipped !== i) { i = skipped; continue; }
354
+ var ch = sql.charAt(i);
355
+ if (ch === "(") { depth += 1; i += 1; continue; }
356
+ if (ch === ")") { depth -= 1; i += 1; continue; }
357
+ if (_isIdentStart(ch)) {
358
+ var we = i + 1;
359
+ while (we < n && _isIdentChar(sql.charAt(we))) we += 1;
360
+ if (depth === 0 && sql.slice(i, we).toUpperCase() === "RETURNING") return true;
361
+ i = we;
362
+ continue;
363
+ }
364
+ i += 1;
365
+ }
366
+ return false;
367
+ }
368
+
369
+ // Does this statement return a row set to the caller? Distinct from the
370
+ // residency gate's read/write split: an `EXPLAIN ANALYZE INSERT` is a WRITE for
371
+ // the gate yet returns plan rows; a DML `... RETURNING` is a write that yields
372
+ // rows. Consumers (e.g. cluster-storage's local exec choosing .all() vs .run())
373
+ // must use .all() for any row-returning statement, including a WITH (CTE) read
374
+ // that the leading keyword alone would mis-route to .run() and SILENTLY DROP.
375
+ // Statement classes that produce a row set for the caller (SELECT and the
376
+ // READ_INFO family — SHOW / DESCRIBE / PRAGMA). Keyed by class name, mirroring
377
+ // _STATEMENT_CLASS_MAP / _RESIDENCY_READ_CLASS.
378
+ var _ROW_RETURNING_CLASS = Object.freeze({ SELECT: true, READ_INFO: true });
379
+
380
+ function statementReturnsRows(sql) {
381
+ if (typeof sql !== "string" || sql.length === 0) return false;
382
+ if (_ROW_RETURNING_CLASS[_classifyStatement(sql)] === true) return true;
383
+ return _hasTopLevelReturning(sql);
384
+ }
385
+
342
386
  // Statement classes that place no rows on the backend, so the cross-
343
387
  // border residency write gate lets them pass without a row tag. Every
344
388
  // other class — DML, ROUTINE (CALL / EXECUTE / DO), a COPY ... FROM
@@ -1810,12 +1854,19 @@ async function _readQuery(sql, params, opts) {
1810
1854
  // was explicitly configured allowCrossBorder (which is audited).
1811
1855
  var _readPosture = _activePosture();
1812
1856
  var _tagPresent = opts.rowResidencyTag && typeof opts.rowResidencyTag === "string";
1857
+ // A replica only carries a real residency CONSTRAINT when its tag names a
1858
+ // specific region. "unrestricted" / "global" mean "no constraint" (the tag
1859
+ // defaults to "unrestricted" when none is configured), so such a replica may
1860
+ // serve any region's rows and must NOT require opts.rowResidencyTag — gating
1861
+ // it would over-reject every regulated read to an untagged replica.
1862
+ var _replicaConstrained = replica.residencyTag &&
1863
+ replica.residencyTag !== "unrestricted" && replica.residencyTag !== "global";
1813
1864
  // Fail CLOSED when the row's region is not identified: a regulated read to a
1814
- // residency-tagged replica without opts.rowResidencyTag would otherwise route
1815
- // residency-restricted rows to an arbitrary-region replica with no check at
1816
- // all (symmetric with the write gate's RESIDENCY_GATE_REQUIRED).
1865
+ // residency-CONSTRAINED replica without opts.rowResidencyTag would otherwise
1866
+ // route residency-restricted rows to an arbitrary-region replica with no check
1867
+ // at all (symmetric with the write gate's RESIDENCY_GATE_REQUIRED).
1817
1868
  if (!_tagPresent && _crossBorderRegulated(_readPosture) &&
1818
- replica.residencyTag && !replica.allowCrossBorder) {
1869
+ _replicaConstrained && !replica.allowCrossBorder) {
1819
1870
  _emit("db.residency.replica.tag_required", "denied", {
1820
1871
  backend: b.name, replicaIdx: replica.index,
1821
1872
  replicaTag: replica.residencyTag, posture: _readPosture,
@@ -2574,6 +2625,11 @@ module.exports = {
2574
2625
  // lock tables live on the externalDb side. See lib/external-db-migrate.js.
2575
2626
  migrate: externalDbMigrate,
2576
2627
  Pool: Pool,
2628
+ // Shared SQL statement classifier (CTE / EXPLAIN aware): does the statement
2629
+ // return a row set? Internal — consumed by cluster-storage's local exec to
2630
+ // choose .all() vs .run() so a WITH (CTE) read is not mis-routed and its rows
2631
+ // lost. Underscore-prefixed: framework-internal, not an operator API surface.
2632
+ _statementReturnsRows: statementReturnsRows,
2577
2633
  _resetForTest: _resetForTest,
2578
2634
  _extractTargetRelation: _extractTargetRelation,
2579
2635
  };
@@ -91,6 +91,18 @@ var DEFAULT_SIGNATURE_MEANINGS = Object.freeze([
91
91
  // must carry §11.10(e) shape. Operators add more via opts.gxpNamespaces.
92
92
  var DEFAULT_GXP_NAMESPACES = Object.freeze(["subject", "consent", "db", "breakglass"]);
93
93
 
94
+ // Non-mutating verb segments. A GxP-namespace event whose final action segment
95
+ // is NOT one of these is treated as a record MODIFICATION and must carry the
96
+ // §11.10(e) before/after/reason shape (fail-closed — an unknown verb is assumed
97
+ // to mutate). hasOwnProperty-guarded lookup (untrusted action key).
98
+ var READ_VERBS = Object.freeze({
99
+ read: 1, viewed: 1, view: 1, get: 1, got: 1, list: 1, listed: 1, query: 1,
100
+ queried: 1, access: 1, accessed: 1, export: 1, exported: 1, history: 1,
101
+ isgranted: 1, check: 1, checked: 1, verify: 1, verified: 1, lookup: 1,
102
+ search: 1, searched: 1, fetch: 1, fetched: 1, render: 1, rendered: 1,
103
+ download: 1, downloaded: 1,
104
+ });
105
+
94
106
  // §11.10(e) — every modification audit must carry timestamp, actor,
95
107
  // before/after pair, and a reason. The framework's audit row shape
96
108
  // already carries `recordedAt` (timestamp) + `actorUserId` + `reason`;
@@ -114,11 +126,15 @@ function _hasRequiredAuditShape(row) {
114
126
  if (!row.action || typeof row.action !== "string") {
115
127
  return { ok: false, reason: "row missing action verb (§11.10(e))" };
116
128
  }
117
- // Modification-shaped events (verbs containing "update" / "modif" /
118
- // "delete" / "rectif" / "erase" / "set") must carry before/after.
129
+ // §11.10(e) requires before/after on every record MODIFICATION. Inferring
130
+ // "is this a modification" from a denylist of mutating verbs silently let
131
+ // off-list verbs (anonymize / revoke / overwrite / replace / merge /
132
+ // withdraw / restrict / objection …) bypass the requirement. Fail CLOSED
133
+ // instead: a GxP-namespace event is treated as a modification UNLESS its
134
+ // final verb segment is on an explicit non-mutating READ allowlist.
119
135
  var verb = row.action.toLowerCase();
120
- var modShape = /\.(update|updated|modif|modified|delete|deleted|rectif|rectified|erase|erased|set|setrole|put|patched)\b/.test(verb) ||
121
- /\.(update|delete|modif|set|put|patch|rectif|erase)/.test(verb);
136
+ var lastSeg = verb.indexOf(".") === -1 ? verb : verb.slice(verb.lastIndexOf(".") + 1);
137
+ var modShape = !Object.prototype.hasOwnProperty.call(READ_VERBS, lastSeg);
122
138
  if (modShape) {
123
139
  var meta = row.metadata;
124
140
  // Audit chain stores metadata as a JSON string when read back —
@@ -263,7 +279,16 @@ function posture(opts) {
263
279
  }, "denied");
264
280
  return { ok: false, reason: "record-hash-mismatch" };
265
281
  }
266
- if (verifyWith && signed.signature) {
282
+ if (verifyWith) {
283
+ // A configured verifier means a signature is REQUIRED — a null/empty
284
+ // signature must fail closed (recordHash alone is self-consistency, not
285
+ // authentication; accepting it is alg:none-style signature stripping).
286
+ if (!signed.signature) {
287
+ _emit("fda21cfr11.signature.verified", {
288
+ printedName: signed.printedName, ok: false, reason: "signature-required",
289
+ }, "denied");
290
+ return { ok: false, reason: "signature-required" };
291
+ }
267
292
  var sigBuf = Buffer.from(signed.signature, "base64");
268
293
  var payload = JSON.stringify({
269
294
  printedName: signed.printedName,
@@ -41,6 +41,7 @@ var validateOpts = require("./validate-opts");
41
41
  var lazyRequire = require("./lazy-require");
42
42
  var safeJson = require("./safe-json");
43
43
  var C = require("./constants");
44
+ var atomicFile = require("./atomic-file");
44
45
  var { defineClass } = require("./framework-error");
45
46
  var FlagError = defineClass("FlagError", { alwaysPermanent: true });
46
47
 
@@ -128,7 +129,10 @@ function localFile(opts) {
128
129
  validateOpts.requireNonEmptyString(opts.path,
129
130
  "providers.localFile: path", FlagError, "flag/bad-provider");
130
131
  var raw;
131
- try { raw = nodeFs.readFileSync(opts.path, "utf8"); }
132
+ // Capped fd-bound read; the cap precedes the alloc so an oversized flag file
133
+ // can't OOM boot. refuseSymlink stays OFF: a flag file is commonly a k8s
134
+ // ConfigMap mount, which is a symlink chain — refusing it would break that.
135
+ try { raw = atomicFile.fdSafeReadSync(opts.path, { maxBytes: C.BYTES.mib(1), encoding: "utf8" }); }
132
136
  catch (e) {
133
137
  throw new FlagError("flag/bad-provider",
134
138
  "providers.localFile: cannot read file " + JSON.stringify(opts.path) +
@@ -154,7 +158,7 @@ function localFile(opts) {
154
158
  try {
155
159
  nodeFs.watch(opts.path, { persistent: false }, function () {
156
160
  try {
157
- var nextRaw = nodeFs.readFileSync(opts.path, "utf8");
161
+ var nextRaw = atomicFile.fdSafeReadSync(opts.path, { maxBytes: C.BYTES.mib(1), encoding: "utf8" });
158
162
  var nextParsed = safeJson.parse(nextRaw, { maxBytes: C.BYTES.mib(1) });
159
163
  if (nextParsed && nextParsed.flags) {
160
164
  for (var k in nextParsed.flags) {
@@ -252,7 +252,7 @@ function _renderField(field) {
252
252
  var control;
253
253
  if (type === "textarea") control = _renderTextarea(field);
254
254
  else if (type === "select") control = _renderSelect(field);
255
- else if (INPUT_TYPES[type]) control = _renderInput(field);
255
+ else if (Object.prototype.hasOwnProperty.call(INPUT_TYPES, type)) control = _renderInput(field);
256
256
  else throw new Error("forms.render: unsupported field type: " + type);
257
257
 
258
258
  // Hidden + submit fields don't need a label wrapper
@@ -1095,13 +1095,49 @@ function makeProfileBuilder(profiles) {
1095
1095
  * posture.piiPolicy; // → "redact"
1096
1096
  */
1097
1097
  function lookupCompliancePosture(name, postures, errorFactory, codePrefix) {
1098
- if (!postures || !postures[name]) {
1098
+ // hasOwnProperty: `name` is caller input; a bracket lookup would let a
1099
+ // prototype key like "constructor" pass the presence check and reach
1100
+ // Object.assign (proto shadowing).
1101
+ if (!postures || !Object.prototype.hasOwnProperty.call(postures, name)) {
1099
1102
  throw errorFactory(codePrefix + ".bad-posture",
1100
1103
  "unknown compliancePosture " + JSON.stringify(name));
1101
1104
  }
1102
1105
  return Object.assign({}, postures[name]);
1103
1106
  }
1104
1107
 
1108
+ /**
1109
+ * @primitive b.gateContract.makePostureAccessor
1110
+ * @signature b.gateContract.makePostureAccessor(postures, opts?)
1111
+ * @since 0.15.14
1112
+ * @status stable
1113
+ * @related b.gateContract.lookupCompliancePosture, b.gateContract.resolveProfileName
1114
+ *
1115
+ * Build the public `compliancePosture(name)` accessor a guard exposes — maps a
1116
+ * compliance-posture name through the guard's own `postures` table to the
1117
+ * profile it selects, returning `opts.fallback` (default `null`) for an
1118
+ * unknown name. Folds the one-line lookup the mail-scanner / content-detect
1119
+ * factories each redefined verbatim (`return POSTURES[name] || null`) into one
1120
+ * proto-shadow-safe helper: the membership test is `hasOwnProperty.call` so a
1121
+ * prototype key (constructor / __proto__ / toString) resolves to the fallback
1122
+ * rather than an inherited Function. Unlike `lookupCompliancePosture` it does
1123
+ * NOT throw and returns the raw mapped value (a profile name string), not an
1124
+ * object copy.
1125
+ *
1126
+ * @opts
1127
+ * fallback: any, // value returned for an unknown / proto-key name (default null)
1128
+ *
1129
+ * @example
1130
+ * var compliancePosture = b.gateContract.makePostureAccessor(COMPLIANCE_POSTURES);
1131
+ * compliancePosture("hipaa"); // → "strict"
1132
+ * compliancePosture("constructor"); // → null (proto key, not an own posture)
1133
+ */
1134
+ function makePostureAccessor(postures, opts) {
1135
+ var fallback = (opts && Object.prototype.hasOwnProperty.call(opts, "fallback")) ? opts.fallback : null;
1136
+ return function (name) {
1137
+ return Object.prototype.hasOwnProperty.call(postures, name) ? postures[name] : fallback;
1138
+ };
1139
+ }
1140
+
1105
1141
  // "GuardCidrError" -> "guardCidr" — the guard's audit/message identity, derived
1106
1142
  // once from its error class name. Used for the default gate's audit/metric
1107
1143
  // prefix AND the profile resolver's error message, so neither re-cases the name.
@@ -1199,9 +1235,13 @@ function makeProfileResolver(cfg) {
1199
1235
  */
1200
1236
  function resolveProfileName(opts, postures, defaultProfile) {
1201
1237
  opts = opts || {};
1202
- return opts.profile ||
1203
- (opts.posture && postures && postures[opts.posture]) ||
1204
- defaultProfile;
1238
+ // hasOwnProperty: opts.posture is caller/operator input; a bracket lookup
1239
+ // would let a prototype key like "constructor" resolve to an inherited
1240
+ // truthy value and become the profile name (proto shadowing).
1241
+ var postureProfile = (opts.posture && postures &&
1242
+ Object.prototype.hasOwnProperty.call(postures, opts.posture))
1243
+ ? postures[opts.posture] : null;
1244
+ return opts.profile || postureProfile || defaultProfile;
1205
1245
  }
1206
1246
 
1207
1247
  /**
@@ -2072,7 +2112,7 @@ Object.freeze(INPUT_CONTRACTS);
2072
2112
 
2073
2113
  function resolveInputContract(contract) {
2074
2114
  if (typeof contract === "function") return contract;
2075
- return INPUT_CONTRACTS[contract] || INPUT_CONTRACTS.text;
2115
+ return Object.prototype.hasOwnProperty.call(INPUT_CONTRACTS, contract) ? INPUT_CONTRACTS[contract] : INPUT_CONTRACTS.text;
2076
2116
  }
2077
2117
 
2078
2118
  /**
@@ -3125,6 +3165,7 @@ module.exports = {
3125
3165
  charThreatDisposition: charThreatDisposition,
3126
3166
  extractBytesAsText: extractBytesAsText,
3127
3167
  lookupCompliancePosture: lookupCompliancePosture,
3168
+ makePostureAccessor: makePostureAccessor,
3128
3169
  ALL_STRICT_POSTURES: ALL_STRICT_POSTURES,
3129
3170
  CHAR_THREATS_REJECT_ALL: CHAR_THREATS_REJECT_ALL,
3130
3171
  DANGEROUS_URL_SCHEMES: DANGEROUS_URL_SCHEMES,