@blamejs/blamejs-shop 0.5.12 → 0.5.13

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 (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -0,0 +1,2226 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * Layer 0 — lib/backup/index.js branch coverage.
6
+ *
7
+ * Targets input-validation / option-default / error-handling branches
8
+ * not exercised by test/00-primitives.js (create/recommendedFiles/
9
+ * run round-trip), backup-object-store-adapter, backup-find-bundles,
10
+ * backup-worker, or backup-residency-posture:
11
+ *
12
+ * - diskStorage direct: bad root, bad bundleId, bundle-exists,
13
+ * bundle-not-found, empty/filtered listBundles, delete/has no-op.
14
+ * - create(): residencyTag validation, schedule/scheduleTest
15
+ * wiring + arg validation, requireFlush hard-fail, HIPAA
16
+ * encrypt:false refusal.
17
+ * - verifyManifestSignature: bad-target / no-manifest / bad-manifest
18
+ * / parsed-object / on-disk string path.
19
+ * - bundleAdapterStorage: format / crypto-strategy / recipient /
20
+ * passphrase / entropy-floor / maxBundleBytes validation,
21
+ * bundle-too-large, opt-in posture gate, directory-format
22
+ * round-trip, bundleInfo / verifyBundle.
23
+ * - fsAdapter: traversal-key refusal, readPartial / statKey /
24
+ * hasKey / deleteKey.
25
+ * - migrate(): bad-from / bad-to / bad bundleId, directory->tar
26
+ * round-trip + idempotency.
27
+ */
28
+
29
+ var fs = require("node:fs");
30
+ var path = require("node:path");
31
+ var os = require("node:os");
32
+ var b = require("../../index");
33
+ var helpers = require("../helpers");
34
+ var check = helpers.check;
35
+
36
+ var VALID_ID = "2026-04-27T14-00-00-123Z-a8f30b21";
37
+ var VALID_ID2 = "2026-04-27T14-30-00-456Z-b1c2d3e4";
38
+ var ABSENT_ID = "2026-04-27T09-00-00-000Z-ffffffff";
39
+ var ID_A = "2026-05-01T10-00-00-000Z-11111111";
40
+ var ID_B = "2026-05-01T10-05-00-000Z-22222222";
41
+ var ID_C = "2026-05-01T10-10-00-000Z-33333333";
42
+
43
+ // A strong passphrase that clears the default 80-bit entropy floor for
44
+ // the wrapWithPassphrase consumer path (matches the sibling backup
45
+ // crypto tests).
46
+ var STRONG_PP = "aLongCorrectHorseBatteryStaple9876!Phrase";
47
+
48
+ // A minimal in-memory adapter implementing ONLY the five required
49
+ // contract methods (no readPartial / statKey). Drives the "legacy
50
+ // adapter" branches: bundleInfo -> envelopeKind "unknown", listBundles
51
+ // with no per-bundle stat, etc. This is a legitimate custom-adapter
52
+ // consumer path, not a mock of a helper-provided fixture.
53
+ function _memAdapter() {
54
+ var store = new Map();
55
+ return {
56
+ async writeFile(key, bytes) { store.set(key, Buffer.from(bytes)); },
57
+ async readFile(key) {
58
+ if (!store.has(key)) {
59
+ var e = new b.backup.BackupError("backup/no-key", "mem: no key " + key);
60
+ throw e;
61
+ }
62
+ return Buffer.from(store.get(key));
63
+ },
64
+ async listKeys(prefix) {
65
+ var out = [];
66
+ store.forEach(function (_v, k) {
67
+ if (!prefix || k.indexOf(prefix) === 0) out.push(k);
68
+ });
69
+ return out;
70
+ },
71
+ async deleteKey(key) { store.delete(key); },
72
+ async hasKey(key) { return store.has(key); },
73
+ };
74
+ }
75
+
76
+ function _tmp(tag) {
77
+ return fs.mkdtempSync(path.join(os.tmpdir(), "bidx-" + tag + "-"));
78
+ }
79
+ function _rm(p) {
80
+ try { fs.rmSync(p, { recursive: true, force: true }); } catch (_e) { /* ignore */ }
81
+ }
82
+ function _mkSrcDir(files) {
83
+ var dir = _tmp("src");
84
+ Object.keys(files).forEach(function (rel) {
85
+ var full = path.join(dir, rel);
86
+ fs.mkdirSync(path.dirname(full), { recursive: true });
87
+ fs.writeFileSync(full, files[rel]);
88
+ });
89
+ return dir;
90
+ }
91
+ function _errOf(e) { return (e && (e.code || e.message)) || String(e); }
92
+
93
+ // ---- diskStorage ----
94
+
95
+ function testDiskStorageValidatesRoot() {
96
+ var threw = null;
97
+ try { b.backup.diskStorage({}); } catch (e) { threw = e; }
98
+ check("diskStorage: missing root refused with no-storage-root",
99
+ threw && threw.code === "backup/no-storage-root");
100
+ var threw2 = null;
101
+ try { b.backup.diskStorage({ root: "" }); } catch (e) { threw2 = e; }
102
+ check("diskStorage: empty root refused",
103
+ threw2 && threw2.code === "backup/no-storage-root");
104
+ }
105
+
106
+ async function testDiskStorageBadBundleId() {
107
+ var root = _tmp("ds-badid");
108
+ try {
109
+ var ds = b.backup.diskStorage({ root: root });
110
+ var src = _mkSrcDir({ "manifest.json": "{}" });
111
+ try {
112
+ var threw = null;
113
+ try { await ds.writeBundle("not-a-valid-id", src); } catch (e) { threw = e; }
114
+ check("diskStorage.writeBundle: bad bundleId refused",
115
+ threw && threw.code === "backup/bad-bundle-id");
116
+ } finally { _rm(src); }
117
+ } finally { _rm(root); }
118
+ }
119
+
120
+ async function testDiskStorageBundleExistsAndNotFound() {
121
+ var root = _tmp("ds-exists");
122
+ var src = _mkSrcDir({ "manifest.json": "{\"v\":1}", "files/a.enc": "AAA" });
123
+ try {
124
+ var ds = b.backup.diskStorage({ root: root });
125
+ await ds.writeBundle(VALID_ID, src);
126
+ check("diskStorage.hasBundle: true after write", await ds.hasBundle(VALID_ID));
127
+
128
+ var threw = null;
129
+ try { await ds.writeBundle(VALID_ID, src); } catch (e) { threw = e; }
130
+ check("diskStorage.writeBundle: duplicate id refused with bundle-exists",
131
+ threw && threw.code === "backup/bundle-exists");
132
+
133
+ var threw2 = null;
134
+ try { await ds.readBundle(ABSENT_ID, path.join(root, "out")); } catch (e) { threw2 = e; }
135
+ check("diskStorage.readBundle: absent bundle refused with bundle-not-found",
136
+ threw2 && threw2.code === "backup/bundle-not-found");
137
+ } finally { _rm(root); _rm(src); }
138
+ }
139
+
140
+ async function testDiskStorageListFiltersAndEmpty() {
141
+ // listBundles on a non-existent root returns [].
142
+ var missing = path.join(os.tmpdir(), "bidx-missing-" + Date.now());
143
+ var dsMissing = b.backup.diskStorage({ root: missing });
144
+ var empty = await dsMissing.listBundles();
145
+ check("diskStorage.listBundles: non-existent root returns []",
146
+ Array.isArray(empty) && empty.length === 0);
147
+
148
+ // listBundles skips non-bundle-id directories + stray files.
149
+ var root = _tmp("ds-list");
150
+ var src = _mkSrcDir({ "manifest.json": "{}", "files/a.enc": "A" });
151
+ try {
152
+ var ds = b.backup.diskStorage({ root: root });
153
+ await ds.writeBundle(VALID_ID, src);
154
+ fs.mkdirSync(path.join(root, "not-a-bundle-dir"));
155
+ fs.writeFileSync(path.join(root, "loose-file.txt"), "junk");
156
+ var listed = await ds.listBundles();
157
+ check("diskStorage.listBundles: only the valid bundle id is returned",
158
+ listed.length === 1 && listed[0].bundleId === VALID_ID);
159
+ check("diskStorage.listBundles: entry carries size + createdAt",
160
+ typeof listed[0].size === "number" && typeof listed[0].createdAt === "string");
161
+ } finally { _rm(root); _rm(src); }
162
+ }
163
+
164
+ async function testDiskStorageDeleteAndHasNoop() {
165
+ var root = _tmp("ds-del");
166
+ try {
167
+ var ds = b.backup.diskStorage({ root: root });
168
+ // deleteBundle on an absent-but-valid id is a silent no-op.
169
+ var threw = null;
170
+ try { await ds.deleteBundle(ABSENT_ID); } catch (e) { threw = e; }
171
+ check("diskStorage.deleteBundle: absent id is a no-op (no throw)", threw === null);
172
+ check("diskStorage.hasBundle: false for absent id", (await ds.hasBundle(ABSENT_ID)) === false);
173
+ // hasBundle on a malformed id refuses via _bundlePath.
174
+ var threw2 = null;
175
+ try { await ds.hasBundle("bad id"); } catch (e) { threw2 = e; }
176
+ check("diskStorage.hasBundle: malformed id returns false (swallowed)", threw2 === null);
177
+ } finally { _rm(root); }
178
+ }
179
+
180
+ // ---- create(): validation + wiring branches ----
181
+
182
+ function _createOpts(dataDir, root, extra) {
183
+ fs.writeFileSync(path.join(dataDir, "db.enc"), Buffer.from([1, 2, 3]));
184
+ var opts = {
185
+ dataDir: dataDir,
186
+ storage: b.backup.diskStorage({ root: root }),
187
+ passphrase: Buffer.from("operator-backup-passphrase"),
188
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
189
+ vaultKeyJson: '{"v":1}',
190
+ audit: false,
191
+ };
192
+ if (extra) Object.keys(extra).forEach(function (k) { opts[k] = extra[k]; });
193
+ return opts;
194
+ }
195
+
196
+ function testCreateResidencyTagValidation() {
197
+ var data = _tmp("res-data");
198
+ var root = _tmp("res-root");
199
+ try {
200
+ var threw = null;
201
+ try { b.backup.create(_createOpts(data, root, { residencyTag: 123 })); } catch (e) { threw = e; }
202
+ check("create: non-string residencyTag refused with bad-residency-tag",
203
+ threw && threw.code === "backup/bad-residency-tag");
204
+
205
+ var threw2 = null;
206
+ try { b.backup.create(_createOpts(data, root, { residencyTag: "" })); } catch (e) { threw2 = e; }
207
+ check("create: empty residencyTag refused",
208
+ threw2 && threw2.code === "backup/bad-residency-tag");
209
+
210
+ // null residencyTag is accepted (means "undeclared").
211
+ var eng = b.backup.create(_createOpts(data, root, { residencyTag: null }));
212
+ check("create: null residencyTag accepted", eng && typeof eng.run === "function");
213
+ } finally { _rm(data); _rm(root); }
214
+ }
215
+
216
+ function testCreateScheduleRequiresScheduler() {
217
+ var data = _tmp("sch-data");
218
+ var root = _tmp("sch-root");
219
+ try {
220
+ var eng = b.backup.create(_createOpts(data, root));
221
+ var threw = null;
222
+ try { eng.schedule({ cron: "0 3 * * *" }); } catch (e) { threw = e; }
223
+ check("create: schedule() without a scheduler refused with no-scheduler",
224
+ threw && threw.code === "backup/no-scheduler");
225
+ var threw2 = null;
226
+ try { eng.scheduleTest({ cron: "0 3 * * *", restoreTo: "/x", verify: function () {} }); } catch (e) { threw2 = e; }
227
+ check("create: scheduleTest() without a scheduler refused with no-scheduler",
228
+ threw2 && threw2.code === "backup/no-scheduler");
229
+ } finally { _rm(data); _rm(root); }
230
+ }
231
+
232
+ function testCreateScheduleArgValidation() {
233
+ var data = _tmp("scha-data");
234
+ var root = _tmp("scha-root");
235
+ try {
236
+ var scheduled = [];
237
+ var fakeScheduler = {
238
+ create: function () {
239
+ return { schedule: function (spec) { scheduled.push(spec); } };
240
+ },
241
+ };
242
+ var eng = b.backup.create(_createOpts(data, root, { scheduler: fakeScheduler }));
243
+
244
+ var threw = null;
245
+ try { eng.schedule({}); } catch (e) { threw = e; }
246
+ check("create: schedule() without cron refused with bad-schedule",
247
+ threw && threw.code === "backup/bad-schedule");
248
+
249
+ var handle = eng.schedule({ cron: "0 3 * * *", name: "nightly" });
250
+ check("create: schedule() returns { name, instance }",
251
+ handle && handle.name === "nightly" && handle.instance);
252
+ check("create: schedule() registered a job on the scheduler instance",
253
+ scheduled.length === 1 && scheduled[0].cron === "0 3 * * *" &&
254
+ typeof scheduled[0].run === "function");
255
+
256
+ var t1 = null;
257
+ try { eng.scheduleTest({}); } catch (e) { t1 = e; }
258
+ check("create: scheduleTest() without cron refused",
259
+ t1 && t1.code === "backup/bad-test-schedule");
260
+ var t2 = null;
261
+ try { eng.scheduleTest({ cron: "0 3 * * *" }); } catch (e) { t2 = e; }
262
+ check("create: scheduleTest() without restoreTo refused",
263
+ t2 && t2.code === "backup/bad-test-restore-to");
264
+ var t3 = null;
265
+ try { eng.scheduleTest({ cron: "0 3 * * *", restoreTo: "/x" }); } catch (e) { t3 = e; }
266
+ check("create: scheduleTest() without verify fn refused",
267
+ t3 && t3.code === "backup/bad-test-verify");
268
+
269
+ var testHandle = eng.scheduleTest({ cron: "0 3 * * *", restoreTo: "/x", verify: function () {} });
270
+ check("create: scheduleTest() returns a handle with default name",
271
+ testHandle && testHandle.name === "blamejs.backup.test");
272
+ } finally { _rm(data); _rm(root); }
273
+ }
274
+
275
+ async function testCreateRequireFlushHardFails() {
276
+ var data = _tmp("rf-data");
277
+ var root = _tmp("rf-root");
278
+ try {
279
+ var eng = b.backup.create(_createOpts(data, root, {
280
+ requireFlush: true,
281
+ flushBeforeBackup: function () { throw new Error("flush-broke"); },
282
+ }));
283
+ var threw = null;
284
+ try { await eng.run(); } catch (e) { threw = e; }
285
+ check("create: requireFlush + failing flush aborts run with flush-required-failed",
286
+ threw && threw.code === "backup/flush-required-failed");
287
+ // No bundle should have landed in storage.
288
+ var listed = await eng.list();
289
+ check("create: aborted flush leaves no bundle in storage", listed.length === 0);
290
+ } finally { _rm(data); _rm(root); }
291
+ }
292
+
293
+ function testCreateHipaaRefusesUnencrypted() {
294
+ var data = _tmp("hip-data");
295
+ var root = _tmp("hip-root");
296
+ b.compliance.clear();
297
+ b.compliance.set("hipaa");
298
+ try {
299
+ var threw = null;
300
+ try { b.backup.create(_createOpts(data, root, { encrypt: false })); } catch (e) { threw = e; }
301
+ check("create: HIPAA posture + encrypt:false refused with encryption-required",
302
+ threw && threw.code === "backup/encryption-required");
303
+ // Default (encrypt on) still constructs under HIPAA.
304
+ var eng = b.backup.create(_createOpts(data, root));
305
+ check("create: HIPAA posture + default encryption constructs",
306
+ eng && typeof eng.run === "function");
307
+ } finally {
308
+ b.compliance.clear();
309
+ _rm(data); _rm(root);
310
+ }
311
+ }
312
+
313
+ // ---- verifyManifestSignature ----
314
+
315
+ function testVerifyManifestSignatureBadTarget() {
316
+ var t1 = null;
317
+ try { b.backup.verifyManifestSignature(12345); } catch (e) { t1 = e; }
318
+ check("verifyManifestSignature: numeric target refused with bad-target",
319
+ t1 && t1.code === "backup/bad-target");
320
+ var t2 = null;
321
+ try { b.backup.verifyManifestSignature(null); } catch (e) { t2 = e; }
322
+ check("verifyManifestSignature: null target refused with bad-target",
323
+ t2 && t2.code === "backup/bad-target");
324
+ }
325
+
326
+ function testVerifyManifestSignatureNoManifest() {
327
+ var dir = _tmp("vms-none");
328
+ try {
329
+ var threw = null;
330
+ try { b.backup.verifyManifestSignature(dir); } catch (e) { threw = e; }
331
+ check("verifyManifestSignature: missing manifest.json refused with no-manifest",
332
+ threw && threw.code === "backup/no-manifest");
333
+ } finally { _rm(dir); }
334
+ }
335
+
336
+ function testVerifyManifestSignatureBadManifest() {
337
+ var dir = _tmp("vms-bad");
338
+ try {
339
+ fs.writeFileSync(path.join(dir, "manifest.json"), "{ this is not valid json ");
340
+ var threw = null;
341
+ try { b.backup.verifyManifestSignature(dir); } catch (e) { threw = e; }
342
+ check("verifyManifestSignature: unparseable manifest refused with bad-manifest",
343
+ threw && threw.code === "backup/bad-manifest");
344
+ } finally { _rm(dir); }
345
+ }
346
+
347
+ function testVerifyManifestSignatureParsedObject() {
348
+ // A parsed manifest object (version number) with no signature block is
349
+ // NOT a throw — it returns a verdict the caller branches on.
350
+ var verdict = b.backup.verifyManifestSignature({ version: 1 });
351
+ check("verifyManifestSignature: unsigned parsed manifest returns ok:false verdict",
352
+ verdict && verdict.ok === false && typeof verdict.reason === "string");
353
+ // { manifest } wrapper form takes the same path.
354
+ var verdict2 = b.backup.verifyManifestSignature({ manifest: { version: 1 } });
355
+ check("verifyManifestSignature: { manifest } wrapper returns a verdict",
356
+ verdict2 && verdict2.ok === false);
357
+ }
358
+
359
+ async function testVerifyManifestSignatureOnDiskStringPath() {
360
+ // Drive the on-disk string-path reader end-to-end through a real
361
+ // create()/read() bundle (the branch is otherwise integration-only).
362
+ var data = _tmp("vms-disk-data");
363
+ var root = _tmp("vms-disk-root");
364
+ var pull = path.join(os.tmpdir(), "bidx-vms-pull-" + Date.now());
365
+ try {
366
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("ENC"));
367
+ var eng = b.backup.create({
368
+ dataDir: data,
369
+ storage: b.backup.diskStorage({ root: root }),
370
+ passphrase: Buffer.from("pp"),
371
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
372
+ vaultKeyJson: '{"v":1}',
373
+ audit: false,
374
+ });
375
+ var r = await eng.run();
376
+ await eng.read(r.bundleId, pull);
377
+ var verdict = b.backup.verifyManifestSignature(pull);
378
+ check("verifyManifestSignature: on-disk manifest parses + returns a verdict object",
379
+ verdict && typeof verdict.ok === "boolean");
380
+ // Pinning a fingerprint the manifest can't satisfy returns ok:false,
381
+ // not a throw.
382
+ var pinned = b.backup.verifyManifestSignature(pull, {
383
+ expectedFingerprint: "de".repeat(64),
384
+ });
385
+ check("verifyManifestSignature: unmatchable pinned fingerprint returns ok:false",
386
+ pinned && pinned.ok === false);
387
+ } finally { _rm(data); _rm(root); _rm(pull); }
388
+ }
389
+
390
+ // ---- bundleAdapterStorage: construction validation ----
391
+
392
+ function _fsAdapter(tag) {
393
+ return b.backup.bundleAdapterStorage.fsAdapter({ root: _tmp(tag) });
394
+ }
395
+
396
+ function testAdapterStorageConstructionValidation() {
397
+ var t;
398
+
399
+ t = null;
400
+ try { b.backup.bundleAdapterStorage({ adapter: {} }); } catch (e) { t = e; }
401
+ check("bundleAdapterStorage: adapter missing methods refused with bad-adapter",
402
+ t && t.code === "backup/bad-adapter");
403
+
404
+ t = null;
405
+ try { b.backup.bundleAdapterStorage({ adapter: _fsAdapter("f1"), format: "zip" }); } catch (e) { t = e; }
406
+ check("bundleAdapterStorage: unknown format refused with bad-format",
407
+ t && t.code === "backup/bad-format");
408
+
409
+ t = null;
410
+ try { b.backup.bundleAdapterStorage({ adapter: _fsAdapter("f2"), cryptoStrategy: "rot13" }); } catch (e) { t = e; }
411
+ check("bundleAdapterStorage: unknown cryptoStrategy refused with bad-crypto-strategy",
412
+ t && t.code === "backup/bad-crypto-strategy");
413
+
414
+ t = null;
415
+ try { b.backup.bundleAdapterStorage({ adapter: _fsAdapter("f3"), cryptoStrategy: "recipient" }); } catch (e) { t = e; }
416
+ check("bundleAdapterStorage: recipient strategy without recipient refused with no-recipient",
417
+ t && t.code === "backup/no-recipient");
418
+
419
+ t = null;
420
+ try { b.backup.bundleAdapterStorage({ adapter: _fsAdapter("f4"), cryptoStrategy: "passphrase" }); } catch (e) { t = e; }
421
+ check("bundleAdapterStorage: passphrase strategy without passphrase refused with no-passphrase",
422
+ t && t.code === "backup/no-passphrase");
423
+
424
+ t = null;
425
+ try {
426
+ b.backup.bundleAdapterStorage({
427
+ adapter: _fsAdapter("f5"), cryptoStrategy: "recipient", recipient: {}, format: "directory",
428
+ });
429
+ } catch (e) { t = e; }
430
+ check("bundleAdapterStorage: recipient + directory format refused (envelope needs bundled format)",
431
+ t && t.code === "backup/recipient-strategy-needs-bundled-format");
432
+ }
433
+
434
+ function testAdapterStorageEntropyFloorValidation() {
435
+ // NaN / Infinity / negative passphraseMinEntropyBits must be refused
436
+ // upfront so the HIPAA/PCI-DSS 128-bit floor can't be NaN'd out.
437
+ ["nan", "inf", "neg"].forEach(function (kind) {
438
+ var val = kind === "nan" ? NaN : kind === "inf" ? Infinity : -10;
439
+ var t = null;
440
+ try {
441
+ b.backup.bundleAdapterStorage({
442
+ adapter: _fsAdapter("ent-" + kind),
443
+ cryptoStrategy: "passphrase",
444
+ passphrase: "x",
445
+ passphraseMinEntropyBits: val,
446
+ });
447
+ } catch (e) { t = e; }
448
+ check("bundleAdapterStorage: passphraseMinEntropyBits=" + kind + " refused with bad-arg",
449
+ t && t.code === "backup/bad-arg");
450
+ });
451
+ }
452
+
453
+ function testAdapterStorageMaxBundleBytesValidation() {
454
+ ["nan", "neg", "zero"].forEach(function (kind) {
455
+ var val = kind === "nan" ? NaN : kind === "neg" ? -1 : 0;
456
+ var t = null;
457
+ try {
458
+ b.backup.bundleAdapterStorage({ adapter: _fsAdapter("mbb-" + kind), maxBundleBytes: val });
459
+ } catch (e) { t = e; }
460
+ check("bundleAdapterStorage: maxBundleBytes=" + kind + " refused with bad-arg",
461
+ t && t.code === "backup/bad-arg");
462
+ });
463
+ }
464
+
465
+ function testAdapterStoragePostureGateOptIn() {
466
+ // The posture gate is opt-in via opts.posture (see the reported
467
+ // asymmetry with create(), which reads the ambient posture). When
468
+ // opts.posture names a regulated posture, cryptoStrategy:"none" is
469
+ // refused.
470
+ var t = null;
471
+ try {
472
+ b.backup.bundleAdapterStorage({ adapter: _fsAdapter("pg"), posture: "hipaa", cryptoStrategy: "none" });
473
+ } catch (e) { t = e; }
474
+ check("bundleAdapterStorage: opts.posture=hipaa + cryptoStrategy none refused",
475
+ t && t.code === "backup/posture-requires-encryption");
476
+ }
477
+
478
+ async function testAdapterStorageBundleTooLarge() {
479
+ var root = _tmp("tl-root");
480
+ var src = _mkSrcDir({ "big.bin": Buffer.alloc(2048) });
481
+ try {
482
+ var storage = b.backup.bundleAdapterStorage({
483
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
484
+ format: "tar",
485
+ maxBundleBytes: 512,
486
+ });
487
+ var threw = null;
488
+ try { await storage.writeBundle(VALID_ID, src); } catch (e) { threw = e; }
489
+ check("bundleAdapterStorage.writeBundle: oversize source refused with bundle-too-large",
490
+ threw && threw.code === "backup/bundle-too-large");
491
+ } finally { _rm(root); _rm(src); }
492
+ }
493
+
494
+ async function testAdapterStoragePassphraseFloorEnforcedOnWrite() {
495
+ // An explicit high entropy floor makes a weak passphrase fail at
496
+ // write time (drives the real wrapWithPassphrase consumer path).
497
+ var root = _tmp("pf-root");
498
+ var src = _mkSrcDir({ "a.txt": "data" });
499
+ try {
500
+ var storage = b.backup.bundleAdapterStorage({
501
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
502
+ format: "tar",
503
+ cryptoStrategy: "passphrase",
504
+ passphrase: "ab",
505
+ passphraseMinEntropyBits: 256,
506
+ });
507
+ var threw = null;
508
+ try { await storage.writeBundle(VALID_ID, src); } catch (e) { threw = e; }
509
+ check("bundleAdapterStorage: weak passphrase below entropy floor refused on write",
510
+ threw && /weak-passphrase|entropy/i.test(_errOf(threw)));
511
+ } finally { _rm(root); _rm(src); }
512
+ }
513
+
514
+ // ---- bundleAdapterStorage: directory-format round-trip ----
515
+
516
+ async function testAdapterStorageDirectoryRoundTrip() {
517
+ var root = _tmp("dir-root");
518
+ var src = _mkSrcDir({ "manifest.json": "{\"version\":1}", "files/a.enc": "AAA" });
519
+ var dest = path.join(os.tmpdir(), "bidx-dir-dest-" + Date.now());
520
+ try {
521
+ var storage = b.backup.bundleAdapterStorage({
522
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
523
+ format: "directory",
524
+ });
525
+ await storage.writeBundle(VALID_ID, src);
526
+ check("adapter/directory: hasBundle true after write", await storage.hasBundle(VALID_ID));
527
+
528
+ var info = await storage.bundleInfo(VALID_ID);
529
+ check("adapter/directory: bundleInfo reports directory format + no envelope",
530
+ info.format === "directory" && info.envelopeKind === "none");
531
+
532
+ var listed = await storage.listBundles();
533
+ check("adapter/directory: listBundles reports the bundle with directory format",
534
+ listed.length === 1 && listed[0].bundleId === VALID_ID && listed[0].format === "directory");
535
+
536
+ var vb = await storage.verifyBundle(VALID_ID);
537
+ check("adapter/directory: verifyBundle ok:true (manifest presence is the check)",
538
+ vb.ok === true && vb.format === "directory" && vb.entryCount === null);
539
+
540
+ await storage.readBundle(VALID_ID, dest);
541
+ check("adapter/directory: readBundle recovers the file bytes",
542
+ fs.readFileSync(path.join(dest, "files", "a.enc"), "utf8") === "AAA");
543
+
544
+ var dupe = null;
545
+ try { await storage.writeBundle(VALID_ID, src); } catch (e) { dupe = e; }
546
+ check("adapter/directory: duplicate write refused with bundle-exists",
547
+ dupe && dupe.code === "backup/bundle-exists");
548
+
549
+ var de = null;
550
+ try { await storage.readBundle(VALID_ID, dest); } catch (e) { de = e; }
551
+ check("adapter/directory: readBundle into existing dest refused with dest-exists",
552
+ de && de.code === "backup/dest-exists");
553
+
554
+ await storage.deleteBundle(VALID_ID);
555
+ check("adapter/directory: hasBundle false after delete",
556
+ (await storage.hasBundle(VALID_ID)) === false);
557
+ } finally { _rm(root); _rm(src); _rm(dest); }
558
+ }
559
+
560
+ async function testAdapterStorageTarVerifyAndMissing() {
561
+ var root = _tmp("tar-root");
562
+ var src = _mkSrcDir({ "x.txt": "hello", "y.txt": "world" });
563
+ try {
564
+ var storage = b.backup.bundleAdapterStorage({
565
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
566
+ format: "tar",
567
+ });
568
+ await storage.writeBundle(VALID_ID, src);
569
+ var vb = await storage.verifyBundle(VALID_ID);
570
+ check("adapter/tar: verifyBundle walks tar entries + counts them",
571
+ vb.ok === true && vb.format === "tar" && vb.entryCount === 2);
572
+
573
+ var nf = null;
574
+ try { await storage.bundleInfo(ABSENT_ID); } catch (e) { nf = e; }
575
+ check("adapter/tar: bundleInfo on absent bundle refused with bundle-not-found",
576
+ nf && nf.code === "backup/bundle-not-found");
577
+
578
+ var ns = null;
579
+ try { await storage.writeBundle(VALID_ID2, path.join(os.tmpdir(), "no-such-src-" + Date.now())); } catch (e) { ns = e; }
580
+ check("adapter/tar: writeBundle with missing sourceDir refused with no-source",
581
+ ns && ns.code === "backup/no-source");
582
+ } finally { _rm(root); _rm(src); }
583
+ }
584
+
585
+ // ---- fsAdapter capabilities ----
586
+
587
+ async function testFsAdapterTraversalRefused() {
588
+ var root = _tmp("fsad-trav");
589
+ try {
590
+ var adapter = b.backup.bundleAdapterStorage.fsAdapter({ root: root });
591
+ var t = null;
592
+ try { await adapter.writeFile("../escape", Buffer.from("x")); } catch (e) { t = e; }
593
+ check("fsAdapter.writeFile: traversal key refused with bad-key",
594
+ t && t.code === "backup/bad-key");
595
+
596
+ // A '..'-only pre-screen missed the absolute / drive-letter / NTFS-stream
597
+ // class the key resolves through under root. Each must be refused so a key
598
+ // built from untrusted input can't escape root or write a file's data
599
+ // stream. Sibling of the manifest.validate / bundle.create path checks.
600
+ var badKeys = {
601
+ "absolute key": "/etc/shadow",
602
+ "drive-letter key": "C:" + "\\" + "Windows" + "\\" + "evil",
603
+ "NTFS-ADS key": "blob.enc:evil",
604
+ // Cross-platform: a backslash-traversal key is a harmless literal filename
605
+ // under POSIX path semantics but climbs out of root when the portable
606
+ // store is later read on Windows, so it is gated under win32 semantics on
607
+ // every host. A host-only resolve would accept these on POSIX.
608
+ "backslash-parent key": ".." + "\\" + "evil",
609
+ "backslash-traversal key": "a" + "\\" + ".." + "\\" + ".." + "\\" + "evil",
610
+ };
611
+ for (var label in badKeys) {
612
+ if (!Object.prototype.hasOwnProperty.call(badKeys, label)) continue;
613
+ var te = null;
614
+ try { await adapter.writeFile(badKeys[label], Buffer.from("x")); } catch (e) { te = e; }
615
+ check("fsAdapter.writeFile: " + label + " refused with bad-key",
616
+ te && te.code === "backup/bad-key");
617
+ }
618
+ } finally { _rm(root); }
619
+ }
620
+
621
+ async function testFsAdapterReadPartialAndStat() {
622
+ var root = _tmp("fsad-rp");
623
+ try {
624
+ var adapter = b.backup.bundleAdapterStorage.fsAdapter({ root: root });
625
+ await adapter.writeFile("k1", Buffer.from("hello-world"));
626
+ var head = await adapter.readPartial("k1", 5);
627
+ check("fsAdapter.readPartial: returns only the requested leading bytes",
628
+ Buffer.isBuffer(head) && head.toString() === "hello");
629
+
630
+ var st = await adapter.statKey("k1");
631
+ check("fsAdapter.statKey: reports size + mtimeMs for an existing key",
632
+ st && st.size === 11 && typeof st.mtimeMs === "number");
633
+ check("fsAdapter.statKey: null for a missing key", (await adapter.statKey("nope")) === null);
634
+ check("fsAdapter.hasKey: true for existing / false for missing",
635
+ (await adapter.hasKey("k1")) === true && (await adapter.hasKey("nope")) === false);
636
+
637
+ var t = null;
638
+ try { await adapter.readPartial("nope", 4); } catch (e) { t = e; }
639
+ check("fsAdapter.readPartial: missing key refused with no-key",
640
+ t && t.code === "backup/no-key");
641
+
642
+ var delThrew = null;
643
+ try { await adapter.deleteKey("nope"); } catch (e) { delThrew = e; }
644
+ check("fsAdapter.deleteKey: absent key is a silent no-op", delThrew === null);
645
+ } finally { _rm(root); }
646
+ }
647
+
648
+ // ---- migrate ----
649
+
650
+ async function testMigrateValidation() {
651
+ var t1 = null;
652
+ try { await b.backup.migrate({ from: {}, to: {} }); } catch (e) { t1 = e; }
653
+ check("migrate: bad from backend refused with bad-from",
654
+ t1 && t1.code === "backup/bad-from");
655
+
656
+ var t2 = null;
657
+ try {
658
+ await b.backup.migrate({
659
+ from: { readBundle: function () {}, listBundles: function () {} },
660
+ to: {},
661
+ });
662
+ } catch (e) { t2 = e; }
663
+ check("migrate: bad to backend refused with bad-to",
664
+ t2 && t2.code === "backup/bad-to");
665
+
666
+ var t3 = null;
667
+ try {
668
+ await b.backup.migrate({
669
+ from: { readBundle: function () {}, listBundles: function () {} },
670
+ to: { writeBundle: function () {}, hasBundle: function () {} },
671
+ bundleId: "not-valid",
672
+ });
673
+ } catch (e) { t3 = e; }
674
+ check("migrate: malformed bundleId refused with bad-bundle-id",
675
+ t3 && t3.code === "backup/bad-bundle-id");
676
+ }
677
+
678
+ async function testMigrateDirectoryToTarRoundTrip() {
679
+ var fromRoot = _tmp("mig-from");
680
+ var toRoot = _tmp("mig-to");
681
+ var src = _mkSrcDir({ "manifest.json": "{\"version\":1}", "files/d.enc": "DDD" });
682
+ try {
683
+ var from = b.backup.bundleAdapterStorage({
684
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: fromRoot }),
685
+ format: "directory",
686
+ });
687
+ var to = b.backup.bundleAdapterStorage({
688
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: toRoot }),
689
+ format: "tar",
690
+ });
691
+ await from.writeBundle(VALID_ID, src);
692
+
693
+ var result = await b.backup.migrate({ from: from, to: to });
694
+ check("migrate: directory->tar migrates the bundle",
695
+ result.migrated === 1 && result.skipped === 0 && result.total === 1);
696
+ check("migrate: destination now holds the bundle", await to.hasBundle(VALID_ID));
697
+ var toInfo = await to.bundleInfo(VALID_ID);
698
+ check("migrate: destination bundle is tar format", toInfo.format === "tar");
699
+
700
+ // Re-running is idempotent: destination already has it → skipped.
701
+ var again = await b.backup.migrate({ from: from, to: to });
702
+ check("migrate: re-run is idempotent (skipped, not re-migrated)",
703
+ again.migrated === 0 && again.skipped === 1);
704
+ } finally { _rm(fromRoot); _rm(toRoot); _rm(src); }
705
+ }
706
+
707
+ // ---- recommendedFiles ----
708
+
709
+ function testRecommendedFiles() {
710
+ // Default (encrypted + wrapped): db.enc + db.key.enc + vault.key.sealed
711
+ // + audit-sign key sealed.
712
+ var def = b.backup.recommendedFiles();
713
+ check("recommendedFiles: encrypted default includes db.enc + db.key.enc",
714
+ def[0].relativePath === "db.enc" && def[1].relativePath === "db.key.enc");
715
+ check("recommendedFiles: wrapped vault sealed + audit-sign sealed",
716
+ /vault\.key\.sealed$/.test(def[2].relativePath) && /\.sealed$/.test(def[3].relativePath) &&
717
+ def[3].required === false);
718
+
719
+ // Plain DB + plaintext vault: live db file + unsealed vault + unsealed
720
+ // audit key.
721
+ var plain = b.backup.recommendedFiles({ atRest: "plain", vaultMode: "plaintext", dbName: "app.db" });
722
+ check("recommendedFiles: plain at-rest uses the live db filename",
723
+ plain[0].relativePath === "app.db");
724
+ check("recommendedFiles: plaintext vault mode uses unsealed key names",
725
+ !/\.sealed$/.test(plain[1].relativePath) && !/\.sealed$/.test(plain[2].relativePath));
726
+
727
+ // Operator-supplied additional sealed files append as vault-sealed.
728
+ var extra = b.backup.recommendedFiles({ additionalSealed: ["ca.key.sealed", "tls/privkey.pem.sealed"] });
729
+ var tail = extra.slice(-2);
730
+ check("recommendedFiles: additionalSealed appended as vault-sealed entries",
731
+ tail[0].relativePath === "ca.key.sealed" && tail[0].kind === "vault-sealed" &&
732
+ tail[1].relativePath === "tls/privkey.pem.sealed" && tail[1].required === false);
733
+ }
734
+
735
+ // ---- create(): run() happy path + retention + error branches ----
736
+
737
+ async function testCreateRunRoundTripAndRetention() {
738
+ var data = _tmp("run-data");
739
+ var root = _tmp("run-root");
740
+ var pull = path.join(os.tmpdir(), "bidx-run-pull-" + Date.now());
741
+ try {
742
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("PAYLOAD-1"));
743
+ var eng = b.backup.create({
744
+ dataDir: data,
745
+ storage: b.backup.diskStorage({ root: root }),
746
+ passphrase: Buffer.from("operator-backup-passphrase-256bit"),
747
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
748
+ // Async vaultKeyJson resolver drives the promise-await branch.
749
+ vaultKeyJson: async function () { return '{"version":1}'; },
750
+ retention: { keep: 1 },
751
+ audit: false,
752
+ });
753
+ var r1 = await eng.run({ metadata: { reason: "first" } });
754
+ check("create.run: returns a summary with bundleId + fileCount + durationMs",
755
+ typeof r1.bundleId === "string" && typeof r1.fileCount === "number" &&
756
+ typeof r1.durationMs === "number" && r1.storage === "local");
757
+ // Second run trips retention keep:1 -> the older bundle is swept.
758
+ var r2 = await eng.run();
759
+ check("create.run: retention swept the older bundle (keep:1)",
760
+ typeof r2.retentionPurged !== "undefined" && r2.retentionPurged.length === 1);
761
+ var listed = await eng.list();
762
+ check("create.run: exactly one bundle remains after retention sweep",
763
+ listed.length === 1 && listed[0].bundleId === r2.bundleId);
764
+
765
+ // read() the surviving bundle back through the consumer path.
766
+ await eng.read(r2.bundleId, pull);
767
+ check("create.read: recovers the bundle manifest",
768
+ fs.existsSync(path.join(pull, "manifest.json")));
769
+
770
+ // delete() through the consumer path.
771
+ await eng.delete(r2.bundleId);
772
+ check("create.delete: bundle gone after delete",
773
+ (await eng.list()).length === 0);
774
+ } finally { _rm(data); _rm(root); _rm(pull); }
775
+ }
776
+
777
+ async function testCreateRunFlushWarningBestEffort() {
778
+ // requireFlush omitted (best-effort): a failing flush logs a warning
779
+ // but the run continues to produce a bundle.
780
+ var data = _tmp("fw2-data");
781
+ var root = _tmp("fw2-root");
782
+ try {
783
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
784
+ var eng = b.backup.create({
785
+ dataDir: data,
786
+ storage: b.backup.diskStorage({ root: root }),
787
+ passphrase: "pp",
788
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
789
+ vaultKeyJson: '{"v":1}',
790
+ flushBeforeBackup: function () { throw new Error("flush-broke-but-soft"); },
791
+ audit: false,
792
+ });
793
+ var r = await eng.run();
794
+ check("create.run: best-effort flush failure does NOT abort the run",
795
+ typeof r.bundleId === "string" && (await eng.list()).length === 1);
796
+ } finally { _rm(data); _rm(root); }
797
+ }
798
+
799
+ async function testCreateRunVaultKeyJsonFailures() {
800
+ var data = _tmp("vk-data");
801
+ var root = _tmp("vk-root");
802
+ try {
803
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
804
+ // vaultKeyJson function returning an empty string -> bad-vault-key.
805
+ var eng1 = b.backup.create({
806
+ dataDir: data, storage: b.backup.diskStorage({ root: root }),
807
+ passphrase: "pp", files: [{ relativePath: "db.enc", kind: "raw", required: true }],
808
+ vaultKeyJson: function () { return ""; }, audit: false,
809
+ });
810
+ var t1 = null;
811
+ try { await eng1.run(); } catch (e) { t1 = e; }
812
+ check("create.run: vaultKeyJson fn returning empty string refused with bad-vault-key",
813
+ t1 && t1.code === "backup/bad-vault-key");
814
+
815
+ // vaultKeyJson of the wrong type (number, not string/function) is
816
+ // accepted at construction (!== undefined) but fails inside run().
817
+ var eng2 = b.backup.create({
818
+ dataDir: data, storage: b.backup.diskStorage({ root: root }),
819
+ passphrase: "pp", files: [{ relativePath: "db.enc", kind: "raw", required: true }],
820
+ vaultKeyJson: 12345, audit: false,
821
+ });
822
+ var t2 = null;
823
+ try { await eng2.run(); } catch (e) { t2 = e; }
824
+ check("create.run: non-string/non-fn vaultKeyJson refused with no-vault-key-json",
825
+ t2 && t2.code === "backup/no-vault-key-json");
826
+ } finally { _rm(data); _rm(root); }
827
+ }
828
+
829
+ async function testCreateRunBackupBundleFailure() {
830
+ // A required include file that doesn't exist makes backupBundle.create
831
+ // throw; run() cleans staging + rethrows.
832
+ var data = _tmp("bb-data");
833
+ var root = _tmp("bb-root");
834
+ try {
835
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
836
+ var eng = b.backup.create({
837
+ dataDir: data, storage: b.backup.diskStorage({ root: root }),
838
+ passphrase: "pp",
839
+ files: [{ relativePath: "does-not-exist.enc", kind: "raw", required: true }],
840
+ vaultKeyJson: '{"v":1}', audit: false,
841
+ });
842
+ var threw = null;
843
+ try { await eng.run(); } catch (e) { threw = e; }
844
+ check("create.run: missing required include file aborts the run",
845
+ threw !== null);
846
+ check("create.run: no bundle landed after bundle-build failure",
847
+ (await eng.list()).length === 0);
848
+ } finally { _rm(data); _rm(root); }
849
+ }
850
+
851
+ async function testCreateRunStorageWriteFailure() {
852
+ var data = _tmp("sw-data");
853
+ var root = _tmp("sw-root");
854
+ try {
855
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
856
+ var base = b.backup.diskStorage({ root: root });
857
+ var storage = Object.assign({}, base, {
858
+ writeBundle: async function () { throw new Error("disk-full"); },
859
+ });
860
+ var eng = b.backup.create({
861
+ dataDir: data, storage: storage, passphrase: "pp",
862
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
863
+ vaultKeyJson: '{"v":1}', audit: false,
864
+ });
865
+ var threw = null;
866
+ try { await eng.run(); } catch (e) { threw = e; }
867
+ check("create.run: storage.writeBundle failure surfaces as storage-write-failed",
868
+ threw && threw.code === "backup/storage-write-failed");
869
+ } finally { _rm(data); _rm(root); }
870
+ }
871
+
872
+ async function testCreateRetentionSweepFailure() {
873
+ // A storage whose listBundles throws makes purgeOlder throw; the
874
+ // retention sweep is best-effort so the run still SUCCEEDS.
875
+ var data = _tmp("rs-data");
876
+ var root = _tmp("rs-root");
877
+ try {
878
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
879
+ var base = b.backup.diskStorage({ root: root });
880
+ var listCalls = 0;
881
+ var storage = Object.assign({}, base, {
882
+ listBundles: async function () {
883
+ listCalls += 1;
884
+ // First call is the retention sweep inside run() -> throw so the
885
+ // sweep fails; later direct list() calls succeed.
886
+ if (listCalls === 1) throw new Error("list-transient");
887
+ return base.listBundles();
888
+ },
889
+ });
890
+ var eng = b.backup.create({
891
+ dataDir: data, storage: storage, passphrase: "pp",
892
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
893
+ vaultKeyJson: '{"v":1}', retention: { keep: 2 }, audit: false,
894
+ });
895
+ var r = await eng.run();
896
+ check("create.run: retention sweep failure does not fail the run",
897
+ typeof r.bundleId === "string" && typeof r.retentionPurged === "undefined");
898
+ check("create.run: the bundle is still written despite sweep failure",
899
+ (await eng.list()).length === 1);
900
+ } finally { _rm(data); _rm(root); }
901
+ }
902
+
903
+ async function testCreatePurgeOlderPerBundleDeleteFailure() {
904
+ // purgeOlder swallows per-bundle delete failures (best-effort) and
905
+ // reports only the ids it managed to delete.
906
+ var data = _tmp("pg-data");
907
+ var root = _tmp("pg-root");
908
+ try {
909
+ var base = b.backup.diskStorage({ root: root });
910
+ var storage = Object.assign({}, base, {
911
+ deleteBundle: async function () { throw new Error("delete-denied"); },
912
+ });
913
+ // Seed two bundles directly so purgeOlder has something to sweep.
914
+ var srcDir = _mkSrcDir({ "manifest.json": "{}" });
915
+ await base.writeBundle(ID_A, srcDir);
916
+ await base.writeBundle(ID_B, srcDir);
917
+ _rm(srcDir);
918
+ var eng = b.backup.create({
919
+ dataDir: (fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X")), data),
920
+ storage: storage, passphrase: "pp",
921
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
922
+ vaultKeyJson: '{"v":1}', audit: false,
923
+ });
924
+ var res = await eng.purgeOlder({ keep: 0 });
925
+ check("create.purgeOlder: delete failures leave deleted list empty (best-effort)",
926
+ res.kept === 0 && res.deleted.length === 0);
927
+ } finally { _rm(data); _rm(root); }
928
+ }
929
+
930
+ async function testCreateDeleteReadBadId() {
931
+ var data = _tmp("dr-data");
932
+ var root = _tmp("dr-root");
933
+ try {
934
+ var eng = b.backup.create(_createOpts(data, root));
935
+ var t1 = null;
936
+ try { await eng.delete("not-a-valid-id"); } catch (e) { t1 = e; }
937
+ check("create.delete: malformed bundleId refused with bad-bundle-id",
938
+ t1 && t1.code === "backup/bad-bundle-id");
939
+ var t2 = null;
940
+ try { await eng.read("not-a-valid-id", "/x"); } catch (e) { t2 = e; }
941
+ check("create.read: malformed bundleId refused with bad-bundle-id",
942
+ t2 && t2.code === "backup/bad-bundle-id");
943
+ } finally { _rm(data); _rm(root); }
944
+ }
945
+
946
+ // ---- create(): residency posture branches (no db needed) ----
947
+
948
+ function testCreateResidencyUndeclaredWarning() {
949
+ var data = _tmp("ru-data");
950
+ var root = _tmp("ru-root");
951
+ b.compliance.clear();
952
+ b.compliance.set("gdpr");
953
+ try {
954
+ // Under a regulated posture with NO residencyTag + no db residency,
955
+ // create() emits an advisory (undeclared) warning and constructs.
956
+ var eng = b.backup.create(_createOpts(data, root));
957
+ check("create: gdpr posture + undeclared residency constructs (advisory only)",
958
+ eng && typeof eng.run === "function");
959
+ } finally { b.compliance.clear(); _rm(data); _rm(root); }
960
+ }
961
+
962
+ function testCreateResidencyPerRowCrossBorder() {
963
+ var data = _tmp("rp-data");
964
+ var root = _tmp("rp-root");
965
+ b.compliance.clear();
966
+ b.compliance.set("gdpr");
967
+ // Declare a per-row-residency table that admits rows in a region other
968
+ // than the backup destination; create() surfaces the per-row
969
+ // cross-border advisory (policy-based; no db / row scan needed).
970
+ b.cryptoField.declarePerRowResidency("bidx_residents", {
971
+ residencyColumn: "region",
972
+ allowedTags: ["eu-west-1", "us-east-1", "global"],
973
+ });
974
+ try {
975
+ var eng = b.backup.create(_createOpts(data, root, { residencyTag: "eu-west-1" }));
976
+ check("create: gdpr + declared per-row cross-border region constructs (advisory)",
977
+ eng && typeof eng.run === "function");
978
+ // Confirm the declaration is what the create() path reads.
979
+ var declared = b.cryptoField.listPerRowResidency();
980
+ check("create: per-row residency declaration is visible to the residency gate",
981
+ declared.some(function (t) { return t.table === "bidx_residents"; }));
982
+ } finally {
983
+ b.compliance.clear();
984
+ _rm(data); _rm(root);
985
+ }
986
+ }
987
+
988
+ // ---- bundleAdapterStorage: tar.gz / recipient / passphrase round-trips ----
989
+
990
+ async function testAdapterTarGzRoundTrip() {
991
+ var root = _tmp("tgz-root");
992
+ var src = _mkSrcDir({ "manifest.json": "{\"version\":1}", "files/a.enc": "AAAA" });
993
+ var dest = path.join(os.tmpdir(), "bidx-tgz-dest-" + Date.now());
994
+ try {
995
+ var storage = b.backup.bundleAdapterStorage({
996
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
997
+ format: "tar.gz",
998
+ });
999
+ await storage.writeBundle(VALID_ID, src);
1000
+ var info = await storage.bundleInfo(VALID_ID);
1001
+ check("adapter/tar.gz: bundleInfo reports tar.gz format + none envelope + size",
1002
+ info.format === "tar.gz" && info.envelopeKind === "none" &&
1003
+ typeof info.sizeBytes === "number" && info.sizeBytes > 0);
1004
+ var vb = await storage.verifyBundle(VALID_ID);
1005
+ check("adapter/tar.gz: verifyBundle walks the gz-wrapped tar entries",
1006
+ vb.ok === true && vb.format === "tar.gz" && vb.entryCount === 2);
1007
+ await storage.readBundle(VALID_ID, dest);
1008
+ check("adapter/tar.gz: readBundle recovers the file bytes",
1009
+ fs.readFileSync(path.join(dest, "files", "a.enc"), "utf8") === "AAAA");
1010
+ } finally { _rm(root); _rm(src); _rm(dest); }
1011
+ }
1012
+
1013
+ async function testAdapterPassphraseRoundTrip() {
1014
+ var root = _tmp("pp-rt-root");
1015
+ var src = _mkSrcDir({ "a.txt": "secret-payload" });
1016
+ var dest = path.join(os.tmpdir(), "bidx-pp-dest-" + Date.now());
1017
+ try {
1018
+ var storage = b.backup.bundleAdapterStorage({
1019
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
1020
+ format: "tar",
1021
+ cryptoStrategy: "passphrase",
1022
+ passphrase: STRONG_PP,
1023
+ });
1024
+ await storage.writeBundle(VALID_ID, src);
1025
+ var info = await storage.bundleInfo(VALID_ID);
1026
+ check("adapter/passphrase: bundleInfo reports passphrase envelope",
1027
+ info.envelopeKind === "passphrase" && info.format === "tar");
1028
+ var vb = await storage.verifyBundle(VALID_ID);
1029
+ check("adapter/passphrase: verifyBundle decrypts + walks entries",
1030
+ vb.ok === true && vb.envelopeKind === "passphrase" && vb.entryCount === 1);
1031
+ await storage.readBundle(VALID_ID, dest);
1032
+ check("adapter/passphrase: readBundle decrypts under the configured passphrase",
1033
+ fs.readFileSync(path.join(dest, "a.txt"), "utf8") === "secret-payload");
1034
+ } finally { _rm(root); _rm(src); _rm(dest); }
1035
+ }
1036
+
1037
+ async function testAdapterRecipientRoundTrip() {
1038
+ var root = _tmp("rcp-rt-root");
1039
+ var src = _mkSrcDir({ "phi.json": "{\"patient\":7}" });
1040
+ var dest = path.join(os.tmpdir(), "bidx-rcp-dest-" + Date.now());
1041
+ try {
1042
+ var pair = b.crypto.generateEncryptionKeyPair();
1043
+ var storage = b.backup.bundleAdapterStorage({
1044
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
1045
+ format: "tar.gz",
1046
+ cryptoStrategy: "recipient",
1047
+ recipient: pair,
1048
+ });
1049
+ await storage.writeBundle(VALID_ID, src);
1050
+ var info = await storage.bundleInfo(VALID_ID);
1051
+ check("adapter/recipient: bundleInfo reports recipient envelope",
1052
+ info.envelopeKind === "recipient" && info.format === "tar.gz");
1053
+ var vb = await storage.verifyBundle(VALID_ID);
1054
+ check("adapter/recipient: verifyBundle unwraps + walks entries",
1055
+ vb.ok === true && vb.envelopeKind === "recipient" && vb.entryCount === 1);
1056
+ await storage.readBundle(VALID_ID, dest);
1057
+ check("adapter/recipient: readBundle unwraps under the configured recipient",
1058
+ fs.readFileSync(path.join(dest, "phi.json"), "utf8") === "{\"patient\":7}");
1059
+ } finally { _rm(root); _rm(src); _rm(dest); }
1060
+ }
1061
+
1062
+ async function testAdapterListBundlesWithStats() {
1063
+ var root = _tmp("ls-stat-root");
1064
+ var src = _mkSrcDir({ "a.txt": "x" });
1065
+ try {
1066
+ var storage = b.backup.bundleAdapterStorage({
1067
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
1068
+ format: "tar",
1069
+ });
1070
+ await storage.writeBundle(VALID_ID, src);
1071
+ var listed = await storage.listBundles({ withStats: true });
1072
+ check("adapter.listBundles({withStats}): fans out statKey for size + createdAt",
1073
+ listed.length === 1 && typeof listed[0].size === "number" && listed[0].size > 0 &&
1074
+ typeof listed[0].createdAt === "string");
1075
+ } finally { _rm(root); _rm(src); }
1076
+ }
1077
+
1078
+ async function testAdapterVerifyBundleErrorBranches() {
1079
+ var root = _tmp("vb-err-root");
1080
+ var src = _mkSrcDir({ "a.txt": "data" });
1081
+ try {
1082
+ var pair = b.crypto.generateEncryptionKeyPair();
1083
+ // Absent bundle -> bundleInfo throws -> verifyBundle returns ok:false.
1084
+ var plain = b.backup.bundleAdapterStorage({
1085
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }), format: "tar",
1086
+ });
1087
+ var vAbsent = await plain.verifyBundle(ABSENT_ID);
1088
+ check("verifyBundle: absent bundle -> ok:false with an error entry",
1089
+ vAbsent.ok === false && vAbsent.errors.length === 1);
1090
+
1091
+ // Write a recipient bundle, then verify it through a store with NO
1092
+ // recipient -> no-recipient-for-verify.
1093
+ var recStore = b.backup.bundleAdapterStorage({
1094
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
1095
+ format: "tar", cryptoStrategy: "recipient", recipient: pair,
1096
+ });
1097
+ await recStore.writeBundle(VALID_ID, src);
1098
+ var noKeyRec = await plain.verifyBundle(VALID_ID);
1099
+ check("verifyBundle: recipient bundle without a recipient -> no-recipient-for-verify",
1100
+ noKeyRec.ok === false && noKeyRec.errors.indexOf("backup/no-recipient-for-verify") !== -1);
1101
+
1102
+ // Write a passphrase bundle, verify through a store with no passphrase.
1103
+ var ppStore = b.backup.bundleAdapterStorage({
1104
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
1105
+ format: "tar", cryptoStrategy: "passphrase", passphrase: STRONG_PP,
1106
+ });
1107
+ await ppStore.writeBundle(VALID_ID2, src);
1108
+ var noKeyPp = await plain.verifyBundle(VALID_ID2);
1109
+ check("verifyBundle: passphrase bundle without a passphrase -> no-passphrase-for-verify",
1110
+ noKeyPp.ok === false && noKeyPp.errors.indexOf("backup/no-passphrase-for-verify") !== -1);
1111
+
1112
+ // Corrupt a tar.gz payload (invalid gzip magic) -> the decompress
1113
+ // step throws -> verifyBundle returns ok:false with the error captured.
1114
+ var corruptRoot = _tmp("vb-corrupt-root");
1115
+ try {
1116
+ var adapter = b.backup.bundleAdapterStorage.fsAdapter({ root: corruptRoot });
1117
+ var cStore = b.backup.bundleAdapterStorage({ adapter: adapter, format: "tar.gz" });
1118
+ await cStore.writeBundle(ID_A, src);
1119
+ await adapter.writeFile(ID_A + "/bundle.tar.gz", Buffer.from("definitely-not-gzip-bytes"));
1120
+ var vCorrupt = await cStore.verifyBundle(ID_A);
1121
+ check("verifyBundle: corrupt tar.gz payload -> ok:false with a captured error",
1122
+ vCorrupt.ok === false && vCorrupt.errors.length === 1);
1123
+ } finally { _rm(corruptRoot); }
1124
+ } finally { _rm(root); _rm(src); }
1125
+ }
1126
+
1127
+ async function testAdapterFindBundles() {
1128
+ var root = _tmp("find-root");
1129
+ var src = _mkSrcDir({ "a.txt": "x" });
1130
+ try {
1131
+ var storage = b.backup.bundleAdapterStorage({
1132
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }), format: "tar",
1133
+ });
1134
+ var bad = null;
1135
+ try { await storage.findBundles("not-a-fn"); } catch (e) { bad = e; }
1136
+ check("findBundles: non-function predicate refused with bad-arg",
1137
+ bad && bad.code === "backup/bad-arg");
1138
+
1139
+ await storage.writeBundle(ID_A, src);
1140
+ await storage.writeBundle(ID_B, src);
1141
+ var found = await storage.findBundles(function (entry) { return entry.bundleId === ID_B; });
1142
+ check("findBundles: returns only entries the predicate accepts",
1143
+ found.length === 1 && found[0].bundleId === ID_B);
1144
+ } finally { _rm(root); _rm(src); }
1145
+ }
1146
+
1147
+ async function testAdapterCloneBundle() {
1148
+ var root = _tmp("clone-root");
1149
+ var src = _mkSrcDir({ "a.txt": "clone-me" });
1150
+ try {
1151
+ var storage = b.backup.bundleAdapterStorage({
1152
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }), format: "tar",
1153
+ });
1154
+ await storage.writeBundle(ID_A, src);
1155
+
1156
+ var same = null;
1157
+ try { await storage.cloneBundle(ID_A, ID_A); } catch (e) { same = e; }
1158
+ check("cloneBundle: same src/dst id refused with clone-same-id",
1159
+ same && same.code === "backup/clone-same-id");
1160
+
1161
+ var res = await storage.cloneBundle(ID_A, ID_B);
1162
+ check("cloneBundle: tar clone copies the single payload key",
1163
+ res.format === "tar" && res.keysCopied === 1 && res.bytesCopied > 0 &&
1164
+ (await storage.hasBundle(ID_B)));
1165
+
1166
+ var dstExists = null;
1167
+ try { await storage.cloneBundle(ID_A, ID_B); } catch (e) { dstExists = e; }
1168
+ check("cloneBundle: existing dst without overwrite refused with clone-dst-exists",
1169
+ dstExists && dstExists.code === "backup/clone-dst-exists");
1170
+
1171
+ // overwrite:true purges the destination first, then re-copies.
1172
+ var res2 = await storage.cloneBundle(ID_A, ID_B, { overwrite: true });
1173
+ check("cloneBundle: overwrite:true replaces the destination bytes",
1174
+ res2.keysCopied === 1 && (await storage.hasBundle(ID_B)));
1175
+
1176
+ // Directory-format clone walks every key under the source prefix.
1177
+ var dirRoot = _tmp("clone-dir-root");
1178
+ try {
1179
+ var dirStore = b.backup.bundleAdapterStorage({
1180
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dirRoot }), format: "directory",
1181
+ });
1182
+ var dsrc = _mkSrcDir({ "manifest.json": "{\"version\":1}", "files/a.enc": "DD" });
1183
+ try {
1184
+ await dirStore.writeBundle(ID_A, dsrc);
1185
+ var dres = await dirStore.cloneBundle(ID_A, ID_C);
1186
+ check("cloneBundle: directory clone copies every key under the prefix",
1187
+ dres.format === "directory" && dres.keysCopied >= 2 && (await dirStore.hasBundle(ID_C)));
1188
+ } finally { _rm(dsrc); }
1189
+ } finally { _rm(dirRoot); }
1190
+ } finally { _rm(root); _rm(src); }
1191
+ }
1192
+
1193
+ async function testAdapterRewrapBundleBranches() {
1194
+ var src = _mkSrcDir({ "a.txt": "rewrap-me" });
1195
+ try {
1196
+ // format-not-wrappable: a directory bundle carries no envelope.
1197
+ var dirRoot = _tmp("rw-dir-root");
1198
+ try {
1199
+ var dirStore = b.backup.bundleAdapterStorage({
1200
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dirRoot }), format: "directory",
1201
+ });
1202
+ var dsrc = _mkSrcDir({ "manifest.json": "{}" });
1203
+ try {
1204
+ await dirStore.writeBundle(VALID_ID, dsrc);
1205
+ var nf = null;
1206
+ try { await dirStore.rewrapBundle(VALID_ID, {}); } catch (e) { nf = e; }
1207
+ check("rewrapBundle: directory bundle refused with format-not-wrappable",
1208
+ nf && nf.code === "backup/format-not-wrappable");
1209
+ } finally { _rm(dsrc); }
1210
+ } finally { _rm(dirRoot); }
1211
+
1212
+ // no-envelope-to-rewrap: a plaintext tar bundle has envelopeKind none.
1213
+ var plainRoot = _tmp("rw-plain-root");
1214
+ try {
1215
+ var plainStore = b.backup.bundleAdapterStorage({
1216
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: plainRoot }), format: "tar",
1217
+ });
1218
+ await plainStore.writeBundle(VALID_ID, src);
1219
+ var ne = null;
1220
+ try { await plainStore.rewrapBundle(VALID_ID, {}); } catch (e) { ne = e; }
1221
+ check("rewrapBundle: plaintext tar bundle refused with no-envelope-to-rewrap",
1222
+ ne && ne.code === "backup/no-envelope-to-rewrap");
1223
+ } finally { _rm(plainRoot); }
1224
+
1225
+ // passphrase rewrap: missing newPassphrase, then a real rotation.
1226
+ var ppRoot = _tmp("rw-pp-root");
1227
+ var ppVerify = path.join(os.tmpdir(), "bidx-rw-pp-v-" + Date.now());
1228
+ try {
1229
+ var oldPp = b.crypto.generateBytes(24).toString("hex");
1230
+ var newPp = b.crypto.generateBytes(24).toString("hex");
1231
+ var ppStore = b.backup.bundleAdapterStorage({
1232
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: ppRoot }),
1233
+ format: "tar", cryptoStrategy: "passphrase", passphrase: oldPp,
1234
+ });
1235
+ await ppStore.writeBundle(VALID_ID, src);
1236
+ var noNew = null;
1237
+ try { await ppStore.rewrapBundle(VALID_ID, {}); } catch (e) { noNew = e; }
1238
+ check("rewrapBundle: passphrase rotation without newPassphrase refused",
1239
+ noNew && noNew.code === "backup/no-new-passphrase");
1240
+ var rw = await ppStore.rewrapBundle(VALID_ID, { newPassphrase: newPp });
1241
+ check("rewrapBundle: passphrase rotation returns passphrase envelope kinds",
1242
+ rw.oldEnvelopeKind === "passphrase" && rw.newEnvelopeKind === "passphrase" &&
1243
+ rw.bytesRewritten > 0);
1244
+ var rotated = b.backup.bundleAdapterStorage({
1245
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: ppRoot }),
1246
+ format: "tar", cryptoStrategy: "passphrase", passphrase: newPp,
1247
+ });
1248
+ await rotated.readBundle(VALID_ID, ppVerify);
1249
+ check("rewrapBundle: bundle restores under the NEW passphrase after rotation",
1250
+ fs.readFileSync(path.join(ppVerify, "a.txt"), "utf8") === "rewrap-me");
1251
+ } finally { _rm(ppRoot); _rm(ppVerify); }
1252
+
1253
+ // recipient rewrap: missing newRecipient, then a real rotation.
1254
+ var rcpRoot = _tmp("rw-rcp-root");
1255
+ try {
1256
+ var oldPair = b.crypto.generateEncryptionKeyPair();
1257
+ var newPair = b.crypto.generateEncryptionKeyPair();
1258
+ var rcpStore = b.backup.bundleAdapterStorage({
1259
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: rcpRoot }),
1260
+ format: "tar.gz", cryptoStrategy: "recipient", recipient: oldPair,
1261
+ });
1262
+ await rcpStore.writeBundle(VALID_ID, src);
1263
+ var noNewR = null;
1264
+ try { await rcpStore.rewrapBundle(VALID_ID, {}); } catch (e) { noNewR = e; }
1265
+ check("rewrapBundle: recipient rotation without newRecipient refused",
1266
+ noNewR && noNewR.code === "backup/no-new-recipient");
1267
+ var rwR = await rcpStore.rewrapBundle(VALID_ID, { newRecipient: newPair });
1268
+ check("rewrapBundle: recipient rotation returns recipient envelope kinds",
1269
+ rwR.oldEnvelopeKind === "recipient" && rwR.newEnvelopeKind === "recipient");
1270
+ } finally { _rm(rcpRoot); }
1271
+ } finally { _rm(src); }
1272
+ }
1273
+
1274
+ async function testAdapterKeyRotationBranches() {
1275
+ var src = _mkSrcDir({ "a.txt": "rotate" });
1276
+ try {
1277
+ // dualWrap unsupported.
1278
+ var noneRoot = _tmp("kr-none-root");
1279
+ try {
1280
+ var noneStore = b.backup.bundleAdapterStorage({
1281
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: noneRoot }), format: "tar",
1282
+ });
1283
+ var dw = null;
1284
+ try { await noneStore.keyRotation({ dualWrap: true }); } catch (e) { dw = e; }
1285
+ check("keyRotation: dualWrap refused with dual-wrap-unsupported",
1286
+ dw && dw.code === "backup/dual-wrap-unsupported");
1287
+ var noEnv = null;
1288
+ try { await noneStore.keyRotation({}); } catch (e) { noEnv = e; }
1289
+ check("keyRotation: cryptoStrategy none refused with no-envelope-to-rewrap",
1290
+ noEnv && noEnv.code === "backup/no-envelope-to-rewrap");
1291
+ } finally { _rm(noneRoot); }
1292
+
1293
+ // recipient storage without newRecipient.
1294
+ var rcpRoot = _tmp("kr-rcp-root");
1295
+ try {
1296
+ var rcpStore = b.backup.bundleAdapterStorage({
1297
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: rcpRoot }),
1298
+ format: "tar.gz", cryptoStrategy: "recipient", recipient: b.crypto.generateEncryptionKeyPair(),
1299
+ });
1300
+ var noR = null;
1301
+ try { await rcpStore.keyRotation({}); } catch (e) { noR = e; }
1302
+ check("keyRotation: recipient strategy without newRecipient refused with no-recipient",
1303
+ noR && noR.code === "backup/no-recipient");
1304
+ } finally { _rm(rcpRoot); }
1305
+
1306
+ // passphrase storage without newPassphrase, then a full rotation +
1307
+ // post-rotation verify (composes rewrapAllBundles + verifyAllBundles).
1308
+ var ppRoot = _tmp("kr-pp-root");
1309
+ try {
1310
+ var oldPp = b.crypto.generateBytes(24).toString("hex");
1311
+ var newPp = b.crypto.generateBytes(24).toString("hex");
1312
+ var ppStore = b.backup.bundleAdapterStorage({
1313
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: ppRoot }),
1314
+ format: "tar", cryptoStrategy: "passphrase", passphrase: oldPp, audit: false,
1315
+ });
1316
+ var badPp = null;
1317
+ try { await ppStore.keyRotation({}); } catch (e) { badPp = e; }
1318
+ check("keyRotation: passphrase strategy without newPassphrase refused with bad-passphrase",
1319
+ badPp && badPp.code === "backup/bad-passphrase");
1320
+
1321
+ await ppStore.writeBundle(ID_A, src);
1322
+ await ppStore.writeBundle(ID_B, src);
1323
+ var report = await ppStore.keyRotation({ newPassphrase: newPp });
1324
+ check("keyRotation: rotates every passphrase bundle + verifies under the new key",
1325
+ report.total === 2 && report.rotated === 2 && report.failed === 0 &&
1326
+ report.verified === 2 && report.verifyFailed === 0 &&
1327
+ /^rotation-/.test(report.rotationId));
1328
+
1329
+ var fresh = b.backup.bundleAdapterStorage({
1330
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: ppRoot }),
1331
+ format: "tar", cryptoStrategy: "passphrase", passphrase: newPp,
1332
+ });
1333
+ var v = await fresh.verifyAllBundles();
1334
+ check("keyRotation: fresh new-key storage verifies all rotated bundles",
1335
+ v.total === 2 && v.ok === 2 && v.failed === 0);
1336
+ } finally { _rm(ppRoot); }
1337
+ } finally { _rm(src); }
1338
+ }
1339
+
1340
+ // ---- legacy (minimal) in-memory adapter branches ----
1341
+
1342
+ async function testMemAdapterLegacyBranches() {
1343
+ var src = _mkSrcDir({ "a.txt": "mem-payload", "b/c.txt": "nested" });
1344
+ var dest = path.join(os.tmpdir(), "bidx-mem-dest-" + Date.now());
1345
+ try {
1346
+ var storage = b.backup.bundleAdapterStorage({ adapter: _memAdapter(), format: "tar" });
1347
+ await storage.writeBundle(VALID_ID, src);
1348
+ check("memAdapter: hasBundle true after write", await storage.hasBundle(VALID_ID));
1349
+
1350
+ // bundleInfo on an adapter without readPartial -> envelopeKind unknown,
1351
+ // sizeBytes null (no statKey).
1352
+ var info = await storage.bundleInfo(VALID_ID);
1353
+ check("memAdapter: bundleInfo reports envelopeKind unknown (no readPartial capability)",
1354
+ info.envelopeKind === "unknown" && info.sizeBytes === null && info.format === "tar");
1355
+
1356
+ // listBundles without statKey -> size/createdAt stay null even with
1357
+ // withStats requested.
1358
+ var listed = await storage.listBundles({ withStats: true });
1359
+ check("memAdapter: listBundles leaves size/createdAt null without statKey",
1360
+ listed.length === 1 && listed[0].size === null && listed[0].createdAt === null);
1361
+
1362
+ await storage.readBundle(VALID_ID, dest);
1363
+ check("memAdapter: readBundle recovers a nested file through the tar path",
1364
+ fs.readFileSync(path.join(dest, "b", "c.txt"), "utf8") === "nested");
1365
+
1366
+ await storage.deleteBundle(VALID_ID);
1367
+ check("memAdapter: hasBundle false after delete",
1368
+ (await storage.hasBundle(VALID_ID)) === false);
1369
+ } finally { _rm(src); _rm(dest); }
1370
+ }
1371
+
1372
+ // ---- objectStoreAdapter (local b.objectStore backend; no network) ----
1373
+
1374
+ function testObjectStoreAdapterPrefixValidation() {
1375
+ var rootDir = _tmp("os-prefix-root");
1376
+ try {
1377
+ var client = b.objectStore.buildBackend({ protocol: "local", rootDir: rootDir });
1378
+ var t1 = null;
1379
+ try { b.backup.bundleAdapterStorage.objectStoreAdapter(client, { prefix: 123 }); } catch (e) { t1 = e; }
1380
+ check("objectStoreAdapter: non-string prefix refused with bad-arg",
1381
+ t1 && t1.code === "backup/bad-arg");
1382
+ var t2 = null;
1383
+ try { b.backup.bundleAdapterStorage.objectStoreAdapter(client, { prefix: "../evil" }); } catch (e) { t2 = e; }
1384
+ check("objectStoreAdapter: traversal prefix refused with bad-arg",
1385
+ t2 && t2.code === "backup/bad-arg");
1386
+ // Bad client (missing methods) refused with bad-adapter.
1387
+ var t3 = null;
1388
+ try { b.backup.bundleAdapterStorage.objectStoreAdapter({}); } catch (e) { t3 = e; }
1389
+ check("objectStoreAdapter: client missing methods refused with bad-adapter",
1390
+ t3 && t3.code === "backup/bad-adapter");
1391
+ } finally { _rm(rootDir); }
1392
+ }
1393
+
1394
+ async function testObjectStoreAdapterKeyValidationAndMisses() {
1395
+ var rootDir = _tmp("os-key-root");
1396
+ try {
1397
+ var client = b.objectStore.buildBackend({ protocol: "local", rootDir: rootDir });
1398
+ // Trailing-slash prefix is stripped; adapter still round-trips.
1399
+ var adapter = b.backup.bundleAdapterStorage.objectStoreAdapter(client, { prefix: "scoped///" });
1400
+
1401
+ var empty = null;
1402
+ try { await adapter.writeFile("", Buffer.from("x")); } catch (e) { empty = e; }
1403
+ check("objectStoreAdapter.writeFile: empty key refused with bad-key",
1404
+ empty && empty.code === "backup/bad-key");
1405
+ var trav = null;
1406
+ try { await adapter.writeFile("../escape", Buffer.from("x")); } catch (e) { trav = e; }
1407
+ check("objectStoreAdapter.writeFile: traversal key refused with bad-key",
1408
+ trav && trav.code === "backup/bad-key");
1409
+ var badBytes = null;
1410
+ try { await adapter.writeFile("k1", "not-a-buffer"); } catch (e) { badBytes = e; }
1411
+ check("objectStoreAdapter.writeFile: non-Buffer bytes refused with bad-arg",
1412
+ badBytes && badBytes.code === "backup/bad-arg");
1413
+
1414
+ // Missing-key contract across the read family.
1415
+ var missRead = null;
1416
+ try { await adapter.readFile("nope"); } catch (e) { missRead = e; }
1417
+ check("objectStoreAdapter.readFile: missing key -> no-key", missRead && missRead.code === "backup/no-key");
1418
+ var missPartial = null;
1419
+ try { await adapter.readPartial("nope", 4); } catch (e) { missPartial = e; }
1420
+ check("objectStoreAdapter.readPartial: missing key -> no-key", missPartial && missPartial.code === "backup/no-key");
1421
+ check("objectStoreAdapter.statKey: null for a missing key", (await adapter.statKey("nope")) === null);
1422
+ check("objectStoreAdapter.hasKey: false for a missing key", (await adapter.hasKey("nope")) === false);
1423
+ var delMiss = null;
1424
+ try { await adapter.deleteKey("nope"); } catch (e) { delMiss = e; }
1425
+ check("objectStoreAdapter.deleteKey: missing key is a silent no-op", delMiss === null);
1426
+
1427
+ // Round-trip a real key through the scoped prefix.
1428
+ await adapter.writeFile("k1", Buffer.from("hello-object-store"));
1429
+ var back = await adapter.readFile("k1");
1430
+ check("objectStoreAdapter: writeFile/readFile round-trips under the stripped prefix",
1431
+ back.toString() === "hello-object-store");
1432
+ var head = await adapter.readPartial("k1", 5);
1433
+ check("objectStoreAdapter.readPartial: returns the leading bytes via range GET",
1434
+ head.toString() === "hello");
1435
+ var st = await adapter.statKey("k1");
1436
+ check("objectStoreAdapter.statKey: reports size for an existing key", st && st.size === 18);
1437
+ var keys = await adapter.listKeys("");
1438
+ check("objectStoreAdapter.listKeys: enumerates keys with the prefix stripped",
1439
+ keys.indexOf("k1") !== -1);
1440
+ } finally { _rm(rootDir); }
1441
+ }
1442
+
1443
+ async function testObjectStoreAdapterBundleRoundTrip() {
1444
+ var rootDir = _tmp("os-bundle-root");
1445
+ var src = _mkSrcDir({ "data.json": "{\"v\":9}" });
1446
+ var dest = path.join(os.tmpdir(), "bidx-os-dest-" + Date.now());
1447
+ try {
1448
+ var client = b.objectStore.buildBackend({ protocol: "local", rootDir: rootDir });
1449
+ var storage = b.backup.bundleAdapterStorage({
1450
+ adapter: b.backup.bundleAdapterStorage.objectStoreAdapter(client, { prefix: "bkp" }),
1451
+ format: "tar.gz",
1452
+ });
1453
+ await storage.writeBundle(VALID_ID, src);
1454
+ check("objectStoreAdapter: hasBundle true after put", await storage.hasBundle(VALID_ID));
1455
+ var info = await storage.bundleInfo(VALID_ID);
1456
+ check("objectStoreAdapter: bundleInfo reports tar.gz + size via head()",
1457
+ info.format === "tar.gz" && typeof info.sizeBytes === "number" && info.sizeBytes > 0);
1458
+ var listed = await storage.listBundles({ withStats: true });
1459
+ check("objectStoreAdapter: listBundles({withStats}) reports size from head()",
1460
+ listed.length === 1 && typeof listed[0].size === "number");
1461
+ await storage.readBundle(VALID_ID, dest);
1462
+ check("objectStoreAdapter: bundle round-trips through the local object store",
1463
+ fs.readFileSync(path.join(dest, "data.json"), "utf8") === "{\"v\":9}");
1464
+ await storage.deleteBundle(VALID_ID);
1465
+ check("objectStoreAdapter: hasBundle false after deleteBundle",
1466
+ (await storage.hasBundle(VALID_ID)) === false);
1467
+ } finally { _rm(rootDir); _rm(src); _rm(dest); }
1468
+ }
1469
+
1470
+ // ---- migrate: single-bundle + deleteSourceOnSuccess ----
1471
+
1472
+ async function testMigrateSingleIdAndDeleteSource() {
1473
+ var fromRoot = _tmp("migs-from");
1474
+ var toRoot = _tmp("migs-to");
1475
+ var src = _mkSrcDir({ "manifest.json": "{\"version\":1}", "files/d.enc": "DD" });
1476
+ try {
1477
+ var from = b.backup.bundleAdapterStorage({
1478
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: fromRoot }), format: "directory",
1479
+ });
1480
+ var to = b.backup.bundleAdapterStorage({
1481
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: toRoot }), format: "tar",
1482
+ });
1483
+ await from.writeBundle(ID_A, src);
1484
+ await from.writeBundle(ID_B, src);
1485
+
1486
+ // Single-bundle migrate targets only the named id.
1487
+ var one = await b.backup.migrate({ from: from, to: to, bundleId: ID_A });
1488
+ check("migrate: single bundleId migrates exactly that bundle",
1489
+ one.total === 1 && one.migrated === 1 && (await to.hasBundle(ID_A)) &&
1490
+ (await to.hasBundle(ID_B)) === false);
1491
+
1492
+ // deleteSourceOnSuccess removes the source bundle after a successful
1493
+ // write.
1494
+ var two = await b.backup.migrate({
1495
+ from: from, to: to, bundleId: ID_B, deleteSourceOnSuccess: true,
1496
+ });
1497
+ check("migrate: deleteSourceOnSuccess prunes the migrated source bundle",
1498
+ two.migrated === 1 && (await to.hasBundle(ID_B)) &&
1499
+ (await from.hasBundle(ID_B)) === false);
1500
+ } finally { _rm(fromRoot); _rm(toRoot); _rm(src); }
1501
+ }
1502
+
1503
+ // ---- runInWorker ----
1504
+
1505
+ function _writeWorker(name, body) {
1506
+ var dir = _tmp("wk-" + name);
1507
+ var file = path.join(dir, "worker.js");
1508
+ fs.writeFileSync(file, body);
1509
+ return { dir: dir, file: file };
1510
+ }
1511
+
1512
+ async function testRunInWorkerValidation() {
1513
+ var noScript = null;
1514
+ try { await b.backup.runInWorker({}); } catch (e) { noScript = e; }
1515
+ check("runInWorker: missing workerScript rejects with no-worker-script",
1516
+ noScript && noScript.code === "backup/no-worker-script");
1517
+
1518
+ var badTimeout = null;
1519
+ try {
1520
+ await b.backup.runInWorker({ workerScript: "/tmp/x.js", timeoutMs: -5 });
1521
+ } catch (e) { badTimeout = e; }
1522
+ check("runInWorker: negative timeoutMs rejects with bad-timeout",
1523
+ badTimeout && badTimeout.code === "backup/bad-timeout");
1524
+ }
1525
+
1526
+ async function testRunInWorkerLifecycle() {
1527
+ await helpers.withTestTimeout("runInWorker lifecycle", async function () {
1528
+ // Worker that posts a message -> resolve.
1529
+ var okW = _writeWorker("ok",
1530
+ "var wt = require('node:worker_threads'); wt.parentPort.postMessage({ echoed: wt.workerData });");
1531
+ try {
1532
+ var msg = await b.backup.runInWorker({ workerScript: okW.file, args: { mode: "full" } });
1533
+ check("runInWorker: resolves with the worker's posted message",
1534
+ msg && msg.echoed && msg.echoed.mode === "full");
1535
+ } finally { _rm(okW.dir); }
1536
+
1537
+ // Worker that throws on load -> rejects via the error event.
1538
+ var errW = _writeWorker("err", "throw new Error('worker-load-boom');");
1539
+ try {
1540
+ var errThrown = null;
1541
+ try { await b.backup.runInWorker({ workerScript: errW.file }); } catch (e) { errThrown = e; }
1542
+ check("runInWorker: a worker that throws on load rejects the promise",
1543
+ errThrown && /worker-load-boom/.test(errThrown.message));
1544
+ } finally { _rm(errW.dir); }
1545
+
1546
+ // Worker that exits non-zero with no message -> worker-nonzero-exit.
1547
+ var exitW = _writeWorker("exit", "process.exit(3);");
1548
+ try {
1549
+ var exitErr = null;
1550
+ try { await b.backup.runInWorker({ workerScript: exitW.file }); } catch (e) { exitErr = e; }
1551
+ check("runInWorker: a non-zero worker exit rejects with worker-nonzero-exit",
1552
+ exitErr && exitErr.code === "backup/worker-nonzero-exit");
1553
+ } finally { _rm(exitW.dir); }
1554
+
1555
+ // Worker that never posts/exits -> timeoutMs terminates it.
1556
+ var hangW = _writeWorker("hang", "setInterval(function () {}, 100000);");
1557
+ try {
1558
+ var toErr = null;
1559
+ try { await b.backup.runInWorker({ workerScript: hangW.file, timeoutMs: 150 }); } catch (e) { toErr = e; }
1560
+ check("runInWorker: a hung worker is terminated with worker-timeout",
1561
+ toErr && toErr.code === "backup/worker-timeout");
1562
+ } finally { _rm(hangW.dir); }
1563
+ }, { timeoutMs: 20000 });
1564
+ }
1565
+
1566
+ // ---- scheduleTest drill closure (failure paths, no signed manifest) ----
1567
+
1568
+ function _capturingScheduler() {
1569
+ var specs = [];
1570
+ return {
1571
+ specs: specs,
1572
+ create: function () {
1573
+ return { schedule: function (spec) { specs.push(spec); return spec; } };
1574
+ },
1575
+ };
1576
+ }
1577
+
1578
+ async function testScheduleTestDrillFailurePaths() {
1579
+ var data = _tmp("drill-data");
1580
+ var root = _tmp("drill-root");
1581
+ var restore = _tmp("drill-restore");
1582
+ try {
1583
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
1584
+
1585
+ // (a) listBundles throws inside the drill -> backup.test.failed, no throw.
1586
+ var listThrowSched = _capturingScheduler();
1587
+ var base = b.backup.diskStorage({ root: root });
1588
+ var listThrowStorage = Object.assign({}, base, {
1589
+ listBundles: async function () { throw new Error("list-down"); },
1590
+ });
1591
+ var eng1 = b.backup.create({
1592
+ dataDir: data, storage: listThrowStorage, passphrase: "pp",
1593
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
1594
+ vaultKeyJson: '{"v":1}', scheduler: listThrowSched, audit: false,
1595
+ });
1596
+ eng1.scheduleTest({ cron: "0 3 * * *", restoreTo: restore, verify: function () { return true; } });
1597
+ var drill1 = null;
1598
+ try { await listThrowSched.specs[0].run(); } catch (e) { drill1 = e; }
1599
+ check("scheduleTest drill: listBundles failure is swallowed (no throw out of the tick)",
1600
+ drill1 === null);
1601
+
1602
+ // (b) empty storage -> "no bundles" failure, no throw.
1603
+ var emptySched = _capturingScheduler();
1604
+ var eng2 = b.backup.create({
1605
+ dataDir: data, storage: b.backup.diskStorage({ root: _tmp("drill-empty") }),
1606
+ passphrase: "pp", files: [{ relativePath: "db.enc", kind: "raw", required: true }],
1607
+ vaultKeyJson: '{"v":1}', scheduler: emptySched, audit: false,
1608
+ });
1609
+ eng2.scheduleTest({ cron: "0 3 * * *", restoreTo: restore, verify: function () { return true; } });
1610
+ var drill2 = null;
1611
+ try { await emptySched.specs[0].run(); } catch (e) { drill2 = e; }
1612
+ check("scheduleTest drill: no bundles in storage is handled (no throw)", drill2 === null);
1613
+
1614
+ // (c) a real (unsigned-manifest) bundle -> signature verify fails ->
1615
+ // backup.test.failed with the operator notify hook invoked.
1616
+ var okSched = _capturingScheduler();
1617
+ var storeRoot = _tmp("drill-store");
1618
+ var eng3 = b.backup.create({
1619
+ dataDir: data, storage: b.backup.diskStorage({ root: storeRoot }),
1620
+ passphrase: "pp", files: [{ relativePath: "db.enc", kind: "raw", required: true }],
1621
+ vaultKeyJson: '{"v":1}', scheduler: okSched, audit: false,
1622
+ });
1623
+ await eng3.run();
1624
+ var verifyCalled = false;
1625
+ var notifyInfo = [];
1626
+ eng3.scheduleTest({
1627
+ cron: "0 3 * * *", restoreTo: restore,
1628
+ verify: function () { verifyCalled = true; return true; },
1629
+ notify: function (info) { notifyInfo.push(info); },
1630
+ });
1631
+ var drill3 = null;
1632
+ try { await okSched.specs[0].run(); } catch (e) { drill3 = e; }
1633
+ check("scheduleTest drill: unsigned-manifest bundle fails signature verify without throwing",
1634
+ drill3 === null && verifyCalled === false);
1635
+ check("scheduleTest drill: operator notify hook fired with a failure outcome",
1636
+ notifyInfo.length === 1 && notifyInfo[0].outcome === "failure");
1637
+
1638
+ // (d) stagingDir already exists -> the drill refuses to overwrite.
1639
+ var existsSched = _capturingScheduler();
1640
+ var eng4 = b.backup.create({
1641
+ dataDir: data, storage: b.backup.diskStorage({ root: storeRoot }),
1642
+ passphrase: "pp", files: [{ relativePath: "db.enc", kind: "raw", required: true }],
1643
+ vaultKeyJson: '{"v":1}', scheduler: existsSched, audit: false,
1644
+ });
1645
+ var bundles = await eng4.list();
1646
+ var collideDir = path.join(restore, "test-" + bundles[0].bundleId.replace(/[:.]/g, "-"));
1647
+ fs.mkdirSync(collideDir, { recursive: true });
1648
+ eng4.scheduleTest({ cron: "0 3 * * *", restoreTo: restore, verify: function () { return true; } });
1649
+ var drill4 = null;
1650
+ try { await existsSched.specs[0].run(); } catch (e) { drill4 = e; }
1651
+ check("scheduleTest drill: pre-existing staging dir is refused (no throw)", drill4 === null);
1652
+ } finally { _rm(data); _rm(root); _rm(restore); }
1653
+ }
1654
+
1655
+ async function testDiskStorageReadDestExists() {
1656
+ var root = _tmp("ds-de-root");
1657
+ var src = _mkSrcDir({ "manifest.json": "{}" });
1658
+ var dest = _tmp("ds-de-dest"); // pre-existing destination
1659
+ try {
1660
+ var ds = b.backup.diskStorage({ root: root });
1661
+ await ds.writeBundle(VALID_ID, src);
1662
+ var threw = null;
1663
+ try { await ds.readBundle(VALID_ID, dest); } catch (e) { threw = e; }
1664
+ check("diskStorage.readBundle: pre-existing destDir refused with dest-exists",
1665
+ threw && threw.code === "backup/dest-exists");
1666
+ } finally { _rm(root); _rm(src); _rm(dest); }
1667
+ }
1668
+
1669
+ function testCreateConstructionValidation() {
1670
+ var root = _tmp("cv-root");
1671
+ try {
1672
+ var storage = b.backup.diskStorage({ root: root });
1673
+ var t1 = null;
1674
+ try { b.backup.create({ storage: storage }); } catch (e) { t1 = e; }
1675
+ check("create: missing dataDir refused with no-datadir",
1676
+ t1 && t1.code === "backup/no-datadir");
1677
+
1678
+ var data = _tmp("cv-data");
1679
+ try {
1680
+ var t2 = null;
1681
+ try { b.backup.create({ dataDir: data, storage: storage, passphrase: 123, files: [{}], vaultKeyJson: "{}" }); } catch (e) { t2 = e; }
1682
+ check("create: non-Buffer/non-string passphrase refused with no-passphrase",
1683
+ t2 && t2.code === "backup/no-passphrase");
1684
+
1685
+ var t3 = null;
1686
+ try { b.backup.create({ dataDir: data, storage: storage, passphrase: "pp", files: [], vaultKeyJson: "{}" }); } catch (e) { t3 = e; }
1687
+ check("create: empty files array refused with no-files",
1688
+ t3 && t3.code === "backup/no-files");
1689
+
1690
+ var t4 = null;
1691
+ try { b.backup.create({ dataDir: data, storage: storage, passphrase: "pp", files: [{ relativePath: "x" }] }); } catch (e) { t4 = e; }
1692
+ check("create: missing vaultKeyJson refused with no-vault-key-json",
1693
+ t4 && t4.code === "backup/no-vault-key-json");
1694
+ } finally { _rm(data); }
1695
+ } finally { _rm(root); }
1696
+ }
1697
+
1698
+ async function testCreateScheduleClosureRuns() {
1699
+ var data = _tmp("scc-data");
1700
+ var root = _tmp("scc-root");
1701
+ try {
1702
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("X"));
1703
+ var captured = [];
1704
+ var fakeScheduler = {
1705
+ create: function () {
1706
+ return { schedule: function (spec) { captured.push(spec); } };
1707
+ },
1708
+ };
1709
+ var eng = b.backup.create({
1710
+ dataDir: data, storage: b.backup.diskStorage({ root: root }), passphrase: "pp",
1711
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
1712
+ vaultKeyJson: '{"v":1}', scheduler: fakeScheduler, audit: false,
1713
+ });
1714
+ eng.schedule({ cron: "0 3 * * *", name: "nightly" });
1715
+ // Fire the registered run closure directly — it invokes run() and
1716
+ // swallows errors (errors are audited inside run()).
1717
+ await captured[0].run();
1718
+ check("create.schedule: the registered run closure produces a bundle",
1719
+ (await eng.list()).length === 1);
1720
+ } finally { _rm(data); _rm(root); }
1721
+ }
1722
+
1723
+ async function testAdapterHipaaPassphraseFloorAndBadId() {
1724
+ var root = _tmp("hpf-root");
1725
+ var src = _mkSrcDir({ "a.txt": "x" });
1726
+ var dest = path.join(os.tmpdir(), "bidx-hpf-dest-" + Date.now());
1727
+ try {
1728
+ // Explicit posture:"hipaa" raises the passphrase entropy floor to 128
1729
+ // bits at construction. A high-entropy passphrase still writes/reads.
1730
+ var storage = b.backup.bundleAdapterStorage({
1731
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }),
1732
+ format: "tar",
1733
+ cryptoStrategy: "passphrase",
1734
+ passphrase: b.crypto.generateBytes(32).toString("hex"),
1735
+ posture: "hipaa",
1736
+ });
1737
+ // A malformed bundleId is refused by the shared _ensureBundleId guard.
1738
+ var badId = null;
1739
+ try { await storage.writeBundle("not-valid", src); } catch (e) { badId = e; }
1740
+ check("adapter.writeBundle: malformed bundleId refused with bad-bundle-id",
1741
+ badId && badId.code === "backup/bad-bundle-id");
1742
+
1743
+ await storage.writeBundle(VALID_ID, src);
1744
+ await storage.readBundle(VALID_ID, dest);
1745
+ check("adapter/hipaa passphrase: 128-bit-floor bundle round-trips with a strong passphrase",
1746
+ fs.readFileSync(path.join(dest, "a.txt"), "utf8") === "x");
1747
+ } finally { _rm(root); _rm(src); _rm(dest); }
1748
+ }
1749
+
1750
+ async function testAdapterReadBundleNotFoundAndCryptoTarReads() {
1751
+ var src = _mkSrcDir({ "a.txt": "cryptotar" });
1752
+ try {
1753
+ // readBundle on an absent bundle -> bundle-not-found.
1754
+ var nfRoot = _tmp("rb-nf-root");
1755
+ try {
1756
+ var nfStore = b.backup.bundleAdapterStorage({
1757
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: nfRoot }), format: "tar",
1758
+ });
1759
+ var nf = null;
1760
+ try { await nfStore.readBundle(ABSENT_ID, path.join(nfRoot, "out")); } catch (e) { nf = e; }
1761
+ check("adapter.readBundle: absent bundle refused with bundle-not-found",
1762
+ nf && nf.code === "backup/bundle-not-found");
1763
+ } finally { _rm(nfRoot); }
1764
+
1765
+ // tar.gz + passphrase read path (gz unwrapWithPassphrase branch).
1766
+ var tgzRoot = _tmp("rb-tgz-root");
1767
+ var tgzDest = path.join(os.tmpdir(), "bidx-rb-tgz-" + Date.now());
1768
+ try {
1769
+ var tgz = b.backup.bundleAdapterStorage({
1770
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: tgzRoot }),
1771
+ format: "tar.gz", cryptoStrategy: "passphrase", passphrase: STRONG_PP,
1772
+ });
1773
+ await tgz.writeBundle(VALID_ID, src);
1774
+ await tgz.readBundle(VALID_ID, tgzDest);
1775
+ check("adapter.readBundle: tar.gz + passphrase decrypts + gunzips on restore",
1776
+ fs.readFileSync(path.join(tgzDest, "a.txt"), "utf8") === "cryptotar");
1777
+ } finally { _rm(tgzRoot); _rm(tgzDest); }
1778
+
1779
+ // tar (non-gz) + recipient read path (hasTar recipient-unwrap branch).
1780
+ var tarRoot = _tmp("rb-tar-root");
1781
+ var tarDest = path.join(os.tmpdir(), "bidx-rb-tar-" + Date.now());
1782
+ try {
1783
+ var pair = b.crypto.generateEncryptionKeyPair();
1784
+ var tarStore = b.backup.bundleAdapterStorage({
1785
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: tarRoot }),
1786
+ format: "tar", cryptoStrategy: "recipient", recipient: pair,
1787
+ });
1788
+ await tarStore.writeBundle(VALID_ID, src);
1789
+ await tarStore.readBundle(VALID_ID, tarDest);
1790
+ check("adapter.readBundle: tar + recipient unwraps on restore",
1791
+ fs.readFileSync(path.join(tarDest, "a.txt"), "utf8") === "cryptotar");
1792
+ } finally { _rm(tarRoot); _rm(tarDest); }
1793
+ } finally { _rm(src); }
1794
+ }
1795
+
1796
+ async function testAdapterDirectoryListWithStats() {
1797
+ var root = _tmp("dls-root");
1798
+ var src = _mkSrcDir({ "manifest.json": "{\"version\":1}", "files/a.enc": "AA" });
1799
+ try {
1800
+ var storage = b.backup.bundleAdapterStorage({
1801
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: root }), format: "directory",
1802
+ });
1803
+ await storage.writeBundle(VALID_ID, src);
1804
+ var listed = await storage.listBundles({ withStats: true });
1805
+ check("adapter/directory: listBundles({withStats}) stats the manifest key for size",
1806
+ listed.length === 1 && listed[0].format === "directory" &&
1807
+ typeof listed[0].size === "number" && typeof listed[0].createdAt === "string");
1808
+ // bundleInfo on a directory bundle stats the manifest too.
1809
+ var info = await storage.bundleInfo(VALID_ID);
1810
+ check("adapter/directory: bundleInfo stats manifest for size + createdAt",
1811
+ info.format === "directory" && typeof info.sizeBytes === "number" &&
1812
+ typeof info.createdAt === "string");
1813
+ } finally { _rm(root); _rm(src); }
1814
+ }
1815
+
1816
+ async function testAdapterRewrapUnknownAndMissingKeys() {
1817
+ var src = _mkSrcDir({ "a.txt": "rw2" });
1818
+ try {
1819
+ // A legacy adapter (no readPartial) makes bundleInfo report
1820
+ // envelopeKind "unknown"; rewrap falls back to sniffing the loaded
1821
+ // sealed bytes.
1822
+ var oldPp = b.crypto.generateBytes(24).toString("hex");
1823
+ var newPp = b.crypto.generateBytes(24).toString("hex");
1824
+ var mem = _memAdapter();
1825
+ var memStore = b.backup.bundleAdapterStorage({
1826
+ adapter: mem, format: "tar", cryptoStrategy: "passphrase", passphrase: oldPp,
1827
+ });
1828
+ await memStore.writeBundle(VALID_ID, src);
1829
+ var infoUnknown = await memStore.bundleInfo(VALID_ID);
1830
+ check("rewrap-precondition: legacy adapter bundleInfo reports envelopeKind unknown",
1831
+ infoUnknown.envelopeKind === "unknown");
1832
+ var rw = await memStore.rewrapBundle(VALID_ID, {
1833
+ newPassphrase: newPp,
1834
+ passphraseMinEntropyBits: 200, // higher than the storage floor -> effectiveFloor raise
1835
+ });
1836
+ check("rewrapBundle: unknown-envelope bundle is sniffed + rotated as passphrase",
1837
+ rw.oldEnvelopeKind === "passphrase" && rw.newEnvelopeKind === "passphrase");
1838
+
1839
+ // no-old-recipient: recipient envelope, explicit null old key.
1840
+ var rcpRoot = _tmp("rw2-rcp-root");
1841
+ try {
1842
+ var pair = b.crypto.generateEncryptionKeyPair();
1843
+ var newPair = b.crypto.generateEncryptionKeyPair();
1844
+ var rcpStore = b.backup.bundleAdapterStorage({
1845
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: rcpRoot }),
1846
+ format: "tar.gz", cryptoStrategy: "recipient", recipient: pair,
1847
+ });
1848
+ await rcpStore.writeBundle(VALID_ID, src);
1849
+ var noOldR = null;
1850
+ try { await rcpStore.rewrapBundle(VALID_ID, { oldRecipient: null, newRecipient: newPair }); } catch (e) { noOldR = e; }
1851
+ check("rewrapBundle: recipient rotation with a null old key refused with no-old-recipient",
1852
+ noOldR && noOldR.code === "backup/no-old-recipient");
1853
+ } finally { _rm(rcpRoot); }
1854
+
1855
+ // no-old-passphrase: passphrase envelope, explicit null old key.
1856
+ var ppRoot = _tmp("rw2-pp-root");
1857
+ try {
1858
+ var ppStore = b.backup.bundleAdapterStorage({
1859
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: ppRoot }),
1860
+ format: "tar", cryptoStrategy: "passphrase", passphrase: oldPp,
1861
+ });
1862
+ await ppStore.writeBundle(VALID_ID, src);
1863
+ var noOldP = null;
1864
+ try { await ppStore.rewrapBundle(VALID_ID, { oldPassphrase: null, newPassphrase: newPp }); } catch (e) { noOldP = e; }
1865
+ check("rewrapBundle: passphrase rotation with a null old key refused with no-old-passphrase",
1866
+ noOldP && noOldP.code === "backup/no-old-passphrase");
1867
+ } finally { _rm(ppRoot); }
1868
+ } finally { _rm(src); }
1869
+ }
1870
+
1871
+ async function testAdapterBatchPools() {
1872
+ var root = _tmp("batch-root");
1873
+ var src = _mkSrcDir({ "a.txt": "batch" });
1874
+ var oldPp = b.crypto.generateBytes(24).toString("hex");
1875
+ var newPp = b.crypto.generateBytes(24).toString("hex");
1876
+ try {
1877
+ var fsA = b.backup.bundleAdapterStorage.fsAdapter({ root: root });
1878
+ var ppStore = b.backup.bundleAdapterStorage({
1879
+ adapter: fsA, format: "tar", cryptoStrategy: "passphrase", passphrase: oldPp, audit: false,
1880
+ });
1881
+ // Three passphrase bundles (wrappable).
1882
+ await ppStore.writeBundle(ID_A, src);
1883
+ await ppStore.writeBundle(ID_B, src);
1884
+ await ppStore.writeBundle(ID_C, src);
1885
+ // A plaintext tar bundle (no envelope -> skipped by rewrapAllBundles).
1886
+ var plainStore = b.backup.bundleAdapterStorage({ adapter: fsA, format: "tar" });
1887
+ await plainStore.writeBundle("2026-05-01T11-00-00-000Z-44444444", src);
1888
+ // A directory bundle (format-not-wrappable -> skipped in _spawn).
1889
+ var dirStore = b.backup.bundleAdapterStorage({ adapter: fsA, format: "directory" });
1890
+ var dsrc = _mkSrcDir({ "manifest.json": "{\"version\":1}" });
1891
+ try { await dirStore.writeBundle("2026-05-01T11-05-00-000Z-55555555", dsrc); }
1892
+ finally { _rm(dsrc); }
1893
+
1894
+ // rewrapAllBundles with concurrency:1 drives the drain+refill loop and
1895
+ // both skip paths (directory format + no-envelope).
1896
+ var rot = await ppStore.rewrapAllBundles({ newPassphrase: newPp, concurrency: 1 });
1897
+ check("rewrapAllBundles: rotates the three passphrase bundles",
1898
+ rot.total === 5 && rot.rotated === 3);
1899
+ check("rewrapAllBundles: skips the directory + plaintext-tar bundles",
1900
+ rot.skipped === 2 && rot.failed === 0);
1901
+
1902
+ // verifyAllBundles under the NEW key, concurrency:1 (drain+refill).
1903
+ var freshOk = b.backup.bundleAdapterStorage({
1904
+ adapter: fsA, format: "tar", cryptoStrategy: "passphrase", passphrase: newPp,
1905
+ });
1906
+ var vAll = await freshOk.verifyAllBundles({ concurrency: 1 });
1907
+ check("verifyAllBundles: reports a per-bundle result for every bundle",
1908
+ vAll.total === 5 && vAll.results.length === 5);
1909
+
1910
+ // A store holding the WRONG passphrase makes the rotated bundles fail
1911
+ // verification -> the failed counter increments (stopOnFirstFailure).
1912
+ var wrongKey = b.backup.bundleAdapterStorage({
1913
+ adapter: fsA, format: "tar", cryptoStrategy: "passphrase",
1914
+ passphrase: b.crypto.generateBytes(24).toString("hex"),
1915
+ });
1916
+ var vFail = await wrongKey.verifyAllBundles({ stopOnFirstFailure: true });
1917
+ check("verifyAllBundles: a wrong-key store reports at least one failed bundle",
1918
+ vFail.failed >= 1);
1919
+ } finally { _rm(root); _rm(src); }
1920
+ }
1921
+
1922
+ async function testObjectStoreAdapterNoPrefixList() {
1923
+ var rootDir = _tmp("os-np-root");
1924
+ try {
1925
+ var client = b.objectStore.buildBackend({ protocol: "local", rootDir: rootDir });
1926
+ // No prefix -> listKeys returns keys verbatim (the else branch).
1927
+ var adapter = b.backup.bundleAdapterStorage.objectStoreAdapter(client);
1928
+ await adapter.writeFile("k1", Buffer.from("a"));
1929
+ await adapter.writeFile("k2", Buffer.from("bb"));
1930
+ var keys = await adapter.listKeys("");
1931
+ check("objectStoreAdapter.listKeys: no-prefix adapter returns keys verbatim",
1932
+ keys.indexOf("k1") !== -1 && keys.indexOf("k2") !== -1);
1933
+ // Uint8Array bytes are accepted + normalized to Buffer.
1934
+ await adapter.writeFile("k3", new Uint8Array([1, 2, 3]));
1935
+ var back = await adapter.readFile("k3");
1936
+ check("objectStoreAdapter.writeFile: accepts Uint8Array bytes",
1937
+ Buffer.isBuffer(back) && back.length === 3);
1938
+ } finally { _rm(rootDir); }
1939
+ }
1940
+
1941
+ async function testObjectStoreAdapterRethrowsUnexpectedErrors() {
1942
+ // A client that throws a NON-NOT_FOUND error must NOT be swallowed —
1943
+ // the adapter's NOT_FOUND translation is deliberately narrow.
1944
+ var boom = new Error("upstream-503");
1945
+ var client = {
1946
+ put: async function () { throw boom; },
1947
+ get: async function () { throw boom; },
1948
+ head: async function () { throw boom; },
1949
+ delete: async function () { throw boom; },
1950
+ list: async function () { throw boom; },
1951
+ };
1952
+ var adapter = b.backup.bundleAdapterStorage.objectStoreAdapter(client);
1953
+ var checks = [
1954
+ ["readFile", function () { return adapter.readFile("k"); }],
1955
+ ["deleteKey", function () { return adapter.deleteKey("k"); }],
1956
+ ["hasKey", function () { return adapter.hasKey("k"); }],
1957
+ ["readPartial", function () { return adapter.readPartial("k", 4); }],
1958
+ ["statKey", function () { return adapter.statKey("k"); }],
1959
+ ];
1960
+ for (var i = 0; i < checks.length; i += 1) {
1961
+ var name = checks[i][0];
1962
+ var thrown = null;
1963
+ try { await checks[i][1](); } catch (e) { thrown = e; }
1964
+ check("objectStoreAdapter." + name + ": a non-NOT_FOUND error is rethrown, not swallowed",
1965
+ thrown === boom);
1966
+ }
1967
+
1968
+ // A client whose delete raises the framework's NOT_FOUND convention is
1969
+ // treated as an idempotent no-op (the adapter delete contract).
1970
+ var notFound = Object.assign(new Error("gone"), { code: "NOT_FOUND" });
1971
+ var nfClient = {
1972
+ put: async function () {}, get: async function () {}, head: async function () {},
1973
+ delete: async function () { throw notFound; }, list: async function () { return { items: [] }; },
1974
+ };
1975
+ var nfAdapter = b.backup.bundleAdapterStorage.objectStoreAdapter(nfClient);
1976
+ var delThrew = null;
1977
+ try { await nfAdapter.deleteKey("k"); } catch (e) { delThrew = e; }
1978
+ check("objectStoreAdapter.deleteKey: a NOT_FOUND delete is swallowed (idempotent)",
1979
+ delThrew === null);
1980
+ }
1981
+
1982
+ async function testObjectStoreAdapterPaginationRunaway() {
1983
+ // A misbehaving backend that reports truncated:true forever (with a
1984
+ // continuation token) is refused after the pagination cap rather than
1985
+ // spinning indefinitely.
1986
+ var calls = 0;
1987
+ var client = {
1988
+ put: async function () {},
1989
+ get: async function () { return Buffer.alloc(0); },
1990
+ head: async function () { return { size: 0 }; },
1991
+ delete: async function () {},
1992
+ list: async function () {
1993
+ calls += 1;
1994
+ return { items: [{ key: "runaway/key" }], truncated: true, continuationToken: "next" };
1995
+ },
1996
+ };
1997
+ var adapter = b.backup.bundleAdapterStorage.objectStoreAdapter(client);
1998
+ var thrown = null;
1999
+ try { await adapter.listKeys(""); } catch (e) { thrown = e; }
2000
+ check("objectStoreAdapter.listKeys: runaway pagination refused with list-pagination-runaway",
2001
+ thrown && thrown.code === "backup/list-pagination-runaway" && calls > 1000);
2002
+ }
2003
+
2004
+ async function testRewrapAllBundlesFailedPath() {
2005
+ // A bundle whose passphrase payload is corrupt makes rewrapBundle fail
2006
+ // with a crypto (non "no-envelope") error -> rewrapAllBundles records
2007
+ // it in the failed bucket (stopOnFirstFailure aborts the walk).
2008
+ var root = _tmp("rwa-fail-root");
2009
+ var src = _mkSrcDir({ "a.txt": "x" });
2010
+ var oldPp = b.crypto.generateBytes(24).toString("hex");
2011
+ var newPp = b.crypto.generateBytes(24).toString("hex");
2012
+ try {
2013
+ var adapter = b.backup.bundleAdapterStorage.fsAdapter({ root: root });
2014
+ var store = b.backup.bundleAdapterStorage({
2015
+ adapter: adapter, format: "tar", cryptoStrategy: "passphrase", passphrase: oldPp, audit: false,
2016
+ });
2017
+ await store.writeBundle(ID_A, src);
2018
+ // Corrupt the sealed AEAD body while preserving the passphrase
2019
+ // envelope magic header — the bundle is still detected as a
2020
+ // passphrase envelope but authentication fails on unwrap, so
2021
+ // rewrapBundle rejects with a crypto (non "no-envelope") error.
2022
+ var sealed = await adapter.readFile(ID_A + "/bundle.tar");
2023
+ var corrupt = Buffer.from(sealed);
2024
+ for (var ci = corrupt.length - 8; ci < corrupt.length; ci += 1) corrupt[ci] = corrupt[ci] ^ 0xff;
2025
+ await adapter.writeFile(ID_A + "/bundle.tar", corrupt);
2026
+ var rep = await store.rewrapAllBundles({ newPassphrase: newPp, stopOnFirstFailure: true });
2027
+ check("rewrapAllBundles: a crypto failure lands in the failed bucket",
2028
+ rep.failed >= 1 && rep.rotated === 0);
2029
+ } finally { _rm(root); _rm(src); }
2030
+ }
2031
+
2032
+ // ---- db-backed: residency mismatch + signed-manifest restore drill ----
2033
+
2034
+ // setupTestDb doesn't expose dataResidency, so this mirrors its
2035
+ // reset+init sequence but declares a db residency region. A real
2036
+ // vault + audit chain means backupBundle.create signs the manifest,
2037
+ // which the drill's signature-verify step needs to reach the PASSED
2038
+ // path. Runs LAST + tears the framework fully back down.
2039
+ async function testDbBackedResidencyAndDrillPass() {
2040
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "bidx-db-"));
2041
+ helpers.setTestPassphraseEnv();
2042
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
2043
+ b.cluster._resetForTest();
2044
+ b.audit._resetForTest();
2045
+ b.vault._resetForTest();
2046
+ b.db._resetForTest();
2047
+ await b.vault.init({ dataDir: tmpDir });
2048
+ await b.db.init({
2049
+ dataDir: tmpDir,
2050
+ tmpDir: path.join(tmpDir, "tmpfs"),
2051
+ allowNonTmpfsTmpDir: true,
2052
+ dataResidency: { region: "eu-west-1" },
2053
+ schema: [],
2054
+ });
2055
+
2056
+ var data = _tmp("db-data");
2057
+ var root = _tmp("db-root");
2058
+ var root2 = _tmp("db-root2");
2059
+ var storeRoot = _tmp("db-store");
2060
+ var restore = _tmp("db-restore");
2061
+ var PP = Buffer.from("operator-backup-passphrase-256bit-entropy-here");
2062
+ try {
2063
+ fs.writeFileSync(path.join(data, "db.enc"), Buffer.from("ENVELOPE-BYTES"));
2064
+ fs.writeFileSync(path.join(data, "db.key.enc"), Buffer.from("SEALED-DEK-BYTES"));
2065
+
2066
+ // Residency mismatch: db region eu-west-1 vs backup residencyTag
2067
+ // us-east-1 under gdpr posture, no allowCrossBorder -> refused.
2068
+ b.compliance.clear();
2069
+ b.compliance.set("gdpr");
2070
+ var mismatch = null;
2071
+ try {
2072
+ b.backup.create({
2073
+ dataDir: data, storage: b.backup.diskStorage({ root: root }), passphrase: PP,
2074
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
2075
+ vaultKeyJson: '{"version":1}', residencyTag: "us-east-1",
2076
+ });
2077
+ } catch (e) { mismatch = e; }
2078
+ check("create: gdpr + db residency != backup residencyTag refused with residency-mismatch",
2079
+ mismatch && mismatch.code === "backup/residency-mismatch");
2080
+
2081
+ // allowCrossBorder + legalBasis suppresses the mismatch throw.
2082
+ var okCross = b.backup.create({
2083
+ dataDir: data, storage: b.backup.diskStorage({ root: root2 }), passphrase: PP,
2084
+ files: [{ relativePath: "db.enc", kind: "raw", required: true }],
2085
+ vaultKeyJson: '{"version":1}', residencyTag: "us-east-1",
2086
+ allowCrossBorder: true, legalBasis: "EU SCCs 2021/914",
2087
+ });
2088
+ check("create: allowCrossBorder + legalBasis suppresses the residency mismatch",
2089
+ okCross && typeof okCross.run === "function");
2090
+ b.compliance.clear();
2091
+
2092
+ // Signed-manifest restore drill -> PASSED path (no posture so the
2093
+ // create() residency gate stays out of the way of the run).
2094
+ var sched = _capturingScheduler();
2095
+ var eng = b.backup.create({
2096
+ dataDir: data, storage: b.backup.diskStorage({ root: storeRoot }), passphrase: PP,
2097
+ files: [
2098
+ { relativePath: "db.enc", kind: "raw", required: true },
2099
+ { relativePath: "db.key.enc", kind: "raw", required: true },
2100
+ ],
2101
+ vaultKeyJson: '{"version":1,"kid":"k1"}', scheduler: sched,
2102
+ });
2103
+ var r = await eng.run();
2104
+ var manifest = JSON.parse(
2105
+ fs.readFileSync(path.join(storeRoot, r.bundleId, "manifest.json"), "utf8"));
2106
+ check("db-drill: the stored manifest carries a real signature block",
2107
+ manifest.signature && typeof manifest.signature.value === "string" &&
2108
+ manifest.signature.value.length > 0);
2109
+
2110
+ var verifyCtx = null;
2111
+ var notify = [];
2112
+ eng.scheduleTest({
2113
+ cron: "0 3 * * 0", restoreTo: restore, posture: "hipaa",
2114
+ verify: async function (ctx) { verifyCtx = ctx; return true; },
2115
+ notify: async function (info) { notify.push(info); },
2116
+ });
2117
+ await sched.specs[0].run();
2118
+ check("db-drill: PASSED path handed the operator a verified-signature manifest + fingerprint",
2119
+ verifyCtx !== null && verifyCtx.bundleId === r.bundleId &&
2120
+ typeof verifyCtx.sigFingerprint === "string" && verifyCtx.sigFingerprint.length > 0 &&
2121
+ verifyCtx.manifest && verifyCtx.manifest.version === 1);
2122
+ check("db-drill: notify hook fired with a success outcome on the passing drill",
2123
+ notify.length === 1 && notify[0].outcome === "success" && notify[0].bundleId === r.bundleId);
2124
+ check("db-drill: the drill cleaned its staging dir after a passing run",
2125
+ !fs.existsSync(verifyCtx.outDir));
2126
+ } finally {
2127
+ b.compliance.clear();
2128
+ _rm(data); _rm(root); _rm(root2); _rm(storeRoot); _rm(restore);
2129
+ await helpers.teardownTestDb(tmpDir);
2130
+ }
2131
+ }
2132
+
2133
+ async function run() {
2134
+ testDiskStorageValidatesRoot();
2135
+ await testDiskStorageBadBundleId();
2136
+ await testDiskStorageBundleExistsAndNotFound();
2137
+ await testDiskStorageListFiltersAndEmpty();
2138
+ await testDiskStorageDeleteAndHasNoop();
2139
+
2140
+ testCreateResidencyTagValidation();
2141
+ testCreateScheduleRequiresScheduler();
2142
+ testCreateScheduleArgValidation();
2143
+ await testCreateRequireFlushHardFails();
2144
+ testCreateHipaaRefusesUnencrypted();
2145
+
2146
+ testVerifyManifestSignatureBadTarget();
2147
+ testVerifyManifestSignatureNoManifest();
2148
+ testVerifyManifestSignatureBadManifest();
2149
+ testVerifyManifestSignatureParsedObject();
2150
+ await testVerifyManifestSignatureOnDiskStringPath();
2151
+
2152
+ testAdapterStorageConstructionValidation();
2153
+ testAdapterStorageEntropyFloorValidation();
2154
+ testAdapterStorageMaxBundleBytesValidation();
2155
+ testAdapterStoragePostureGateOptIn();
2156
+ await testAdapterStorageBundleTooLarge();
2157
+ await testAdapterStoragePassphraseFloorEnforcedOnWrite();
2158
+ await testAdapterStorageDirectoryRoundTrip();
2159
+ await testAdapterStorageTarVerifyAndMissing();
2160
+
2161
+ await testFsAdapterTraversalRefused();
2162
+ await testFsAdapterReadPartialAndStat();
2163
+
2164
+ await testMigrateValidation();
2165
+ await testMigrateDirectoryToTarRoundTrip();
2166
+
2167
+ testRecommendedFiles();
2168
+ await testDiskStorageReadDestExists();
2169
+ testCreateConstructionValidation();
2170
+ await testCreateScheduleClosureRuns();
2171
+
2172
+ await testCreateRunRoundTripAndRetention();
2173
+ await testCreateRunFlushWarningBestEffort();
2174
+ await testCreateRunVaultKeyJsonFailures();
2175
+ await testCreateRunBackupBundleFailure();
2176
+ await testCreateRunStorageWriteFailure();
2177
+ await testCreateRetentionSweepFailure();
2178
+ await testCreatePurgeOlderPerBundleDeleteFailure();
2179
+ await testCreateDeleteReadBadId();
2180
+ testCreateResidencyUndeclaredWarning();
2181
+ testCreateResidencyPerRowCrossBorder();
2182
+
2183
+ await testAdapterTarGzRoundTrip();
2184
+ await testAdapterPassphraseRoundTrip();
2185
+ await testAdapterRecipientRoundTrip();
2186
+ await testAdapterListBundlesWithStats();
2187
+ await testAdapterVerifyBundleErrorBranches();
2188
+ await testAdapterFindBundles();
2189
+ await testAdapterCloneBundle();
2190
+ await testAdapterRewrapBundleBranches();
2191
+ await testAdapterKeyRotationBranches();
2192
+ await testMemAdapterLegacyBranches();
2193
+ await testAdapterHipaaPassphraseFloorAndBadId();
2194
+ await testAdapterReadBundleNotFoundAndCryptoTarReads();
2195
+ await testAdapterDirectoryListWithStats();
2196
+ await testAdapterRewrapUnknownAndMissingKeys();
2197
+ await testAdapterBatchPools();
2198
+
2199
+ await testRewrapAllBundlesFailedPath();
2200
+
2201
+ testObjectStoreAdapterPrefixValidation();
2202
+ await testObjectStoreAdapterKeyValidationAndMisses();
2203
+ await testObjectStoreAdapterBundleRoundTrip();
2204
+ await testObjectStoreAdapterNoPrefixList();
2205
+ await testObjectStoreAdapterRethrowsUnexpectedErrors();
2206
+ await testObjectStoreAdapterPaginationRunaway();
2207
+
2208
+ await testMigrateSingleIdAndDeleteSource();
2209
+
2210
+ await testRunInWorkerValidation();
2211
+ await testRunInWorkerLifecycle();
2212
+
2213
+ await testScheduleTestDrillFailurePaths();
2214
+
2215
+ // db-backed group — runs last, tears the framework fully back down.
2216
+ await testDbBackedResidencyAndDrillPass();
2217
+ }
2218
+
2219
+ module.exports = { run: run };
2220
+
2221
+ if (require.main === module) {
2222
+ run().then(
2223
+ function () { console.log("[backup-index] OK — " + helpers.getChecks() + " checks passed"); },
2224
+ function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
2225
+ );
2226
+ }