@blamejs/blamejs-shop 0.0.44
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 +87 -0
- package/LICENSE +17 -0
- package/README.md +117 -0
- package/SECURITY.md +139 -0
- package/lib/admin.js +952 -0
- package/lib/analytics.js +267 -0
- package/lib/cart.js +279 -0
- package/lib/catalog-import.js +344 -0
- package/lib/catalog.js +769 -0
- package/lib/checkout.js +320 -0
- package/lib/config.js +151 -0
- package/lib/customers.js +322 -0
- package/lib/email.js +242 -0
- package/lib/externaldb-d1.js +283 -0
- package/lib/index.js +57 -0
- package/lib/inventory-alerts.js +198 -0
- package/lib/newsletter.js +142 -0
- package/lib/order.js +380 -0
- package/lib/payment.js +318 -0
- package/lib/pricing.js +185 -0
- package/lib/r2-bridge.js +169 -0
- package/lib/shipping.js +185 -0
- package/lib/storefront.js +2160 -0
- package/lib/subscriptions.js +410 -0
- package/lib/tax.js +161 -0
- package/lib/theme.js +194 -0
- package/lib/vendor/MANIFEST.json +19 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +23 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +34 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/project.yaml +16 -0
- package/lib/vendor/blamejs/.dockerignore +45 -0
- package/lib/vendor/blamejs/.gitattributes +42 -0
- package/lib/vendor/blamejs/.github/CODEOWNERS +4 -0
- package/lib/vendor/blamejs/.github/FUNDING.yml +2 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/bug_report.md +58 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/feature_request.md +99 -0
- package/lib/vendor/blamejs/.github/PULL_REQUEST_TEMPLATE.md +77 -0
- package/lib/vendor/blamejs/.github/dependabot.yml +37 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +148 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +107 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +122 -0
- package/lib/vendor/blamejs/.github/workflows/ci.yml +511 -0
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +50 -0
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +655 -0
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +406 -0
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +101 -0
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +134 -0
- package/lib/vendor/blamejs/.gitignore +102 -0
- package/lib/vendor/blamejs/.gitleaks.toml +166 -0
- package/lib/vendor/blamejs/.hadolint.yaml +18 -0
- package/lib/vendor/blamejs/.npmrc +5 -0
- package/lib/vendor/blamejs/.pinact.yaml +17 -0
- package/lib/vendor/blamejs/ARCHITECTURE.md +158 -0
- package/lib/vendor/blamejs/CHANGELOG.md +1351 -0
- package/lib/vendor/blamejs/CODE_OF_CONDUCT.md +86 -0
- package/lib/vendor/blamejs/CONTRIBUTING.md +156 -0
- package/lib/vendor/blamejs/GOVERNANCE.md +201 -0
- package/lib/vendor/blamejs/LICENSE +201 -0
- package/lib/vendor/blamejs/LTS-CALENDAR.md +29 -0
- package/lib/vendor/blamejs/MIGRATING.md +29 -0
- package/lib/vendor/blamejs/NOTICE +81 -0
- package/lib/vendor/blamejs/README.md +304 -0
- package/lib/vendor/blamejs/SECURITY.md +432 -0
- package/lib/vendor/blamejs/api-snapshot.json +48709 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.png +0 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.svg +129 -0
- package/lib/vendor/blamejs/bench/README.md +77 -0
- package/lib/vendor/blamejs/bench/_helpers.js +70 -0
- package/lib/vendor/blamejs/bench/baseline.json +183 -0
- package/lib/vendor/blamejs/bench/crypto-hash.bench.js +19 -0
- package/lib/vendor/blamejs/bench/crypto-symmetric.bench.js +28 -0
- package/lib/vendor/blamejs/bench/run.js +140 -0
- package/lib/vendor/blamejs/bench/safe-json.bench.js +31 -0
- package/lib/vendor/blamejs/bin/blamejs.js +13 -0
- package/lib/vendor/blamejs/docker/caddy/Caddyfile +46 -0
- package/lib/vendor/blamejs/docker/coredns/Corefile +37 -0
- package/lib/vendor/blamejs/docker/haproxy/haproxy.cfg +52 -0
- package/lib/vendor/blamejs/docker/init/generate-certs.sh +118 -0
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +87 -0
- package/lib/vendor/blamejs/docker/mitmproxy/config.yaml +16 -0
- package/lib/vendor/blamejs/docker/mongo/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/mysql/my.cnf +12 -0
- package/lib/vendor/blamejs/docker/nats/nats.conf +33 -0
- package/lib/vendor/blamejs/docker/postgres/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/postgres/postgresql.conf +18 -0
- package/lib/vendor/blamejs/docker/rabbitmq/rabbitmq.conf +18 -0
- package/lib/vendor/blamejs/docker/redis/redis.conf +15 -0
- package/lib/vendor/blamejs/docker/squid/squid.conf +24 -0
- package/lib/vendor/blamejs/docker/syslog/syslog-ng.conf +34 -0
- package/lib/vendor/blamejs/docker-compose.test.yml +545 -0
- package/lib/vendor/blamejs/docs/cis-postgres-crosswalk.md +102 -0
- package/lib/vendor/blamejs/docs/cis-sqlite-equivalent.md +92 -0
- package/lib/vendor/blamejs/eslint.config.mjs +204 -0
- package/lib/vendor/blamejs/examples/wiki/Caddyfile +40 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +218 -0
- package/lib/vendor/blamejs/examples/wiki/Dockerfile +120 -0
- package/lib/vendor/blamejs/examples/wiki/README.md +157 -0
- package/lib/vendor/blamejs/examples/wiki/cli-snapshot.json +250 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +231 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +166 -0
- package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +217 -0
- package/lib/vendor/blamejs/examples/wiki/lib/auto-site-entries.js +139 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +555 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-cli.js +507 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-env-vars.js +435 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-errors.js +282 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-vendored-deps.js +321 -0
- package/lib/vendor/blamejs/examples/wiki/lib/nav.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/lib/opts-resolver.js +75 -0
- package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +508 -0
- package/lib/vendor/blamejs/examples/wiki/lib/section.js +276 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +587 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +318 -0
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +122 -0
- package/lib/vendor/blamejs/examples/wiki/migrations/0001-pages-schema.js +74 -0
- package/lib/vendor/blamejs/examples/wiki/package.json +18 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.png +0 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.svg +129 -0
- package/lib/vendor/blamejs/examples/wiki/public/robots.txt +5 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/MANIFEST.json +30 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.css +1 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/public/wiki.css +1250 -0
- package/lib/vendor/blamejs/examples/wiki/routes/admin.js +366 -0
- package/lib/vendor/blamejs/examples/wiki/routes/integration.js +230 -0
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +266 -0
- package/lib/vendor/blamejs/examples/wiki/scripts/backfill-module-metadata.js +214 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/0001-default-pages.js +35 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/_index.js +34 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/api.js +76 -0
- package/lib/vendor/blamejs/examples/wiki/server.js +129 -0
- package/lib/vendor/blamejs/examples/wiki/site.config.js +197 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/README.md +38 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/auth/password-hash.example.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/src/editor.js +103 -0
- package/lib/vendor/blamejs/examples/wiki/src/wiki.js +349 -0
- package/lib/vendor/blamejs/examples/wiki/test/AUDIT.md +155 -0
- package/lib/vendor/blamejs/examples/wiki/test/codebase-patterns.test.js +594 -0
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +741 -0
- package/lib/vendor/blamejs/examples/wiki/test/find-missing-pages.js +254 -0
- package/lib/vendor/blamejs/examples/wiki/test/integration.js +391 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-cli-snapshot.js +379 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-env-snapshot.js +346 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-nav-coverage.js +212 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-site-coverage.js +252 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-source-comment-blocks.js +107 -0
- package/lib/vendor/blamejs/examples/wiki/views/_layout.html +115 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/api-keys.html +51 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/dashboard.html +22 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/edit.html +17 -0
- package/lib/vendor/blamejs/examples/wiki/views/home.html +85 -0
- package/lib/vendor/blamejs/examples/wiki/views/login.html +18 -0
- package/lib/vendor/blamejs/examples/wiki/views/page.html +5 -0
- package/lib/vendor/blamejs/examples/wiki/views/partials/nav.html +13 -0
- package/lib/vendor/blamejs/examples/wiki/views/search.html +19 -0
- package/lib/vendor/blamejs/examples/wiki/wiki.config.js +15 -0
- package/lib/vendor/blamejs/fuzz/README.md +137 -0
- package/lib/vendor/blamejs/fuzz/_expected.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-agent-registry.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-csv.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/01-basic.csv +3 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/02-formula.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/03-hyperlink.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-dsn.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-email.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-email_seed_corpus/01-basic.eml +5 -0
- package/lib/vendor/blamejs/fuzz/guard-envelope.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-payload.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-topic.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-html.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/01-basic.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/02-script.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/03-event.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/04-jsurl.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-idempotency-key.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-imap-command.fuzz.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-jmap.fuzz.js +41 -0
- package/lib/vendor/blamejs/fuzz/guard-json.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/01-basic.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/02-proto.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/03-dupkey.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/04-nan.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/05-bom.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-list-id.fuzz.js +21 -0
- package/lib/vendor/blamejs/fuzz/guard-list-unsubscribe.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-compose.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-move.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-query.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-reply.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-sieve.fuzz.js +36 -0
- package/lib/vendor/blamejs/fuzz/guard-managesieve-command.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/01-basic.md +2 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/02-jsurl.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/03-jsimg.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-message-id.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-pop3-command.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-posture-chain.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-saga-config.fuzz.js +32 -0
- package/lib/vendor/blamejs/fuzz/guard-smtp-command.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-snapshot-envelope.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-stream-args.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-svg.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/01-basic.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/02-script.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-tenant-id.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-trace-context.fuzz.js +30 -0
- package/lib/vendor/blamejs/fuzz/guard-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/02-xxe.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/01-basic.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/02-anchor.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/03-norway.yaml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/04-multidoc.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini_seed_corpus/01-basic.ini +2 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml_seed_corpus/01-basic.toml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml_seed_corpus/01-basic.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/safe-decompress.fuzz.js +49 -0
- package/lib/vendor/blamejs/fuzz/safe-dns.fuzz.js +29 -0
- package/lib/vendor/blamejs/fuzz/safe-ical.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-icap.fuzz.js +42 -0
- package/lib/vendor/blamejs/fuzz/safe-json.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/01-object.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/02-array.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/03-string.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/04-proto.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/05-deep.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/02-filter.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/03-deepscan.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/04-slice.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-mime.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/safe-mount-info.fuzz.js +33 -0
- package/lib/vendor/blamejs/fuzz/safe-sieve.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/safe-smtp.fuzz.js +64 -0
- package/lib/vendor/blamejs/fuzz/safe-url.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/02-userinfo.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/03-dangerous.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/04-data.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/05-ipv6.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/06-idn.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-vcard.fuzz.js +16 -0
- package/lib/vendor/blamejs/index.js +678 -0
- package/lib/vendor/blamejs/keys/release-pqc-pub.json +7 -0
- package/lib/vendor/blamejs/lib/_test/crypto-fixtures.js +67 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +598 -0
- package/lib/vendor/blamejs/lib/a2a.js +407 -0
- package/lib/vendor/blamejs/lib/acme.js +1448 -0
- package/lib/vendor/blamejs/lib/agent-audit.js +45 -0
- package/lib/vendor/blamejs/lib/agent-event-bus.js +382 -0
- package/lib/vendor/blamejs/lib/agent-idempotency.js +497 -0
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +717 -0
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +366 -0
- package/lib/vendor/blamejs/lib/agent-saga.js +321 -0
- package/lib/vendor/blamejs/lib/agent-snapshot.js +676 -0
- package/lib/vendor/blamejs/lib/agent-stream.js +269 -0
- package/lib/vendor/blamejs/lib/agent-tenant.js +632 -0
- package/lib/vendor/blamejs/lib/agent-trace.js +281 -0
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +184 -0
- package/lib/vendor/blamejs/lib/ai-content-detect.js +268 -0
- package/lib/vendor/blamejs/lib/ai-input.js +201 -0
- package/lib/vendor/blamejs/lib/ai-model-manifest.js +363 -0
- package/lib/vendor/blamejs/lib/ai-pref.js +340 -0
- package/lib/vendor/blamejs/lib/api-key.js +721 -0
- package/lib/vendor/blamejs/lib/api-snapshot.js +458 -0
- package/lib/vendor/blamejs/lib/app-shutdown.js +557 -0
- package/lib/vendor/blamejs/lib/app.js +365 -0
- package/lib/vendor/blamejs/lib/archive.js +547 -0
- package/lib/vendor/blamejs/lib/arg-parser.js +697 -0
- package/lib/vendor/blamejs/lib/argon2-builtin.js +173 -0
- package/lib/vendor/blamejs/lib/asn1-der.js +424 -0
- package/lib/vendor/blamejs/lib/asyncapi-bindings.js +160 -0
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +143 -0
- package/lib/vendor/blamejs/lib/asyncapi.js +575 -0
- package/lib/vendor/blamejs/lib/atomic-file.js +1023 -0
- package/lib/vendor/blamejs/lib/audit-chain.js +266 -0
- package/lib/vendor/blamejs/lib/audit-daily-review.js +389 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +751 -0
- package/lib/vendor/blamejs/lib/audit-tools.js +1113 -0
- package/lib/vendor/blamejs/lib/audit.js +1671 -0
- package/lib/vendor/blamejs/lib/auth/aal.js +169 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +220 -0
- package/lib/vendor/blamejs/lib/auth/acr-vocabulary.js +265 -0
- package/lib/vendor/blamejs/lib/auth/ato-kill-switch.js +112 -0
- package/lib/vendor/blamejs/lib/auth/auth-time-tracker.js +111 -0
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +573 -0
- package/lib/vendor/blamejs/lib/auth/ciba.js +637 -0
- package/lib/vendor/blamejs/lib/auth/dpop.js +516 -0
- package/lib/vendor/blamejs/lib/auth/elevation-grant.js +306 -0
- package/lib/vendor/blamejs/lib/auth/fal.js +229 -0
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +681 -0
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +519 -0
- package/lib/vendor/blamejs/lib/auth/jwt.js +430 -0
- package/lib/vendor/blamejs/lib/auth/lockout.js +449 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +2141 -0
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +657 -0
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +531 -0
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +600 -0
- package/lib/vendor/blamejs/lib/auth/passkey.js +676 -0
- package/lib/vendor/blamejs/lib/auth/password.js +693 -0
- package/lib/vendor/blamejs/lib/auth/saml.js +2109 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-disclosure.js +95 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +225 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +197 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +728 -0
- package/lib/vendor/blamejs/lib/auth/status-list.js +272 -0
- package/lib/vendor/blamejs/lib/auth/step-up-policy.js +335 -0
- package/lib/vendor/blamejs/lib/auth/step-up.js +454 -0
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +505 -0
- package/lib/vendor/blamejs/lib/auth-header.js +148 -0
- package/lib/vendor/blamejs/lib/backup/bundle.js +265 -0
- package/lib/vendor/blamejs/lib/backup/crypto.js +176 -0
- package/lib/vendor/blamejs/lib/backup/index.js +1001 -0
- package/lib/vendor/blamejs/lib/backup/manifest.js +443 -0
- package/lib/vendor/blamejs/lib/boot-gates.js +174 -0
- package/lib/vendor/blamejs/lib/breach-deadline.js +272 -0
- package/lib/vendor/blamejs/lib/break-glass.js +1753 -0
- package/lib/vendor/blamejs/lib/budr.js +205 -0
- package/lib/vendor/blamejs/lib/bundler.js +461 -0
- package/lib/vendor/blamejs/lib/cache-redis.js +256 -0
- package/lib/vendor/blamejs/lib/cache-status.js +288 -0
- package/lib/vendor/blamejs/lib/cache.js +1331 -0
- package/lib/vendor/blamejs/lib/calendar.js +1240 -0
- package/lib/vendor/blamejs/lib/canonical-json.js +143 -0
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +473 -0
- package/lib/vendor/blamejs/lib/cert.js +763 -0
- package/lib/vendor/blamejs/lib/chain-writer.js +259 -0
- package/lib/vendor/blamejs/lib/circuit-breaker.js +101 -0
- package/lib/vendor/blamejs/lib/cli-helpers.js +237 -0
- package/lib/vendor/blamejs/lib/cli.js +2328 -0
- package/lib/vendor/blamejs/lib/client-hints.js +318 -0
- package/lib/vendor/blamejs/lib/cloud-events.js +277 -0
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +317 -0
- package/lib/vendor/blamejs/lib/cluster-storage.js +351 -0
- package/lib/vendor/blamejs/lib/cluster.js +1017 -0
- package/lib/vendor/blamejs/lib/cms-codec.js +826 -0
- package/lib/vendor/blamejs/lib/codepoint-class.js +262 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +190 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +205 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-risk.js +189 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +200 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +821 -0
- package/lib/vendor/blamejs/lib/compliance-eaa.js +204 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-aliases.js +167 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +206 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fuzzy.js +297 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +569 -0
- package/lib/vendor/blamejs/lib/compliance.js +1558 -0
- package/lib/vendor/blamejs/lib/config-drift.js +426 -0
- package/lib/vendor/blamejs/lib/config.js +446 -0
- package/lib/vendor/blamejs/lib/consent.js +369 -0
- package/lib/vendor/blamejs/lib/constants.js +209 -0
- package/lib/vendor/blamejs/lib/content-credentials.js +704 -0
- package/lib/vendor/blamejs/lib/cookies.js +560 -0
- package/lib/vendor/blamejs/lib/cra-report.js +299 -0
- package/lib/vendor/blamejs/lib/credential-hash.js +394 -0
- package/lib/vendor/blamejs/lib/crypto-field.js +1017 -0
- package/lib/vendor/blamejs/lib/crypto-hpke-pq.js +187 -0
- package/lib/vendor/blamejs/lib/crypto-hpke.js +256 -0
- package/lib/vendor/blamejs/lib/crypto.js +1908 -0
- package/lib/vendor/blamejs/lib/csp.js +271 -0
- package/lib/vendor/blamejs/lib/csv.js +418 -0
- package/lib/vendor/blamejs/lib/daemon.js +481 -0
- package/lib/vendor/blamejs/lib/dark-patterns.js +488 -0
- package/lib/vendor/blamejs/lib/data-act.js +328 -0
- package/lib/vendor/blamejs/lib/db-collection.js +587 -0
- package/lib/vendor/blamejs/lib/db-declare-row-policy.js +267 -0
- package/lib/vendor/blamejs/lib/db-declare-view.js +420 -0
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +333 -0
- package/lib/vendor/blamejs/lib/db-query.js +802 -0
- package/lib/vendor/blamejs/lib/db-role-context.js +50 -0
- package/lib/vendor/blamejs/lib/db-schema.js +322 -0
- package/lib/vendor/blamejs/lib/db.js +3111 -0
- package/lib/vendor/blamejs/lib/dbsc.js +299 -0
- package/lib/vendor/blamejs/lib/ddl-change-control.js +523 -0
- package/lib/vendor/blamejs/lib/deprecate.js +377 -0
- package/lib/vendor/blamejs/lib/dev.js +405 -0
- package/lib/vendor/blamejs/lib/dora.js +402 -0
- package/lib/vendor/blamejs/lib/dr-runbook.js +368 -0
- package/lib/vendor/blamejs/lib/dsr.js +1188 -0
- package/lib/vendor/blamejs/lib/dual-control.js +526 -0
- package/lib/vendor/blamejs/lib/early-hints.js +212 -0
- package/lib/vendor/blamejs/lib/error-page.js +420 -0
- package/lib/vendor/blamejs/lib/events.js +214 -0
- package/lib/vendor/blamejs/lib/external-db-migrate.js +659 -0
- package/lib/vendor/blamejs/lib/external-db.js +1877 -0
- package/lib/vendor/blamejs/lib/fapi2.js +394 -0
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +395 -0
- package/lib/vendor/blamejs/lib/fdx.js +370 -0
- package/lib/vendor/blamejs/lib/fedcm.js +264 -0
- package/lib/vendor/blamejs/lib/file-type.js +360 -0
- package/lib/vendor/blamejs/lib/file-upload.js +1256 -0
- package/lib/vendor/blamejs/lib/flag-cache.js +136 -0
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +135 -0
- package/lib/vendor/blamejs/lib/flag-providers.js +279 -0
- package/lib/vendor/blamejs/lib/flag-targeting.js +210 -0
- package/lib/vendor/blamejs/lib/flag.js +346 -0
- package/lib/vendor/blamejs/lib/forms.js +525 -0
- package/lib/vendor/blamejs/lib/framework-error.js +724 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +845 -0
- package/lib/vendor/blamejs/lib/framework-sha1-hibp.js +34 -0
- package/lib/vendor/blamejs/lib/fsm.js +469 -0
- package/lib/vendor/blamejs/lib/gate-contract.js +1661 -0
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +261 -0
- package/lib/vendor/blamejs/lib/graphql-federation.js +234 -0
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +179 -0
- package/lib/vendor/blamejs/lib/guard-all.js +555 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +901 -0
- package/lib/vendor/blamejs/lib/guard-auth.js +451 -0
- package/lib/vendor/blamejs/lib/guard-cidr.js +676 -0
- package/lib/vendor/blamejs/lib/guard-csv.js +1176 -0
- package/lib/vendor/blamejs/lib/guard-domain.js +814 -0
- package/lib/vendor/blamejs/lib/guard-dsn.js +382 -0
- package/lib/vendor/blamejs/lib/guard-email.js +951 -0
- package/lib/vendor/blamejs/lib/guard-envelope.js +294 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +217 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +150 -0
- package/lib/vendor/blamejs/lib/guard-filename.js +956 -0
- package/lib/vendor/blamejs/lib/guard-graphql.js +731 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +164 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +144 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +154 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +44 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +470 -0
- package/lib/vendor/blamejs/lib/guard-html.js +1209 -0
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +151 -0
- package/lib/vendor/blamejs/lib/guard-image.js +584 -0
- package/lib/vendor/blamejs/lib/guard-imap-command.js +337 -0
- package/lib/vendor/blamejs/lib/guard-jmap.js +321 -0
- package/lib/vendor/blamejs/lib/guard-json.js +935 -0
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +512 -0
- package/lib/vendor/blamejs/lib/guard-jwt.js +772 -0
- package/lib/vendor/blamejs/lib/guard-list-id.js +318 -0
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +412 -0
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +282 -0
- package/lib/vendor/blamejs/lib/guard-mail-move.js +202 -0
- package/lib/vendor/blamejs/lib/guard-mail-query.js +310 -0
- package/lib/vendor/blamejs/lib/guard-mail-reply.js +172 -0
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +207 -0
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +566 -0
- package/lib/vendor/blamejs/lib/guard-markdown.js +768 -0
- package/lib/vendor/blamejs/lib/guard-message-id.js +267 -0
- package/lib/vendor/blamejs/lib/guard-mime.js +609 -0
- package/lib/vendor/blamejs/lib/guard-oauth.js +650 -0
- package/lib/vendor/blamejs/lib/guard-pdf.js +569 -0
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +317 -0
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +201 -0
- package/lib/vendor/blamejs/lib/guard-regex.js +632 -0
- package/lib/vendor/blamejs/lib/guard-saga-config.js +157 -0
- package/lib/vendor/blamejs/lib/guard-shell.js +522 -0
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +594 -0
- package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +168 -0
- package/lib/vendor/blamejs/lib/guard-stream-args.js +166 -0
- package/lib/vendor/blamejs/lib/guard-svg.js +1163 -0
- package/lib/vendor/blamejs/lib/guard-template.js +490 -0
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +138 -0
- package/lib/vendor/blamejs/lib/guard-time.js +586 -0
- package/lib/vendor/blamejs/lib/guard-trace-context.js +172 -0
- package/lib/vendor/blamejs/lib/guard-uuid.js +548 -0
- package/lib/vendor/blamejs/lib/guard-xml.js +666 -0
- package/lib/vendor/blamejs/lib/guard-yaml.js +726 -0
- package/lib/vendor/blamejs/lib/hal.js +125 -0
- package/lib/vendor/blamejs/lib/handlers.js +350 -0
- package/lib/vendor/blamejs/lib/honeytoken.js +168 -0
- package/lib/vendor/blamejs/lib/html-balance.js +347 -0
- package/lib/vendor/blamejs/lib/http-client-cache.js +923 -0
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +519 -0
- package/lib/vendor/blamejs/lib/http-client.js +2152 -0
- package/lib/vendor/blamejs/lib/http-message-signature.js +589 -0
- package/lib/vendor/blamejs/lib/http2-teardown.js +34 -0
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +398 -0
- package/lib/vendor/blamejs/lib/i18n.js +931 -0
- package/lib/vendor/blamejs/lib/iab-mspa.js +257 -0
- package/lib/vendor/blamejs/lib/iab-tcf.js +461 -0
- package/lib/vendor/blamejs/lib/importmap-integrity.js +90 -0
- package/lib/vendor/blamejs/lib/inbox.js +435 -0
- package/lib/vendor/blamejs/lib/incident-report.js +314 -0
- package/lib/vendor/blamejs/lib/ip-utils.js +102 -0
- package/lib/vendor/blamejs/lib/jobs.js +185 -0
- package/lib/vendor/blamejs/lib/jose-jwe-experimental.js +228 -0
- package/lib/vendor/blamejs/lib/jsonapi.js +230 -0
- package/lib/vendor/blamejs/lib/keychain.js +865 -0
- package/lib/vendor/blamejs/lib/lazy-require.js +48 -0
- package/lib/vendor/blamejs/lib/legal-hold.js +374 -0
- package/lib/vendor/blamejs/lib/local-db-thin.js +321 -0
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +369 -0
- package/lib/vendor/blamejs/lib/log-stream-local.js +146 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +410 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +286 -0
- package/lib/vendor/blamejs/lib/log-stream-syslog.js +310 -0
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +199 -0
- package/lib/vendor/blamejs/lib/log-stream.js +584 -0
- package/lib/vendor/blamejs/lib/log.js +625 -0
- package/lib/vendor/blamejs/lib/lro.js +200 -0
- package/lib/vendor/blamejs/lib/mail-agent.js +786 -0
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +417 -0
- package/lib/vendor/blamejs/lib/mail-arf.js +343 -0
- package/lib/vendor/blamejs/lib/mail-auth.js +2144 -0
- package/lib/vendor/blamejs/lib/mail-bimi.js +1047 -0
- package/lib/vendor/blamejs/lib/mail-bounce.js +955 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1286 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +789 -0
- package/lib/vendor/blamejs/lib/mail-crypto.js +108 -0
- package/lib/vendor/blamejs/lib/mail-dav.js +1224 -0
- package/lib/vendor/blamejs/lib/mail-deploy.js +1119 -0
- package/lib/vendor/blamejs/lib/mail-dkim.js +1250 -0
- package/lib/vendor/blamejs/lib/mail-greylist.js +448 -0
- package/lib/vendor/blamejs/lib/mail-helo.js +473 -0
- package/lib/vendor/blamejs/lib/mail-journal.js +435 -0
- package/lib/vendor/blamejs/lib/mail-mdn.js +424 -0
- package/lib/vendor/blamejs/lib/mail-rbl.js +392 -0
- package/lib/vendor/blamejs/lib/mail-require-tls.js +198 -0
- package/lib/vendor/blamejs/lib/mail-scan.js +502 -0
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +629 -0
- package/lib/vendor/blamejs/lib/mail-server-imap.js +1858 -0
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +1565 -0
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +908 -0
- package/lib/vendor/blamejs/lib/mail-server-mx.js +969 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +915 -0
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +315 -0
- package/lib/vendor/blamejs/lib/mail-server-registry.js +378 -0
- package/lib/vendor/blamejs/lib/mail-server-submission.js +1396 -0
- package/lib/vendor/blamejs/lib/mail-server-tls.js +445 -0
- package/lib/vendor/blamejs/lib/mail-sieve.js +557 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +284 -0
- package/lib/vendor/blamejs/lib/mail-srs.js +248 -0
- package/lib/vendor/blamejs/lib/mail-store-fts.js +394 -0
- package/lib/vendor/blamejs/lib/mail-store.js +929 -0
- package/lib/vendor/blamejs/lib/mail-unsubscribe.js +400 -0
- package/lib/vendor/blamejs/lib/mail.js +1971 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +473 -0
- package/lib/vendor/blamejs/lib/mcp.js +950 -0
- package/lib/vendor/blamejs/lib/metrics.js +1503 -0
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/ai-act-disclosure.js +203 -0
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +981 -0
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +137 -0
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +171 -0
- package/lib/vendor/blamejs/lib/middleware/attach-user.js +220 -0
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +293 -0
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +1519 -0
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +217 -0
- package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +122 -0
- package/lib/vendor/blamejs/lib/middleware/compose-pipeline.js +355 -0
- package/lib/vendor/blamejs/lib/middleware/compression.js +489 -0
- package/lib/vendor/blamejs/lib/middleware/cookies.js +130 -0
- package/lib/vendor/blamejs/lib/middleware/cors.js +386 -0
- package/lib/vendor/blamejs/lib/middleware/csp-nonce.js +388 -0
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +499 -0
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +243 -0
- package/lib/vendor/blamejs/lib/middleware/db-role-for.js +304 -0
- package/lib/vendor/blamejs/lib/middleware/dpop.js +402 -0
- package/lib/vendor/blamejs/lib/middleware/error-handler.js +69 -0
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +168 -0
- package/lib/vendor/blamejs/lib/middleware/flag-context.js +110 -0
- package/lib/vendor/blamejs/lib/middleware/gpc.js +153 -0
- package/lib/vendor/blamejs/lib/middleware/headers.js +242 -0
- package/lib/vendor/blamejs/lib/middleware/health.js +438 -0
- package/lib/vendor/blamejs/lib/middleware/host-allowlist.js +189 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +964 -0
- package/lib/vendor/blamejs/lib/middleware/index.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/nel.js +214 -0
- package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +237 -0
- package/lib/vendor/blamejs/lib/middleware/no-cache.js +106 -0
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +277 -0
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +556 -0
- package/lib/vendor/blamejs/lib/middleware/request-id.js +79 -0
- package/lib/vendor/blamejs/lib/middleware/request-log.js +205 -0
- package/lib/vendor/blamejs/lib/middleware/require-aal.js +138 -0
- package/lib/vendor/blamejs/lib/middleware/require-auth.js +144 -0
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +290 -0
- package/lib/vendor/blamejs/lib/middleware/require-content-type.js +113 -0
- package/lib/vendor/blamejs/lib/middleware/require-methods.js +97 -0
- package/lib/vendor/blamejs/lib/middleware/require-mtls.js +212 -0
- package/lib/vendor/blamejs/lib/middleware/require-step-up.js +226 -0
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +375 -0
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +285 -0
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +170 -0
- package/lib/vendor/blamejs/lib/middleware/span-http-server.js +280 -0
- package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +323 -0
- package/lib/vendor/blamejs/lib/middleware/sse.js +200 -0
- package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/trace-propagate.js +148 -0
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +749 -0
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +164 -0
- package/lib/vendor/blamejs/lib/migration-files.js +37 -0
- package/lib/vendor/blamejs/lib/migrations.js +385 -0
- package/lib/vendor/blamejs/lib/mime-parse.js +198 -0
- package/lib/vendor/blamejs/lib/money.js +699 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +572 -0
- package/lib/vendor/blamejs/lib/mtls-engine-default.js +501 -0
- package/lib/vendor/blamejs/lib/network-byte-quota.js +308 -0
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +533 -0
- package/lib/vendor/blamejs/lib/network-dns.js +1930 -0
- package/lib/vendor/blamejs/lib/network-heartbeat.js +425 -0
- package/lib/vendor/blamejs/lib/network-nts.js +574 -0
- package/lib/vendor/blamejs/lib/network-proxy.js +265 -0
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +836 -0
- package/lib/vendor/blamejs/lib/network-tls.js +3126 -0
- package/lib/vendor/blamejs/lib/network.js +346 -0
- package/lib/vendor/blamejs/lib/nis2-report.js +181 -0
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +293 -0
- package/lib/vendor/blamejs/lib/nonce-store.js +177 -0
- package/lib/vendor/blamejs/lib/notify.js +683 -0
- package/lib/vendor/blamejs/lib/ntp-check.js +458 -0
- package/lib/vendor/blamejs/lib/numeric-bounds.js +111 -0
- package/lib/vendor/blamejs/lib/numeric-checks.js +40 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +349 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +488 -0
- package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +351 -0
- package/lib/vendor/blamejs/lib/object-store/gcs.js +515 -0
- package/lib/vendor/blamejs/lib/object-store/http-put.js +153 -0
- package/lib/vendor/blamejs/lib/object-store/http-request.js +38 -0
- package/lib/vendor/blamejs/lib/object-store/index.js +197 -0
- package/lib/vendor/blamejs/lib/object-store/local.js +163 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +1133 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +957 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +420 -0
- package/lib/vendor/blamejs/lib/observability-tracer.js +395 -0
- package/lib/vendor/blamejs/lib/observability.js +720 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +248 -0
- package/lib/vendor/blamejs/lib/openapi-schema-walk.js +192 -0
- package/lib/vendor/blamejs/lib/openapi-security.js +169 -0
- package/lib/vendor/blamejs/lib/openapi-yaml.js +154 -0
- package/lib/vendor/blamejs/lib/openapi.js +489 -0
- package/lib/vendor/blamejs/lib/otel-export.js +278 -0
- package/lib/vendor/blamejs/lib/outbox.js +547 -0
- package/lib/vendor/blamejs/lib/pagination.js +542 -0
- package/lib/vendor/blamejs/lib/parsers/index.js +91 -0
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +642 -0
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +293 -0
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +784 -0
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +390 -0
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +1015 -0
- package/lib/vendor/blamejs/lib/permissions.js +793 -0
- package/lib/vendor/blamejs/lib/pick.js +105 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +351 -0
- package/lib/vendor/blamejs/lib/pqc-gate.js +279 -0
- package/lib/vendor/blamejs/lib/pqc-software.js +271 -0
- package/lib/vendor/blamejs/lib/problem-details.js +482 -0
- package/lib/vendor/blamejs/lib/process-spawn.js +196 -0
- package/lib/vendor/blamejs/lib/promise-pool.js +162 -0
- package/lib/vendor/blamejs/lib/protobuf-encoder.js +190 -0
- package/lib/vendor/blamejs/lib/protocol-dispatcher.js +161 -0
- package/lib/vendor/blamejs/lib/public-suffix.js +403 -0
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +154 -0
- package/lib/vendor/blamejs/lib/pubsub-redis.js +167 -0
- package/lib/vendor/blamejs/lib/pubsub.js +463 -0
- package/lib/vendor/blamejs/lib/queue-local.js +476 -0
- package/lib/vendor/blamejs/lib/queue-redis.js +745 -0
- package/lib/vendor/blamejs/lib/queue-sqs.js +319 -0
- package/lib/vendor/blamejs/lib/queue.js +1016 -0
- package/lib/vendor/blamejs/lib/redact.js +1007 -0
- package/lib/vendor/blamejs/lib/redis-client.js +520 -0
- package/lib/vendor/blamejs/lib/render.js +285 -0
- package/lib/vendor/blamejs/lib/request-helpers.js +767 -0
- package/lib/vendor/blamejs/lib/resource-access-lock.js +116 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +340 -0
- package/lib/vendor/blamejs/lib/restore-rollback.js +365 -0
- package/lib/vendor/blamejs/lib/restore.js +409 -0
- package/lib/vendor/blamejs/lib/retention.js +640 -0
- package/lib/vendor/blamejs/lib/retry.js +523 -0
- package/lib/vendor/blamejs/lib/router.js +1289 -0
- package/lib/vendor/blamejs/lib/safe-async.js +1184 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +562 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +297 -0
- package/lib/vendor/blamejs/lib/safe-dns.js +665 -0
- package/lib/vendor/blamejs/lib/safe-ical.js +634 -0
- package/lib/vendor/blamejs/lib/safe-icap.js +502 -0
- package/lib/vendor/blamejs/lib/safe-json.js +946 -0
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +285 -0
- package/lib/vendor/blamejs/lib/safe-mime.js +831 -0
- package/lib/vendor/blamejs/lib/safe-mount-info.js +306 -0
- package/lib/vendor/blamejs/lib/safe-path.js +254 -0
- package/lib/vendor/blamejs/lib/safe-redirect.js +106 -0
- package/lib/vendor/blamejs/lib/safe-schema.js +1810 -0
- package/lib/vendor/blamejs/lib/safe-sieve.js +684 -0
- package/lib/vendor/blamejs/lib/safe-smtp.js +185 -0
- package/lib/vendor/blamejs/lib/safe-sql.js +363 -0
- package/lib/vendor/blamejs/lib/safe-url.js +428 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +473 -0
- package/lib/vendor/blamejs/lib/sandbox-worker.js +135 -0
- package/lib/vendor/blamejs/lib/sandbox.js +358 -0
- package/lib/vendor/blamejs/lib/scheduler.js +827 -0
- package/lib/vendor/blamejs/lib/sd-notify.js +269 -0
- package/lib/vendor/blamejs/lib/sec-cyber.js +214 -0
- package/lib/vendor/blamejs/lib/security-assert.js +395 -0
- package/lib/vendor/blamejs/lib/seeders.js +620 -0
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +309 -0
- package/lib/vendor/blamejs/lib/self-update.js +804 -0
- package/lib/vendor/blamejs/lib/server-timing.js +174 -0
- package/lib/vendor/blamejs/lib/session-device-binding.js +431 -0
- package/lib/vendor/blamejs/lib/session-stores.js +138 -0
- package/lib/vendor/blamejs/lib/session.js +1162 -0
- package/lib/vendor/blamejs/lib/slug.js +381 -0
- package/lib/vendor/blamejs/lib/sse.js +349 -0
- package/lib/vendor/blamejs/lib/ssrf-guard.js +792 -0
- package/lib/vendor/blamejs/lib/standard-webhooks.js +183 -0
- package/lib/vendor/blamejs/lib/static.js +1249 -0
- package/lib/vendor/blamejs/lib/storage.js +1272 -0
- package/lib/vendor/blamejs/lib/stream-throttle.js +235 -0
- package/lib/vendor/blamejs/lib/structured-fields.js +244 -0
- package/lib/vendor/blamejs/lib/subject.js +667 -0
- package/lib/vendor/blamejs/lib/tcpa-10dlc.js +175 -0
- package/lib/vendor/blamejs/lib/template.js +931 -0
- package/lib/vendor/blamejs/lib/tenant-quota.js +545 -0
- package/lib/vendor/blamejs/lib/test-harness.js +275 -0
- package/lib/vendor/blamejs/lib/testing.js +1185 -0
- package/lib/vendor/blamejs/lib/time.js +578 -0
- package/lib/vendor/blamejs/lib/tls-exporter.js +239 -0
- package/lib/vendor/blamejs/lib/totp.js +318 -0
- package/lib/vendor/blamejs/lib/tracing.js +546 -0
- package/lib/vendor/blamejs/lib/uuid.js +207 -0
- package/lib/vendor/blamejs/lib/validate-opts.js +381 -0
- package/lib/vendor/blamejs/lib/vault/index.js +638 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +311 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-source.js +198 -0
- package/lib/vendor/blamejs/lib/vault/rotate.js +803 -0
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +471 -0
- package/lib/vendor/blamejs/lib/vault/wrap.js +296 -0
- package/lib/vendor/blamejs/lib/vault-aad.js +259 -0
- package/lib/vendor/blamejs/lib/vendor/.vendor-data-pubkey +4 -0
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +161 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.data.js +68 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.pem +33 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.data.js +1325 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.txt +10002 -0
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +9 -0
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +18 -0
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +181 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +16382 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5881 -0
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +328 -0
- package/lib/vendor/blamejs/lib/vendor/vendor-data-pubkey.js +16 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +520 -0
- package/lib/vendor/blamejs/lib/vex.js +630 -0
- package/lib/vendor/blamejs/lib/watcher.js +608 -0
- package/lib/vendor/blamejs/lib/web-push-vapid.js +322 -0
- package/lib/vendor/blamejs/lib/webhook.js +977 -0
- package/lib/vendor/blamejs/lib/websocket-channels.js +327 -0
- package/lib/vendor/blamejs/lib/websocket.js +1561 -0
- package/lib/vendor/blamejs/lib/wiki-concepts.js +338 -0
- package/lib/vendor/blamejs/lib/worker-pool.js +464 -0
- package/lib/vendor/blamejs/lib/ws-client.js +978 -0
- package/lib/vendor/blamejs/lib/xml-c14n.js +506 -0
- package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +164 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +19 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/README.md +88 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/build.sh +26 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/project.yaml +28 -0
- package/lib/vendor/blamejs/package.json +81 -0
- package/lib/vendor/blamejs/release-notes/v0.0.x.json +310 -0
- package/lib/vendor/blamejs/release-notes/v0.1.x.json +1798 -0
- package/lib/vendor/blamejs/release-notes/v0.10.x.json +1288 -0
- package/lib/vendor/blamejs/release-notes/v0.11.x.json +2551 -0
- package/lib/vendor/blamejs/release-notes/v0.12.0.json +64 -0
- package/lib/vendor/blamejs/release-notes/v0.12.1.json +32 -0
- package/lib/vendor/blamejs/release-notes/v0.12.2.json +45 -0
- package/lib/vendor/blamejs/release-notes/v0.2.x.json +706 -0
- package/lib/vendor/blamejs/release-notes/v0.3.x.json +786 -0
- package/lib/vendor/blamejs/release-notes/v0.4.x.json +588 -0
- package/lib/vendor/blamejs/release-notes/v0.5.x.json +390 -0
- package/lib/vendor/blamejs/release-notes/v0.6.x.json +1947 -0
- package/lib/vendor/blamejs/release-notes/v0.7.x.json +3811 -0
- package/lib/vendor/blamejs/release-notes/v0.8.x.json +3318 -0
- package/lib/vendor/blamejs/release-notes/v0.9.x.json +2257 -0
- package/lib/vendor/blamejs/scripts/build-vendored-sbom.js +325 -0
- package/lib/vendor/blamejs/scripts/check-api-snapshot.js +62 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +108 -0
- package/lib/vendor/blamejs/scripts/check-pack-against-gitignore.js +83 -0
- package/lib/vendor/blamejs/scripts/check-services.js +483 -0
- package/lib/vendor/blamejs/scripts/check-vendor-currency.js +349 -0
- package/lib/vendor/blamejs/scripts/consolidate-release-notes.js +216 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +275 -0
- package/lib/vendor/blamejs/scripts/generate-changelog-entry.js +577 -0
- package/lib/vendor/blamejs/scripts/generate-release-signing-key.js +79 -0
- package/lib/vendor/blamejs/scripts/publish-dep-confusion-placeholder.sh +101 -0
- package/lib/vendor/blamejs/scripts/refresh-api-snapshot.js +31 -0
- package/lib/vendor/blamejs/scripts/refresh-vendor-manifest.js +132 -0
- package/lib/vendor/blamejs/scripts/release.js +652 -0
- package/lib/vendor/blamejs/scripts/sha3-digest.js +62 -0
- package/lib/vendor/blamejs/scripts/sign-release-artifact.js +92 -0
- package/lib/vendor/blamejs/scripts/test-integration.js +181 -0
- package/lib/vendor/blamejs/scripts/test-wiki-integration.js +126 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +77 -0
- package/lib/vendor/blamejs/scripts/vendor-data-gen.js +186 -0
- package/lib/vendor/blamejs/scripts/vendor-data-keygen.js +101 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +278 -0
- package/lib/vendor/blamejs/test/00-primitives.js +19075 -0
- package/lib/vendor/blamejs/test/10-state.js +622 -0
- package/lib/vendor/blamejs/test/20-db.js +561 -0
- package/lib/vendor/blamejs/test/30-chain.js +2110 -0
- package/lib/vendor/blamejs/test/40-consumers.js +2453 -0
- package/lib/vendor/blamejs/test/50-integration.js +486 -0
- package/lib/vendor/blamejs/test/_helpers.js +10 -0
- package/lib/vendor/blamejs/test/_smoke-worker.js +69 -0
- package/lib/vendor/blamejs/test/fixtures/exploit-corpus/corpus.json +368 -0
- package/lib/vendor/blamejs/test/fixtures/http-client-stream-payload.txt +2 -0
- package/lib/vendor/blamejs/test/fixtures/worker-pool/echo.js +52 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle-worker.js +24 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle.js +203 -0
- package/lib/vendor/blamejs/test/helpers/_shape-match.js +513 -0
- package/lib/vendor/blamejs/test/helpers/check.js +36 -0
- package/lib/vendor/blamejs/test/helpers/cluster.js +70 -0
- package/lib/vendor/blamejs/test/helpers/db.js +143 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +207 -0
- package/lib/vendor/blamejs/test/helpers/fs-watch.js +101 -0
- package/lib/vendor/blamejs/test/helpers/http.js +14 -0
- package/lib/vendor/blamejs/test/helpers/index.js +93 -0
- package/lib/vendor/blamejs/test/helpers/json-round-trip.js +120 -0
- package/lib/vendor/blamejs/test/helpers/mocks.js +20 -0
- package/lib/vendor/blamejs/test/helpers/otel.js +13 -0
- package/lib/vendor/blamejs/test/helpers/services.js +380 -0
- package/lib/vendor/blamejs/test/helpers/wait.js +206 -0
- package/lib/vendor/blamejs/test/integration/cache.test.js +235 -0
- package/lib/vendor/blamejs/test/integration/cluster-provider-mysql.test.js +174 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +611 -0
- package/lib/vendor/blamejs/test/integration/http-client.test.js +129 -0
- package/lib/vendor/blamejs/test/integration/log-stream.test.js +219 -0
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +181 -0
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +152 -0
- package/lib/vendor/blamejs/test/integration/mail-smtp.test.js +161 -0
- package/lib/vendor/blamejs/test/integration/mtls-ca.test.js +289 -0
- package/lib/vendor/blamejs/test/integration/network-dns.test.js +123 -0
- package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +101 -0
- package/lib/vendor/blamejs/test/integration/ntp-check.test.js +89 -0
- package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +403 -0
- package/lib/vendor/blamejs/test/integration/pqc-pkcs8-forward-compat.test.js +271 -0
- package/lib/vendor/blamejs/test/integration/pubsub.test.js +137 -0
- package/lib/vendor/blamejs/test/integration/queue-redis.test.js +352 -0
- package/lib/vendor/blamejs/test/integration/redis-client-tls.test.js +96 -0
- package/lib/vendor/blamejs/test/integration/ssrf-guard.test.js +98 -0
- package/lib/vendor/blamejs/test/integration/websocket-permessage-deflate.test.js +261 -0
- package/lib/vendor/blamejs/test/integration/ws-client-roundtrip.test.js +230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +211 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +219 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-orchestrator.test.js +390 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-posture-chain.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-stream.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-tenant.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-trace.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +44 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-content-detect.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-input.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-model-manifest.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-pref.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +1080 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +311 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-zip-stream.test.js +291 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +267 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +929 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-conflict-path.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-cve-defensive.test.js +176 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-export-cadf.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-segregation.test.js +115 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-ml-dsa-65.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge-verifier.test.js +485 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +331 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +572 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password-audit.test.js +61 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +258 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-worker.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +131 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-smuggling.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/boot-gates.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +861 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/budr.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bundler-engine.test.js +209 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache-status.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +871 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/canonical-json-jcs.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cdn-cache-control.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-audit-verify-chain.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-backup.test.js +135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-config-drift.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-file-type.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-helpers.test.js +145 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-mtls.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-password.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-restore.test.js +160 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-retention.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-security.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-vault.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/client-hints.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +237 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-cascade.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +712 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config-drift.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +31 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-envelope.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +193 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke-pq.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-mlkem768-x25519.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-namespace-hash.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-random-int.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +210 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection-extensions.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-init-extensions.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-extensions.test.js +191 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-role-for.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-vacuum.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +184 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-row-policy.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-view.test.js +303 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-dnssec-algorithm.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-null-mx.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dr-runbook.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr-state-rules.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +786 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/early-hints.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/events.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/exploit-replay.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-routing.test.js +531 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fapi2.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +156 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fdx.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +434 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +432 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-type.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +887 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forensic-snapshot.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fsm.test.js +375 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +321 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-agent-registry.test.js +87 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-all.test.js +328 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +694 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-dsn.test.js +296 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +234 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-envelope.test.js +192 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-payload.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-topic.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +386 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +859 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +92 -0
- 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 +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +317 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-id.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-unsubscribe.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-compose.test.js +111 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-move.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-query.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-reply.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-sieve.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +301 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +265 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-message-id.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +161 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-posture-chain.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-saga-config.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-smtp-command.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-snapshot-envelope.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-stream-args.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +288 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-tenant-id.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-trace-context.test.js +102 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/hal.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +692 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +225 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +991 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-mspa.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-tcf.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +612 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +166 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jose-jwe-experimental.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-api.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-round-trip-helper.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +159 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/local-db-thin.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-cloudwatch.test.js +489 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp-grpc.test.js +207 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/lro.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +417 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +208 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +910 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +502 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +680 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-canspam.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +297 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +514 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +627 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-feedback-id.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-mdn.test.js +334 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-rbl.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-require-tls.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +336 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +732 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +840 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +285 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +229 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +394 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-spam-score.test.js +204 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-srs.test.js +152 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-unsubscribe.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +439 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-tool-registry.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-shadow-registry.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +224 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-compose-pipeline.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-paths.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nel.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +372 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +635 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-heartbeat-passive.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-build-options.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-ct-inclusion.test.js +179 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +447 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nist-crosswalk.test.js +42 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/no-cache.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/notify.test.js +707 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/numeric-bounds.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +877 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pagination.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +324 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +546 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-software.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +195 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/process-spawn.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/promise-pool.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protected-resource-metadata.test.js +68 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protobuf-encoder.test.js +138 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protocol-dispatcher.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/public-suffix.test.js +197 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +232 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-dlq-extend-lease.test.js +178 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-priority-rate-progress.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +300 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +338 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-registry.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +335 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-log.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-auth-cache-control.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/resource-access-lock.test.js +52 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retry.test.js +535 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-cross-origin-redirect.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-parallel.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +248 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +451 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +289 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-icap.test.js +206 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mount-info.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sieve.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-smtp.test.js +95 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-idn-homograph.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-slo.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +238 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +700 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-notify.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sec-cyber.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/seeders.test.js +816 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update-standalone-verifier.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/server-timing.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +247 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/shape-match.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +952 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/slug.test.js +330 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +233 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/source-comment-blocks.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/speculation-rules.test.js +319 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sse.test.js +148 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/standard-webhooks.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +487 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-chunk-scratch.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +773 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/stream-throttle.test.js +173 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tcpa-10dlc.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +571 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-harness.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +119 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-ct.test.js +275 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-verify.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-pinset-drift.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-preferred-groups.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tracing.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/uuid.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-aad.test.js +277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-seal-pem-file.test.js +252 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-data.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-manifest.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vex.test.js +661 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +308 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/web-push-vapid.test.js +144 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +674 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +360 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +349 -0
- package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +717 -0
- package/lib/vendor/blamejs/test/layer-5-integration/bundler-output.test.js +444 -0
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-5-integration/security-chaos.test.js +308 -0
- package/lib/vendor/blamejs/test/smoke.js +431 -0
- package/lib/webhooks.js +305 -0
- package/package.json +43 -0
|
@@ -0,0 +1,1671 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module b.audit
|
|
4
|
+
* @featured true
|
|
5
|
+
* @nav Observability
|
|
6
|
+
* @title Audit
|
|
7
|
+
*
|
|
8
|
+
* @intro
|
|
9
|
+
* Tamper-evident, append-only record of every privileged action — the
|
|
10
|
+
* forensic surface every compliance posture (HIPAA / PCI-DSS / SOC 2 /
|
|
11
|
+
* GDPR / SOX / DORA) bottoms out on. The `audit_log` table is baked
|
|
12
|
+
* into db.js's schema runner so apps cannot opt out; the chain is
|
|
13
|
+
* verified at boot and a break refuses-to-boot.
|
|
14
|
+
*
|
|
15
|
+
* Hash chain: every row carries `prevHash` + `rowHash` computed over
|
|
16
|
+
* the SEALED form of the row plus a nonce. Verification recomputes
|
|
17
|
+
* directly from disk without unsealing — auditors can confirm
|
|
18
|
+
* integrity without holding the vault key. Periodic SLH-DSA-SHAKE-256f
|
|
19
|
+
* checkpoints (post-quantum signatures over the chain tip) anchor the
|
|
20
|
+
* chain to off-line evidence; tampering that recomputes hashes still
|
|
21
|
+
* fails checkpoint verification.
|
|
22
|
+
*
|
|
23
|
+
* Namespaces: framework owns `auth.*` / `system.*` / `audit.*` /
|
|
24
|
+
* `consent.*` / `subject.*`; apps call `registerNamespace("orders")`
|
|
25
|
+
* at boot before emitting `orders.created`. Unregistered namespaces
|
|
26
|
+
* are rejected so typos don't become silent unobservable events.
|
|
27
|
+
*
|
|
28
|
+
* Action shape — the 5W form: WHO (`actor.userId` / sessionId / ip /
|
|
29
|
+
* userAgent), WHAT (`action` = "namespace.verb[.qualifier]"), WHEN
|
|
30
|
+
* (`recordedAt` ms epoch + monotonic counter), WHERE (`resource.kind`
|
|
31
|
+
* / id), HOW (`outcome` ∈ {success, failure, denied} + `reason` +
|
|
32
|
+
* `metadata`).
|
|
33
|
+
*
|
|
34
|
+
* Two emit paths:
|
|
35
|
+
* - `record(event)` — async, throws on bad input, awaits the chain
|
|
36
|
+
* append. Use when the caller needs durability before continuing.
|
|
37
|
+
* - `emit(event)` / `safeEmit(event)` — synchronous fire-and-forget;
|
|
38
|
+
* events buffer in an AsyncHandler and drain serially through
|
|
39
|
+
* record(). `safeEmit` is drop-silent on malformed input by
|
|
40
|
+
* design: it runs in request hot paths where throwing would crash
|
|
41
|
+
* the request that triggered the audit attempt.
|
|
42
|
+
*
|
|
43
|
+
* Reserved metadata keys: `traceId` (cross-request correlation,
|
|
44
|
+
* `beginTrace()` mints), `parentEventId`, `before` / `after` (state
|
|
45
|
+
* diff for change events), `evidenceRef` (pointer to signed PDF /
|
|
46
|
+
* ticket).
|
|
47
|
+
*
|
|
48
|
+
* @card
|
|
49
|
+
* Tamper-evident, append-only record of every privileged action — the forensic surface every compliance posture (HIPAA / PCI-DSS / SOC 2 / GDPR / SOX / DORA) bottoms out on.
|
|
50
|
+
*/
|
|
51
|
+
var auditChain = require("./audit-chain");
|
|
52
|
+
var auditSign = require("./audit-sign");
|
|
53
|
+
var chainWriter = require("./chain-writer");
|
|
54
|
+
var cluster = require("./cluster");
|
|
55
|
+
var clusterStorage = require("./cluster-storage");
|
|
56
|
+
var { generateToken } = require("./crypto");
|
|
57
|
+
var cryptoField = require("./crypto-field");
|
|
58
|
+
var safeSql = require("./safe-sql");
|
|
59
|
+
var dbRoleContext = require("./db-role-context");
|
|
60
|
+
var handlers = require("./handlers");
|
|
61
|
+
var { boot } = require("./log");
|
|
62
|
+
var redact = require("./redact");
|
|
63
|
+
var safeAsync = require("./safe-async");
|
|
64
|
+
var C = require("./constants");
|
|
65
|
+
var lazyRequire = require("./lazy-require");
|
|
66
|
+
var observability = require("./observability");
|
|
67
|
+
var { AuditSegregationError, ClusterError } = require("./framework-error");
|
|
68
|
+
|
|
69
|
+
var log = boot("audit");
|
|
70
|
+
|
|
71
|
+
// External shadow-store callbacks are bounded by the same hot-path
|
|
72
|
+
// timeout the framework's own SQL paths use. A stalled operator
|
|
73
|
+
// network call that neither resolves nor rejects MUST NOT block the
|
|
74
|
+
// audit critical path — b.audit.record() must return, emit/safeEmit
|
|
75
|
+
// drains must not stall behind it. On timeout the shadow record is
|
|
76
|
+
// dropped (audit.shadow_timeout observability event) and the
|
|
77
|
+
// framework chain row remains committed — audit emission MUST NOT
|
|
78
|
+
// crash or stall the request that triggered it.
|
|
79
|
+
var EXTERNAL_STORE_TIMEOUT_MS = C.TIME.seconds(30);
|
|
80
|
+
|
|
81
|
+
// External shadow store registered via `b.audit.useStore({ record })`.
|
|
82
|
+
// When set, every successful framework chain.append also fires
|
|
83
|
+
// `_externalStore.record(rowResult)` so operators can replicate audit
|
|
84
|
+
// records to an immutable external destination (AWS QLDB, Azure
|
|
85
|
+
// Confidential Ledger, Google Cloud Audit Logs, an in-house WORM
|
|
86
|
+
// appliance, a SIEM, etc.) WITHOUT giving up the framework's tamper-
|
|
87
|
+
// evident chain integrity. The framework's chain remains authoritative;
|
|
88
|
+
// the operator's record receives the fully-formed row (logical fields +
|
|
89
|
+
// `_id` + `recordedAt` + `monotonicCounter` + `prevHash` + `rowHash`).
|
|
90
|
+
//
|
|
91
|
+
// Shadow failures are drop-silent — hot-path observability sinks
|
|
92
|
+
// must not crash the path that emitted them. An audit-shadow
|
|
93
|
+
// failure surfaces via `b.observability` as `audit.shadow_failed`;
|
|
94
|
+
// the framework chain row still committed and downstream
|
|
95
|
+
// verifyChain still works against the framework store.
|
|
96
|
+
var _externalStore = null;
|
|
97
|
+
|
|
98
|
+
// Per-operation timeout for framework-state SQL. A misbehaving
|
|
99
|
+
// external-db driver hanging on a query shouldn't hang audit forever.
|
|
100
|
+
// 30s is generous for genuinely slow networks while still bounding
|
|
101
|
+
// the worst case.
|
|
102
|
+
var FRAMEWORK_SQL_TIMEOUT_MS = C.TIME.seconds(30);
|
|
103
|
+
|
|
104
|
+
// ---- Resilience-wrapped SQL operations (audit-specific reads) ----
|
|
105
|
+
// Chain APPEND lives in chain-writer (race-safe via mutex, retry, timeout).
|
|
106
|
+
// The wrappers below cover audit-specific reads/writes that aren't part
|
|
107
|
+
// of the chain append: checkpoint queries, verifyCheckpoints reads,
|
|
108
|
+
// audit-tip cluster-row updates.
|
|
109
|
+
|
|
110
|
+
async function _readLastCheckpointCounter() {
|
|
111
|
+
return await safeAsync.withTimeout(
|
|
112
|
+
safeAsync.asyncRetry(function () {
|
|
113
|
+
return clusterStorage.executeOne(
|
|
114
|
+
"SELECT atMonotonicCounter FROM audit_checkpoints " +
|
|
115
|
+
"ORDER BY atMonotonicCounter DESC LIMIT 1"
|
|
116
|
+
);
|
|
117
|
+
}),
|
|
118
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
119
|
+
{ name: "audit.readLastCheckpoint" }
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function _readAllAuditRowsAsc() {
|
|
124
|
+
return await safeAsync.withTimeout(
|
|
125
|
+
safeAsync.asyncRetry(function () {
|
|
126
|
+
return clusterStorage.executeAll(
|
|
127
|
+
'SELECT * FROM "audit_log" ORDER BY monotonicCounter ASC'
|
|
128
|
+
);
|
|
129
|
+
}),
|
|
130
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
131
|
+
{ name: "audit.readAllRowsAsc" }
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function _readAllCheckpointsAsc() {
|
|
136
|
+
return await safeAsync.withTimeout(
|
|
137
|
+
safeAsync.asyncRetry(function () {
|
|
138
|
+
return clusterStorage.executeAll(
|
|
139
|
+
"SELECT * FROM audit_checkpoints ORDER BY atMonotonicCounter ASC"
|
|
140
|
+
);
|
|
141
|
+
}),
|
|
142
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
143
|
+
{ name: "audit.readAllCheckpoints" }
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function _readAuditRowHashAtCounter(counter) {
|
|
148
|
+
return await safeAsync.withTimeout(
|
|
149
|
+
safeAsync.asyncRetry(function () {
|
|
150
|
+
return clusterStorage.executeOne(
|
|
151
|
+
"SELECT rowHash FROM audit_log WHERE monotonicCounter = ?",
|
|
152
|
+
[counter]
|
|
153
|
+
);
|
|
154
|
+
}),
|
|
155
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
156
|
+
{ name: "audit.readRowHashAtCounter" }
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function _insertAuditRow(allCols, values) {
|
|
161
|
+
// No retry — non-idempotent. Timeout only.
|
|
162
|
+
var placeholders = allCols.map(function () { return "?"; }).join(", ");
|
|
163
|
+
var quoted = allCols.map(function (c) { return '"' + c + '"'; }).join(", ");
|
|
164
|
+
return await safeAsync.withTimeout(
|
|
165
|
+
clusterStorage.execute(
|
|
166
|
+
"INSERT INTO audit_log (" + quoted + ") VALUES (" + placeholders + ")",
|
|
167
|
+
values
|
|
168
|
+
),
|
|
169
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
170
|
+
{ name: "audit.insertRow" }
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function _insertCheckpoint(values) {
|
|
175
|
+
return await safeAsync.withTimeout(
|
|
176
|
+
clusterStorage.execute(
|
|
177
|
+
"INSERT INTO audit_checkpoints (_id, createdAt, atMonotonicCounter, atRowHash, signature, publicKeyFingerprint, fencingToken) " +
|
|
178
|
+
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
179
|
+
values
|
|
180
|
+
),
|
|
181
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
182
|
+
{ name: "audit.insertCheckpoint" }
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function _upsertAuditTip(counter, rowHash, signedAt, fencingToken) {
|
|
187
|
+
// Cluster-mode only. Single atomic INSERT … ON CONFLICT … DO UPDATE
|
|
188
|
+
// … WHERE … RETURNING. The WHERE clause is the canonical
|
|
189
|
+
// fencing-token guard from blamejs-cluster-spec.md — it enforces
|
|
190
|
+
// monotonic-non-decreasing fencingToken at the database level so a
|
|
191
|
+
// partitioned old leader cannot overwrite the tip even if its
|
|
192
|
+
// application-layer cluster.requireLeader() gate somehow allowed
|
|
193
|
+
// the call through.
|
|
194
|
+
//
|
|
195
|
+
// Update accepted iff the row's stored fencingToken <= incoming one
|
|
196
|
+
// (same-token re-write is fine; a strictly-lower token is fenced
|
|
197
|
+
// out). On rejection RETURNING produces 0 rows — we surface that
|
|
198
|
+
// as ClusterError(code='FENCED_OUT', permanent=true) so the
|
|
199
|
+
// dispatching node knows it's been superseded and should step down
|
|
200
|
+
// rather than retry.
|
|
201
|
+
var result = await safeAsync.withTimeout(
|
|
202
|
+
clusterStorage.execute(
|
|
203
|
+
"INSERT INTO _blamejs_audit_tip " +
|
|
204
|
+
" (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
|
|
205
|
+
"VALUES ('audit', ?, ?, ?, ?) " +
|
|
206
|
+
"ON CONFLICT (scope) DO UPDATE SET " +
|
|
207
|
+
" atMonotonicCounter = EXCLUDED.atMonotonicCounter, " +
|
|
208
|
+
" rowHash = EXCLUDED.rowHash, " +
|
|
209
|
+
" signedAt = EXCLUDED.signedAt, " +
|
|
210
|
+
" fencingToken = EXCLUDED.fencingToken " +
|
|
211
|
+
"WHERE _blamejs_audit_tip.fencingToken <= EXCLUDED.fencingToken " +
|
|
212
|
+
"RETURNING fencingToken",
|
|
213
|
+
[counter, rowHash, signedAt, fencingToken]
|
|
214
|
+
),
|
|
215
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
216
|
+
{ name: "audit.upsertAuditTip" }
|
|
217
|
+
);
|
|
218
|
+
if (!result.rows || result.rows.length === 0) {
|
|
219
|
+
throw new ClusterError(
|
|
220
|
+
"FENCED_OUT",
|
|
221
|
+
"audit-tip update rejected: incoming fencingToken=" + fencingToken +
|
|
222
|
+
" is below the stored token (this leader has been fenced out " +
|
|
223
|
+
"by a higher-token successor)",
|
|
224
|
+
true
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Every namespace any framework primitive emits on must be listed here.
|
|
230
|
+
// A primitive that adds a new namespace adds it here in the same patch.
|
|
231
|
+
// Smoke walks lib/ at boot-time-equivalent (layer-0-primitives/audit-framework-namespaces.test.js)
|
|
232
|
+
// and fails if any emitted namespace is missing from this list.
|
|
233
|
+
//
|
|
234
|
+
// Why this list and not auto-registration via registerNamespace() at
|
|
235
|
+
// each primitive's create(): namespace registration must be effective
|
|
236
|
+
// the first time ANY primitive emits, regardless of which primitive
|
|
237
|
+
// the operator initialized first. Operators wiring just b.scheduler
|
|
238
|
+
// without ever calling b.apiKey.create() still trip the apikey verify
|
|
239
|
+
// path (e.g. through middleware they didn't write); the action-name
|
|
240
|
+
// validation needs to know about apikey at boot, not at first call.
|
|
241
|
+
var FRAMEWORK_NAMESPACES = [
|
|
242
|
+
// Generic buckets
|
|
243
|
+
"auth", "system", "audit", "consent", "subject",
|
|
244
|
+
// Per-primitive namespaces — keep alphabetical
|
|
245
|
+
"apikey", // b.apiKey
|
|
246
|
+
"backup", // b.backup
|
|
247
|
+
"breakglass", // b.breakGlass — column-policy / row-enforcement step-up auth (audit namespace lowercased per the validator's `namespace.verb` rule, same convention as b.apiKey → apikey.*)
|
|
248
|
+
"cache", // b.cache
|
|
249
|
+
"compliance", // b.compliance (compliance.posture.set / cleared)
|
|
250
|
+
"config", // b.configDrift (config.baseline.captured / config.drift.detected / config.baseline.tamper / config.baseline.unreadable)
|
|
251
|
+
"csrf", // b.middleware.csrfProtect (csrf.bad_cookie_value)
|
|
252
|
+
// (system.crypto.hybrid_disabled rides under "system" so no separate namespace)
|
|
253
|
+
"db", // b.db / b.middleware.dbRoleFor / b.externalDb.runAs
|
|
254
|
+
// (role-switching, RLS-shaped events)
|
|
255
|
+
"dkim", // b.mail.dkim (DKIM-Signature generation events)
|
|
256
|
+
"dora", // b.dora (DORA Article 17: dora.incident.classified / reported / draftFinal)
|
|
257
|
+
"dsr", // b.dsr (Data Subject Rights workflow: dsr.ticket.* / dsr.source.*)
|
|
258
|
+
"dual", // b.dualControl (dual.grant.requested / approved / denied / consumed / expired / self_approval_denied)
|
|
259
|
+
"mail", // b.mail (b.mail-bounce uses "system.mail.*")
|
|
260
|
+
"mtls", // b.mtlsCa engine algorithm-selection audit (mtls.engine.algorithm_selected)
|
|
261
|
+
"network", // b.middleware.networkAllowlist (network.gate.denied)
|
|
262
|
+
"notify", // b.notify
|
|
263
|
+
"objectstore", // b.objectStore.bucketOps (objectstore.bucket.* / objectstore.object.*)
|
|
264
|
+
"openapi", // b.openapi (openapi.document.built / openapi.document.served)
|
|
265
|
+
"asyncapi", // b.asyncapi (asyncapi.document.built)
|
|
266
|
+
"vault", // b.vault.aad (vault.aad.sealed / vault.aad.unseal_failed)
|
|
267
|
+
"wsclient", // b.wsClient (wsclient.connected / closed / error)
|
|
268
|
+
"inbox", // b.inbox (inbox.received / handled / handle_failed / swept)
|
|
269
|
+
"flag", // b.flag (flag.evaluated / flag.evaluation.error / flag.cache.bust)
|
|
270
|
+
"permissions", // b.permissions
|
|
271
|
+
"pqcagent", // b.pqcAgent (pqcagent.operator_group.accepted)
|
|
272
|
+
"restore", // b.restore
|
|
273
|
+
"retention", // b.retention (retention.rule.declared / sweep.started / row.processed / sweep.completed / sweep.failed)
|
|
274
|
+
"scheduler", // b.scheduler (lifecycle: scheduler.start / scheduler.stop;
|
|
275
|
+
// tick/task events use "system.scheduler.*")
|
|
276
|
+
"seeders", // b.seeders
|
|
277
|
+
"webhook", // b.webhook
|
|
278
|
+
"sse", // b.sse (sse.channel_opened / closed / injection_refused)
|
|
279
|
+
"mcp", // b.mcp.serverGuard (mcp.auth.* / mcp.tool.* / mcp.resource.* / mcp.register.* / mcp.envelope.*)
|
|
280
|
+
"graphqlfederation", // b.graphqlFederation.guardSdl (sdl-refused / sdl-allowed)
|
|
281
|
+
"aiinput", // b.ai.input.classify (aiInput.classify)
|
|
282
|
+
"a2a", // b.a2a (a2a.card_signed / verified / rejected)
|
|
283
|
+
"darkpatterns", // b.darkPatterns (darkPatterns.attest / cancel-blocked)
|
|
284
|
+
"budr", // b.budr (budr.declared)
|
|
285
|
+
"seccyber", // b.secCyber (seccyber.eight_k_artifact)
|
|
286
|
+
"iabtcf", // b.iabTcf (iabtcf.refused / iabtcf.accepted)
|
|
287
|
+
"fapi2", // b.fapi2 (fapi2.posture_asserted)
|
|
288
|
+
"contentcredentials", // b.contentCredentials (contentcredentials.signed / verified)
|
|
289
|
+
"aipref", // b.aiPref (aipref.paid_crawl_refused)
|
|
290
|
+
"fdx", // b.fdx (fdx.bound / fdx.consent_receipt_issued)
|
|
291
|
+
"tcpa10dlc", // b.tcpa10dlc (tcpa10dlc.consent_recorded / consent_revoked)
|
|
292
|
+
"iabmspa", // b.iabMspa (iabmspa.processing_refused)
|
|
293
|
+
"vendor", // b.configDrift.verifyVendorIntegrity (vendor.integrity.verified / tampered)
|
|
294
|
+
"honeytoken", // b.honeytoken (honeytoken.issued / tripped)
|
|
295
|
+
"csp", // b.middleware.cspReport (csp.violation)
|
|
296
|
+
"resourceaccesslock", // b.resourceAccessLock (resourceaccesslock.mode_changed / refused)
|
|
297
|
+
"process", // b.processSpawn (process.spawn / process.spawn.failed)
|
|
298
|
+
"keychain", // b.keychain (keychain.stored / keychain.retrieved / keychain.removed)
|
|
299
|
+
"fda21cfr11", // b.fda21cfr11 (signature.created / verified / gxp.assert_failed / audit.refused / posture.installed)
|
|
300
|
+
"ddl", // b.ddlChangeControl (ddl.change.proposed / approved / rejected / applied / apply_refused)
|
|
301
|
+
"migrations", // b.migrations + b.externalDb.migrate (migrations.history.appended / verified / tampered)
|
|
302
|
+
"dlp", // b.redact.installOutboundDlp (dlp.outbound.refused / redacted / scanned / installed)
|
|
303
|
+
"session", // b.sessionDeviceBinding (session.device.bound / drift / refused)
|
|
304
|
+
"sandbox", // b.sandbox (sandbox.run / sandbox.run.refused — operator-supplied transform isolation)
|
|
305
|
+
"safeurl", // b.safeUrl.parse (safeurl.idn_homograph.refused — UTS #39 mixed-script host-label refusal)
|
|
306
|
+
"http", // b.middleware.bodyParser (http.chunked.malformed.refused — RFC 9112 §7.1 chunked-decode failure with Connection: close) // allow:raw-byte-literal — RFC number in prose
|
|
307
|
+
"cryptofield", // b.cryptoField.eraseRow (cryptofield.vacuum.skipped — F-RTBF-2 vacuum-after-erase signal when DB not initialized at erase time)
|
|
308
|
+
"acme", // b.acme (acme.account.registered / order.* / cert.issued / cert.renewed / cert.renew.skipped — RFC 8555 + RFC 9773 ARI workflow)
|
|
309
|
+
"cert", // b.cert (cert.account.generated / cert.issued / cert.renewed / cert.renew-failed / cert.challenge-cleanup — turnkey cert-manager lifecycle)
|
|
310
|
+
"tls", // b.router 0-RTT posture (tls.0rtt.refused / tls.0rtt.replayed) — RFC 8446 §8 anti-replay surface // allow:raw-byte-literal — RFC number in prose
|
|
311
|
+
"workerpool", // b.workerPool (workerpool.created / terminated / task.completed / task.failed / task.timeout / spawn.failed — generic worker_threads pool)
|
|
312
|
+
"jwt", // b.auth.jwt-external (jwt.jwe.refused — RFC 7516 5-segment JWE refusal)
|
|
313
|
+
"dr", // b.drRunbook (dr.runbook.emitted)
|
|
314
|
+
"guardfilename", // b.guardFilename (guardfilename.sanitize.stripped)
|
|
315
|
+
"legalhold", // b.legalHold (legalhold.placed / released / place_rejected / release_rejected)
|
|
316
|
+
"networkheartbeat", // b.network.heartbeat.passive (networkheartbeat.passive.timeout)
|
|
317
|
+
"router", // b.router (router.redirect.cross_origin.refused / allowed)
|
|
318
|
+
"http2", // b.router h2 GOAWAY tracker (http2.window_update.refused — CVE-2026-21714)
|
|
319
|
+
"tenant", // b.tenantQuota (tenant.quota.exceeded / tenant.budget.exceeded / tenant.crossover)
|
|
320
|
+
"httpclient", // b.httpClient.cache (httpclient.cache.hit / .miss / .stale / .revalidated / .evicted — RFC 9111 outbound HTTP cache)
|
|
321
|
+
"mailmdn", // b.mailMdn (mailmdn.generated / mailmdn.suppressed — RFC 3798/8098 Message Disposition Notification)
|
|
322
|
+
"mailarf", // b.mailArf (mailarf.parsed / mailarf.malformed — RFC 5965 abuse-feedback ingestion)
|
|
323
|
+
"mailbimi", // b.mail.bimi (mail.bimi.vmc.fetched / verified — RFC 9091 VMC chain validation)
|
|
324
|
+
"localdb", // b.localDb.thin (localdb.thin.opened / recovered / closed — desktop-daemon SQLite wrapper)
|
|
325
|
+
"dataact", // b.dataAct (EU Data Act 2023/2854 — product_declared / user_access / share_with_third_party / share_refused / switch_request)
|
|
326
|
+
"idempotency", // b.middleware.idempotencyKey (idempotency.missing_key / bad_key / replay / key_reuse_mismatch / cache_store / store_read_failed / store_write_failed / skip_5xx / body_too_large — draft-ietf-httpapi-idempotency-key)
|
|
327
|
+
"aibom", // b.ai.modelManifest (aibom.signed / aibom.verified — CycloneDX 1.6 ML-BOM)
|
|
328
|
+
"aicontentdetect", // b.ai.aiContentDetect (aicontentdetect.report — AB-853 / EU AI Act Art. 50 inbound provenance)
|
|
329
|
+
"sdnotify", // b.sdNotify (sdnotify.send / sdnotify.send.skipped — systemd Type=notify)
|
|
330
|
+
"bootgates", // b.bootGates (bootgates.passed / bootgates.failed / bootgates.onfail_threw — boot-invariant runner)
|
|
331
|
+
"metrics", // b.metrics.snapshot.shadowRegistry (metrics.shadow.cardinality_dropped — namespaced metrics export)
|
|
332
|
+
"jose", // b.jose.jwe.experimental (jose.jwe.experimental.encrypt / .decrypt — ML-KEM-JWE pre-IANA)
|
|
333
|
+
];
|
|
334
|
+
var registeredNamespaces = new Set(FRAMEWORK_NAMESPACES);
|
|
335
|
+
|
|
336
|
+
// All hashable columns of audit_log (everything in the table except the chain
|
|
337
|
+
// bookkeeping itself). This list MUST match what's actually written by INSERT
|
|
338
|
+
// and what's read back by verify; the canonicalizer needs the same key set
|
|
339
|
+
// at both ends or the hash will mismatch on missing-vs-null keys.
|
|
340
|
+
var HASHABLE_COLS = [
|
|
341
|
+
"_id", "recordedAt", "monotonicCounter",
|
|
342
|
+
"actorUserId", "actorUserIdHash",
|
|
343
|
+
"actorIp",
|
|
344
|
+
"actorUserAgent", "actorSessionId",
|
|
345
|
+
"action", "resourceKind",
|
|
346
|
+
"resourceId", "resourceIdHash",
|
|
347
|
+
"outcome", "reason", "metadata", "requestId",
|
|
348
|
+
];
|
|
349
|
+
|
|
350
|
+
// Lazy db ref — avoids circular require (db -> audit -> db on init paths).
|
|
351
|
+
var db = lazyRequire(function () { return require("./db"); });
|
|
352
|
+
|
|
353
|
+
// Chain-writer instance owns the race-safe chain append: counter primer,
|
|
354
|
+
// chain mutex, prev-tip read, hash compute, INSERT. Per the framework
|
|
355
|
+
// rule that repeated tasks become primitives, the audit_log and
|
|
356
|
+
// consent_log chains both consume chain-writer.
|
|
357
|
+
var _chainWriter = chainWriter.create({
|
|
358
|
+
table: "audit_log",
|
|
359
|
+
hashableColumns: HASHABLE_COLS,
|
|
360
|
+
columnsForInsert: [
|
|
361
|
+
"_id", "recordedAt", "monotonicCounter",
|
|
362
|
+
"actorUserId", "actorUserIdHash",
|
|
363
|
+
"actorIp",
|
|
364
|
+
"actorUserAgent", "actorSessionId",
|
|
365
|
+
"action", "resourceKind",
|
|
366
|
+
"resourceId", "resourceIdHash",
|
|
367
|
+
"outcome", "reason", "metadata", "requestId",
|
|
368
|
+
"prevHash", "rowHash", "nonce", "fencingToken",
|
|
369
|
+
],
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// ---- Public API ----
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @primitive b.audit.registerNamespace
|
|
376
|
+
* @signature b.audit.registerNamespace(name)
|
|
377
|
+
* @since 0.1.0
|
|
378
|
+
* @related b.audit.record, b.audit.safeEmit
|
|
379
|
+
*
|
|
380
|
+
* Register an action namespace at app bootstrap so `record()` / `emit()`
|
|
381
|
+
* accept events under it. Names must match `[a-z][a-z0-9_]*`. Calling
|
|
382
|
+
* twice is a no-op. Framework namespaces (auth / system / audit /
|
|
383
|
+
* consent / subject + every per-primitive namespace) are pre-registered.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* b.audit.registerNamespace("orders");
|
|
387
|
+
* b.audit.safeEmit({
|
|
388
|
+
* action: "orders.shipped",
|
|
389
|
+
* actor: { userId: "u-42" },
|
|
390
|
+
* outcome: "success",
|
|
391
|
+
* });
|
|
392
|
+
*/
|
|
393
|
+
function registerNamespace(name) {
|
|
394
|
+
if (typeof name !== "string" || !/^[a-z][a-z0-9_]*$/.test(name)) {
|
|
395
|
+
throw new Error("audit namespace must match [a-z][a-z0-9_]* — got: " + name);
|
|
396
|
+
}
|
|
397
|
+
if (FRAMEWORK_NAMESPACES.indexOf(name) !== -1) return;
|
|
398
|
+
registeredNamespaces.add(name);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function _validateAction(action) {
|
|
402
|
+
if (typeof action !== "string" || !/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(action)) {
|
|
403
|
+
throw new Error(
|
|
404
|
+
"audit action must be 'namespace.verb[.qualifier...]' (lowercase, dot-separated) — got: " + action
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
var ns = action.split(".")[0];
|
|
408
|
+
if (!registeredNamespaces.has(ns)) {
|
|
409
|
+
throw new Error(
|
|
410
|
+
"audit namespace '" + ns + "' is not registered. " +
|
|
411
|
+
"Call audit.registerNamespace('" + ns + "') at app bootstrap before recording '" + action + "'."
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* @primitive b.audit.record
|
|
418
|
+
* @signature b.audit.record(event)
|
|
419
|
+
* @since 0.1.0
|
|
420
|
+
* @compliance hipaa, pci-dss, gdpr, soc2, sox-404
|
|
421
|
+
* @related b.audit.safeEmit, b.audit.emit, b.audit.flush
|
|
422
|
+
*
|
|
423
|
+
* Append one event to the audit chain and await durability. Throws on a
|
|
424
|
+
* bad action shape, an unregistered namespace, or an outcome outside
|
|
425
|
+
* {success, failure, denied}. The chain-writer serializes the actual
|
|
426
|
+
* INSERT under a mutex so concurrent record() calls produce a strictly
|
|
427
|
+
* monotonic counter and a valid prevHash → rowHash chain.
|
|
428
|
+
*
|
|
429
|
+
* Use record() when the caller must know the row landed before
|
|
430
|
+
* continuing (consent grants, break-glass unseals, change-control
|
|
431
|
+
* approvals). For request hot paths where best-effort is acceptable,
|
|
432
|
+
* prefer safeEmit().
|
|
433
|
+
*
|
|
434
|
+
* @opts
|
|
435
|
+
* actor: { userId, ip, userAgent, sessionId },
|
|
436
|
+
* action: "namespace.verb[.qualifier]",
|
|
437
|
+
* resource: { kind, id },
|
|
438
|
+
* outcome: "success" | "failure" | "denied",
|
|
439
|
+
* reason: string,
|
|
440
|
+
* metadata: object, // serialized to JSON
|
|
441
|
+
* requestId: string,
|
|
442
|
+
*
|
|
443
|
+
* @example
|
|
444
|
+
* await b.audit.record({
|
|
445
|
+
* actor: { userId: "u-42", ip: "10.0.0.1" },
|
|
446
|
+
* action: "consent.granted",
|
|
447
|
+
* resource: { kind: "purpose", id: "marketing" },
|
|
448
|
+
* outcome: "success",
|
|
449
|
+
* metadata: { traceId: b.audit.beginTrace() },
|
|
450
|
+
* });
|
|
451
|
+
*/
|
|
452
|
+
async function record(event) {
|
|
453
|
+
if (!event || typeof event !== "object") {
|
|
454
|
+
throw new Error("audit.record requires an event object");
|
|
455
|
+
}
|
|
456
|
+
_validateAction(event.action);
|
|
457
|
+
if (!event.outcome || ["success", "failure", "denied"].indexOf(event.outcome) === -1) {
|
|
458
|
+
throw new Error("audit.record outcome must be 'success', 'failure', or 'denied'");
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return observability.tap("audit.record",
|
|
462
|
+
{ action: event.action, outcome: event.outcome },
|
|
463
|
+
async function () {
|
|
464
|
+
// Build the audit-specific logical row; chain-writer handles _id /
|
|
465
|
+
// recordedAt / monotonicCounter / sealing / null-fill / hashing /
|
|
466
|
+
// insert / fencing-token / chain mutex / counter primer.
|
|
467
|
+
var actor = event.actor || {};
|
|
468
|
+
var resource = event.resource || {};
|
|
469
|
+
var logical = {
|
|
470
|
+
actorUserId: actor.userId || null,
|
|
471
|
+
actorIp: actor.ip || null,
|
|
472
|
+
actorUserAgent: actor.userAgent || null,
|
|
473
|
+
actorSessionId: actor.sessionId || null,
|
|
474
|
+
action: event.action,
|
|
475
|
+
resourceKind: resource.kind || null,
|
|
476
|
+
resourceId: resource.id || null,
|
|
477
|
+
outcome: event.outcome,
|
|
478
|
+
reason: event.reason || null,
|
|
479
|
+
metadata: event.metadata ? JSON.stringify(event.metadata) : null,
|
|
480
|
+
requestId: event.requestId || null,
|
|
481
|
+
};
|
|
482
|
+
var appended = await _chainWriter.append(logical);
|
|
483
|
+
// Operator-registered shadow store: replicate the fully-formed
|
|
484
|
+
// row to an immutable external destination. Drop-silent on
|
|
485
|
+
// failure — the framework chain is authoritative and already
|
|
486
|
+
// committed; the shadow is a best-effort archival, and an
|
|
487
|
+
// unreachable destination must not crash the audit caller.
|
|
488
|
+
// The operator's record receives the SAME object the framework
|
|
489
|
+
// returns to its caller, so external consumers see identical
|
|
490
|
+
// hashes / counters / ids for cross-store reconciliation.
|
|
491
|
+
if (_externalStore && typeof _externalStore.record === "function") {
|
|
492
|
+
// Bound the operator-supplied callback so a stalled network
|
|
493
|
+
// call can't hang the audit critical path. Timeout, throw,
|
|
494
|
+
// and resolve paths all converge on the framework chain row
|
|
495
|
+
// staying durable — the shadow is best-effort archival.
|
|
496
|
+
try {
|
|
497
|
+
await safeAsync.withTimeout(
|
|
498
|
+
Promise.resolve().then(function () { return _externalStore.record(appended); }),
|
|
499
|
+
EXTERNAL_STORE_TIMEOUT_MS,
|
|
500
|
+
{ name: "audit.shadowRecord" }
|
|
501
|
+
);
|
|
502
|
+
} catch (e) {
|
|
503
|
+
var isTimeout = e && (e.code === "ETIMEDOUT" || /timeout/i.test(e.message || ""));
|
|
504
|
+
try {
|
|
505
|
+
observability.event(isTimeout ? "audit.shadow_timeout" : "audit.shadow_failed", {
|
|
506
|
+
action: appended.action,
|
|
507
|
+
monotonicCounter: appended.monotonicCounter,
|
|
508
|
+
error: (e && e.message) || String(e),
|
|
509
|
+
timeoutMs: isTimeout ? EXTERNAL_STORE_TIMEOUT_MS : undefined,
|
|
510
|
+
});
|
|
511
|
+
} catch (_obs) { /* drop-silent — observability is itself hot-path */ }
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return appended;
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @primitive b.audit.useStore
|
|
521
|
+
* @signature b.audit.useStore({ record })
|
|
522
|
+
* @since 0.11.4
|
|
523
|
+
* @status stable
|
|
524
|
+
* @compliance hipaa, pci-dss, gdpr, soc2, sox-404
|
|
525
|
+
* @related b.audit.record, b.audit.safeEmit
|
|
526
|
+
*
|
|
527
|
+
* Register an operator-supplied shadow store for every audit chain
|
|
528
|
+
* append. The framework's tamper-evident chain remains authoritative
|
|
529
|
+
* (HIPAA §164.312(b) / PCI-DSS Req 10 / SOX-404 / ISO 27001 A.12.4.1
|
|
530
|
+
* posture preserved); the operator's `record(row)` async function is
|
|
531
|
+
* called AFTER each successful framework chain.append with the FULL
|
|
532
|
+
* appended row — `{ _id, recordedAt, monotonicCounter, prevHash,
|
|
533
|
+
* rowHash, action, outcome, actorUserId, ..., metadata }` — so
|
|
534
|
+
* external consumers see identical hashes for cross-store
|
|
535
|
+
* reconciliation.
|
|
536
|
+
*
|
|
537
|
+
* Typical use: replicate audit records to an immutable external
|
|
538
|
+
* destination (AWS QLDB / Azure Confidential Ledger / Google Cloud
|
|
539
|
+
* Audit Logs / an in-house WORM appliance / a SIEM forwarder).
|
|
540
|
+
* Operators in regulated industries often need their audit trail in
|
|
541
|
+
* a destination outside the application's own database for
|
|
542
|
+
* separation-of-duties (PCI-DSS Req 10.5.3) or independent retention
|
|
543
|
+
* (HIPAA §164.312(b) / SEC 17a-4 WORM).
|
|
544
|
+
*
|
|
545
|
+
* Failure posture: if the operator's `record` throws / rejects /
|
|
546
|
+
* times out (30s hard cap — a stalled network call MUST NOT block
|
|
547
|
+
* the audit critical path), the shadow failure is surfaced via
|
|
548
|
+
* `b.observability` as either `audit.shadow_failed` (throw/reject)
|
|
549
|
+
* or `audit.shadow_timeout` (cap exceeded) with `{ action,
|
|
550
|
+
* monotonicCounter, error, timeoutMs }` metadata, and the framework
|
|
551
|
+
* chain append still succeeds (the row is durable in the framework's
|
|
552
|
+
* own table; the shadow is a best-effort archival). Hot-path
|
|
553
|
+
* observability sinks emit drop-silent — an unreachable / hanging
|
|
554
|
+
* shadow MUST NOT crash or stall the request path that triggered
|
|
555
|
+
* the audit attempt.
|
|
556
|
+
*
|
|
557
|
+
* Call this once at boot, BEFORE the first `b.audit.record` /
|
|
558
|
+
* `b.audit.emit` / `b.audit.safeEmit`. Switching stores on a running
|
|
559
|
+
* app strands every prior audit row in the previous shadow store —
|
|
560
|
+
* the framework chain has them, but the new shadow doesn't unless
|
|
561
|
+
* the operator backfills.
|
|
562
|
+
*
|
|
563
|
+
* Pass `null` (or `{ record: null }`) to unregister and revert to
|
|
564
|
+
* chain-only mode.
|
|
565
|
+
*
|
|
566
|
+
* @opts
|
|
567
|
+
* record: async function (row), // operator's persistence callback
|
|
568
|
+
*
|
|
569
|
+
* @example
|
|
570
|
+
* var b = require("@blamejs/core");
|
|
571
|
+
* await b.vault.init({ dataDir: "/var/lib/blamejs", mode: "plaintext" });
|
|
572
|
+
* await b.db.init({ dataDir: "/var/lib/blamejs" });
|
|
573
|
+
* b.audit.useStore({
|
|
574
|
+
* record: async function (row) {
|
|
575
|
+
* // Replicate to AWS QLDB / Azure Confidential Ledger / etc.
|
|
576
|
+
* await externalLedger.append({
|
|
577
|
+
* id: row._id,
|
|
578
|
+
* recordedAt: row.recordedAt,
|
|
579
|
+
* monotonicCounter: row.monotonicCounter,
|
|
580
|
+
* prevHash: row.prevHash,
|
|
581
|
+
* rowHash: row.rowHash,
|
|
582
|
+
* action: row.action,
|
|
583
|
+
* outcome: row.outcome,
|
|
584
|
+
* metadata: row.metadata,
|
|
585
|
+
* });
|
|
586
|
+
* },
|
|
587
|
+
* });
|
|
588
|
+
* // Every b.audit.* append now also lands in externalLedger.
|
|
589
|
+
*/
|
|
590
|
+
function useStore(store) {
|
|
591
|
+
if (store === null || store === undefined) {
|
|
592
|
+
_externalStore = null;
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (typeof store !== "object") {
|
|
596
|
+
throw new Error("audit.useStore: store must be an object with a record(row) function, or null to unregister");
|
|
597
|
+
}
|
|
598
|
+
// `{ record: null }` unregisters explicitly (mirrors the null arg path).
|
|
599
|
+
if (store.record === null || store.record === undefined) {
|
|
600
|
+
_externalStore = null;
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (typeof store.record !== "function") {
|
|
604
|
+
throw new Error("audit.useStore: store.record must be an async function (row) => void");
|
|
605
|
+
}
|
|
606
|
+
_externalStore = store;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// ---- Query ----
|
|
610
|
+
//
|
|
611
|
+
// Plain-field criteria translate into derived-hash equality where the column
|
|
612
|
+
// is sealed. Returns unsealed rows for the auditor's view.
|
|
613
|
+
//
|
|
614
|
+
// Self-logging (PCI DSS 10.2.3): every read of audit_log is itself recorded
|
|
615
|
+
// as an 'audit.read' event before the query runs, so an exfiltration attempt
|
|
616
|
+
// is forensically visible. The recursion guard (_selfLogging flag) prevents
|
|
617
|
+
// the audit.read recording from triggering its own self-log; queries
|
|
618
|
+
// SPECIFICALLY filtering for action='audit.read' don't auto-log either
|
|
619
|
+
// (otherwise legitimate audit auditing produces a Russell-set spiral).
|
|
620
|
+
var _selfLogging = false;
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* @primitive b.audit.query
|
|
624
|
+
* @signature b.audit.query(criteria)
|
|
625
|
+
* @since 0.1.0
|
|
626
|
+
* @compliance pci-dss, soc2
|
|
627
|
+
* @related b.audit.verify, b.audit.verifyCheckpoints
|
|
628
|
+
*
|
|
629
|
+
* Read audit rows matching the criteria, returning unsealed rows for
|
|
630
|
+
* the auditor's view. Every call self-logs an `audit.read` event before
|
|
631
|
+
* returning (PCI DSS 10.2.3) so exfiltration attempts are forensically
|
|
632
|
+
* visible; recursion is guarded so the self-log doesn't trigger its own
|
|
633
|
+
* self-log. Plain-field criteria translate into derived-hash equality
|
|
634
|
+
* where the column is sealed.
|
|
635
|
+
*
|
|
636
|
+
* @opts
|
|
637
|
+
* from: number | Date | string, // recordedAt >=
|
|
638
|
+
* to: number | Date | string, // recordedAt <=
|
|
639
|
+
* actorUserId: string,
|
|
640
|
+
* resourceId: string,
|
|
641
|
+
* action: string,
|
|
642
|
+
* resourceKind: string,
|
|
643
|
+
* outcome: "success" | "failure" | "denied",
|
|
644
|
+
* limit: number,
|
|
645
|
+
* offset: number,
|
|
646
|
+
*
|
|
647
|
+
* @example
|
|
648
|
+
* var rows = await b.audit.query({
|
|
649
|
+
* action: "consent.granted",
|
|
650
|
+
* from: Date.now() - 86400000,
|
|
651
|
+
* limit: 100,
|
|
652
|
+
* });
|
|
653
|
+
* rows.length; // → 42
|
|
654
|
+
*/
|
|
655
|
+
async function query(criteria) {
|
|
656
|
+
criteria = criteria || {};
|
|
657
|
+
if (!_selfLogging && criteria.action !== "audit.read") {
|
|
658
|
+
_selfLogging = true;
|
|
659
|
+
try {
|
|
660
|
+
await record({
|
|
661
|
+
actor: criteria.actor || {},
|
|
662
|
+
action: "audit.read",
|
|
663
|
+
outcome: "success",
|
|
664
|
+
metadata: {
|
|
665
|
+
criteria: _redactCriteria(criteria),
|
|
666
|
+
traceId: criteria.traceId || null,
|
|
667
|
+
},
|
|
668
|
+
});
|
|
669
|
+
} finally {
|
|
670
|
+
_selfLogging = false;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// In single-node mode the query builder gives us field-crypto unsealing
|
|
675
|
+
// for free. In cluster mode we read raw rows from external-db and
|
|
676
|
+
// unseal manually.
|
|
677
|
+
if (cluster.isClusterMode()) {
|
|
678
|
+
return await _queryCluster(criteria);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
var q = db().from("audit_log");
|
|
682
|
+
|
|
683
|
+
if (criteria.from) q = q.where("recordedAt", ">=", _toMs(criteria.from));
|
|
684
|
+
if (criteria.to) q = q.where("recordedAt", "<=", _toMs(criteria.to));
|
|
685
|
+
if (criteria.actorUserId) q = q.where({ actorUserId: criteria.actorUserId });
|
|
686
|
+
if (criteria.resourceId) q = q.where({ resourceId: criteria.resourceId });
|
|
687
|
+
if (criteria.action) q = q.where({ action: criteria.action });
|
|
688
|
+
if (criteria.resourceKind) q = q.where({ resourceKind: criteria.resourceKind });
|
|
689
|
+
if (criteria.outcome) q = q.where({ outcome: criteria.outcome });
|
|
690
|
+
|
|
691
|
+
q.orderBy("monotonicCounter", "asc");
|
|
692
|
+
if (criteria.limit != null) q.limit(criteria.limit);
|
|
693
|
+
if (criteria.offset != null) q.offset(criteria.offset);
|
|
694
|
+
|
|
695
|
+
return q.all();
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async function _queryCluster(criteria) {
|
|
699
|
+
var conds = [];
|
|
700
|
+
var params = [];
|
|
701
|
+
if (criteria.from) {
|
|
702
|
+
conds.push("recordedAt >= ?");
|
|
703
|
+
params.push(_toMs(criteria.from));
|
|
704
|
+
}
|
|
705
|
+
if (criteria.to) {
|
|
706
|
+
conds.push("recordedAt <= ?");
|
|
707
|
+
params.push(_toMs(criteria.to));
|
|
708
|
+
}
|
|
709
|
+
if (criteria.actorUserId) {
|
|
710
|
+
var auh = cryptoField.lookupHash("audit_log", "actorUserId", criteria.actorUserId);
|
|
711
|
+
if (auh) { conds.push(auh.field + " = ?"); params.push(auh.value); }
|
|
712
|
+
}
|
|
713
|
+
if (criteria.resourceId) {
|
|
714
|
+
var rh = cryptoField.lookupHash("audit_log", "resourceId", criteria.resourceId);
|
|
715
|
+
if (rh) { conds.push(rh.field + " = ?"); params.push(rh.value); }
|
|
716
|
+
}
|
|
717
|
+
if (criteria.action) { conds.push("action = ?"); params.push(criteria.action); }
|
|
718
|
+
if (criteria.resourceKind) { conds.push("resourceKind = ?"); params.push(criteria.resourceKind); }
|
|
719
|
+
if (criteria.outcome) { conds.push("outcome = ?"); params.push(criteria.outcome); }
|
|
720
|
+
|
|
721
|
+
var sql = "SELECT * FROM audit_log";
|
|
722
|
+
if (conds.length > 0) sql += " WHERE " + conds.join(" AND ");
|
|
723
|
+
sql += " ORDER BY monotonicCounter ASC";
|
|
724
|
+
if (criteria.limit != null) { sql += " LIMIT ?"; params.push(criteria.limit); }
|
|
725
|
+
if (criteria.offset != null) { sql += " OFFSET ?"; params.push(criteria.offset); }
|
|
726
|
+
|
|
727
|
+
var rows = await clusterStorage.executeAll(sql, params);
|
|
728
|
+
return rows.map(function (row) { return cryptoField.unsealRow("audit_log", row); });
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Audit-readable summary of the criteria without storing raw subject IDs
|
|
732
|
+
// in plaintext anywhere outside the sealed columns of audit_log itself.
|
|
733
|
+
function _redactCriteria(c) {
|
|
734
|
+
return {
|
|
735
|
+
from: c.from || null,
|
|
736
|
+
to: c.to || null,
|
|
737
|
+
action: c.action || null,
|
|
738
|
+
resourceKind: c.resourceKind || null,
|
|
739
|
+
outcome: c.outcome || null,
|
|
740
|
+
hasUserFilter: !!c.actorUserId,
|
|
741
|
+
hasResourceFilter: !!c.resourceId,
|
|
742
|
+
limit: c.limit != null ? c.limit : null,
|
|
743
|
+
offset: c.offset != null ? c.offset : null,
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Generate a fresh trace id apps can thread through their request handlers
|
|
748
|
+
// and pass into audit.record() / consent.grant() / etc. via the metadata
|
|
749
|
+
// field. Width matches the W3C traceparent trace-id format (16 random
|
|
750
|
+
// bytes hex-encoded → 32 chars). Routed through C.BYTES so the byte
|
|
751
|
+
// count has a single source of truth.
|
|
752
|
+
var TRACE_ID_BYTES = C.BYTES.bytes(16);
|
|
753
|
+
/**
|
|
754
|
+
* @primitive b.audit.beginTrace
|
|
755
|
+
* @signature b.audit.beginTrace()
|
|
756
|
+
* @since 0.1.0
|
|
757
|
+
* @related b.audit.record, b.audit.query
|
|
758
|
+
*
|
|
759
|
+
* Mint a fresh 32-hex-char trace id apps thread through linked events
|
|
760
|
+
* via `metadata.traceId`. Width matches the W3C traceparent trace-id
|
|
761
|
+
* format (16 random bytes hex-encoded), so the id is interoperable with
|
|
762
|
+
* OpenTelemetry / W3C Trace Context propagation.
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* var traceId = b.audit.beginTrace();
|
|
766
|
+
* await b.audit.record({
|
|
767
|
+
* action: "subject.export.requested",
|
|
768
|
+
* outcome: "success",
|
|
769
|
+
* metadata: { traceId: traceId },
|
|
770
|
+
* });
|
|
771
|
+
* await b.audit.record({
|
|
772
|
+
* action: "subject.export.delivered",
|
|
773
|
+
* outcome: "success",
|
|
774
|
+
* metadata: { traceId: traceId, parentEventId: "..." },
|
|
775
|
+
* });
|
|
776
|
+
*/
|
|
777
|
+
function beginTrace() {
|
|
778
|
+
return generateToken(TRACE_ID_BYTES);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// ---- Checkpoints (tamper-proof external anchor) ----
|
|
782
|
+
|
|
783
|
+
// Build the canonical bytes that get signed for a checkpoint at a given
|
|
784
|
+
// chain tip. Keep this format stable across the framework's lifetime —
|
|
785
|
+
// changing it invalidates every prior checkpoint signature.
|
|
786
|
+
var CHECKPOINT_FORMAT = "blamejs-audit-checkpoint-v1";
|
|
787
|
+
function _checkpointPayload(atMonotonicCounter, atRowHash, createdAt) {
|
|
788
|
+
// Use a fixed multi-line layout. Avoids JSON serializer quirks; portable
|
|
789
|
+
// to any verifier reading the same column triple from the DB.
|
|
790
|
+
return Buffer.from(
|
|
791
|
+
CHECKPOINT_FORMAT + "\n" +
|
|
792
|
+
String(atMonotonicCounter) + "\n" +
|
|
793
|
+
atRowHash + "\n" +
|
|
794
|
+
String(createdAt),
|
|
795
|
+
"utf8"
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Anchor the current chain tip with a fresh ML-DSA-87 signature. Inserts
|
|
800
|
+
// a row into audit_checkpoints. Updates <dataDir>/audit.tip for boot-time
|
|
801
|
+
// rollback detection.
|
|
802
|
+
//
|
|
803
|
+
// opts:
|
|
804
|
+
// skipIfUnchanged: bool — return null without inserting if the chain tip
|
|
805
|
+
// hasn't advanced since the most recent checkpoint
|
|
806
|
+
/**
|
|
807
|
+
* @primitive b.audit.checkpoint
|
|
808
|
+
* @signature b.audit.checkpoint(opts)
|
|
809
|
+
* @since 0.4.0
|
|
810
|
+
* @compliance soc2, pci-dss, sox-404
|
|
811
|
+
* @related b.audit.verifyCheckpoints, b.audit.verify
|
|
812
|
+
*
|
|
813
|
+
* Anchor the current chain tip with a fresh ML-DSA-87 (post-quantum)
|
|
814
|
+
* signature. Inserts a row into `audit_checkpoints` and updates the
|
|
815
|
+
* boot-time rollback-detection sidecar (single-node) or the cluster
|
|
816
|
+
* audit-tip row (cluster mode, fencing-token guarded). Cluster mode
|
|
817
|
+
* requires the caller hold leader status — `cluster.requireLeader()`
|
|
818
|
+
* throws otherwise.
|
|
819
|
+
*
|
|
820
|
+
* Returns the inserted checkpoint row, or `null` when the chain is
|
|
821
|
+
* empty / `skipIfUnchanged` and the tip hasn't advanced.
|
|
822
|
+
*
|
|
823
|
+
* @opts
|
|
824
|
+
* skipIfUnchanged: boolean, // null-return when tip didn't move
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* var ckpt = await b.audit.checkpoint({ skipIfUnchanged: true });
|
|
828
|
+
* if (ckpt) {
|
|
829
|
+
* console.log("anchored at counter", ckpt.atMonotonicCounter);
|
|
830
|
+
* }
|
|
831
|
+
*/
|
|
832
|
+
async function checkpoint(opts) {
|
|
833
|
+
cluster.requireLeader();
|
|
834
|
+
opts = opts || {};
|
|
835
|
+
|
|
836
|
+
var tip = await safeAsync.withTimeout(
|
|
837
|
+
safeAsync.asyncRetry(function () {
|
|
838
|
+
return clusterStorage.executeOne(
|
|
839
|
+
"SELECT _id, monotonicCounter, rowHash FROM audit_log " +
|
|
840
|
+
"ORDER BY monotonicCounter DESC LIMIT 1"
|
|
841
|
+
);
|
|
842
|
+
}),
|
|
843
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
844
|
+
{ name: "audit.checkpoint.readTip" }
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
if (!tip) return null; // empty audit log; nothing to anchor
|
|
848
|
+
|
|
849
|
+
if (opts.skipIfUnchanged) {
|
|
850
|
+
var lastCkpt = await _readLastCheckpointCounter();
|
|
851
|
+
if (lastCkpt && Number(lastCkpt.atMonotonicCounter) >= Number(tip.monotonicCounter)) {
|
|
852
|
+
return null; // already anchored at this tip
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
var createdAt = Date.now();
|
|
857
|
+
var counter = Number(tip.monotonicCounter);
|
|
858
|
+
var payload = _checkpointPayload(counter, tip.rowHash, createdAt);
|
|
859
|
+
var signature = auditSign.sign(payload);
|
|
860
|
+
var pubFp = auditSign.getPublicKeyFingerprint();
|
|
861
|
+
|
|
862
|
+
var ckptId = generateToken(TRACE_ID_BYTES);
|
|
863
|
+
var fencingToken = cluster.fencingToken();
|
|
864
|
+
await _insertCheckpoint(
|
|
865
|
+
[ckptId, createdAt, counter, tip.rowHash, signature, pubFp, fencingToken]
|
|
866
|
+
);
|
|
867
|
+
|
|
868
|
+
// Update rollback-detection sidecar (single-node) or audit-tip row
|
|
869
|
+
// (cluster mode).
|
|
870
|
+
//
|
|
871
|
+
// Single-node sidecar is best-effort — a sidecar write failure must
|
|
872
|
+
// not block checkpointing because the chain itself is already
|
|
873
|
+
// committed.
|
|
874
|
+
//
|
|
875
|
+
// Cluster-mode audit-tip is NOT best-effort: the upsert's WHERE
|
|
876
|
+
// clause is the fencing-token guard, and a FENCED_OUT response
|
|
877
|
+
// means the local node has been superseded by a newer leader. The
|
|
878
|
+
// checkpoint row was already inserted at this point but propagating
|
|
879
|
+
// the error up makes the leadership-loss visible to the caller — it
|
|
880
|
+
// also means the caller can audit the leader-lost transition and
|
|
881
|
+
// step down. Other audit-tip errors (network blip, transient DB)
|
|
882
|
+
// also surface so the operator can react.
|
|
883
|
+
if (cluster.isClusterMode()) {
|
|
884
|
+
await _upsertAuditTip(counter, tip.rowHash, String(createdAt), fencingToken);
|
|
885
|
+
} else {
|
|
886
|
+
try {
|
|
887
|
+
db()._writeAuditTip({
|
|
888
|
+
atMonotonicCounter: counter,
|
|
889
|
+
atRowHash: tip.rowHash,
|
|
890
|
+
anchoredAt: createdAt,
|
|
891
|
+
checkpointId: ckptId,
|
|
892
|
+
publicKeyFingerprint: pubFp,
|
|
893
|
+
version: 1,
|
|
894
|
+
});
|
|
895
|
+
} catch (_e) { /* best effort */ }
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
return {
|
|
899
|
+
_id: ckptId,
|
|
900
|
+
createdAt: createdAt,
|
|
901
|
+
atMonotonicCounter: counter,
|
|
902
|
+
atRowHash: tip.rowHash,
|
|
903
|
+
publicKeyFingerprint: pubFp,
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// Walk every checkpoint, verify its signature against the current public
|
|
908
|
+
// key (or one matching the row's stored fingerprint). Also confirms the
|
|
909
|
+
// audit_log row at atMonotonicCounter still has the recorded rowHash.
|
|
910
|
+
//
|
|
911
|
+
// Returns { ok, checkpointsVerified, breakAt? }.
|
|
912
|
+
/**
|
|
913
|
+
* @primitive b.audit.verifyCheckpoints
|
|
914
|
+
* @signature b.audit.verifyCheckpoints()
|
|
915
|
+
* @since 0.4.0
|
|
916
|
+
* @compliance soc2, pci-dss, sox-404
|
|
917
|
+
* @related b.audit.checkpoint, b.audit.verify
|
|
918
|
+
*
|
|
919
|
+
* Walk every checkpoint and verify (a) the public-key fingerprint
|
|
920
|
+
* matches the current signing key, (b) the ML-DSA-87 signature over the
|
|
921
|
+
* payload still verifies, (c) the audit_log row at the anchored counter
|
|
922
|
+
* still has the recorded rowHash. Catches tampering that recomputed
|
|
923
|
+
* chain hashes after holding the vault key, because the off-chain
|
|
924
|
+
* signature anchor is unforgeable without the signing key.
|
|
925
|
+
*
|
|
926
|
+
* Returns `{ ok: true, checkpointsVerified }` on success, or
|
|
927
|
+
* `{ ok: false, checkpointsVerified, breakAt, checkpointId, reason }`
|
|
928
|
+
* at the first break.
|
|
929
|
+
*
|
|
930
|
+
* @example
|
|
931
|
+
* var result = await b.audit.verifyCheckpoints();
|
|
932
|
+
* if (!result.ok) {
|
|
933
|
+
* throw new Error("audit checkpoint break at " + result.breakAt +
|
|
934
|
+
* ": " + result.reason);
|
|
935
|
+
* }
|
|
936
|
+
* result.checkpointsVerified; // → 17
|
|
937
|
+
*/
|
|
938
|
+
async function verifyCheckpoints() {
|
|
939
|
+
var rows = await _readAllCheckpointsAsc();
|
|
940
|
+
|
|
941
|
+
if (rows.length === 0) return { ok: true, checkpointsVerified: 0 };
|
|
942
|
+
|
|
943
|
+
var currentFp = auditSign.getPublicKeyFingerprint();
|
|
944
|
+
var currentPub = auditSign.getPublicKey();
|
|
945
|
+
|
|
946
|
+
for (var i = 0; i < rows.length; i++) {
|
|
947
|
+
var c = rows[i];
|
|
948
|
+
// Public key check: only the current key is accepted — there is no
|
|
949
|
+
// key-history table, so any rotation requires re-signing existing
|
|
950
|
+
// checkpoints. A fingerprint mismatch fails verification.
|
|
951
|
+
if (c.publicKeyFingerprint !== currentFp) {
|
|
952
|
+
return {
|
|
953
|
+
ok: false,
|
|
954
|
+
checkpointsVerified: i,
|
|
955
|
+
breakAt: i,
|
|
956
|
+
checkpointId: c._id,
|
|
957
|
+
reason: "public key fingerprint mismatch (key rotated without history?)",
|
|
958
|
+
expected: currentFp,
|
|
959
|
+
actual: c.publicKeyFingerprint,
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
var payload = _checkpointPayload(Number(c.atMonotonicCounter), c.atRowHash, Number(c.createdAt));
|
|
963
|
+
var sigBuf = Buffer.isBuffer(c.signature) ? c.signature : Buffer.from(c.signature);
|
|
964
|
+
if (!auditSign.verify(payload, sigBuf, currentPub)) {
|
|
965
|
+
return {
|
|
966
|
+
ok: false,
|
|
967
|
+
checkpointsVerified: i,
|
|
968
|
+
breakAt: i,
|
|
969
|
+
checkpointId: c._id,
|
|
970
|
+
reason: "ML-DSA-87 signature failed",
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
// Also confirm the audit row at atMonotonicCounter still matches the
|
|
974
|
+
// anchored rowHash. If someone tampered with audit_log AND recomputed
|
|
975
|
+
// hashes (requiring vault key), this catches them via the off-chain
|
|
976
|
+
// signature anchor.
|
|
977
|
+
var anchored = await _readAuditRowHashAtCounter(c.atMonotonicCounter);
|
|
978
|
+
if (!anchored) {
|
|
979
|
+
return {
|
|
980
|
+
ok: false,
|
|
981
|
+
checkpointsVerified: i,
|
|
982
|
+
breakAt: i,
|
|
983
|
+
checkpointId: c._id,
|
|
984
|
+
reason: "anchored audit_log row missing (counter=" + c.atMonotonicCounter + ")",
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
if (anchored.rowHash !== c.atRowHash) {
|
|
988
|
+
return {
|
|
989
|
+
ok: false,
|
|
990
|
+
checkpointsVerified: i,
|
|
991
|
+
breakAt: i,
|
|
992
|
+
checkpointId: c._id,
|
|
993
|
+
reason: "anchored rowHash mismatch — audit_log was tampered with",
|
|
994
|
+
expected: c.atRowHash,
|
|
995
|
+
actual: anchored.rowHash,
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
return { ok: true, checkpointsVerified: rows.length };
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
function _toMs(value) {
|
|
1003
|
+
if (typeof value === "number") return value;
|
|
1004
|
+
if (value instanceof Date) return value.getTime();
|
|
1005
|
+
if (typeof value === "string") {
|
|
1006
|
+
var ms = Date.parse(value);
|
|
1007
|
+
if (isNaN(ms)) throw new Error("invalid date: " + value);
|
|
1008
|
+
return ms;
|
|
1009
|
+
}
|
|
1010
|
+
throw new Error("invalid date value");
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// ---- Verify ----
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* @primitive b.audit.verify
|
|
1017
|
+
* @signature b.audit.verify(opts)
|
|
1018
|
+
* @since 0.1.0
|
|
1019
|
+
* @compliance hipaa, pci-dss, gdpr, soc2, sox-404
|
|
1020
|
+
* @related b.audit.verifyCheckpoints, b.audit.query
|
|
1021
|
+
*
|
|
1022
|
+
* Walk every audit_log row in monotonic order and recompute each
|
|
1023
|
+
* `rowHash` against the canonicalized columns + nonce, confirming each
|
|
1024
|
+
* row's `prevHash` matches the previous row's `rowHash`. Catches any
|
|
1025
|
+
* insert / delete / mutation between checkpoints. Runs at boot in
|
|
1026
|
+
* `db.init()`; operators also call it from a periodic job.
|
|
1027
|
+
*
|
|
1028
|
+
* Returns `{ ok: true, rowsVerified }` on a clean chain, or
|
|
1029
|
+
* `{ ok: false, rowsVerified, breakAt, reason }` at the first break.
|
|
1030
|
+
*
|
|
1031
|
+
* @opts
|
|
1032
|
+
* from: number, // start counter (incremental verify after a known-good checkpoint)
|
|
1033
|
+
* to: number, // end counter
|
|
1034
|
+
*
|
|
1035
|
+
* @example
|
|
1036
|
+
* var result = await b.audit.verify();
|
|
1037
|
+
* if (!result.ok) {
|
|
1038
|
+
* console.error("audit chain break at row", result.breakAt);
|
|
1039
|
+
* process.exit(1);
|
|
1040
|
+
* }
|
|
1041
|
+
*/
|
|
1042
|
+
async function verify(opts) {
|
|
1043
|
+
// verifyChain just needs an executeAll; route through the same
|
|
1044
|
+
// resilience-wrapped reader the rest of audit uses.
|
|
1045
|
+
return await auditChain.verifyChain(
|
|
1046
|
+
function (sql, params) {
|
|
1047
|
+
return safeAsync.withTimeout(
|
|
1048
|
+
safeAsync.asyncRetry(function () {
|
|
1049
|
+
return clusterStorage.executeAll(sql, params || []);
|
|
1050
|
+
}),
|
|
1051
|
+
FRAMEWORK_SQL_TIMEOUT_MS,
|
|
1052
|
+
{ name: "audit.verifyChain" }
|
|
1053
|
+
);
|
|
1054
|
+
},
|
|
1055
|
+
"audit_log",
|
|
1056
|
+
opts
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// ---- Test helpers ----
|
|
1061
|
+
|
|
1062
|
+
function _resetForTest() {
|
|
1063
|
+
registeredNamespaces = new Set(FRAMEWORK_NAMESPACES);
|
|
1064
|
+
_externalStore = null;
|
|
1065
|
+
db.reset();
|
|
1066
|
+
_chainWriter._resetForTest();
|
|
1067
|
+
// Drop pending buffered emits and cancel the age-flush timer on the
|
|
1068
|
+
// old handler before dereferencing it. Without this, the old
|
|
1069
|
+
// handler's setTimeout (scheduled when emits buffer below maxBatch)
|
|
1070
|
+
// fires AFTER the next test's db.init has opened a fresh database —
|
|
1071
|
+
// the buffered items then drain through chain-writer into the wrong
|
|
1072
|
+
// tmpDir's audit_log, breaking chain verify on the next-next test.
|
|
1073
|
+
// shutdownSync is the explicit "drop, don't drain" path because
|
|
1074
|
+
// draining to a stale or changing backing store is exactly the bug.
|
|
1075
|
+
// The handler's flush also checks ctx.isShutdown() between items, so
|
|
1076
|
+
// an in-flight drain that's mid-batch when reset fires bails out
|
|
1077
|
+
// instead of writing the rest of the batch to the new database.
|
|
1078
|
+
if (_auditHandler) {
|
|
1079
|
+
try { _auditHandler.shutdownSync("audit._resetForTest"); }
|
|
1080
|
+
catch (e) { log.debug("reset-handler-shutdown-failed: " + (e && e.message || e)); }
|
|
1081
|
+
_auditHandler = null;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// ---- Handler-backed emit + flush ----
|
|
1086
|
+
//
|
|
1087
|
+
// emit() is the call-site API for fire-and-forget audit emission from
|
|
1088
|
+
// middleware / log-stream / external-db hooks / queue / storage / subject.
|
|
1089
|
+
// It is SYNCHRONOUS, NEVER throws, and NEVER returns a Promise — request-
|
|
1090
|
+
// path code can call it without await and without try/catch.
|
|
1091
|
+
//
|
|
1092
|
+
// Internally events queue in an AsyncHandler. flush() drains the queue
|
|
1093
|
+
// to the audit chain (single writer in-process, serialized via the
|
|
1094
|
+
// chain mutex). Tests, shutdown, and any code that needs audit-row
|
|
1095
|
+
// durability before reading audit_log calls await audit.flush().
|
|
1096
|
+
//
|
|
1097
|
+
// Why this beats fire-and-forget Promises:
|
|
1098
|
+
// - No leaked Promises across test/shutdown boundaries
|
|
1099
|
+
// - Errors go through a single onError hook (visible to operators)
|
|
1100
|
+
// - Recursive emits during flush land in the buffer for the next
|
|
1101
|
+
// drain cycle — no infinite loop in cluster-mode dispatchers
|
|
1102
|
+
// - Tests have a deterministic "audit is durable now" point
|
|
1103
|
+
var _auditHandler = null;
|
|
1104
|
+
|
|
1105
|
+
function _ensureHandler() {
|
|
1106
|
+
if (_auditHandler) return _auditHandler;
|
|
1107
|
+
_auditHandler = handlers.create({
|
|
1108
|
+
name: "audit",
|
|
1109
|
+
flush: async function (batch, ctx) {
|
|
1110
|
+
// Drain by serially writing each event through record(). The chain
|
|
1111
|
+
// mutex inside record() further serializes vs concurrent direct
|
|
1112
|
+
// record() callers.
|
|
1113
|
+
//
|
|
1114
|
+
// Between items, check the handler's shutdown probe — if a test
|
|
1115
|
+
// (or operator) reset audit while this batch was in flight, the
|
|
1116
|
+
// remaining items would otherwise drain through the chain-writer
|
|
1117
|
+
// into a database that no longer represents the chain those
|
|
1118
|
+
// items were emitted against. Early-exit drops them; the
|
|
1119
|
+
// alternative is silent corruption of the next chain.
|
|
1120
|
+
var droppedThisBatch = 0;
|
|
1121
|
+
for (var i = 0; i < batch.length; i++) {
|
|
1122
|
+
if (ctx && ctx.isShutdown && ctx.isShutdown()) return;
|
|
1123
|
+
try { await record(batch[i]); }
|
|
1124
|
+
catch (e) {
|
|
1125
|
+
droppedThisBatch += 1;
|
|
1126
|
+
// Per-item failure shouldn't drop the whole batch; log and
|
|
1127
|
+
// continue. The handler's onError gets called for batch-
|
|
1128
|
+
// wide failures only.
|
|
1129
|
+
log.error("flush dropped event: " +
|
|
1130
|
+
(e && e.message ? e.message : String(e)) +
|
|
1131
|
+
" (action=" + (batch[i] && batch[i].action) + ")");
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
// Surface chain-write integrity failures via observability so
|
|
1135
|
+
// operators alerting on rate-drop see something. The audit
|
|
1136
|
+
// chain itself can't carry the signal — the chain is what's
|
|
1137
|
+
// broken — so observability is the only sink left.
|
|
1138
|
+
if (droppedThisBatch > 0) {
|
|
1139
|
+
observability.safeEvent("system.audit.chain_write_dropped",
|
|
1140
|
+
droppedThisBatch, { batchSize: batch.length });
|
|
1141
|
+
}
|
|
1142
|
+
},
|
|
1143
|
+
});
|
|
1144
|
+
return _auditHandler;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* @primitive b.audit.emit
|
|
1149
|
+
* @signature b.audit.emit(event)
|
|
1150
|
+
* @since 0.1.0
|
|
1151
|
+
* @related b.audit.safeEmit, b.audit.record, b.audit.flush
|
|
1152
|
+
*
|
|
1153
|
+
* Synchronous fire-and-forget emit — events buffer in an AsyncHandler
|
|
1154
|
+
* and drain serially through `record()`. Returns immediately; never
|
|
1155
|
+
* returns a Promise. Unlike `safeEmit()`, emit() does NOT normalize
|
|
1156
|
+
* outcome / action and does NOT redact metadata — callers pass already-
|
|
1157
|
+
* shaped events. Most call sites should prefer `safeEmit` instead;
|
|
1158
|
+
* `emit` is the lower-level surface the framework's own bound-actor
|
|
1159
|
+
* wrapper uses.
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* b.audit.emit({
|
|
1163
|
+
* actor: { userId: "u-42" },
|
|
1164
|
+
* action: "system.config.reloaded",
|
|
1165
|
+
* outcome: "success",
|
|
1166
|
+
* metadata: { source: "SIGHUP" },
|
|
1167
|
+
* });
|
|
1168
|
+
*/
|
|
1169
|
+
function emit(event) {
|
|
1170
|
+
_ensureHandler().emit(event);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// Outcome normalization — drop-silent on a strict `outcome` mismatch
|
|
1174
|
+
// dropped a class of audit rows across the framework (every
|
|
1175
|
+
// non-{success, failure, denied} outcome from b.flag / b.outbox /
|
|
1176
|
+
// b.inbox / b.session / b.db / b.config-drift / b.compliance-aiAct
|
|
1177
|
+
// landed in the handler's catch-and-log path instead of the chain).
|
|
1178
|
+
// safeEmit owns the normalization; record() stays strict so direct
|
|
1179
|
+
// callers see the typo loudly.
|
|
1180
|
+
var OUTCOME_NORMALIZE = {
|
|
1181
|
+
ok: "success",
|
|
1182
|
+
okay: "success",
|
|
1183
|
+
pass: "success",
|
|
1184
|
+
passed: "success",
|
|
1185
|
+
success: "success",
|
|
1186
|
+
succeeded: "success",
|
|
1187
|
+
warn: "success",
|
|
1188
|
+
warning: "success",
|
|
1189
|
+
duplicate: "success",
|
|
1190
|
+
skip: "success",
|
|
1191
|
+
skipped: "success",
|
|
1192
|
+
fail: "failure",
|
|
1193
|
+
failed: "failure",
|
|
1194
|
+
failure: "failure",
|
|
1195
|
+
err: "failure",
|
|
1196
|
+
error: "failure",
|
|
1197
|
+
denied: "denied",
|
|
1198
|
+
refused: "denied",
|
|
1199
|
+
deny: "denied",
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
function _normalizeOutcome(o) {
|
|
1203
|
+
if (typeof o !== "string") return "success";
|
|
1204
|
+
var n = OUTCOME_NORMALIZE[o.toLowerCase()];
|
|
1205
|
+
return n || "success";
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// Hyphens in action segments fall outside the underscore-only
|
|
1209
|
+
// regex enforced by record(). Replace at the segment boundary so
|
|
1210
|
+
// "compliance.aiact.biometric-id-categorisation" lands as
|
|
1211
|
+
// "compliance.aiact.biometric_id_categorisation" and reaches the
|
|
1212
|
+
// chain instead of dropping. The action namespace prefix (the part
|
|
1213
|
+
// before the first dot) is left strict — namespaces are
|
|
1214
|
+
// operator-registered and should be plain identifiers.
|
|
1215
|
+
function _normalizeAction(action) {
|
|
1216
|
+
if (typeof action !== "string") return action;
|
|
1217
|
+
return action.replace(/-/g, "_");
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// safeEmit — fire-and-forget audit emit with safe defaults + try/catch.
|
|
1221
|
+
//
|
|
1222
|
+
// Most modules wrap emit() in their own _emit helper that fills in
|
|
1223
|
+
// `actor: {}`, `outcome: "success"`, etc. and catches the throw so an
|
|
1224
|
+
// audit outage doesn't crash the request handler. This is that helper,
|
|
1225
|
+
// hoisted out so each module can stop redefining it.
|
|
1226
|
+
//
|
|
1227
|
+
// Drop-silent on malformed input by design. safeEmit is called from
|
|
1228
|
+
// request hot paths where throwing on a
|
|
1229
|
+
// missing `action` would mean a malformed audit attempt crashes the
|
|
1230
|
+
// request that triggered it — strictly worse than the missing audit
|
|
1231
|
+
// row. Operators who need a hard guarantee the event landed should call
|
|
1232
|
+
// record() and await it with their own error handling. The audit chain
|
|
1233
|
+
// itself is verified at boot, so a silently dropped row shows up in the
|
|
1234
|
+
// next chain integrity sweep.
|
|
1235
|
+
/**
|
|
1236
|
+
* @primitive b.audit.safeEmit
|
|
1237
|
+
* @signature b.audit.safeEmit(event)
|
|
1238
|
+
* @since 0.1.0
|
|
1239
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
1240
|
+
* @related b.audit.emit, b.audit.record, b.audit.flush
|
|
1241
|
+
*
|
|
1242
|
+
* Hot-path-safe fire-and-forget audit emit. Drop-silent on malformed
|
|
1243
|
+
* input by design — safeEmit runs from request middleware, log-stream
|
|
1244
|
+
* hooks, and finalizers where throwing on a missing `action` would
|
|
1245
|
+
* crash the request that triggered the audit attempt. Operators who
|
|
1246
|
+
* need durability guarantees call `record()` and await it.
|
|
1247
|
+
*
|
|
1248
|
+
* Built-in normalization: action segments with hyphens become
|
|
1249
|
+
* underscores ("biometric-id" → "biometric_id"); outcome aliases
|
|
1250
|
+
* collapse to {success, failure, denied} ("ok" → "success", "error" →
|
|
1251
|
+
* "failure", "refused" → "denied"). Actor / reason / metadata pass
|
|
1252
|
+
* through `b.redact.redact()` so connection strings, JWTs, PEM blocks,
|
|
1253
|
+
* AWS keys, and SSNs are scrubbed before they reach the chain.
|
|
1254
|
+
*
|
|
1255
|
+
* @opts
|
|
1256
|
+
* actor: { userId, ip, userAgent, sessionId },
|
|
1257
|
+
* action: "namespace.verb[.qualifier]",
|
|
1258
|
+
* resource: { kind, id },
|
|
1259
|
+
* outcome: string, // normalized
|
|
1260
|
+
* reason: string, // redacted
|
|
1261
|
+
* metadata: object, // redacted
|
|
1262
|
+
* requestId: string,
|
|
1263
|
+
*
|
|
1264
|
+
* @example
|
|
1265
|
+
* b.audit.safeEmit({
|
|
1266
|
+
* actor: { userId: req.user && req.user.id },
|
|
1267
|
+
* action: "auth.login",
|
|
1268
|
+
* outcome: "success",
|
|
1269
|
+
* metadata: { traceId: req.traceId, ua: req.headers["user-agent"] },
|
|
1270
|
+
* });
|
|
1271
|
+
*/
|
|
1272
|
+
function safeEmit(event) {
|
|
1273
|
+
if (!event || typeof event !== "object") return;
|
|
1274
|
+
if (typeof event.action !== "string") return; // can't emit without an action
|
|
1275
|
+
try {
|
|
1276
|
+
// Scrub credentials before they hit the audit handler. Operators
|
|
1277
|
+
// who pass `metadata: { reason: e.message }` from a caught error
|
|
1278
|
+
// can land DB connection strings, bearer tokens, and JWT compact-
|
|
1279
|
+
// serialization fixtures in audit rows; redact.redact() catches the
|
|
1280
|
+
// common shapes (sensitive field names + value-shape detectors:
|
|
1281
|
+
// credit-card / JWT / PEM / AWS key / SSN / connection string) and
|
|
1282
|
+
// replaces them with markers. Same pass also applies to actor +
|
|
1283
|
+
// reason so the entire event surface is consistent. Drop-silent on
|
|
1284
|
+
// redact failure — never break the caller's audit attempt.
|
|
1285
|
+
var actor = event.actor || {};
|
|
1286
|
+
var reason = event.reason || null;
|
|
1287
|
+
var metadata = event.metadata || null;
|
|
1288
|
+
try {
|
|
1289
|
+
actor = redact.redact(actor);
|
|
1290
|
+
if (reason !== null) reason = redact.redact(reason);
|
|
1291
|
+
if (metadata !== null) metadata = redact.redact(metadata);
|
|
1292
|
+
} catch (_e) { /* fall through with original values */ }
|
|
1293
|
+
_ensureHandler().emit({
|
|
1294
|
+
actor: actor,
|
|
1295
|
+
action: _normalizeAction(event.action),
|
|
1296
|
+
resource: event.resource || null,
|
|
1297
|
+
outcome: _normalizeOutcome(event.outcome),
|
|
1298
|
+
reason: reason,
|
|
1299
|
+
metadata: metadata,
|
|
1300
|
+
requestId: event.requestId || null,
|
|
1301
|
+
});
|
|
1302
|
+
} catch (_e) { /* audit best-effort — never break the caller */ }
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* @primitive b.audit.flush
|
|
1307
|
+
* @signature b.audit.flush()
|
|
1308
|
+
* @since 0.1.0
|
|
1309
|
+
* @related b.audit.emit, b.audit.safeEmit
|
|
1310
|
+
*
|
|
1311
|
+
* Drain the AsyncHandler buffer — every queued `emit()` / `safeEmit()`
|
|
1312
|
+
* lands in the audit chain before the returned Promise resolves. Tests,
|
|
1313
|
+
* graceful shutdown, and any code that needs to read audit_log
|
|
1314
|
+
* immediately after emitting awaits flush().
|
|
1315
|
+
*
|
|
1316
|
+
* @example
|
|
1317
|
+
* b.audit.safeEmit({ action: "system.shutdown.requested", outcome: "success" });
|
|
1318
|
+
* await b.audit.flush();
|
|
1319
|
+
* var rows = await b.audit.query({ action: "system.shutdown.requested" });
|
|
1320
|
+
* rows.length; // → 1
|
|
1321
|
+
*/
|
|
1322
|
+
async function flush() {
|
|
1323
|
+
if (!_auditHandler) return;
|
|
1324
|
+
await _auditHandler.drain();
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// ---- SOX §404 / SOC 2 CC1.3 — actor-binding + segregation of duties ----
|
|
1328
|
+
//
|
|
1329
|
+
// Anyone with write access to the audit_log table can INSERT a row
|
|
1330
|
+
// claiming any actor identity. The framework already records actor
|
|
1331
|
+
// from the request context, but a privileged caller (operator script,
|
|
1332
|
+
// migration runner, anyone with the externalDb credentials) can claim
|
|
1333
|
+
// a different actor.
|
|
1334
|
+
//
|
|
1335
|
+
// bindActor(actorId, opts) returns a wrapper around audit.safeEmit /
|
|
1336
|
+
// audit.record that refuses any event whose actor.userId mismatches
|
|
1337
|
+
// the bound identity OR the SQL-bound role (when db-role-context is
|
|
1338
|
+
// active).
|
|
1339
|
+
//
|
|
1340
|
+
// SQL-side enforcement lives in lib/cluster-storage.js's framework-
|
|
1341
|
+
// schema generator — see generateActorBindingTriggerSql() below for
|
|
1342
|
+
// the Postgres trigger DDL. Operators apply that DDL in a migration
|
|
1343
|
+
// when they boot under sox-404 / soc2 / pci-dss posture so a non-
|
|
1344
|
+
// framework writer can't INSERT rows under a different role.
|
|
1345
|
+
function _checkActorBinding(actorId, eventActorId, opts) {
|
|
1346
|
+
if (!actorId) return true; // unbound — no enforcement
|
|
1347
|
+
if (!eventActorId) {
|
|
1348
|
+
return { ok: false, reason: "event missing actor.userId — refused under bound emit" };
|
|
1349
|
+
}
|
|
1350
|
+
if (eventActorId !== actorId) {
|
|
1351
|
+
return { ok: false,
|
|
1352
|
+
reason: "actor mismatch: bound='" + actorId + "', event='" + eventActorId + "'" };
|
|
1353
|
+
}
|
|
1354
|
+
// db-role-context check — when the caller is inside a runWithRole
|
|
1355
|
+
// scope, the SQL-bound role and the bound actor must agree (subject
|
|
1356
|
+
// to the operator-supplied `roleEquivalent` mapping).
|
|
1357
|
+
if (opts && typeof opts.roleEquivalent === "function") {
|
|
1358
|
+
var role = dbRoleContext.getRole();
|
|
1359
|
+
if (role && !opts.roleEquivalent(actorId, role)) {
|
|
1360
|
+
return { ok: false,
|
|
1361
|
+
reason: "db-role mismatch: bound actor '" + actorId +
|
|
1362
|
+
"' is not equivalent to SQL role '" + role + "'" };
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
return { ok: true };
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* @primitive b.audit.bindActor
|
|
1370
|
+
* @signature b.audit.bindActor(actorId, opts)
|
|
1371
|
+
* @since 0.7.0
|
|
1372
|
+
* @compliance sox-404, soc2
|
|
1373
|
+
* @related b.audit.assertSegregation, b.audit.generateActorBindingTriggerSql
|
|
1374
|
+
*
|
|
1375
|
+
* Wrap `safeEmit` / `record` so any event whose `actor.userId` doesn't
|
|
1376
|
+
* match the bound id is refused (and an `audit.actor_binding.violation`
|
|
1377
|
+
* event is recorded under the bound actor). When `opts.roleEquivalent`
|
|
1378
|
+
* is provided and the caller is inside a `db-role-context.runWithRole`
|
|
1379
|
+
* scope, the SQL-bound role and bound actor must agree per the
|
|
1380
|
+
* operator-supplied mapping.
|
|
1381
|
+
*
|
|
1382
|
+
* Pair with `generateActorBindingTriggerSql()` for SQL-side enforcement
|
|
1383
|
+
* — application-layer binding catches typos; the trigger catches
|
|
1384
|
+
* privileged callers bypassing the framework.
|
|
1385
|
+
*
|
|
1386
|
+
* @opts
|
|
1387
|
+
* roleEquivalent: function (actorId, sqlRole) -> boolean,
|
|
1388
|
+
*
|
|
1389
|
+
* @example
|
|
1390
|
+
* var bound = b.audit.bindActor("u-42");
|
|
1391
|
+
* bound.safeEmit({
|
|
1392
|
+
* actor: { userId: "u-42" },
|
|
1393
|
+
* action: "orders.shipped",
|
|
1394
|
+
* outcome: "success",
|
|
1395
|
+
* });
|
|
1396
|
+
* bound.safeEmit({
|
|
1397
|
+
* actor: { userId: "u-other" },
|
|
1398
|
+
* action: "orders.shipped",
|
|
1399
|
+
* outcome: "success",
|
|
1400
|
+
* });
|
|
1401
|
+
* // → drops + records "audit.actor_binding.violation" under u-42
|
|
1402
|
+
*/
|
|
1403
|
+
function bindActor(actorId, opts) {
|
|
1404
|
+
if (typeof actorId !== "string" || actorId.length === 0) {
|
|
1405
|
+
throw new AuditSegregationError("audit/bind-actor-missing",
|
|
1406
|
+
"audit.bindActor: actorId must be a non-empty string");
|
|
1407
|
+
}
|
|
1408
|
+
opts = opts || {};
|
|
1409
|
+
function _violationEmit(eventAction, reason) {
|
|
1410
|
+
try {
|
|
1411
|
+
// Surface via the un-bound _ensureHandler so the violation row
|
|
1412
|
+
// lands in the chain regardless of bind state.
|
|
1413
|
+
_ensureHandler().emit({
|
|
1414
|
+
action: "audit.actor_binding.violation",
|
|
1415
|
+
outcome: "denied",
|
|
1416
|
+
actor: { userId: actorId },
|
|
1417
|
+
metadata: { attemptedAction: eventAction, reason: reason },
|
|
1418
|
+
});
|
|
1419
|
+
} catch (_e) { /* drop-silent — never break the caller */ }
|
|
1420
|
+
}
|
|
1421
|
+
function boundSafeEmit(event) {
|
|
1422
|
+
var rv = _checkActorBinding(actorId,
|
|
1423
|
+
event && event.actor && event.actor.userId, opts);
|
|
1424
|
+
if (rv !== true && !rv.ok) {
|
|
1425
|
+
_violationEmit(event && event.action, rv.reason);
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
safeEmit(event);
|
|
1429
|
+
}
|
|
1430
|
+
async function boundRecord(event) {
|
|
1431
|
+
var rv = _checkActorBinding(actorId,
|
|
1432
|
+
event && event.actor && event.actor.userId, opts);
|
|
1433
|
+
if (rv !== true && !rv.ok) {
|
|
1434
|
+
_violationEmit(event && event.action, rv.reason);
|
|
1435
|
+
throw new AuditSegregationError("audit/actor-binding-violation",
|
|
1436
|
+
"audit.bindActor.record: " + rv.reason);
|
|
1437
|
+
}
|
|
1438
|
+
return await record(event);
|
|
1439
|
+
}
|
|
1440
|
+
return {
|
|
1441
|
+
actorId: actorId,
|
|
1442
|
+
safeEmit: boundSafeEmit,
|
|
1443
|
+
record: boundRecord,
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// Trigger-SQL generator — operators apply the returned DDL via
|
|
1448
|
+
// b.externalDb.migrate so the database itself refuses INSERTs into
|
|
1449
|
+
// _blamejs_audit_log where the row's stored actor mismatches the
|
|
1450
|
+
// SQL session's current_user.
|
|
1451
|
+
//
|
|
1452
|
+
// opts.column — defaults to "actorUserId"; operators with a separate
|
|
1453
|
+
// role mapping table pass an explicit column name.
|
|
1454
|
+
// opts.roleMappingFn — Postgres function name that maps the row's
|
|
1455
|
+
// actorUserId to the expected SQL role; defaults to identity match
|
|
1456
|
+
// (current_user must equal the actorUserId).
|
|
1457
|
+
// opts.tableName — defaults to "_blamejs_audit_log".
|
|
1458
|
+
// opts.allowRoles — array of roles allowed to insert ANY actor (e.g.
|
|
1459
|
+
// the framework's own service account); skipped checks for those
|
|
1460
|
+
// roles.
|
|
1461
|
+
//
|
|
1462
|
+
// Returns { up: ddl, down: ddl } so the migration runner can install +
|
|
1463
|
+
// uninstall.
|
|
1464
|
+
/**
|
|
1465
|
+
* @primitive b.audit.generateActorBindingTriggerSql
|
|
1466
|
+
* @signature b.audit.generateActorBindingTriggerSql(opts)
|
|
1467
|
+
* @since 0.7.0
|
|
1468
|
+
* @compliance sox-404, soc2
|
|
1469
|
+
* @related b.audit.bindActor, b.audit.assertSegregation
|
|
1470
|
+
*
|
|
1471
|
+
* Emit Postgres trigger DDL that refuses INSERTs into the audit_log
|
|
1472
|
+
* table whose stored `actorUserId` column doesn't match the SQL
|
|
1473
|
+
* session's `current_user`. Operators apply the returned `up` script
|
|
1474
|
+
* via `b.externalDb.migrate` under sox-404 / soc2 posture so a
|
|
1475
|
+
* privileged caller (operator script, migration runner) can't write
|
|
1476
|
+
* audit rows under a different actor identity.
|
|
1477
|
+
*
|
|
1478
|
+
* Returns `{ up, down, functionName, triggerName }` for migration
|
|
1479
|
+
* runner symmetry.
|
|
1480
|
+
*
|
|
1481
|
+
* @opts
|
|
1482
|
+
* column: string, // default "actorUserId"
|
|
1483
|
+
* tableName: string, // default "_blamejs_audit_log"
|
|
1484
|
+
* roleMappingFn: string, // SQL fn name mapping actor → role
|
|
1485
|
+
* allowRoles: string[], // roles that bypass the check
|
|
1486
|
+
*
|
|
1487
|
+
* @example
|
|
1488
|
+
* var ddl = b.audit.generateActorBindingTriggerSql({
|
|
1489
|
+
* allowRoles: ["blamejs_service"],
|
|
1490
|
+
* });
|
|
1491
|
+
* await db.query(ddl.up);
|
|
1492
|
+
*/
|
|
1493
|
+
function generateActorBindingTriggerSql(opts) {
|
|
1494
|
+
opts = opts || {};
|
|
1495
|
+
var columnRaw = opts.column || "actorUserId";
|
|
1496
|
+
var tableNameRaw = opts.tableName || "_blamejs_audit_log";
|
|
1497
|
+
var allowRoles = Array.isArray(opts.allowRoles) ? opts.allowRoles : [];
|
|
1498
|
+
var fnNameRaw = "_blamejs_audit_actor_binding_check";
|
|
1499
|
+
var trigNameRaw = "_blamejs_audit_actor_binding_trig";
|
|
1500
|
+
// Quote-and-validate every identifier through safeSql.quoteIdentifier
|
|
1501
|
+
// so operator-supplied opts.column / opts.tableName / opts.roleMappingFn
|
|
1502
|
+
// can't reach raw concatenation. PostgreSQL + SQLite both use the
|
|
1503
|
+
// double-quote dialect.
|
|
1504
|
+
var qColumn = safeSql.quoteIdentifier(columnRaw, "postgres");
|
|
1505
|
+
var qTable = safeSql.quoteIdentifier(tableNameRaw, "postgres");
|
|
1506
|
+
var qFn = safeSql.quoteIdentifier(fnNameRaw, "postgres");
|
|
1507
|
+
var qTrig = safeSql.quoteIdentifier(trigNameRaw, "postgres");
|
|
1508
|
+
var qRoleMapFn = opts.roleMappingFn
|
|
1509
|
+
? safeSql.quoteIdentifier(opts.roleMappingFn, "postgres")
|
|
1510
|
+
: null;
|
|
1511
|
+
var allowList = allowRoles.length === 0 ? "" :
|
|
1512
|
+
" IF current_user IN (" +
|
|
1513
|
+
allowRoles.map(function (r) { return "'" + r.replace(/'/g, "''") + "'"; }).join(", ") +
|
|
1514
|
+
") THEN RETURN NEW; END IF;\n";
|
|
1515
|
+
var roleMatch = qRoleMapFn
|
|
1516
|
+
? " IF " + qRoleMapFn + "(NEW." + qColumn + ") IS DISTINCT FROM current_user THEN\n"
|
|
1517
|
+
: " IF NEW." + qColumn + " IS DISTINCT FROM current_user THEN\n";
|
|
1518
|
+
var up =
|
|
1519
|
+
"CREATE OR REPLACE FUNCTION " + qFn + "() RETURNS trigger AS $$\n" +
|
|
1520
|
+
"BEGIN\n" +
|
|
1521
|
+
allowList +
|
|
1522
|
+
roleMatch +
|
|
1523
|
+
" RAISE EXCEPTION 'segregation-of-duties violation: actor=% does not match current_user=%', NEW." + qColumn + ", current_user\n" +
|
|
1524
|
+
" USING ERRCODE = 'P0001';\n" +
|
|
1525
|
+
" END IF;\n" +
|
|
1526
|
+
" RETURN NEW;\n" +
|
|
1527
|
+
"END;\n" +
|
|
1528
|
+
"$$ LANGUAGE plpgsql;\n" +
|
|
1529
|
+
"DROP TRIGGER IF EXISTS " + qTrig + " ON " + qTable + ";\n" +
|
|
1530
|
+
"CREATE TRIGGER " + qTrig + "\n" +
|
|
1531
|
+
" BEFORE INSERT ON " + qTable + "\n" +
|
|
1532
|
+
" FOR EACH ROW EXECUTE FUNCTION " + qFn + "();\n";
|
|
1533
|
+
var down =
|
|
1534
|
+
"DROP TRIGGER IF EXISTS " + qTrig + " ON " + qTable + ";\n" +
|
|
1535
|
+
"DROP FUNCTION IF EXISTS " + qFn + "();\n";
|
|
1536
|
+
return { up: up, down: down, functionName: fnNameRaw, triggerName: trigNameRaw };
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
// Boot-time check operators wire under sox-404 / soc2 posture. Verifies
|
|
1540
|
+
// the trigger function + trigger row are present in the externalDb
|
|
1541
|
+
// information_schema. Returns { ok, missing? } so the caller decides
|
|
1542
|
+
// whether to refuse boot.
|
|
1543
|
+
/**
|
|
1544
|
+
* @primitive b.audit.assertSegregation
|
|
1545
|
+
* @signature b.audit.assertSegregation(opts)
|
|
1546
|
+
* @since 0.7.0
|
|
1547
|
+
* @compliance sox-404, soc2
|
|
1548
|
+
* @related b.audit.generateActorBindingTriggerSql, b.audit.bindActor
|
|
1549
|
+
*
|
|
1550
|
+
* Boot-time check that confirms the actor-binding trigger function and
|
|
1551
|
+
* trigger row exist in the externalDb's `pg_proc` / `pg_trigger`
|
|
1552
|
+
* catalogs. Throws `AuditSegregationError` with the missing artifacts
|
|
1553
|
+
* named when either is absent — operators wire this into the
|
|
1554
|
+
* sox-404 / soc2 boot sequence so a forgotten migration refuses-to-boot
|
|
1555
|
+
* instead of silently shipping without enforcement.
|
|
1556
|
+
*
|
|
1557
|
+
* @opts
|
|
1558
|
+
* db: { query(sql, params) -> { rows } }, // required
|
|
1559
|
+
* functionName: string,
|
|
1560
|
+
* triggerName: string,
|
|
1561
|
+
*
|
|
1562
|
+
* @example
|
|
1563
|
+
* await b.audit.assertSegregation({ db: externalDb });
|
|
1564
|
+
* // throws if the trigger DDL hasn't been applied
|
|
1565
|
+
*/
|
|
1566
|
+
async function assertSegregation(opts) {
|
|
1567
|
+
opts = opts || {};
|
|
1568
|
+
var db = opts.db || null;
|
|
1569
|
+
if (!db || typeof db.query !== "function") {
|
|
1570
|
+
throw new AuditSegregationError("audit/segregation-no-db",
|
|
1571
|
+
"audit.assertSegregation: opts.db with a query() method is required");
|
|
1572
|
+
}
|
|
1573
|
+
var fnName = opts.functionName || "_blamejs_audit_actor_binding_check";
|
|
1574
|
+
var trigName = opts.triggerName || "_blamejs_audit_actor_binding_trig";
|
|
1575
|
+
var fnRes = await db.query(
|
|
1576
|
+
"SELECT 1 FROM pg_proc WHERE proname = $1 LIMIT 1", [fnName]
|
|
1577
|
+
);
|
|
1578
|
+
var fnPresent = !!(fnRes && fnRes.rows && fnRes.rows.length > 0);
|
|
1579
|
+
var trigRes = await db.query(
|
|
1580
|
+
"SELECT 1 FROM pg_trigger WHERE tgname = $1 LIMIT 1", [trigName]
|
|
1581
|
+
);
|
|
1582
|
+
var trigPresent = !!(trigRes && trigRes.rows && trigRes.rows.length > 0);
|
|
1583
|
+
var missing = [];
|
|
1584
|
+
if (!fnPresent) missing.push("function:" + fnName);
|
|
1585
|
+
if (!trigPresent) missing.push("trigger:" + trigName);
|
|
1586
|
+
var ok = missing.length === 0;
|
|
1587
|
+
if (!ok) {
|
|
1588
|
+
safeEmit({
|
|
1589
|
+
action: "audit.actor_binding.violation",
|
|
1590
|
+
outcome: "denied",
|
|
1591
|
+
metadata: {
|
|
1592
|
+
reason: "boot-time segregation check failed",
|
|
1593
|
+
missing: missing,
|
|
1594
|
+
},
|
|
1595
|
+
});
|
|
1596
|
+
throw new AuditSegregationError("audit/segregation-not-installed",
|
|
1597
|
+
"audit.assertSegregation: SQL-side actor-binding trigger missing — " +
|
|
1598
|
+
"apply the DDL from audit.generateActorBindingTriggerSql() under sox-404 / soc2 posture. " +
|
|
1599
|
+
"Missing: " + missing.join(", "));
|
|
1600
|
+
}
|
|
1601
|
+
return { ok: ok, missing: missing };
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// applyPosture — F-POSTURE-1 cascade hook. b.compliance.set(posture)
|
|
1605
|
+
// calls this to record the active posture so audit emissions can
|
|
1606
|
+
// surface the regulatory regime in metadata where downstream tooling
|
|
1607
|
+
// (forensic export, SIEM correlation) needs it. The chain itself is
|
|
1608
|
+
// posture-agnostic (every posture audits with the same SLH-DSA-SHAKE-
|
|
1609
|
+
// 256f signing key); this hook captures the posture name so query()
|
|
1610
|
+
// callers that filter by-posture have a stable column to look at.
|
|
1611
|
+
var _activePosture = null;
|
|
1612
|
+
/**
|
|
1613
|
+
* @primitive b.audit.applyPosture
|
|
1614
|
+
* @signature b.audit.applyPosture(posture)
|
|
1615
|
+
* @since 0.7.27
|
|
1616
|
+
* @compliance hipaa, pci-dss, gdpr, soc2, sox-404
|
|
1617
|
+
* @related b.audit.activePosture, b.compliance
|
|
1618
|
+
*
|
|
1619
|
+
* Cascade hook called by `b.compliance.set(posture)` to record the
|
|
1620
|
+
* active regulatory regime. The chain itself is posture-agnostic —
|
|
1621
|
+
* every posture audits with the same SLH-DSA-SHAKE-256f signing key —
|
|
1622
|
+
* but downstream tooling (forensic export, SIEM correlation) reads the
|
|
1623
|
+
* stored posture to filter / route. Returns `{ posture }` on accept,
|
|
1624
|
+
* `null` on a non-string / empty argument.
|
|
1625
|
+
*
|
|
1626
|
+
* @example
|
|
1627
|
+
* b.audit.applyPosture("hipaa");
|
|
1628
|
+
* b.audit.activePosture(); // → "hipaa"
|
|
1629
|
+
*/
|
|
1630
|
+
function applyPosture(posture) {
|
|
1631
|
+
if (typeof posture !== "string" || posture.length === 0) return null;
|
|
1632
|
+
_activePosture = posture;
|
|
1633
|
+
return { posture: posture };
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* @primitive b.audit.activePosture
|
|
1637
|
+
* @signature b.audit.activePosture()
|
|
1638
|
+
* @since 0.7.27
|
|
1639
|
+
* @related b.audit.applyPosture
|
|
1640
|
+
*
|
|
1641
|
+
* Return the posture string most recently passed to `applyPosture()`,
|
|
1642
|
+
* or `null` if none has been set. Read-only accessor for downstream
|
|
1643
|
+
* tooling that wants to tag audit-derived artifacts with the regime.
|
|
1644
|
+
*
|
|
1645
|
+
* @example
|
|
1646
|
+
* b.audit.applyPosture("pci-dss");
|
|
1647
|
+
* b.audit.activePosture(); // → "pci-dss"
|
|
1648
|
+
*/
|
|
1649
|
+
function activePosture() { return _activePosture; }
|
|
1650
|
+
|
|
1651
|
+
module.exports = {
|
|
1652
|
+
registerNamespace: registerNamespace,
|
|
1653
|
+
record: record,
|
|
1654
|
+
useStore: useStore,
|
|
1655
|
+
emit: emit,
|
|
1656
|
+
safeEmit: safeEmit,
|
|
1657
|
+
applyPosture: applyPosture,
|
|
1658
|
+
activePosture: activePosture,
|
|
1659
|
+
bindActor: bindActor,
|
|
1660
|
+
assertSegregation: assertSegregation,
|
|
1661
|
+
generateActorBindingTriggerSql: generateActorBindingTriggerSql,
|
|
1662
|
+
flush: flush,
|
|
1663
|
+
query: query,
|
|
1664
|
+
verify: verify,
|
|
1665
|
+
beginTrace: beginTrace,
|
|
1666
|
+
checkpoint: checkpoint,
|
|
1667
|
+
verifyCheckpoints: verifyCheckpoints,
|
|
1668
|
+
CHECKPOINT_FORMAT: CHECKPOINT_FORMAT,
|
|
1669
|
+
FRAMEWORK_NAMESPACES: FRAMEWORK_NAMESPACES,
|
|
1670
|
+
_resetForTest: _resetForTest,
|
|
1671
|
+
};
|