@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.
- package/CHANGELOG.md +2 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +632 -416
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
- package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/.gitignore +2 -0
- package/lib/vendor/blamejs/CHANGELOG.md +122 -0
- package/lib/vendor/blamejs/NOTICE +26 -1
- package/lib/vendor/blamejs/SECURITY.md +1 -1
- package/lib/vendor/blamejs/api-snapshot.json +207 -5
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
- package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
- package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
- package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
- package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
- package/lib/vendor/blamejs/index.js +6 -0
- package/lib/vendor/blamejs/lib/a2a.js +4 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
- package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
- package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
- package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
- package/lib/vendor/blamejs/lib/archive-read.js +8 -0
- package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
- package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
- package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
- package/lib/vendor/blamejs/lib/audit.js +71 -8
- package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
- package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
- package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
- package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
- package/lib/vendor/blamejs/lib/backup/index.js +16 -5
- package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
- package/lib/vendor/blamejs/lib/base32.js +21 -0
- package/lib/vendor/blamejs/lib/break-glass.js +19 -10
- package/lib/vendor/blamejs/lib/bundler.js +5 -1
- package/lib/vendor/blamejs/lib/cache-status.js +3 -7
- package/lib/vendor/blamejs/lib/calendar.js +21 -1
- package/lib/vendor/blamejs/lib/cbor.js +12 -1
- package/lib/vendor/blamejs/lib/cert.js +29 -11
- package/lib/vendor/blamejs/lib/cli.js +94 -24
- package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
- package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
- package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
- package/lib/vendor/blamejs/lib/content-digest.js +2 -1
- package/lib/vendor/blamejs/lib/cookies.js +13 -3
- package/lib/vendor/blamejs/lib/cose.js +31 -16
- package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
- package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
- package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
- package/lib/vendor/blamejs/lib/crypto.js +314 -19
- package/lib/vendor/blamejs/lib/csp.js +11 -3
- package/lib/vendor/blamejs/lib/daemon.js +270 -24
- package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
- package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
- package/lib/vendor/blamejs/lib/db-query.js +34 -7
- package/lib/vendor/blamejs/lib/db.js +18 -6
- package/lib/vendor/blamejs/lib/dbsc.js +17 -0
- package/lib/vendor/blamejs/lib/dev.js +21 -2
- package/lib/vendor/blamejs/lib/dsr.js +157 -102
- package/lib/vendor/blamejs/lib/external-db.js +41 -2
- package/lib/vendor/blamejs/lib/file-upload.js +25 -7
- package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
- package/lib/vendor/blamejs/lib/forms.js +113 -27
- package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
- package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
- package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
- package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
- package/lib/vendor/blamejs/lib/guard-html.js +26 -53
- package/lib/vendor/blamejs/lib/guard-image.js +24 -5
- package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
- package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
- package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
- package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
- package/lib/vendor/blamejs/lib/guard-time.js +1 -1
- package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
- package/lib/vendor/blamejs/lib/html-balance.js +3 -3
- package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
- package/lib/vendor/blamejs/lib/http-client.js +39 -7
- package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
- package/lib/vendor/blamejs/lib/i18n.js +35 -21
- package/lib/vendor/blamejs/lib/incident-report.js +8 -1
- package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
- package/lib/vendor/blamejs/lib/json-path.js +23 -1
- package/lib/vendor/blamejs/lib/jwk.js +20 -3
- package/lib/vendor/blamejs/lib/link-header.js +2 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream.js +8 -3
- package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
- package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
- package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
- package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
- package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
- package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
- package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
- package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
- package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
- package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
- package/lib/vendor/blamejs/lib/mail.js +15 -5
- package/lib/vendor/blamejs/lib/metrics.js +268 -63
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
- package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
- package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
- package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
- package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
- package/lib/vendor/blamejs/lib/network-dns.js +21 -2
- package/lib/vendor/blamejs/lib/network-tls.js +69 -7
- package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
- package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
- package/lib/vendor/blamejs/lib/outbox.js +1 -1
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
- package/lib/vendor/blamejs/lib/permissions.js +6 -3
- package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
- package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
- package/lib/vendor/blamejs/lib/pubsub.js +20 -9
- package/lib/vendor/blamejs/lib/queue-local.js +8 -1
- package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
- package/lib/vendor/blamejs/lib/redact.js +54 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
- package/lib/vendor/blamejs/lib/restore.js +19 -0
- package/lib/vendor/blamejs/lib/retention.js +12 -4
- package/lib/vendor/blamejs/lib/router.js +60 -6
- package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
- package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
- package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
- package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
- package/lib/vendor/blamejs/lib/safe-object.js +80 -0
- package/lib/vendor/blamejs/lib/safe-path.js +52 -4
- package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
- package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
- package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
- package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
- package/lib/vendor/blamejs/lib/scheduler.js +8 -1
- package/lib/vendor/blamejs/lib/security-assert.js +6 -6
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
- package/lib/vendor/blamejs/lib/self-update.js +517 -87
- package/lib/vendor/blamejs/lib/server-timing.js +2 -4
- package/lib/vendor/blamejs/lib/session.js +34 -12
- package/lib/vendor/blamejs/lib/sql.js +15 -1
- package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
- package/lib/vendor/blamejs/lib/static.js +55 -13
- package/lib/vendor/blamejs/lib/storage.js +8 -2
- package/lib/vendor/blamejs/lib/subject.js +6 -1
- package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
- package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
- package/lib/vendor/blamejs/lib/tsa.js +34 -13
- package/lib/vendor/blamejs/lib/uri-template.js +8 -1
- package/lib/vendor/blamejs/lib/vault/index.js +13 -0
- package/lib/vendor/blamejs/lib/vc.js +44 -5
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
- package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
- package/lib/vendor/blamejs/lib/watcher.js +89 -17
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
- package/lib/vendor/blamejs/lib/webhook.js +12 -2
- package/lib/vendor/blamejs/lib/ws-client.js +32 -1
- package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
- package/lib/vendor/blamejs/package-lock.json +2 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
- package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
- package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
- package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
- package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
- package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
- package/lib/vendor/blamejs/socket.yml +94 -0
- package/lib/vendor/blamejs/test/00-primitives.js +605 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
- package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
- package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
- package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
- package/lib/vendor/blamejs/test/smoke.js +2 -0
- package/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
- package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
- package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
- package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
- package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
- package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
|
@@ -922,7 +922,20 @@ async function testDbStoreUpgradePath() {
|
|
|
922
922
|
$p: JSON.stringify({ id: "DSR-LEGACY-1", status: "pending", subject: { email: "legacy@example.com" } }),
|
|
923
923
|
});
|
|
924
924
|
|
|
925
|
-
//
|
|
925
|
+
// Also seed an OVERSIZED legacy plaintext row: its payload cannot be
|
|
926
|
+
// re-sealed into the vaulted store (the sealed form exceeds b.sql's
|
|
927
|
+
// per-value ceiling). The backfill must SKIP it — leaving it un-migrated —
|
|
928
|
+
// rather than crash provisioning with a SqlBuilderError.
|
|
929
|
+
var bigLegacy = "x".repeat(C.BYTES.mib(50));
|
|
930
|
+
b.db.prepare("INSERT INTO dsr_tickets (id, type, status, subject_email, submitted_at, deadline_at, payload) " +
|
|
931
|
+
"VALUES ($id, $type, $status, $email, $sa, $da, $p)").run({
|
|
932
|
+
$id: "DSR-LEGACY-BIG", $type: "access", $status: "pending",
|
|
933
|
+
$email: "big@example.com", $sa: Date.now(), $da: Date.now() + 1000, $p: bigLegacy,
|
|
934
|
+
});
|
|
935
|
+
bigLegacy = null; // release the big string promptly
|
|
936
|
+
|
|
937
|
+
// Constructing the store runs ensureSchema → reconciles the columns AND
|
|
938
|
+
// runs the legacy backfill (which must not crash on the oversized row).
|
|
926
939
|
var h = _dbDsr();
|
|
927
940
|
var cols = b.db.prepare("PRAGMA table_info(dsr_tickets)").all({});
|
|
928
941
|
var names = cols.map(function (c) { return c.name; });
|
|
@@ -956,6 +969,21 @@ async function testDbStoreUpgradePath() {
|
|
|
956
969
|
rawLegacy.subject_email_hash.length > 0);
|
|
957
970
|
check("dbStore upgrade: legacy subject_email sealed at rest by backfill (now erasable)",
|
|
958
971
|
rawLegacy && rawLegacy.subject_email !== "legacy@example.com");
|
|
972
|
+
|
|
973
|
+
// The oversized legacy row was migrated for FINDABILITY without crashing:
|
|
974
|
+
// its subject columns are sealed and its derived hash is populated (so
|
|
975
|
+
// list({ subject }) and the erasure purge see it — no un-erasable PII),
|
|
976
|
+
// while its over-cap payload is left plaintext (it cannot be sealed, but
|
|
977
|
+
// it is DB-encrypted at rest and removed when the row is erased).
|
|
978
|
+
var rawBig = b.db.prepare(
|
|
979
|
+
"SELECT subject_email, subject_email_hash, payload FROM dsr_tickets WHERE id = $id")
|
|
980
|
+
.all({ $id: "DSR-LEGACY-BIG" })[0];
|
|
981
|
+
check("dbStore upgrade: oversized legacy row hash populated (findable by subject lookup, erasable)",
|
|
982
|
+
rawBig && typeof rawBig.subject_email_hash === "string" && rawBig.subject_email_hash.length > 0);
|
|
983
|
+
check("dbStore upgrade: oversized legacy row subject sealed at rest",
|
|
984
|
+
rawBig && rawBig.subject_email !== "big@example.com");
|
|
985
|
+
check("dbStore upgrade: over-cap payload left plaintext (not sealed, but erasable via row delete)",
|
|
986
|
+
rawBig && typeof rawBig.payload === "string" && rawBig.payload.indexOf("vault:") !== 0);
|
|
959
987
|
} finally {
|
|
960
988
|
await teardownTestDb(tmpDir);
|
|
961
989
|
}
|
|
@@ -1038,6 +1066,816 @@ async function testResealValidationAndStore() {
|
|
|
1038
1066
|
}
|
|
1039
1067
|
}
|
|
1040
1068
|
|
|
1069
|
+
// ---- create() adversarial validation ----
|
|
1070
|
+
|
|
1071
|
+
async function testCreateBadSource() {
|
|
1072
|
+
var threw = null;
|
|
1073
|
+
try {
|
|
1074
|
+
b.dsr.create({
|
|
1075
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1076
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1077
|
+
// second source has neither query nor erase → invalid
|
|
1078
|
+
sources: [{ name: "ok", query: async function () { return []; } }, { name: "bad" }],
|
|
1079
|
+
});
|
|
1080
|
+
} catch (e) { threw = e; }
|
|
1081
|
+
check("dsr.create: source missing query/erase → dsr/bad-source",
|
|
1082
|
+
threw && threw.code === "dsr/bad-source");
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
function testCreateBadPosture() {
|
|
1086
|
+
var threw = null;
|
|
1087
|
+
try {
|
|
1088
|
+
b.dsr.create({
|
|
1089
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1090
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1091
|
+
sources: [{ name: "x", query: async function () { return []; } }],
|
|
1092
|
+
posture: 123, // non-string posture
|
|
1093
|
+
});
|
|
1094
|
+
} catch (e) { threw = e; }
|
|
1095
|
+
check("dsr.create: non-string posture → dsr/bad-posture",
|
|
1096
|
+
threw && threw.code === "dsr/bad-posture");
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
function testCreateBadDefaultVerificationLevel() {
|
|
1100
|
+
var threw = null;
|
|
1101
|
+
try {
|
|
1102
|
+
b.dsr.create({
|
|
1103
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1104
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1105
|
+
sources: [{ name: "x", query: async function () { return []; } }],
|
|
1106
|
+
verificationLevel: "bogus",
|
|
1107
|
+
});
|
|
1108
|
+
} catch (e) { threw = e; }
|
|
1109
|
+
check("dsr.create: invalid verificationLevel → dsr/bad-verification-level",
|
|
1110
|
+
threw && threw.code === "dsr/bad-verification-level");
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
function testCreateBadMinVerificationByType() {
|
|
1114
|
+
var threw = null;
|
|
1115
|
+
try {
|
|
1116
|
+
b.dsr.create({
|
|
1117
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1118
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1119
|
+
sources: [{ name: "x", query: async function () { return []; } }],
|
|
1120
|
+
minVerificationByType: { erasure: "bogus-level" },
|
|
1121
|
+
});
|
|
1122
|
+
} catch (e) { threw = e; }
|
|
1123
|
+
check("dsr.create: invalid minVerificationByType value → dsr/bad-min-verification",
|
|
1124
|
+
threw && threw.code === "dsr/bad-min-verification");
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// ---- submit() adversarial ----
|
|
1128
|
+
|
|
1129
|
+
async function testSubmitBadInput() {
|
|
1130
|
+
var dsr = _makeDsr();
|
|
1131
|
+
var threwNull = null;
|
|
1132
|
+
try { await dsr.submit(null); } catch (e) { threwNull = e; }
|
|
1133
|
+
check("dsr.submit: null input → dsr/bad-submit",
|
|
1134
|
+
threwNull && threwNull.code === "dsr/bad-submit");
|
|
1135
|
+
var threwStr = null;
|
|
1136
|
+
try { await dsr.submit("not-an-object"); } catch (e) { threwStr = e; }
|
|
1137
|
+
check("dsr.submit: non-object input → dsr/bad-submit",
|
|
1138
|
+
threwStr && threwStr.code === "dsr/bad-submit");
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
async function testSubmitIdentityResolverThrows() {
|
|
1142
|
+
// Distinct from testSubmitIdentityResolverFails (resolver RETURNS null):
|
|
1143
|
+
// here the resolver THROWS, exercising the reject-audit + wrap path.
|
|
1144
|
+
var dsr = b.dsr.create({
|
|
1145
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1146
|
+
posture: "gdpr",
|
|
1147
|
+
identityResolver: async function () { throw new Error("resolver backend down"); },
|
|
1148
|
+
sources: [{ name: "x", query: async function () { return []; } }],
|
|
1149
|
+
});
|
|
1150
|
+
var threw = null;
|
|
1151
|
+
try { await dsr.submit({ type: "access", subject: { email: "a@b.com" } }); }
|
|
1152
|
+
catch (e) { threw = e; }
|
|
1153
|
+
check("dsr.submit: identityResolver throw → dsr/identity-resolver-failed",
|
|
1154
|
+
threw && threw.code === "dsr/identity-resolver-failed");
|
|
1155
|
+
check("dsr.submit: identity-resolver error surfaced in message",
|
|
1156
|
+
threw && /resolver backend down/.test(threw.message || ""));
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
async function testSubmitBadVerificationLevel() {
|
|
1160
|
+
var dsr = _makeDsr();
|
|
1161
|
+
var threw = null;
|
|
1162
|
+
try {
|
|
1163
|
+
await dsr.submit({
|
|
1164
|
+
type: "access",
|
|
1165
|
+
subject: { email: "alice@example.com" },
|
|
1166
|
+
verificationLevel: "ultra",
|
|
1167
|
+
});
|
|
1168
|
+
} catch (e) { threw = e; }
|
|
1169
|
+
check("dsr.submit: invalid verificationLevel → dsr/bad-verification-level",
|
|
1170
|
+
threw && threw.code === "dsr/bad-verification-level");
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// ---- process() adversarial / wrong-state ----
|
|
1174
|
+
|
|
1175
|
+
async function testProcessAlreadyInProgress() {
|
|
1176
|
+
// Drive a ticket into "in_progress" (the concurrent-processor guard state)
|
|
1177
|
+
// via the store, then re-process → dsr/already-in-progress.
|
|
1178
|
+
var store = b.dsr.memoryTicketStore();
|
|
1179
|
+
var dsr = _makeDsr({ ticketStore: store });
|
|
1180
|
+
var ticket = await dsr.submit({
|
|
1181
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1182
|
+
});
|
|
1183
|
+
var t = await store.get(ticket.id);
|
|
1184
|
+
t.status = "in_progress";
|
|
1185
|
+
await store.update(ticket.id, t);
|
|
1186
|
+
var threw = null;
|
|
1187
|
+
try { await dsr.process(ticket.id); } catch (e) { threw = e; }
|
|
1188
|
+
check("dsr.process: in_progress ticket → dsr/already-in-progress",
|
|
1189
|
+
threw && threw.code === "dsr/already-in-progress");
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
async function testProcessBadVerificationLevel() {
|
|
1193
|
+
var dsr = _makeDsr();
|
|
1194
|
+
var ticket = await dsr.submit({
|
|
1195
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1196
|
+
});
|
|
1197
|
+
var threw = null;
|
|
1198
|
+
try { await dsr.process(ticket.id, { verificationLevel: "not-a-level" }); }
|
|
1199
|
+
catch (e) { threw = e; }
|
|
1200
|
+
check("dsr.process: invalid verificationLevel → dsr/bad-verification-level",
|
|
1201
|
+
threw && threw.code === "dsr/bad-verification-level");
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
async function testProcessErasurePurgeFailure() {
|
|
1205
|
+
// The erasure-completion purge is best-effort: a store.delete() failure
|
|
1206
|
+
// must NOT unwind the completed erasure. Wrap the memory store so delete
|
|
1207
|
+
// throws; the erasure still completes and the prior ticket survives.
|
|
1208
|
+
var real = b.dsr.memoryTicketStore();
|
|
1209
|
+
var store = {
|
|
1210
|
+
insert: real.insert,
|
|
1211
|
+
get: real.get,
|
|
1212
|
+
list: real.list,
|
|
1213
|
+
update: real.update,
|
|
1214
|
+
delete: async function () { throw new Error("delete backend unreachable"); },
|
|
1215
|
+
};
|
|
1216
|
+
var dsr = _makeDsr({ ticketStore: store });
|
|
1217
|
+
var prior = await dsr.submit({
|
|
1218
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1219
|
+
});
|
|
1220
|
+
var erasure = await dsr.submit({
|
|
1221
|
+
type: "erasure", subject: { email: "alice@example.com" },
|
|
1222
|
+
verificationLevel: "secondary",
|
|
1223
|
+
});
|
|
1224
|
+
var result = await dsr.process(erasure.id, { verificationLevel: "secondary" });
|
|
1225
|
+
check("dsr.process erasure: completes despite purge delete() failure",
|
|
1226
|
+
result.status === "completed");
|
|
1227
|
+
var priorStill = await store.get(prior.id);
|
|
1228
|
+
check("dsr.process erasure: purge delete() failure leaves prior ticket intact",
|
|
1229
|
+
priorStill && priorStill.id === prior.id);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
async function testAuditDisabled() {
|
|
1233
|
+
// audit:false disables emission — the _emitAudit early-return path. The
|
|
1234
|
+
// workflow must still function end-to-end with the audit sink off.
|
|
1235
|
+
var dsr = _makeDsr({ audit: false });
|
|
1236
|
+
var ticket = await dsr.submit({
|
|
1237
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1238
|
+
});
|
|
1239
|
+
var result = await dsr.process(ticket.id);
|
|
1240
|
+
check("dsr audit:false: submit + process still complete",
|
|
1241
|
+
result.status === "completed" && ticket.status === "pending");
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
async function testProcessQueryNonArrayRows() {
|
|
1245
|
+
// rows = Array.isArray(rows) ? len : (rows ? 1 : 0). A source returning a
|
|
1246
|
+
// truthy non-array counts as 1; a falsy return counts as 0.
|
|
1247
|
+
var dsr = b.dsr.create({
|
|
1248
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1249
|
+
posture: "gdpr",
|
|
1250
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1251
|
+
sources: [
|
|
1252
|
+
{ name: "objsrc", query: async function () { return { single: true }; } },
|
|
1253
|
+
{ name: "nullsrc", query: async function () { return null; } },
|
|
1254
|
+
],
|
|
1255
|
+
});
|
|
1256
|
+
var ticket = await dsr.submit({ type: "access", subject: { email: "x" } });
|
|
1257
|
+
var result = await dsr.process(ticket.id);
|
|
1258
|
+
check("dsr.process: non-array truthy query counts as 1 row",
|
|
1259
|
+
result.sourceResults[0].rows === 1);
|
|
1260
|
+
check("dsr.process: falsy query counts as 0 rows",
|
|
1261
|
+
result.sourceResults[1].rows === 0);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
async function testProcessEraseResultShapes() {
|
|
1265
|
+
// Erase-result normalization: { deleted: n } numeric count, {} → 0 with
|
|
1266
|
+
// null deletedIds, and eraseExclusions falling back from the source spec.
|
|
1267
|
+
var dsr = b.dsr.create({
|
|
1268
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1269
|
+
posture: "gdpr",
|
|
1270
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1271
|
+
minVerificationByType: { erasure: "minimal" },
|
|
1272
|
+
sources: [
|
|
1273
|
+
{ name: "countsrc", erase: async function () { return { deleted: 3 }; } },
|
|
1274
|
+
{ name: "emptysrc", erase: async function () { return {}; } },
|
|
1275
|
+
{ name: "exclsrc", eraseExclusions: ["legal-hold"],
|
|
1276
|
+
erase: async function () { return { deletedIds: [1] }; } },
|
|
1277
|
+
],
|
|
1278
|
+
});
|
|
1279
|
+
var ticket = await dsr.submit({ type: "erasure", subject: { email: "x" } });
|
|
1280
|
+
var result = await dsr.process(ticket.id);
|
|
1281
|
+
check("dsr.process erase: numeric { deleted } count honored",
|
|
1282
|
+
result.sourceResults[0].deleted === 3);
|
|
1283
|
+
check("dsr.process erase: empty erase result → 0 deleted, null deletedIds",
|
|
1284
|
+
result.sourceResults[1].deleted === 0 && result.sourceResults[1].deletedIds === null);
|
|
1285
|
+
check("dsr.process erase: exclusions fall back to source eraseExclusions",
|
|
1286
|
+
Array.isArray(result.sourceResults[2].exclusions) &&
|
|
1287
|
+
result.sourceResults[2].exclusions[0] === "legal-hold");
|
|
1288
|
+
check("dsr.process erase: totalDeleted sums numeric + id-array counts",
|
|
1289
|
+
result.result.totalDeleted === 4);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// ---- cancel / reject / get not-found + defaults ----
|
|
1293
|
+
|
|
1294
|
+
async function testCancelNotFound() {
|
|
1295
|
+
var dsr = _makeDsr();
|
|
1296
|
+
var threw = null;
|
|
1297
|
+
try { await dsr.cancel("DSR-DOES-NOT-EXIST"); } catch (e) { threw = e; }
|
|
1298
|
+
check("dsr.cancel: unknown ticket → dsr/not-found",
|
|
1299
|
+
threw && threw.code === "dsr/not-found");
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
async function testCancelWithoutActorReason() {
|
|
1303
|
+
// cancel() with no opts → cancelledBy / cancelReason default to null; the
|
|
1304
|
+
// subsequent receipt's cancelReason is null too.
|
|
1305
|
+
var dsr = _makeDsr();
|
|
1306
|
+
var ticket = await dsr.submit({
|
|
1307
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1308
|
+
});
|
|
1309
|
+
var cancelled = await dsr.cancel(ticket.id);
|
|
1310
|
+
check("dsr.cancel: no actor → cancelledBy null", cancelled.cancelledBy === null);
|
|
1311
|
+
check("dsr.cancel: no reason → cancelReason null", cancelled.cancelReason === null);
|
|
1312
|
+
var receipt = await dsr.buildReceipt(ticket.id);
|
|
1313
|
+
check("dsr.buildReceipt: cancelled without reason → summary.cancelReason null",
|
|
1314
|
+
receipt.status === "cancelled" && receipt.summary.cancelReason === null);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
async function testRejectNotFound() {
|
|
1318
|
+
var dsr = _makeDsr();
|
|
1319
|
+
var threw = null;
|
|
1320
|
+
try { await dsr.reject("DSR-DOES-NOT-EXIST", { reason: "no such ticket" }); }
|
|
1321
|
+
catch (e) { threw = e; }
|
|
1322
|
+
check("dsr.reject: unknown ticket → dsr/not-found",
|
|
1323
|
+
threw && threw.code === "dsr/not-found");
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
async function testRejectTerminal() {
|
|
1327
|
+
var dsr = _makeDsr();
|
|
1328
|
+
var ticket = await dsr.submit({
|
|
1329
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1330
|
+
});
|
|
1331
|
+
await dsr.process(ticket.id); // → completed (terminal)
|
|
1332
|
+
var threw = null;
|
|
1333
|
+
try { await dsr.reject(ticket.id, { reason: "too late" }); }
|
|
1334
|
+
catch (e) { threw = e; }
|
|
1335
|
+
check("dsr.reject: terminal-state ticket → dsr/terminal-state",
|
|
1336
|
+
threw && threw.code === "dsr/terminal-state");
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
async function testGetViaCoordinator() {
|
|
1340
|
+
var dsr = _makeDsr();
|
|
1341
|
+
var ticket = await dsr.submit({
|
|
1342
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1343
|
+
});
|
|
1344
|
+
var got = await dsr.get(ticket.id);
|
|
1345
|
+
check("dsr.get: coordinator returns the stored ticket",
|
|
1346
|
+
got && got.id === ticket.id && got.status === "pending");
|
|
1347
|
+
var missing = await dsr.get("DSR-NOPE");
|
|
1348
|
+
check("dsr.get: unknown id → null", missing === null);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
async function testListByStatusBadStatus() {
|
|
1352
|
+
var dsr = _makeDsr();
|
|
1353
|
+
var threw = null;
|
|
1354
|
+
try { await dsr.listByStatus("made-up-status"); } catch (e) { threw = e; }
|
|
1355
|
+
check("dsr.listByStatus: invalid status → dsr/bad-status",
|
|
1356
|
+
threw && threw.code === "dsr/bad-status");
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// ---- buildReceipt / buildPortabilityBundle adversarial ----
|
|
1360
|
+
|
|
1361
|
+
async function testBuildReceiptNotFound() {
|
|
1362
|
+
var dsr = _makeDsr();
|
|
1363
|
+
var threw = null;
|
|
1364
|
+
try { await dsr.buildReceipt("DSR-NOPE"); } catch (e) { threw = e; }
|
|
1365
|
+
check("dsr.buildReceipt: unknown ticket → dsr/not-found",
|
|
1366
|
+
threw && threw.code === "dsr/not-found");
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
async function testBuildReceiptExpired() {
|
|
1370
|
+
var dsr = _makeDsr({ deadlineMs: 50 });
|
|
1371
|
+
var ticket = await dsr.submit({
|
|
1372
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1373
|
+
});
|
|
1374
|
+
var expired = await helpers.waitUntil(async function () {
|
|
1375
|
+
var rv = await dsr.expireOverdue();
|
|
1376
|
+
return rv.length >= 1 ? rv : false;
|
|
1377
|
+
}, { label: "dsr.buildReceipt: expired-ticket sweep" });
|
|
1378
|
+
check("dsr.buildReceipt expired: ticket collected", expired.length === 1);
|
|
1379
|
+
var receipt = await dsr.buildReceipt(ticket.id);
|
|
1380
|
+
check("dsr.buildReceipt: expired status echoed", receipt.status === "expired");
|
|
1381
|
+
check("dsr.buildReceipt: expired summary carries deadlineAt",
|
|
1382
|
+
receipt.summary.deadlineAt === ticket.deadlineAt);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
function testPortabilityBadTicket() {
|
|
1386
|
+
var dsr = _makeDsr();
|
|
1387
|
+
var threwNull = null;
|
|
1388
|
+
try { dsr.buildPortabilityBundle(null); } catch (e) { threwNull = e; }
|
|
1389
|
+
check("dsr.buildPortabilityBundle: null ticket → dsr/bad-ticket",
|
|
1390
|
+
threwNull && threwNull.code === "dsr/bad-ticket");
|
|
1391
|
+
var threwNoType = null;
|
|
1392
|
+
try { dsr.buildPortabilityBundle({ id: "x" }); } catch (e) { threwNoType = e; }
|
|
1393
|
+
check("dsr.buildPortabilityBundle: ticket without type → dsr/bad-ticket",
|
|
1394
|
+
threwNoType && threwNoType.code === "dsr/bad-ticket");
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// ---- memoryTicketStore update-not-found + delete ----
|
|
1398
|
+
|
|
1399
|
+
async function testMemoryStoreUpdateNotFoundAndDelete() {
|
|
1400
|
+
var store = b.dsr.memoryTicketStore();
|
|
1401
|
+
await store.insert({ id: "M1", subject: { email: "a" }, status: "pending" });
|
|
1402
|
+
var threw = null;
|
|
1403
|
+
try { await store.update("M-MISSING", { id: "M-MISSING", subject: {}, status: "pending" }); }
|
|
1404
|
+
catch (e) { threw = e; }
|
|
1405
|
+
check("memoryStore.update: missing id → dsr/ticket-not-found",
|
|
1406
|
+
threw && threw.code === "dsr/ticket-not-found");
|
|
1407
|
+
|
|
1408
|
+
var removed = await store.delete("M1");
|
|
1409
|
+
check("memoryStore.delete: existing id returns true", removed === true);
|
|
1410
|
+
check("memoryStore.delete: row is gone", (await store.get("M1")) === null);
|
|
1411
|
+
var removedMissing = await store.delete("M1");
|
|
1412
|
+
check("memoryStore.delete: absent id returns false", removedMissing === false);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// ---- dbTicketStore adversarial + purge + status list + update-not-found ----
|
|
1416
|
+
|
|
1417
|
+
async function testDbStoreBadTable() {
|
|
1418
|
+
var tmpDir = _tmp();
|
|
1419
|
+
await setupTestDb(tmpDir);
|
|
1420
|
+
try {
|
|
1421
|
+
var threw = null;
|
|
1422
|
+
try { b.dsr.dbTicketStore({ db: b.db, table: "evil; DROP TABLE users" }); }
|
|
1423
|
+
catch (e) { threw = e; }
|
|
1424
|
+
check("dbTicketStore: non-identifier table → dsr/bad-table",
|
|
1425
|
+
threw && threw.code === "dsr/bad-table");
|
|
1426
|
+
} finally {
|
|
1427
|
+
await teardownTestDb(tmpDir);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
async function testDbStoreListByStatus() {
|
|
1432
|
+
var tmpDir = _tmp();
|
|
1433
|
+
await setupTestDb(tmpDir);
|
|
1434
|
+
try {
|
|
1435
|
+
var h = _dbDsr();
|
|
1436
|
+
var t1 = await h.dsr.submit({ type: "access", subject: { email: "alice@example.com" } });
|
|
1437
|
+
await h.dsr.process(t1.id);
|
|
1438
|
+
await h.dsr.submit({ type: "access", subject: { email: "alice@example.com" } });
|
|
1439
|
+
var pending = await h.store.list({ status: "pending" });
|
|
1440
|
+
check("dbStore.list({status:pending}): 1 pending ticket",
|
|
1441
|
+
pending.length === 1 && pending[0].status === "pending");
|
|
1442
|
+
var completed = await h.store.list({ status: "completed" });
|
|
1443
|
+
check("dbStore.list({status:completed}): 1 completed ticket",
|
|
1444
|
+
completed.length === 1 && completed[0].status === "completed");
|
|
1445
|
+
var all = await h.store.list(); // no filter → filter || {}
|
|
1446
|
+
check("dbStore.list(): no filter returns every ticket", all.length === 2);
|
|
1447
|
+
} finally {
|
|
1448
|
+
await teardownTestDb(tmpDir);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
async function testDbStoreUpdateNotFound() {
|
|
1453
|
+
var tmpDir = _tmp();
|
|
1454
|
+
await setupTestDb(tmpDir);
|
|
1455
|
+
try {
|
|
1456
|
+
var store = b.dsr.dbTicketStore({ db: b.db });
|
|
1457
|
+
var ghost = {
|
|
1458
|
+
id: "DSR-GHOST", type: "access", status: "pending",
|
|
1459
|
+
subject: { subjectId: "u-x", email: "ghost@example.com", phone: null },
|
|
1460
|
+
submittedAt: Date.now(), deadlineAt: Date.now() + C.TIME.minutes(1),
|
|
1461
|
+
posture: "gdpr", verificationLevel: "minimal",
|
|
1462
|
+
};
|
|
1463
|
+
var threw = null;
|
|
1464
|
+
try { await store.update("DSR-GHOST", ghost); } catch (e) { threw = e; }
|
|
1465
|
+
check("dbStore.update: id absent (0 changes) → dsr/ticket-not-found",
|
|
1466
|
+
threw && threw.code === "dsr/ticket-not-found");
|
|
1467
|
+
} finally {
|
|
1468
|
+
await teardownTestDb(tmpDir);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
async function testDbStorePurgeExpired() {
|
|
1473
|
+
var tmpDir = _tmp();
|
|
1474
|
+
await setupTestDb(tmpDir);
|
|
1475
|
+
try {
|
|
1476
|
+
var store = b.dsr.dbTicketStore({ db: b.db });
|
|
1477
|
+
var now = Date.now();
|
|
1478
|
+
function _mk(id, status, retentionUntil) {
|
|
1479
|
+
return {
|
|
1480
|
+
id: id, type: "access", status: status,
|
|
1481
|
+
subject: { subjectId: "u-" + id, email: id + "@example.com", phone: null },
|
|
1482
|
+
submittedAt: now, deadlineAt: now, retentionUntil: retentionUntil,
|
|
1483
|
+
posture: "gdpr", verificationLevel: "minimal",
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
// Terminal + retention already lapsed → purged.
|
|
1487
|
+
await store.insert(_mk("PAST", "completed", now - C.TIME.days(1)));
|
|
1488
|
+
// Terminal but retention still in the future → retained.
|
|
1489
|
+
await store.insert(_mk("FUTURE", "cancelled", now + C.TIME.days(30)));
|
|
1490
|
+
// Non-terminal (pending) with lapsed retention → not selected at all.
|
|
1491
|
+
await store.insert(_mk("PENDING", "pending", now - C.TIME.days(1)));
|
|
1492
|
+
|
|
1493
|
+
var purged = await store.purgeExpired(); // default asOf = now
|
|
1494
|
+
check("dbStore.purgeExpired(): removes only the lapsed terminal ticket",
|
|
1495
|
+
purged === 1);
|
|
1496
|
+
check("dbStore.purgeExpired(): lapsed terminal row gone",
|
|
1497
|
+
(await store.get("PAST")) === null);
|
|
1498
|
+
check("dbStore.purgeExpired(): future-retention terminal row survives",
|
|
1499
|
+
(await store.get("FUTURE")) !== null);
|
|
1500
|
+
check("dbStore.purgeExpired(): non-terminal pending row survives",
|
|
1501
|
+
(await store.get("PENDING")) !== null);
|
|
1502
|
+
|
|
1503
|
+
// Explicit asOfMs far in the future now lapses the FUTURE ticket too.
|
|
1504
|
+
var purged2 = await store.purgeExpired(now + C.TIME.days(60));
|
|
1505
|
+
check("dbStore.purgeExpired(asOfMs): explicit cutoff lapses the future ticket",
|
|
1506
|
+
purged2 === 1 && (await store.get("FUTURE")) === null);
|
|
1507
|
+
} finally {
|
|
1508
|
+
await teardownTestDb(tmpDir);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
async function testDbStoreTicketTooLarge() {
|
|
1513
|
+
var tmpDir = _tmp();
|
|
1514
|
+
await setupTestDb(tmpDir);
|
|
1515
|
+
try {
|
|
1516
|
+
var store = b.dsr.dbTicketStore({ db: b.db });
|
|
1517
|
+
// A serialized ticket above safeJson.ABSOLUTE_MAX_BYTES (64 MiB) is
|
|
1518
|
+
// refused at write, so the store never holds a payload it could not read
|
|
1519
|
+
// back through safeJson.parse's hard ceiling (write cap == read cap).
|
|
1520
|
+
var oversized = "x".repeat(C.BYTES.mib(64)); // JSON wrapping pushes it over 64 MiB
|
|
1521
|
+
var ticket = {
|
|
1522
|
+
id: "DSR-TOO-BIG", type: "access", status: "pending",
|
|
1523
|
+
subject: { subjectId: "u-1", email: "a@b.com", phone: null },
|
|
1524
|
+
submittedAt: Date.now(), deadlineAt: Date.now() + C.TIME.minutes(1),
|
|
1525
|
+
posture: "gdpr", verificationLevel: "minimal",
|
|
1526
|
+
blob: oversized,
|
|
1527
|
+
};
|
|
1528
|
+
var threw = null;
|
|
1529
|
+
try { await store.insert(ticket); } catch (e) { threw = e; }
|
|
1530
|
+
oversized = null; ticket.blob = null; // release the big string promptly
|
|
1531
|
+
check("dbStore.insert: oversized ticket payload → dsr/ticket-too-large",
|
|
1532
|
+
threw && threw.code === "dsr/ticket-too-large");
|
|
1533
|
+
|
|
1534
|
+
// A vaulted store AEAD-seals + base64-expands (~4/3) the payload before
|
|
1535
|
+
// binding it, so a plaintext between the expansion-safe cap (~48 MiB) and
|
|
1536
|
+
// the 64 MiB read ceiling would seal PAST b.sql's 64 MiB per-value cap. It
|
|
1537
|
+
// must be refused here with the store's own dsr/ticket-too-large error,
|
|
1538
|
+
// not surface as a SqlBuilderError (sql-builder/param-too-large) from the
|
|
1539
|
+
// insert's b.sql path.
|
|
1540
|
+
var nearMax = "x".repeat(C.BYTES.mib(50)); // > the ~48 MiB vaulted cap, < 64 MiB
|
|
1541
|
+
var ticket2 = {
|
|
1542
|
+
id: "DSR-SEAL-EXPAND", type: "access", status: "pending",
|
|
1543
|
+
subject: { subjectId: "u-2", email: "b@c.com", phone: null },
|
|
1544
|
+
submittedAt: Date.now(), deadlineAt: Date.now() + C.TIME.minutes(1),
|
|
1545
|
+
posture: "gdpr", verificationLevel: "minimal",
|
|
1546
|
+
blob: nearMax,
|
|
1547
|
+
};
|
|
1548
|
+
var threw2 = null;
|
|
1549
|
+
try { await store.insert(ticket2); } catch (e) { threw2 = e; }
|
|
1550
|
+
nearMax = null; ticket2.blob = null; // release promptly
|
|
1551
|
+
check("dbStore.insert: vaulted payload that seals past 64 MiB → dsr/ticket-too-large (not SqlBuilderError)",
|
|
1552
|
+
threw2 && threw2.code === "dsr/ticket-too-large");
|
|
1553
|
+
} finally {
|
|
1554
|
+
await teardownTestDb(tmpDir);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
// ---- reseal: real AAD-cell rotation + non-array store guard ----
|
|
1559
|
+
|
|
1560
|
+
async function testResealRotatesAadCell() {
|
|
1561
|
+
var cryptoField = require("../../lib/crypto-field");
|
|
1562
|
+
var vaultAad = require("../../lib/vault-aad");
|
|
1563
|
+
var tmpDir = _tmp();
|
|
1564
|
+
await setupTestDb(tmpDir);
|
|
1565
|
+
try {
|
|
1566
|
+
// Constructing the store registers the dsr_tickets sealed-column schema
|
|
1567
|
+
// with cryptoField (vault is initialized), so sealRow can AAD-seal a cell.
|
|
1568
|
+
b.dsr.dbTicketStore({ db: b.db });
|
|
1569
|
+
var sealed = cryptoField.sealRow("dsr_tickets", {
|
|
1570
|
+
id: "RESEAL-1", subject_email: "rotate@example.com",
|
|
1571
|
+
});
|
|
1572
|
+
check("reseal fixture: subject_email is AAD-sealed",
|
|
1573
|
+
vaultAad.isAadSealed(sealed.subject_email));
|
|
1574
|
+
var origCell = sealed.subject_email;
|
|
1575
|
+
|
|
1576
|
+
var keys = b.vault.getKeysJson();
|
|
1577
|
+
var puts = [];
|
|
1578
|
+
var store = {
|
|
1579
|
+
listAll: function () { return [sealed]; },
|
|
1580
|
+
putResealed: function (row) { puts.push(row); },
|
|
1581
|
+
};
|
|
1582
|
+
var rv = await b.dsr.reseal({ store: store, oldRootJson: keys, newRootJson: keys });
|
|
1583
|
+
check("reseal: one AAD cell rotated + persisted",
|
|
1584
|
+
rv.table === "dsr_tickets" && rv.resealed === 1 && puts.length === 1);
|
|
1585
|
+
check("reseal: rotated cell re-encrypted (ciphertext changed)",
|
|
1586
|
+
sealed.subject_email !== origCell && vaultAad.isAadSealed(sealed.subject_email));
|
|
1587
|
+
var unsealed = cryptoField.unsealRow("dsr_tickets", {
|
|
1588
|
+
id: "RESEAL-1", subject_email: sealed.subject_email,
|
|
1589
|
+
});
|
|
1590
|
+
check("reseal: rotated cell still unseals to the original plaintext",
|
|
1591
|
+
unsealed.subject_email === "rotate@example.com");
|
|
1592
|
+
} finally {
|
|
1593
|
+
await teardownTestDb(tmpDir);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
async function testResealListAllNonArray() {
|
|
1598
|
+
var tmpDir = _tmp();
|
|
1599
|
+
await setupTestDb(tmpDir);
|
|
1600
|
+
try {
|
|
1601
|
+
var keys = b.vault.getKeysJson();
|
|
1602
|
+
var threw = null;
|
|
1603
|
+
try {
|
|
1604
|
+
await b.dsr.reseal({
|
|
1605
|
+
oldRootJson: keys, newRootJson: keys,
|
|
1606
|
+
store: { listAll: function () { return "not-an-array"; }, putResealed: function () {} },
|
|
1607
|
+
});
|
|
1608
|
+
} catch (e) { threw = e; }
|
|
1609
|
+
check("reseal: store.listAll() returning a non-array → dsr/bad-reseal-store",
|
|
1610
|
+
threw && threw.code === "dsr/bad-reseal-store");
|
|
1611
|
+
} finally {
|
|
1612
|
+
await teardownTestDb(tmpDir);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// ---- state-law DSR registry ----
|
|
1617
|
+
|
|
1618
|
+
function testStateRules() {
|
|
1619
|
+
var vcdpa = b.dsr.stateRules("vcdpa");
|
|
1620
|
+
check("stateRules(vcdpa): responseDays 45", vcdpa && vcdpa.responseDays === 45);
|
|
1621
|
+
check("stateRules(vcdpa): cureDays 30", vcdpa.cureDays === 30);
|
|
1622
|
+
check("stateRules(vcdpa): profilingOptOut true", vcdpa.profilingOptOut === true);
|
|
1623
|
+
|
|
1624
|
+
var byAbbr = b.dsr.stateRules("va"); // 2-letter, case-insensitive
|
|
1625
|
+
check("stateRules(VA abbrev): resolves to VA rule",
|
|
1626
|
+
byAbbr && byAbbr.state === "VA" && byAbbr.posture === "vcdpa");
|
|
1627
|
+
|
|
1628
|
+
check("stateRules(unknown): null", b.dsr.stateRules("zz") === null);
|
|
1629
|
+
check("stateRules(non-string): null", b.dsr.stateRules(123) === null);
|
|
1630
|
+
check("stateRules(empty string): null", b.dsr.stateRules("") === null);
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
function testListStateRules() {
|
|
1634
|
+
var all = b.dsr.listStateRules();
|
|
1635
|
+
check("listStateRules: returns a non-empty array",
|
|
1636
|
+
Array.isArray(all) && all.length > 0);
|
|
1637
|
+
check("listStateRules: each entry carries posture + state + responseDays",
|
|
1638
|
+
all.every(function (r) {
|
|
1639
|
+
return typeof r.posture === "string" &&
|
|
1640
|
+
typeof r.state === "string" &&
|
|
1641
|
+
typeof r.responseDays === "number";
|
|
1642
|
+
}));
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// ---- additional default-branch / guard coverage ----
|
|
1646
|
+
|
|
1647
|
+
function testCreateMoreValidation() {
|
|
1648
|
+
var t1 = null;
|
|
1649
|
+
try {
|
|
1650
|
+
b.dsr.create({
|
|
1651
|
+
ticketStore: null, // !store side of _validateTicketStore
|
|
1652
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1653
|
+
sources: [{ name: "x", query: async function () { return []; } }],
|
|
1654
|
+
});
|
|
1655
|
+
} catch (e) { t1 = e; }
|
|
1656
|
+
check("dsr.create: null ticketStore → dsr/bad-store", t1 && t1.code === "dsr/bad-store");
|
|
1657
|
+
|
|
1658
|
+
var t2 = null;
|
|
1659
|
+
try {
|
|
1660
|
+
b.dsr.create({
|
|
1661
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1662
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1663
|
+
sources: [null], // !s side of _validateSource
|
|
1664
|
+
});
|
|
1665
|
+
} catch (e) { t2 = e; }
|
|
1666
|
+
check("dsr.create: null source → dsr/bad-source", t2 && t2.code === "dsr/bad-source");
|
|
1667
|
+
|
|
1668
|
+
var t3 = null;
|
|
1669
|
+
try {
|
|
1670
|
+
b.dsr.create({
|
|
1671
|
+
ticketStore: b.dsr.memoryTicketStore(),
|
|
1672
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1673
|
+
sources: [{ name: "", query: async function () { return []; } }], // empty name
|
|
1674
|
+
});
|
|
1675
|
+
} catch (e) { t3 = e; }
|
|
1676
|
+
check("dsr.create: empty source name → dsr/bad-source", t3 && t3.code === "dsr/bad-source");
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
async function testSubmitResolverThrowsEmptyMessage() {
|
|
1680
|
+
// Resolver throws an Error with an empty message → (e && e.message) is
|
|
1681
|
+
// falsy, so the audit metadata + wrapped-message path takes the String(e)
|
|
1682
|
+
// fallback rather than the message branch.
|
|
1683
|
+
var dsr = b.dsr.create({
|
|
1684
|
+
ticketStore: b.dsr.memoryTicketStore(), posture: "gdpr",
|
|
1685
|
+
identityResolver: async function () { throw new Error(""); },
|
|
1686
|
+
sources: [{ name: "x", query: async function () { return []; } }],
|
|
1687
|
+
});
|
|
1688
|
+
var threw = null;
|
|
1689
|
+
try { await dsr.submit({ type: "access", subject: { email: "a@b.com" } }); }
|
|
1690
|
+
catch (e) { threw = e; }
|
|
1691
|
+
check("dsr.submit: empty-message resolver throw → dsr/identity-resolver-failed",
|
|
1692
|
+
threw && threw.code === "dsr/identity-resolver-failed");
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
async function testProcessSourceThrowsEmptyMessage() {
|
|
1696
|
+
var dsr = b.dsr.create({
|
|
1697
|
+
ticketStore: b.dsr.memoryTicketStore(), posture: "gdpr",
|
|
1698
|
+
identityResolver: async function () { return { subjectId: "u" }; },
|
|
1699
|
+
sources: [{ name: "boom", query: async function () { throw new Error(""); } }],
|
|
1700
|
+
});
|
|
1701
|
+
var ticket = await dsr.submit({ type: "access", subject: { email: "x" } });
|
|
1702
|
+
var result = await dsr.process(ticket.id);
|
|
1703
|
+
check("dsr.process: empty-message source throw recorded via String(e) fallback",
|
|
1704
|
+
result.status === "partially_completed" &&
|
|
1705
|
+
result.sourceResults[0].error === "Error");
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
async function testListBySubjectBadInput() {
|
|
1709
|
+
var dsr = _makeDsr();
|
|
1710
|
+
var r1 = await dsr.listBySubject(null);
|
|
1711
|
+
var r2 = await dsr.listBySubject("not-an-object");
|
|
1712
|
+
check("dsr.listBySubject: non-object subject → []",
|
|
1713
|
+
Array.isArray(r1) && r1.length === 0 && Array.isArray(r2) && r2.length === 0);
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
async function testExpireOverdueNotPast() {
|
|
1717
|
+
var dsr = _makeDsr({ deadlineMs: C.TIME.days(30) });
|
|
1718
|
+
await dsr.submit({ type: "access", subject: { email: "alice@example.com" } });
|
|
1719
|
+
var expired = await dsr.expireOverdue();
|
|
1720
|
+
check("dsr.expireOverdue: pending ticket within deadline not swept",
|
|
1721
|
+
expired.length === 0);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
async function testReceiptSignerPartialResult() {
|
|
1725
|
+
// Signer returns an object with none of issuer/algorithm/signature → each
|
|
1726
|
+
// falls back to null.
|
|
1727
|
+
var dsr = _makeDsr({ receiptSigner: async function () { return {}; } });
|
|
1728
|
+
var ticket = await dsr.submit({
|
|
1729
|
+
type: "access", subject: { email: "alice@example.com" },
|
|
1730
|
+
});
|
|
1731
|
+
await dsr.process(ticket.id);
|
|
1732
|
+
var receipt = await dsr.buildReceipt(ticket.id);
|
|
1733
|
+
check("dsr.buildReceipt: empty signer result → issuer/algorithm/signature null",
|
|
1734
|
+
receipt.issuer === null && receipt.algorithm === null && receipt.signature === null);
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
async function testPortabilityCancelled() {
|
|
1738
|
+
var dsr = _makeDsr();
|
|
1739
|
+
var ticket = await dsr.submit({
|
|
1740
|
+
type: "portability", subject: { email: "alice@example.com" },
|
|
1741
|
+
verificationLevel: "secondary",
|
|
1742
|
+
});
|
|
1743
|
+
await dsr.cancel(ticket.id, { actor: "admin", reason: "withdrew" });
|
|
1744
|
+
var cancelled = await dsr.get(ticket.id);
|
|
1745
|
+
var threw = null;
|
|
1746
|
+
try { dsr.buildPortabilityBundle(cancelled); } catch (e) { threw = e; }
|
|
1747
|
+
check("dsr.buildPortabilityBundle: cancelled portability ticket → dsr/not-completed",
|
|
1748
|
+
threw && threw.code === "dsr/not-completed");
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
async function testMemoryStoreListBySubjectId() {
|
|
1752
|
+
var store = b.dsr.memoryTicketStore();
|
|
1753
|
+
await store.insert({ id: "S1", subject: { subjectId: "u-1", email: "a@b.com" }, status: "pending" });
|
|
1754
|
+
await store.insert({ id: "S2", subject: { subjectId: "u-2", email: "c@d.com" }, status: "pending" });
|
|
1755
|
+
var byId = await store.list({ subject: { subjectId: "u-1" } });
|
|
1756
|
+
check("memoryStore.list: filter by subjectId matches one row",
|
|
1757
|
+
byId.length === 1 && byId[0].id === "S1");
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// A subject filter that carries none of the store's indexable keys (email /
|
|
1761
|
+
// subjectId) — a phone-only subject, an empty subject, or one keyed only on
|
|
1762
|
+
// an alias — must match NOTHING, never every ticket. Fail-open here makes
|
|
1763
|
+
// listBySubject leak every subject's tickets (GDPR Art. 15 cross-subject
|
|
1764
|
+
// disclosure) and lets the erasure-completion purge delete them
|
|
1765
|
+
// (cross-subject destruction). Both ticket stores must fail closed.
|
|
1766
|
+
async function testMemoryStoreSubjectFilterFailClosed() {
|
|
1767
|
+
var store = b.dsr.memoryTicketStore();
|
|
1768
|
+
await store.insert({ id: "P1", subject: { phone: "+15550000001" }, status: "pending" });
|
|
1769
|
+
await store.insert({ id: "P2", subject: { phone: "+15550000002" }, status: "pending" });
|
|
1770
|
+
|
|
1771
|
+
var phoneOnly = await store.list({ subject: { phone: "+15550000001" } });
|
|
1772
|
+
check("memoryStore.list: phone-only subject filter matches nothing (fail-closed)",
|
|
1773
|
+
phoneOnly.length === 0);
|
|
1774
|
+
|
|
1775
|
+
var emptySubj = await store.list({ subject: {} });
|
|
1776
|
+
check("memoryStore.list: empty subject filter matches nothing (fail-closed)",
|
|
1777
|
+
emptySubj.length === 0);
|
|
1778
|
+
|
|
1779
|
+
// Regression guard: an indexable key still matches, and the AND across
|
|
1780
|
+
// both keys still holds.
|
|
1781
|
+
await store.insert({ id: "P3", subject: { subjectId: "u-9", email: "e9@x.com" }, status: "pending" });
|
|
1782
|
+
var byId = await store.list({ subject: { subjectId: "u-9" } });
|
|
1783
|
+
check("memoryStore.list: indexable subjectId still matches after fail-closed guard",
|
|
1784
|
+
byId.length === 1 && byId[0].id === "P3");
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
async function testMemoryStoreErasurePurgeScopedToSubject() {
|
|
1788
|
+
// Two DIFFERENT phone-only subjects. Subject A's erasure-completion purge
|
|
1789
|
+
// lists the store by A's subject and deletes the "other" tickets it finds.
|
|
1790
|
+
// Because a phone-only subject is unindexable, the fail-open list returned
|
|
1791
|
+
// EVERY ticket — so the purge wiped Subject B's data. B's ticket must
|
|
1792
|
+
// survive A's erasure.
|
|
1793
|
+
var store = b.dsr.memoryTicketStore();
|
|
1794
|
+
var dsr = b.dsr.create({
|
|
1795
|
+
ticketStore: store,
|
|
1796
|
+
posture: "ccpa",
|
|
1797
|
+
identityResolver: async function (input) { return { phone: input.phone }; },
|
|
1798
|
+
sources: [{
|
|
1799
|
+
name: "users",
|
|
1800
|
+
query: async function () { return []; },
|
|
1801
|
+
erase: async function () { return { deletedIds: [] }; },
|
|
1802
|
+
}],
|
|
1803
|
+
});
|
|
1804
|
+
var tB = await dsr.submit({ type: "access", subject: { phone: "+15550000002" } });
|
|
1805
|
+
var tAerase = await dsr.submit({
|
|
1806
|
+
type: "erasure", subject: { phone: "+15550000001" }, verificationLevel: "secondary",
|
|
1807
|
+
});
|
|
1808
|
+
await dsr.process(tAerase.id, { actor: "compliance@", verificationLevel: "secondary" });
|
|
1809
|
+
var bStill = await store.get(tB.id);
|
|
1810
|
+
check("dsr erasure purge: subject B's ticket survives subject A's erasure (no cross-subject delete)",
|
|
1811
|
+
bStill !== null);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
async function testDbStoreSubjectFilterFailClosed() {
|
|
1815
|
+
var tmpDir = _tmp();
|
|
1816
|
+
await setupTestDb(tmpDir);
|
|
1817
|
+
try {
|
|
1818
|
+
var store = b.dsr.dbTicketStore({ db: b.db });
|
|
1819
|
+
var now = Date.now();
|
|
1820
|
+
await store.insert({ id: "DB-P1", type: "access", status: "pending",
|
|
1821
|
+
subject: { phone: "+15550000001" }, submittedAt: now, deadlineAt: now + 1000,
|
|
1822
|
+
retentionUntil: now + 1000 });
|
|
1823
|
+
await store.insert({ id: "DB-P2", type: "access", status: "pending",
|
|
1824
|
+
subject: { phone: "+15550000002" }, submittedAt: now, deadlineAt: now + 1000,
|
|
1825
|
+
retentionUntil: now + 1000 });
|
|
1826
|
+
|
|
1827
|
+
var phoneOnly = await store.list({ subject: { phone: "+15550000001" } });
|
|
1828
|
+
check("dbStore.list: phone-only subject filter matches nothing (fail-closed)",
|
|
1829
|
+
phoneOnly.length === 0);
|
|
1830
|
+
|
|
1831
|
+
var emptySubj = await store.list({ subject: {} });
|
|
1832
|
+
check("dbStore.list: empty subject filter matches nothing (fail-closed)",
|
|
1833
|
+
emptySubj.length === 0);
|
|
1834
|
+
|
|
1835
|
+
// Regression guard: an indexable subject still round-trips.
|
|
1836
|
+
await store.insert({ id: "DB-U1", type: "access", status: "pending",
|
|
1837
|
+
subject: { subjectId: "u-9", email: "e9@x.com" }, submittedAt: now,
|
|
1838
|
+
deadlineAt: now + 1000, retentionUntil: now + 1000 });
|
|
1839
|
+
var byEmail = await store.list({ subject: { email: "e9@x.com" } });
|
|
1840
|
+
check("dbStore.list: indexable email still matches after fail-closed guard",
|
|
1841
|
+
byEmail.length === 1 && byEmail[0].id === "DB-U1");
|
|
1842
|
+
} finally {
|
|
1843
|
+
await teardownTestDb(tmpDir);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
function testDbStoreNoArgs() {
|
|
1848
|
+
// dbTicketStore() with no opts → opts || {} → requireMethods refuses the
|
|
1849
|
+
// absent db handle.
|
|
1850
|
+
var threw = null;
|
|
1851
|
+
try { b.dsr.dbTicketStore(); } catch (e) { threw = e; }
|
|
1852
|
+
check("dbTicketStore: no opts → dsr/bad-db", threw && threw.code === "dsr/bad-db");
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
async function testResealNoArgsAndNonSealedRows() {
|
|
1856
|
+
var tmpDir = _tmp();
|
|
1857
|
+
await setupTestDb(tmpDir);
|
|
1858
|
+
try {
|
|
1859
|
+
var t1 = null;
|
|
1860
|
+
try { await b.dsr.reseal(); } catch (e) { t1 = e; }
|
|
1861
|
+
check("dsr.reseal: no args → dsr/bad-root", t1 && t1.code === "dsr/bad-root");
|
|
1862
|
+
|
|
1863
|
+
var keys = b.vault.getKeysJson();
|
|
1864
|
+
var puts = [];
|
|
1865
|
+
var rv = await b.dsr.reseal({
|
|
1866
|
+
oldRootJson: keys, newRootJson: keys,
|
|
1867
|
+
store: {
|
|
1868
|
+
listAll: function () { return [null, "str", { plain: 1 }]; },
|
|
1869
|
+
putResealed: function (r) { puts.push(r); },
|
|
1870
|
+
},
|
|
1871
|
+
});
|
|
1872
|
+
check("dsr.reseal: non-object / plaintext rows rotate nothing",
|
|
1873
|
+
rv.resealed === 0 && puts.length === 0);
|
|
1874
|
+
} finally {
|
|
1875
|
+
await teardownTestDb(tmpDir);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1041
1879
|
// ---- Run all ----
|
|
1042
1880
|
|
|
1043
1881
|
async function run() {
|
|
@@ -1092,15 +1930,77 @@ async function run() {
|
|
|
1092
1930
|
await testReceiptWithSigner();
|
|
1093
1931
|
await testReceiptSignerError();
|
|
1094
1932
|
|
|
1933
|
+
// create() adversarial validation
|
|
1934
|
+
await testCreateBadSource();
|
|
1935
|
+
testCreateBadPosture();
|
|
1936
|
+
testCreateBadDefaultVerificationLevel();
|
|
1937
|
+
testCreateBadMinVerificationByType();
|
|
1938
|
+
|
|
1939
|
+
// submit() adversarial
|
|
1940
|
+
await testSubmitBadInput();
|
|
1941
|
+
await testSubmitIdentityResolverThrows();
|
|
1942
|
+
await testSubmitBadVerificationLevel();
|
|
1943
|
+
|
|
1944
|
+
// process() adversarial / wrong-state
|
|
1945
|
+
await testProcessAlreadyInProgress();
|
|
1946
|
+
await testProcessBadVerificationLevel();
|
|
1947
|
+
await testProcessErasurePurgeFailure();
|
|
1948
|
+
await testAuditDisabled();
|
|
1949
|
+
await testProcessQueryNonArrayRows();
|
|
1950
|
+
await testProcessEraseResultShapes();
|
|
1951
|
+
|
|
1952
|
+
// cancel / reject / get not-found + defaults
|
|
1953
|
+
await testCancelNotFound();
|
|
1954
|
+
await testCancelWithoutActorReason();
|
|
1955
|
+
await testRejectNotFound();
|
|
1956
|
+
await testRejectTerminal();
|
|
1957
|
+
await testGetViaCoordinator();
|
|
1958
|
+
await testListByStatusBadStatus();
|
|
1959
|
+
|
|
1960
|
+
// buildReceipt / buildPortabilityBundle adversarial
|
|
1961
|
+
await testBuildReceiptNotFound();
|
|
1962
|
+
await testBuildReceiptExpired();
|
|
1963
|
+
testPortabilityBadTicket();
|
|
1964
|
+
|
|
1965
|
+
// memoryTicketStore update-not-found + delete
|
|
1966
|
+
await testMemoryStoreUpdateNotFoundAndDelete();
|
|
1967
|
+
|
|
1095
1968
|
// dbTicketStore at-rest sealing + erasure purge + upgrade path
|
|
1096
1969
|
await testDbStoreSealsAtRest();
|
|
1097
1970
|
await testDbStoreLargePayloadRoundTrips();
|
|
1098
1971
|
await testDbStoreErasurePurgesPriorTickets();
|
|
1099
1972
|
await testDbStoreUpgradePath();
|
|
1100
1973
|
await testDbStoreFindsLegacyKeyedMacRows();
|
|
1974
|
+
// dbTicketStore adversarial + purge + status list + update-not-found
|
|
1975
|
+
await testDbStoreBadTable();
|
|
1976
|
+
await testDbStoreListByStatus();
|
|
1977
|
+
await testDbStoreUpdateNotFound();
|
|
1978
|
+
await testDbStorePurgeExpired();
|
|
1979
|
+
await testDbStoreTicketTooLarge();
|
|
1101
1980
|
// AAD_ROTATION descriptor + reseal
|
|
1102
1981
|
testAadRotationDescriptor();
|
|
1103
1982
|
await testResealValidationAndStore();
|
|
1983
|
+
await testResealRotatesAadCell();
|
|
1984
|
+
await testResealListAllNonArray();
|
|
1985
|
+
|
|
1986
|
+
// additional default-branch / guard coverage
|
|
1987
|
+
testCreateMoreValidation();
|
|
1988
|
+
await testSubmitResolverThrowsEmptyMessage();
|
|
1989
|
+
await testProcessSourceThrowsEmptyMessage();
|
|
1990
|
+
await testListBySubjectBadInput();
|
|
1991
|
+
await testExpireOverdueNotPast();
|
|
1992
|
+
await testReceiptSignerPartialResult();
|
|
1993
|
+
await testPortabilityCancelled();
|
|
1994
|
+
await testMemoryStoreListBySubjectId();
|
|
1995
|
+
await testMemoryStoreSubjectFilterFailClosed();
|
|
1996
|
+
await testMemoryStoreErasurePurgeScopedToSubject();
|
|
1997
|
+
await testDbStoreSubjectFilterFailClosed();
|
|
1998
|
+
testDbStoreNoArgs();
|
|
1999
|
+
await testResealNoArgsAndNonSealedRows();
|
|
2000
|
+
|
|
2001
|
+
// state-law DSR registry
|
|
2002
|
+
testStateRules();
|
|
2003
|
+
testListStateRules();
|
|
1104
2004
|
}
|
|
1105
2005
|
|
|
1106
2006
|
module.exports = { run: run };
|