@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
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) blamejs contributors
|
|
3
|
+
"use strict";
|
|
4
|
+
/**
|
|
5
|
+
* b.audit — canonical per-primitive test.
|
|
6
|
+
*
|
|
7
|
+
* Exercises the error / adversarial / defensive / option-default branches
|
|
8
|
+
* of lib/audit.js that the concern-named audit-*.test.js files leave
|
|
9
|
+
* unasserted:
|
|
10
|
+
*
|
|
11
|
+
* - registerNamespace bad-name throw + framework-namespace no-op
|
|
12
|
+
* - record() non-object / bad-action-shape / unregistered-namespace /
|
|
13
|
+
* bad-outcome throws; actor/metadata defaulting
|
|
14
|
+
* - useStore bad-arg refusal + null / { record: null } unregister; shadow
|
|
15
|
+
* failure (throw + timeout-classified) is drop-silent
|
|
16
|
+
* - query() every-criteria filter path, order:"desc", limit/offset,
|
|
17
|
+
* _toMs Date/string/invalid, self-log suppression for action:"audit.read"
|
|
18
|
+
* - checkpoint empty-log null / skipIfUnchanged null / verifyCheckpoints
|
|
19
|
+
* empty + happy
|
|
20
|
+
* - emit() flush drop-path (record throw inside the drain batch)
|
|
21
|
+
* - safeEmit non-object / no-action guards, outcome normalization,
|
|
22
|
+
* action hyphen normalization, credential redaction
|
|
23
|
+
* - namespaced prefix / no-prefix / disabled / alternate-sink / extra-merge
|
|
24
|
+
* - bindActor bad-id throw, actor-match / mismatch / missing violation,
|
|
25
|
+
* roleEquivalent under a db-role scope
|
|
26
|
+
* - generateActorBindingTriggerSql default / allowRoles / roleMappingFn
|
|
27
|
+
* - assertSegregation no-db throw / missing-artifact throw / present ok
|
|
28
|
+
* - applyPosture / activePosture defaulting
|
|
29
|
+
*
|
|
30
|
+
* Run standalone: `node test/layer-0-primitives/audit.test.js`
|
|
31
|
+
* Or via smoke: `node test/smoke.js`
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
var helpers = require("../helpers");
|
|
35
|
+
var b = helpers.b;
|
|
36
|
+
var fs = helpers.fs;
|
|
37
|
+
var os = helpers.os;
|
|
38
|
+
var path = helpers.path;
|
|
39
|
+
var check = helpers.check;
|
|
40
|
+
var waitUntil = helpers.waitUntil;
|
|
41
|
+
var setupTestDb = helpers.setupTestDb;
|
|
42
|
+
var teardownTestDb = helpers.teardownTestDb;
|
|
43
|
+
|
|
44
|
+
function _tmp() { return fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-audit-")); }
|
|
45
|
+
|
|
46
|
+
// ---- Surface ----
|
|
47
|
+
|
|
48
|
+
function testSurface() {
|
|
49
|
+
check("b.audit.record is a function", typeof b.audit.record === "function");
|
|
50
|
+
check("b.audit.query is a function", typeof b.audit.query === "function");
|
|
51
|
+
check("b.audit.emit is a function", typeof b.audit.emit === "function");
|
|
52
|
+
check("b.audit.safeEmit is a function", typeof b.audit.safeEmit === "function");
|
|
53
|
+
check("b.audit.namespaced is a function", typeof b.audit.namespaced === "function");
|
|
54
|
+
check("b.audit.flush is a function", typeof b.audit.flush === "function");
|
|
55
|
+
check("b.audit.verify is a function", typeof b.audit.verify === "function");
|
|
56
|
+
check("b.audit.checkpoint is a function", typeof b.audit.checkpoint === "function");
|
|
57
|
+
check("b.audit.verifyCheckpoints is a function", typeof b.audit.verifyCheckpoints === "function");
|
|
58
|
+
check("b.audit.bindActor is a function", typeof b.audit.bindActor === "function");
|
|
59
|
+
check("b.audit.beginTrace is a function", typeof b.audit.beginTrace === "function");
|
|
60
|
+
check("b.audit.CHECKPOINT_FORMAT is stable",
|
|
61
|
+
b.audit.CHECKPOINT_FORMAT === "blamejs-audit-checkpoint-v1");
|
|
62
|
+
check("b.audit.FRAMEWORK_NAMESPACES lists the generic buckets",
|
|
63
|
+
Array.isArray(b.audit.FRAMEWORK_NAMESPACES) &&
|
|
64
|
+
b.audit.FRAMEWORK_NAMESPACES.indexOf("auth") !== -1 &&
|
|
65
|
+
b.audit.FRAMEWORK_NAMESPACES.indexOf("audit") !== -1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ---- registerNamespace — bad name throw + framework no-op + custom add ----
|
|
69
|
+
|
|
70
|
+
function testRegisterNamespace() {
|
|
71
|
+
var threw = null;
|
|
72
|
+
try { b.audit.registerNamespace("Bad-Upper"); } catch (e) { threw = e; }
|
|
73
|
+
check("registerNamespace rejects a non [a-z][a-z0-9_]* name", threw !== null);
|
|
74
|
+
|
|
75
|
+
threw = null;
|
|
76
|
+
try { b.audit.registerNamespace("9leading"); } catch (e) { threw = e; }
|
|
77
|
+
check("registerNamespace rejects a leading-digit name", threw !== null);
|
|
78
|
+
|
|
79
|
+
threw = null;
|
|
80
|
+
try { b.audit.registerNamespace(12345); } catch (e) { threw = e; }
|
|
81
|
+
check("registerNamespace rejects a non-string name", threw !== null);
|
|
82
|
+
|
|
83
|
+
// Framework namespace → no-op (must NOT throw, must NOT duplicate).
|
|
84
|
+
threw = null;
|
|
85
|
+
try { b.audit.registerNamespace("auth"); } catch (e) { threw = e; }
|
|
86
|
+
check("registerNamespace('auth') is a no-op for a framework namespace", threw === null);
|
|
87
|
+
|
|
88
|
+
// Fresh custom namespace → registered (no throw).
|
|
89
|
+
threw = null;
|
|
90
|
+
try { b.audit.registerNamespace("orders"); } catch (e) { threw = e; }
|
|
91
|
+
check("registerNamespace('orders') accepts a fresh custom namespace", threw === null);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ---- record() — the throw branches (config-time: THROW on bad input) ----
|
|
95
|
+
|
|
96
|
+
async function testRecordThrowBranches() {
|
|
97
|
+
var tmpDir = _tmp();
|
|
98
|
+
await setupTestDb(tmpDir);
|
|
99
|
+
try {
|
|
100
|
+
var threw = null;
|
|
101
|
+
try { await b.audit.record(null); } catch (e) { threw = e; }
|
|
102
|
+
check("record(null) throws — requires an event object", threw !== null);
|
|
103
|
+
|
|
104
|
+
threw = null;
|
|
105
|
+
try { await b.audit.record("not-an-object"); } catch (e) { threw = e; }
|
|
106
|
+
check("record(non-object) throws", threw !== null);
|
|
107
|
+
|
|
108
|
+
// Bad action SHAPE (no namespace.verb dot form).
|
|
109
|
+
threw = null;
|
|
110
|
+
try { await b.audit.record({ action: "noverb", outcome: "success" }); } catch (e) { threw = e; }
|
|
111
|
+
check("record rejects a bad action shape (no dot-separated verb)", threw !== null);
|
|
112
|
+
|
|
113
|
+
// Uppercase action segment — outside the lowercase regex.
|
|
114
|
+
threw = null;
|
|
115
|
+
try { await b.audit.record({ action: "auth.Login", outcome: "success" }); } catch (e) { threw = e; }
|
|
116
|
+
check("record rejects an uppercase action segment", threw !== null);
|
|
117
|
+
|
|
118
|
+
// Unregistered namespace.
|
|
119
|
+
threw = null;
|
|
120
|
+
try { await b.audit.record({ action: "neverregistered.verb", outcome: "success" }); }
|
|
121
|
+
catch (e) { threw = e; }
|
|
122
|
+
check("record rejects an unregistered namespace",
|
|
123
|
+
threw !== null && /not registered/i.test(threw.message || ""));
|
|
124
|
+
|
|
125
|
+
// Bad outcome — not in {success, failure, denied}.
|
|
126
|
+
threw = null;
|
|
127
|
+
try { await b.audit.record({ action: "auth.login", outcome: "maybe" }); } catch (e) { threw = e; }
|
|
128
|
+
check("record rejects an outcome outside {success, failure, denied}", threw !== null);
|
|
129
|
+
|
|
130
|
+
threw = null;
|
|
131
|
+
try { await b.audit.record({ action: "auth.login" }); } catch (e) { threw = e; }
|
|
132
|
+
check("record rejects a missing outcome", threw !== null);
|
|
133
|
+
} finally {
|
|
134
|
+
await teardownTestDb(tmpDir);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---- record() — actor / metadata defaulting (the || {} / ternary branches) ----
|
|
139
|
+
|
|
140
|
+
async function testRecordDefaulting() {
|
|
141
|
+
var tmpDir = _tmp();
|
|
142
|
+
await setupTestDb(tmpDir);
|
|
143
|
+
try {
|
|
144
|
+
// No actor, no resource, no metadata → all default without throwing.
|
|
145
|
+
var appended = await b.audit.record({ action: "system.config.reloaded", outcome: "success" });
|
|
146
|
+
check("record with no actor/resource/metadata still appends",
|
|
147
|
+
appended && typeof appended.rowHash !== "undefined");
|
|
148
|
+
check("record defaulted actorUserId to null", appended.actorUserId === null);
|
|
149
|
+
check("record defaulted metadata to null", appended.metadata === null);
|
|
150
|
+
|
|
151
|
+
// With metadata → JSON-serialized (the truthy ternary side).
|
|
152
|
+
var withMeta = await b.audit.record({
|
|
153
|
+
action: "system.config.reloaded",
|
|
154
|
+
outcome: "success",
|
|
155
|
+
metadata: { source: "SIGHUP" },
|
|
156
|
+
});
|
|
157
|
+
check("record serialized metadata to JSON",
|
|
158
|
+
typeof withMeta.metadata === "string" && withMeta.metadata.indexOf("SIGHUP") !== -1);
|
|
159
|
+
} finally {
|
|
160
|
+
await teardownTestDb(tmpDir);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ---- useStore — bad-arg refusal + shadow failure is drop-silent ----
|
|
165
|
+
|
|
166
|
+
async function testUseStoreRefusalAndShadowFailure() {
|
|
167
|
+
var tmpDir = _tmp();
|
|
168
|
+
await setupTestDb(tmpDir);
|
|
169
|
+
try {
|
|
170
|
+
// Bad-arg refusal (config-time throw).
|
|
171
|
+
var threw = null;
|
|
172
|
+
try { b.audit.useStore("nope"); } catch (e) { threw = e; }
|
|
173
|
+
check("useStore refuses a non-object store", threw !== null);
|
|
174
|
+
|
|
175
|
+
threw = null;
|
|
176
|
+
try { b.audit.useStore({ record: 42 }); } catch (e) { threw = e; }
|
|
177
|
+
check("useStore refuses a non-function record", threw !== null);
|
|
178
|
+
|
|
179
|
+
// Shadow store that THROWS a plain error → drop-silent, chain still commits.
|
|
180
|
+
b.audit.useStore({ record: async function () { throw new Error("shadow down"); } });
|
|
181
|
+
threw = null;
|
|
182
|
+
try {
|
|
183
|
+
await b.audit.record({ action: "auth.login", outcome: "success" });
|
|
184
|
+
} catch (e) { threw = e; }
|
|
185
|
+
check("shadow throw is drop-silent — record() still resolves", threw === null);
|
|
186
|
+
|
|
187
|
+
// Shadow store whose error is TIMEOUT-classified (code ETIMEDOUT) → the
|
|
188
|
+
// isTimeout branch (audit.shadow_timeout) fires; still drop-silent.
|
|
189
|
+
b.audit.useStore({
|
|
190
|
+
record: async function () {
|
|
191
|
+
var e = new Error("shadow slow");
|
|
192
|
+
e.code = "ETIMEDOUT";
|
|
193
|
+
throw e;
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
threw = null;
|
|
197
|
+
try {
|
|
198
|
+
await b.audit.record({ action: "auth.logout", outcome: "success" });
|
|
199
|
+
} catch (e) { threw = e; }
|
|
200
|
+
check("timeout-classified shadow throw is also drop-silent", threw === null);
|
|
201
|
+
|
|
202
|
+
// Shadow error with an EMPTY message (exercises the `e.message || ""`
|
|
203
|
+
// fallback in the failure-classifier) → still drop-silent.
|
|
204
|
+
b.audit.useStore({ record: async function () { throw new Error(""); } });
|
|
205
|
+
threw = null;
|
|
206
|
+
try {
|
|
207
|
+
await b.audit.record({ action: "auth.login.failure", outcome: "failure" });
|
|
208
|
+
} catch (e) { threw = e; }
|
|
209
|
+
check("shadow error with an empty message is drop-silent", threw === null);
|
|
210
|
+
|
|
211
|
+
// Framework chain has both rows despite the shadow failures.
|
|
212
|
+
var loginRows = await b.audit.query({ action: "auth.login" });
|
|
213
|
+
var logoutRows = await b.audit.query({ action: "auth.logout" });
|
|
214
|
+
check("framework chain kept the row past a shadow throw", loginRows.length >= 1);
|
|
215
|
+
check("framework chain kept the row past a shadow timeout", logoutRows.length >= 1);
|
|
216
|
+
|
|
217
|
+
// Unregister via bare null and via { record: null }.
|
|
218
|
+
b.audit.useStore(null);
|
|
219
|
+
b.audit.useStore({ record: async function () {} });
|
|
220
|
+
b.audit.useStore({ record: null });
|
|
221
|
+
// No throw path to assert here beyond reaching the unregister branches.
|
|
222
|
+
check("useStore unregister paths (null + { record: null }) reached", true);
|
|
223
|
+
} finally {
|
|
224
|
+
b.audit.useStore(null);
|
|
225
|
+
await teardownTestDb(tmpDir);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---- query() — criteria filters, order/limit/offset, _toMs, self-log ----
|
|
230
|
+
|
|
231
|
+
async function testQueryCriteriaAndToMs() {
|
|
232
|
+
var tmpDir = _tmp();
|
|
233
|
+
await setupTestDb(tmpDir);
|
|
234
|
+
try {
|
|
235
|
+
b.audit.registerNamespace("orders");
|
|
236
|
+
// Seed a couple of matching rows.
|
|
237
|
+
await b.audit.record({
|
|
238
|
+
actor: { userId: "u-q1" },
|
|
239
|
+
action: "orders.shipped",
|
|
240
|
+
resource: { kind: "order", id: "o-1" },
|
|
241
|
+
outcome: "success",
|
|
242
|
+
});
|
|
243
|
+
await b.audit.record({
|
|
244
|
+
actor: { userId: "u-q1" },
|
|
245
|
+
action: "orders.shipped",
|
|
246
|
+
resource: { kind: "order", id: "o-2" },
|
|
247
|
+
outcome: "failure",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Every-criteria filter in one call: exercises each `if (criteria.x)` arm
|
|
251
|
+
// plus order:"desc", limit, offset, and _redactCriteria's ternaries.
|
|
252
|
+
var rows = await b.audit.query({
|
|
253
|
+
from: new Date(Date.now() - 3600000), // Date branch of _toMs
|
|
254
|
+
to: Date.now() + 3600000, // number branch of _toMs
|
|
255
|
+
actorUserId: "u-q1",
|
|
256
|
+
resourceId: "o-1",
|
|
257
|
+
action: "orders.shipped",
|
|
258
|
+
resourceKind: "order",
|
|
259
|
+
outcome: "success",
|
|
260
|
+
order: "desc",
|
|
261
|
+
limit: 10,
|
|
262
|
+
offset: 0,
|
|
263
|
+
});
|
|
264
|
+
check("query with full criteria returns the matching row", rows.length >= 1);
|
|
265
|
+
check("query honored the resourceId filter",
|
|
266
|
+
rows.every(function (r) { return r.action === "orders.shipped"; }));
|
|
267
|
+
|
|
268
|
+
// _toMs string branch (valid ISO date parse).
|
|
269
|
+
var strRows = await b.audit.query({ from: "2000-01-01T00:00:00Z", action: "orders.shipped" });
|
|
270
|
+
check("query accepts an ISO-8601 string `from` (Date.parse branch)", strRows.length >= 1);
|
|
271
|
+
|
|
272
|
+
// _toMs invalid-string branch → throw.
|
|
273
|
+
var threw = null;
|
|
274
|
+
try { await b.audit.query({ from: "definitely-not-a-date" }); } catch (e) { threw = e; }
|
|
275
|
+
check("query throws on an unparseable string date", threw !== null);
|
|
276
|
+
|
|
277
|
+
// _toMs invalid-value branch (boolean is truthy but not number/Date/string).
|
|
278
|
+
threw = null;
|
|
279
|
+
try { await b.audit.query({ to: true }); } catch (e) { threw = e; }
|
|
280
|
+
check("query throws on a non-date `to` value", threw !== null);
|
|
281
|
+
|
|
282
|
+
// Self-log suppression: a query targeting action:"audit.read" must NOT
|
|
283
|
+
// create a new audit.read self-log; a normal query does.
|
|
284
|
+
var before = (await b.audit.query({ action: "audit.read" })).length;
|
|
285
|
+
// Two audit.read-targeted queries — neither self-logs (suppressed branch).
|
|
286
|
+
await b.audit.query({ action: "audit.read" });
|
|
287
|
+
var after = (await b.audit.query({ action: "audit.read" })).length;
|
|
288
|
+
check("querying action:'audit.read' does not self-log (count is stable)", after === before);
|
|
289
|
+
|
|
290
|
+
// A normal query DOES self-log an audit.read (the un-suppressed branch).
|
|
291
|
+
await b.audit.query({ action: "orders.shipped" });
|
|
292
|
+
var afterNormal = (await b.audit.query({ action: "audit.read" })).length;
|
|
293
|
+
check("a normal query self-logs an audit.read event", afterNormal > before);
|
|
294
|
+
|
|
295
|
+
// No-argument query → criteria defaults to {} (the `criteria || {}` arm)
|
|
296
|
+
// and returns rows without throwing.
|
|
297
|
+
var allRows = await b.audit.query();
|
|
298
|
+
check("query() with no criteria returns rows (default {} criteria)",
|
|
299
|
+
Array.isArray(allRows) && allRows.length >= 1);
|
|
300
|
+
} finally {
|
|
301
|
+
await teardownTestDb(tmpDir);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ---- beginTrace ----
|
|
306
|
+
|
|
307
|
+
async function testBeginTrace() {
|
|
308
|
+
var tmpDir = _tmp();
|
|
309
|
+
await setupTestDb(tmpDir);
|
|
310
|
+
try {
|
|
311
|
+
var t1 = b.audit.beginTrace();
|
|
312
|
+
var t2 = b.audit.beginTrace();
|
|
313
|
+
check("beginTrace returns a 32-hex-char trace id", /^[0-9a-f]{32}$/.test(t1));
|
|
314
|
+
check("beginTrace returns a fresh id each call", t1 !== t2);
|
|
315
|
+
} finally {
|
|
316
|
+
await teardownTestDb(tmpDir);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ---- checkpoint + verifyCheckpoints — empty / skipIfUnchanged / happy ----
|
|
321
|
+
|
|
322
|
+
async function testCheckpointLifecycle() {
|
|
323
|
+
var tmpDir = _tmp();
|
|
324
|
+
await setupTestDb(tmpDir);
|
|
325
|
+
try {
|
|
326
|
+
// Capture the chain's current state rather than assuming it is
|
|
327
|
+
// pristine — under the parallel smoke harness b.audit operates on
|
|
328
|
+
// the shared framework db/chain, so an absolute "empty → 0" would
|
|
329
|
+
// be flaky. Assert relative to this baseline.
|
|
330
|
+
var baseline = await b.audit.verifyCheckpoints();
|
|
331
|
+
check("verifyCheckpoints reports ok:true", baseline.ok === true &&
|
|
332
|
+
typeof baseline.checkpointsVerified === "number");
|
|
333
|
+
|
|
334
|
+
// Empty-chain branches (checkpoint → null) are only exercised when
|
|
335
|
+
// the chain genuinely has no rows yet; guard so the assertion holds
|
|
336
|
+
// whether or not a prior test left rows.
|
|
337
|
+
var emptyCkpt = await b.audit.checkpoint();
|
|
338
|
+
if (baseline.checkpointsVerified === 0 && emptyCkpt === null) {
|
|
339
|
+
check("checkpoint on an empty audit log returns null", emptyCkpt === null);
|
|
340
|
+
} else {
|
|
341
|
+
check("checkpoint on a non-empty log returns null or a checkpoint",
|
|
342
|
+
emptyCkpt === null || (emptyCkpt && emptyCkpt.atRowHash));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Record a row, then anchor a real checkpoint.
|
|
346
|
+
await b.audit.record({ action: "system.boot.completed", outcome: "success" });
|
|
347
|
+
var ckpt = await b.audit.checkpoint();
|
|
348
|
+
check("checkpoint anchors a row (returns the checkpoint)",
|
|
349
|
+
ckpt && typeof ckpt.atMonotonicCounter === "number" && ckpt.atRowHash);
|
|
350
|
+
|
|
351
|
+
// skipIfUnchanged with no new rows → null (tip did not advance).
|
|
352
|
+
var skipped = await b.audit.checkpoint({ skipIfUnchanged: true });
|
|
353
|
+
check("checkpoint({ skipIfUnchanged }) returns null when the tip is unchanged",
|
|
354
|
+
skipped === null);
|
|
355
|
+
|
|
356
|
+
// A second checkpoint() of the SAME already-anchored tip (WITHOUT
|
|
357
|
+
// skipIfUnchanged) must not throw the raw atMonotonicCounter UNIQUE-
|
|
358
|
+
// constraint error: two anchors of one tip sign the identical payload, so
|
|
359
|
+
// the counter is already anchored and the loser returns null idempotently.
|
|
360
|
+
// This is the parallel-checkpoint collision that flaked audit.test.js under
|
|
361
|
+
// SMOKE_PARALLEL when two modules anchored the same counter concurrently.
|
|
362
|
+
var reAnchor = null;
|
|
363
|
+
var reAnchorThrew = false;
|
|
364
|
+
try { reAnchor = await b.audit.checkpoint(); }
|
|
365
|
+
catch (_e) { reAnchorThrew = true; }
|
|
366
|
+
check("re-checkpoint of an already-anchored tip returns null, never a raw UNIQUE throw",
|
|
367
|
+
reAnchorThrew === false && reAnchor === null);
|
|
368
|
+
|
|
369
|
+
// verifyCheckpoints walks the anchored checkpoint and confirms the
|
|
370
|
+
// row — the count strictly increased over the baseline.
|
|
371
|
+
var v = await b.audit.verifyCheckpoints();
|
|
372
|
+
check("verifyCheckpoints confirms the anchored checkpoint",
|
|
373
|
+
v.ok === true && v.checkpointsVerified >= baseline.checkpointsVerified + 1);
|
|
374
|
+
} finally {
|
|
375
|
+
await teardownTestDb(tmpDir);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ---- verify() — clean chain ----
|
|
380
|
+
|
|
381
|
+
async function testVerifyChain() {
|
|
382
|
+
var tmpDir = _tmp();
|
|
383
|
+
await setupTestDb(tmpDir);
|
|
384
|
+
try {
|
|
385
|
+
await b.audit.record({ action: "auth.login", outcome: "success" });
|
|
386
|
+
await b.audit.record({ action: "auth.logout", outcome: "success" });
|
|
387
|
+
var res = await b.audit.verify();
|
|
388
|
+
check("verify() reports a clean chain", res.ok === true && res.rowsVerified >= 2);
|
|
389
|
+
} finally {
|
|
390
|
+
await teardownTestDb(tmpDir);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ---- emit() + flush() drop-path — record throw inside the drain batch ----
|
|
395
|
+
|
|
396
|
+
async function testEmitFlushDropPath() {
|
|
397
|
+
var tmpDir = _tmp();
|
|
398
|
+
await setupTestDb(tmpDir);
|
|
399
|
+
try {
|
|
400
|
+
// emit() does NOT normalize outcome, so a bad outcome makes record()
|
|
401
|
+
// throw inside the handler flush — exercising the per-item catch +
|
|
402
|
+
// system.audit.chain_write_dropped observability path.
|
|
403
|
+
b.audit.emit({ action: "system.stream.dropme", outcome: "TOTALLY_BOGUS" });
|
|
404
|
+
// A good event alongside it drains normally.
|
|
405
|
+
b.audit.emit({ action: "system.stream.kept", outcome: "success" });
|
|
406
|
+
|
|
407
|
+
var flushThrew = null;
|
|
408
|
+
try { await b.audit.flush(); } catch (e) { flushThrew = e; }
|
|
409
|
+
check("flush() does not throw even when a batch item is dropped", flushThrew === null);
|
|
410
|
+
|
|
411
|
+
var dropped = await b.audit.query({ action: "system.stream.dropme" });
|
|
412
|
+
check("the bad-outcome emit was dropped from the chain", dropped.length === 0);
|
|
413
|
+
var kept = await b.audit.query({ action: "system.stream.kept" });
|
|
414
|
+
check("the good emit alongside the dropped one still landed", kept.length >= 1);
|
|
415
|
+
} finally {
|
|
416
|
+
await teardownTestDb(tmpDir);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ---- safeEmit — guards, outcome normalization, action normalization, redaction ----
|
|
421
|
+
|
|
422
|
+
async function testSafeEmitNormalizationAndRedaction() {
|
|
423
|
+
var tmpDir = _tmp();
|
|
424
|
+
await setupTestDb(tmpDir);
|
|
425
|
+
try {
|
|
426
|
+
// Guard branches — drop-silent, no throw, nothing emitted.
|
|
427
|
+
b.audit.safeEmit(null);
|
|
428
|
+
b.audit.safeEmit("not-an-object");
|
|
429
|
+
b.audit.safeEmit({ outcome: "success" }); // missing action (non-string)
|
|
430
|
+
b.audit.safeEmit({ action: 12345 }); // non-string action
|
|
431
|
+
|
|
432
|
+
// Outcome-alias normalization: "ok" → success, "error" → failure,
|
|
433
|
+
// "refused" → denied, non-string → success.
|
|
434
|
+
b.audit.safeEmit({ action: "system.norm.ok", outcome: "ok" });
|
|
435
|
+
b.audit.safeEmit({ action: "system.norm.err", outcome: "error" });
|
|
436
|
+
b.audit.safeEmit({ action: "system.norm.refused", outcome: "refused" });
|
|
437
|
+
b.audit.safeEmit({ action: "system.norm.nonstr", outcome: 999 });
|
|
438
|
+
b.audit.safeEmit({ action: "system.norm.unknown", outcome: "bananas" }); // unknown alias → success
|
|
439
|
+
|
|
440
|
+
// Action hyphen normalization: hyphens in the verb become underscores.
|
|
441
|
+
b.audit.safeEmit({ action: "system.norm.biometric-id-check", outcome: "success" });
|
|
442
|
+
|
|
443
|
+
// Credential redaction: a connection string in `reason` and a secret in
|
|
444
|
+
// `metadata` must be scrubbed before reaching the chain.
|
|
445
|
+
b.audit.safeEmit({
|
|
446
|
+
action: "system.norm.secret",
|
|
447
|
+
outcome: "success",
|
|
448
|
+
reason: "connect postgres://user:hunter2@db:5432/app",
|
|
449
|
+
metadata: { token: "AKIAIOSFODNN7EXAMPLE", note: "keep" },
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
await b.audit.flush();
|
|
453
|
+
|
|
454
|
+
function one(action) {
|
|
455
|
+
return b.audit.query({ action: action }).then(function (r) { return r[0]; });
|
|
456
|
+
}
|
|
457
|
+
var okRow = await one("system.norm.ok");
|
|
458
|
+
check("safeEmit normalized outcome 'ok' → 'success'", okRow && okRow.outcome === "success");
|
|
459
|
+
var errRow = await one("system.norm.err");
|
|
460
|
+
check("safeEmit normalized outcome 'error' → 'failure'", errRow && errRow.outcome === "failure");
|
|
461
|
+
var refRow = await one("system.norm.refused");
|
|
462
|
+
check("safeEmit normalized outcome 'refused' → 'denied'", refRow && refRow.outcome === "denied");
|
|
463
|
+
var nsRow = await one("system.norm.nonstr");
|
|
464
|
+
check("safeEmit normalized a non-string outcome → 'success'", nsRow && nsRow.outcome === "success");
|
|
465
|
+
var unkRow = await one("system.norm.unknown");
|
|
466
|
+
check("safeEmit normalized an unknown outcome alias → 'success'",
|
|
467
|
+
unkRow && unkRow.outcome === "success");
|
|
468
|
+
|
|
469
|
+
var hyphenRow = await one("system.norm.biometric_id_check");
|
|
470
|
+
check("safeEmit normalized hyphens in the action to underscores", !!hyphenRow);
|
|
471
|
+
|
|
472
|
+
var secretRow = await one("system.norm.secret");
|
|
473
|
+
check("safeEmit redacted the connection string in reason",
|
|
474
|
+
secretRow && /REDACTED/i.test(String(secretRow.reason)) &&
|
|
475
|
+
String(secretRow.reason).indexOf("hunter2") === -1);
|
|
476
|
+
check("safeEmit redacted the AWS-key-shaped secret in metadata",
|
|
477
|
+
secretRow && String(secretRow.metadata).indexOf("AKIAIOSFODNN7EXAMPLE") === -1);
|
|
478
|
+
} finally {
|
|
479
|
+
await teardownTestDb(tmpDir);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// ---- namespaced — prefix / no-prefix / disabled / alternate-sink / extra ----
|
|
484
|
+
|
|
485
|
+
async function testNamespaced() {
|
|
486
|
+
var tmpDir = _tmp();
|
|
487
|
+
await setupTestDb(tmpDir);
|
|
488
|
+
try {
|
|
489
|
+
// Alternate sink (object form { audit, sink }) — routes to the operator
|
|
490
|
+
// sink instead of the framework chain; capture directly, no flush needed.
|
|
491
|
+
var captured = [];
|
|
492
|
+
var sink = { safeEmit: function (evt) { captured.push(evt); } };
|
|
493
|
+
|
|
494
|
+
var emitToSink = b.audit.namespaced("gdpr.ropa", { audit: true, sink: sink });
|
|
495
|
+
emitToSink("activity_added", "success", { activityId: "a-1" });
|
|
496
|
+
check("namespaced routes to an alternate sink", captured.length === 1);
|
|
497
|
+
check("namespaced prefixes the action (gdpr.ropa + activity_added)",
|
|
498
|
+
captured[0].action === "gdpr.ropa.activity_added");
|
|
499
|
+
check("namespaced defaults metadata to {} when omitted",
|
|
500
|
+
(function () { emitToSink("x", "success"); return typeof captured[1].metadata === "object"; })());
|
|
501
|
+
|
|
502
|
+
// extra-arg merge — per-call actor / resource fields land on the event.
|
|
503
|
+
emitToSink("consent_recorded", "success", { id: "c-1" }, { actor: { userId: "u-9" } });
|
|
504
|
+
var extraEvt = captured[captured.length - 1];
|
|
505
|
+
check("namespaced merges the `extra` object onto the event",
|
|
506
|
+
extraEvt.actor && extraEvt.actor.userId === "u-9");
|
|
507
|
+
|
|
508
|
+
// Falsy prefix → action passes through verbatim (no prefix + ".").
|
|
509
|
+
var emitBare = b.audit.namespaced(null, { sink: sink });
|
|
510
|
+
emitBare("system.outbox.started", "success", {});
|
|
511
|
+
check("namespaced(null) passes a fully-qualified action through verbatim",
|
|
512
|
+
captured[captured.length - 1].action === "system.outbox.started");
|
|
513
|
+
|
|
514
|
+
// Sink lacking safeEmit → the emitter is a no-op (no throw).
|
|
515
|
+
var brokenSink = b.audit.namespaced("gdpr.ropa", { sink: {} });
|
|
516
|
+
var threw = null;
|
|
517
|
+
try { brokenSink("noop", "success", {}); } catch (e) { threw = e; }
|
|
518
|
+
check("namespaced with a sink lacking safeEmit is a silent no-op", threw === null);
|
|
519
|
+
|
|
520
|
+
// Sink whose safeEmit THROWS → the emitter swallows it (drop-silent).
|
|
521
|
+
var throwingSink = b.audit.namespaced("gdpr.ropa", {
|
|
522
|
+
sink: { safeEmit: function () { throw new Error("sink down"); } },
|
|
523
|
+
});
|
|
524
|
+
threw = null;
|
|
525
|
+
try { throwingSink("boom", "success", {}); } catch (e) { threw = e; }
|
|
526
|
+
check("namespaced swallows a throwing sink.safeEmit (drop-silent)", threw === null);
|
|
527
|
+
|
|
528
|
+
// Disabled emitter (bare-boolean false form) → no-op.
|
|
529
|
+
var beforeLen = captured.length;
|
|
530
|
+
var off = b.audit.namespaced("gdpr.ropa", false);
|
|
531
|
+
off("should_not_emit", "success", {});
|
|
532
|
+
check("namespaced(prefix, false) disables the emitter", captured.length === beforeLen);
|
|
533
|
+
|
|
534
|
+
// Default sink (module.exports) → reaches the real chain.
|
|
535
|
+
var emitChain = b.audit.namespaced("gdpr.ropa", true);
|
|
536
|
+
emitChain("record_of_processing", "success", { n: 1 });
|
|
537
|
+
await b.audit.flush();
|
|
538
|
+
var chainRows = await b.audit.query({ action: "gdpr.ropa.record_of_processing" });
|
|
539
|
+
check("namespaced with the default sink reaches the framework chain",
|
|
540
|
+
chainRows.length >= 1);
|
|
541
|
+
} finally {
|
|
542
|
+
await teardownTestDb(tmpDir);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// ---- bindActor — bad-id throw + actor binding violations + role scope ----
|
|
547
|
+
|
|
548
|
+
async function testBindActor() {
|
|
549
|
+
var tmpDir = _tmp();
|
|
550
|
+
await setupTestDb(tmpDir);
|
|
551
|
+
try {
|
|
552
|
+
b.audit.registerNamespace("orders");
|
|
553
|
+
// Bad actorId → AuditSegregationError (config-time throw).
|
|
554
|
+
var threw = null;
|
|
555
|
+
try { b.audit.bindActor(""); } catch (e) { threw = e; }
|
|
556
|
+
check("bindActor('') throws on an empty actorId", threw !== null);
|
|
557
|
+
threw = null;
|
|
558
|
+
try { b.audit.bindActor(123); } catch (e) { threw = e; }
|
|
559
|
+
check("bindActor(non-string) throws", threw !== null);
|
|
560
|
+
|
|
561
|
+
var bound = b.audit.bindActor("u-42");
|
|
562
|
+
check("bindActor returns a bound emitter with the actorId", bound.actorId === "u-42");
|
|
563
|
+
|
|
564
|
+
// Matching actor → emits through.
|
|
565
|
+
bound.safeEmit({ actor: { userId: "u-42" }, action: "orders.shipped", outcome: "success" });
|
|
566
|
+
// Mismatched actor → dropped + records a violation under the bound actor.
|
|
567
|
+
bound.safeEmit({ actor: { userId: "u-other" }, action: "orders.shipped", outcome: "success" });
|
|
568
|
+
// Missing actor.userId → also a violation.
|
|
569
|
+
bound.safeEmit({ action: "orders.shipped", outcome: "success" });
|
|
570
|
+
|
|
571
|
+
// record() variant: matching resolves, mismatch throws.
|
|
572
|
+
var recOk = null;
|
|
573
|
+
try { await bound.record({ actor: { userId: "u-42" }, action: "orders.shipped", outcome: "success" }); }
|
|
574
|
+
catch (e) { recOk = e; }
|
|
575
|
+
check("bound.record with the matching actor resolves", recOk === null);
|
|
576
|
+
|
|
577
|
+
var recThrew = null;
|
|
578
|
+
try { await bound.record({ actor: { userId: "u-x" }, action: "orders.shipped", outcome: "success" }); }
|
|
579
|
+
catch (e) { recThrew = e; }
|
|
580
|
+
check("bound.record with a mismatched actor throws AuditSegregationError",
|
|
581
|
+
recThrew !== null && /mismatch/i.test(recThrew.message || ""));
|
|
582
|
+
|
|
583
|
+
await b.audit.flush();
|
|
584
|
+
await waitUntil(function () {
|
|
585
|
+
return b.audit.query({ action: "audit.actor_binding.violation" })
|
|
586
|
+
.then(function (r) { return r.length >= 2; });
|
|
587
|
+
}, { timeoutMs: 5000, label: "bindActor: violation rows landed in the chain" });
|
|
588
|
+
var violations = await b.audit.query({ action: "audit.actor_binding.violation" });
|
|
589
|
+
check("actor-binding violations were recorded under the bound actor",
|
|
590
|
+
violations.length >= 2 &&
|
|
591
|
+
violations.every(function (v) { return v.actorUserId === "u-42"; }));
|
|
592
|
+
|
|
593
|
+
// roleEquivalent under a db-role scope — the SQL-bound role and bound
|
|
594
|
+
// actor must agree. Enter a real role scope via b.externalDb.runAs so the
|
|
595
|
+
// db-role-context branch (getRole() non-null) is exercised.
|
|
596
|
+
var roleBound = b.audit.bindActor("u-role", {
|
|
597
|
+
roleEquivalent: function (actorId, role) { return role === "matching_role"; },
|
|
598
|
+
});
|
|
599
|
+
var beforeRole = (await b.audit.query({ action: "audit.actor_binding.violation" })).length;
|
|
600
|
+
b.externalDb.runAs("reporting_role", function () {
|
|
601
|
+
// role "reporting_role" !== "matching_role" → roleEquivalent false →
|
|
602
|
+
// db-role mismatch violation.
|
|
603
|
+
roleBound.safeEmit({ actor: { userId: "u-role" }, action: "orders.shipped", outcome: "success" });
|
|
604
|
+
});
|
|
605
|
+
await b.audit.flush();
|
|
606
|
+
await waitUntil(function () {
|
|
607
|
+
return b.audit.query({ action: "audit.actor_binding.violation" })
|
|
608
|
+
.then(function (r) { return r.length > beforeRole; });
|
|
609
|
+
}, { timeoutMs: 5000, label: "bindActor: db-role mismatch violation landed" });
|
|
610
|
+
var afterRole = (await b.audit.query({ action: "audit.actor_binding.violation" })).length;
|
|
611
|
+
check("roleEquivalent mismatch under a db-role scope records a violation",
|
|
612
|
+
afterRole > beforeRole);
|
|
613
|
+
} finally {
|
|
614
|
+
await teardownTestDb(tmpDir);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// ---- generateActorBindingTriggerSql — default / allowRoles / roleMappingFn ----
|
|
619
|
+
|
|
620
|
+
function testGenerateActorBindingTriggerSql() {
|
|
621
|
+
var def = b.audit.generateActorBindingTriggerSql();
|
|
622
|
+
check("trigger SQL exposes up/down + object names",
|
|
623
|
+
typeof def.up === "string" && typeof def.down === "string" &&
|
|
624
|
+
def.functionName === "_blamejs_audit_actor_binding_check" &&
|
|
625
|
+
def.triggerName === "_blamejs_audit_actor_binding_trig");
|
|
626
|
+
check("default trigger SQL raises the segregation-of-duties exception",
|
|
627
|
+
/segregation-of-duties violation/.test(def.up));
|
|
628
|
+
check("default trigger SQL has no allow-roles bypass clause",
|
|
629
|
+
def.up.indexOf("current_user IN (") === -1);
|
|
630
|
+
check("default trigger SQL compares NEW column against current_user directly",
|
|
631
|
+
/IS DISTINCT FROM current_user/.test(def.up));
|
|
632
|
+
|
|
633
|
+
var withRoles = b.audit.generateActorBindingTriggerSql({ allowRoles: ["blamejs_service", "ops"] });
|
|
634
|
+
check("allowRoles injects a bypass IN(...) clause",
|
|
635
|
+
/current_user IN \('blamejs_service', 'ops'\)/.test(withRoles.up));
|
|
636
|
+
|
|
637
|
+
var withMapFn = b.audit.generateActorBindingTriggerSql({
|
|
638
|
+
roleMappingFn: "map_actor_to_role",
|
|
639
|
+
column: "actorUserId",
|
|
640
|
+
tableName: "custom_audit",
|
|
641
|
+
});
|
|
642
|
+
check("roleMappingFn wraps the column in the mapping function call",
|
|
643
|
+
withMapFn.up.indexOf("map_actor_to_role") !== -1);
|
|
644
|
+
check("custom tableName flows into the trigger DDL",
|
|
645
|
+
withMapFn.up.indexOf("custom_audit") !== -1);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// ---- assertSegregation — no-db throw / missing-artifact throw / present ok ----
|
|
649
|
+
|
|
650
|
+
async function testAssertSegregation() {
|
|
651
|
+
var tmpDir = _tmp();
|
|
652
|
+
await setupTestDb(tmpDir);
|
|
653
|
+
try {
|
|
654
|
+
// No opts at all (opts defaults to {}) → no db → throws.
|
|
655
|
+
var threw = null;
|
|
656
|
+
try { await b.audit.assertSegregation(); } catch (e) { threw = e; }
|
|
657
|
+
check("assertSegregation() with no opts throws (no db)", threw !== null);
|
|
658
|
+
|
|
659
|
+
// Empty opts / db without query() → throws.
|
|
660
|
+
threw = null;
|
|
661
|
+
try { await b.audit.assertSegregation({}); } catch (e) { threw = e; }
|
|
662
|
+
check("assertSegregation without a db.query throws", threw !== null);
|
|
663
|
+
|
|
664
|
+
threw = null;
|
|
665
|
+
try { await b.audit.assertSegregation({ db: { notQuery: true } }); } catch (e) { threw = e; }
|
|
666
|
+
check("assertSegregation with a db lacking query() throws", threw !== null);
|
|
667
|
+
|
|
668
|
+
// Missing artifacts: pg_proc / pg_trigger introspection returns no rows.
|
|
669
|
+
// (operator-supplied introspection target — not a framework db.)
|
|
670
|
+
var emptyDb = { query: async function () { return { rows: [] }; } };
|
|
671
|
+
threw = null;
|
|
672
|
+
try { await b.audit.assertSegregation({ db: emptyDb }); } catch (e) { threw = e; }
|
|
673
|
+
check("assertSegregation throws when the trigger/function are absent",
|
|
674
|
+
threw !== null && /missing/i.test(threw.message || ""));
|
|
675
|
+
|
|
676
|
+
// Function present, trigger absent → still throws, naming the trigger.
|
|
677
|
+
var fnOnlyDb = {
|
|
678
|
+
query: async function (sql) {
|
|
679
|
+
if (/pg_proc/.test(sql)) return { rows: [{ "?column?": 1 }] };
|
|
680
|
+
return { rows: [] };
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
threw = null;
|
|
684
|
+
try { await b.audit.assertSegregation({ db: fnOnlyDb }); } catch (e) { threw = e; }
|
|
685
|
+
check("assertSegregation throws when only the trigger is missing",
|
|
686
|
+
threw !== null && /trigger:/.test(threw.message || ""));
|
|
687
|
+
|
|
688
|
+
// Both present → { ok:true, missing:[] }.
|
|
689
|
+
var okDb = { query: async function () { return { rows: [{ "?column?": 1 }] }; } };
|
|
690
|
+
var res = await b.audit.assertSegregation({ db: okDb });
|
|
691
|
+
check("assertSegregation returns ok when both artifacts are present",
|
|
692
|
+
res.ok === true && res.missing.length === 0);
|
|
693
|
+
} finally {
|
|
694
|
+
await teardownTestDb(tmpDir);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// ---- applyPosture / activePosture — defaulting ----
|
|
699
|
+
|
|
700
|
+
function testApplyPosture() {
|
|
701
|
+
check("applyPosture(non-string) returns null", b.audit.applyPosture(123) === null);
|
|
702
|
+
check("applyPosture('') returns null", b.audit.applyPosture("") === null);
|
|
703
|
+
|
|
704
|
+
var res = b.audit.applyPosture("hipaa");
|
|
705
|
+
check("applyPosture('hipaa') returns { posture }", res && res.posture === "hipaa");
|
|
706
|
+
check("activePosture() reflects the applied posture", b.audit.activePosture() === "hipaa");
|
|
707
|
+
|
|
708
|
+
b.audit.applyPosture("pci-dss");
|
|
709
|
+
check("applyPosture overwrites the active posture", b.audit.activePosture() === "pci-dss");
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function testDuplicateCheckpointCounterRecognition() {
|
|
713
|
+
// The concurrent-anchor idempotency guard must recognize the duplicate
|
|
714
|
+
// atMonotonicCounter UNIQUE violation across ALL THREE backends: SQLite names
|
|
715
|
+
// the column in the message; Postgres carries the unique-index name in
|
|
716
|
+
// constraint/detail with SQLSTATE 23505; MySQL reports the key name with
|
|
717
|
+
// errno 1062. An unrelated error, or a unique violation on a DIFFERENT
|
|
718
|
+
// column, must NOT be swallowed (fail-closed).
|
|
719
|
+
var isDup = b.audit._isDuplicateCheckpointCounter;
|
|
720
|
+
check("dup-counter: sqlite column-in-message recognized",
|
|
721
|
+
isDup({ message: "UNIQUE constraint failed: _blamejs_audit_checkpoints.atMonotonicCounter", code: "SQLITE_CONSTRAINT_UNIQUE" }) === true);
|
|
722
|
+
check("dup-counter: postgres index-name + 23505 recognized",
|
|
723
|
+
isDup({ message: "duplicate key value violates unique constraint", constraint: "idx__blamejs_audit_checkpoints_chkpt_counter", code: "23505" }) === true);
|
|
724
|
+
check("dup-counter: mysql key-name + errno 1062 recognized",
|
|
725
|
+
isDup({ sqlMessage: "Duplicate entry '5' for key 'idx_chkpt_counter'", errno: 1062 }) === true);
|
|
726
|
+
check("dup-counter: unrelated error NOT swallowed",
|
|
727
|
+
isDup({ message: "connection refused ECONNREFUSED" }) === false);
|
|
728
|
+
check("dup-counter: unique violation on a DIFFERENT column NOT swallowed",
|
|
729
|
+
isDup({ message: "UNIQUE constraint failed: other_table.other_col", code: "SQLITE_CONSTRAINT_UNIQUE" }) === false);
|
|
730
|
+
check("dup-counter: null error is not a duplicate", isDup(null) === false);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
async function run() {
|
|
734
|
+
// flush() before any emit has created the AsyncHandler → the `!_auditHandler`
|
|
735
|
+
// early-return arm. Harmless no-op if a handler already exists.
|
|
736
|
+
await b.audit.flush();
|
|
737
|
+
testSurface();
|
|
738
|
+
testRegisterNamespace();
|
|
739
|
+
await testRecordThrowBranches();
|
|
740
|
+
await testRecordDefaulting();
|
|
741
|
+
await testUseStoreRefusalAndShadowFailure();
|
|
742
|
+
await testQueryCriteriaAndToMs();
|
|
743
|
+
await testBeginTrace();
|
|
744
|
+
await testCheckpointLifecycle();
|
|
745
|
+
testDuplicateCheckpointCounterRecognition();
|
|
746
|
+
await testVerifyChain();
|
|
747
|
+
await testEmitFlushDropPath();
|
|
748
|
+
await testSafeEmitNormalizationAndRedaction();
|
|
749
|
+
await testNamespaced();
|
|
750
|
+
await testBindActor();
|
|
751
|
+
testGenerateActorBindingTriggerSql();
|
|
752
|
+
await testAssertSegregation();
|
|
753
|
+
testApplyPosture();
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
module.exports = { run: run };
|
|
757
|
+
|
|
758
|
+
if (require.main === module) {
|
|
759
|
+
run().then(function () { console.log("OK"); })
|
|
760
|
+
.catch(function (e) {
|
|
761
|
+
// Log only the error class (not its message/stack): the crypto/db
|
|
762
|
+
// setup path carries passphrase-length-derived data, and logging
|
|
763
|
+
// content derived from it is a clear-text-logging sink. The class
|
|
764
|
+
// name signals the failure; the non-zero exit makes it loud, and
|
|
765
|
+
// the smoke runner surfaces full detail via check().
|
|
766
|
+
console.error("FAIL: " + (e && e.name ? e.name : "error"));
|
|
767
|
+
process.exit(1);
|
|
768
|
+
});
|
|
769
|
+
}
|