@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,2328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* cli — the engine behind `blamejs` on the command line.
|
|
4
|
+
*
|
|
5
|
+
* bin/blamejs.js is a 4-line shim that calls cli.main(process.argv.slice(2)).
|
|
6
|
+
* Putting the dispatch logic in lib/ means tests drive it without
|
|
7
|
+
* spawning a child process: pass argv + a captured-output writer +
|
|
8
|
+
* env, get an exit code back.
|
|
9
|
+
*
|
|
10
|
+
* var cli = b.cli;
|
|
11
|
+
* var captured = { out: "", err: "" };
|
|
12
|
+
* var rc = await cli.main(["migrate", "status", "--db", "./test.db"], {
|
|
13
|
+
* stdout: { write: function (s) { captured.out += s; } },
|
|
14
|
+
* stderr: { write: function (s) { captured.err += s; } },
|
|
15
|
+
* env: {},
|
|
16
|
+
* cwd: "/repo",
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* Subcommands ship one at a time as the framework grows. The
|
|
20
|
+
* dispatch table is the registry — adding `vault rotate`, `audit verify`,
|
|
21
|
+
* `subject export` etc. lands as new entries here, not new bin scripts.
|
|
22
|
+
*
|
|
23
|
+
* Currently shipped:
|
|
24
|
+
* blamejs migrate up --db <path> [--dir <path>]
|
|
25
|
+
* blamejs migrate down --db <path> [--dir <path>] [--steps N]
|
|
26
|
+
* blamejs migrate status --db <path> [--dir <path>]
|
|
27
|
+
* blamejs dev --command <cmd> [--watch <dir>...] [--grace-ms N]
|
|
28
|
+
* blamejs version
|
|
29
|
+
* blamejs help [<command>]
|
|
30
|
+
*
|
|
31
|
+
* The migrate command operates against a node:sqlite file directly —
|
|
32
|
+
* no vault / framework bootstrap. Encrypted-at-rest dbs are out of
|
|
33
|
+
* scope for this slice; operators with that mode either run migrations
|
|
34
|
+
* before encryption or temporarily switch the file to plaintext.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
var nodeFs = require("node:fs");
|
|
38
|
+
var os = require("node:os");
|
|
39
|
+
var nodePath = require("node:path");
|
|
40
|
+
var apiSnapshot = require("./api-snapshot");
|
|
41
|
+
var argParser = require("./arg-parser");
|
|
42
|
+
var auditChain = require("./audit-chain");
|
|
43
|
+
var auditTools = require("./audit-tools");
|
|
44
|
+
var backup = require("./backup");
|
|
45
|
+
var canonicalJson = require("./canonical-json");
|
|
46
|
+
var cliHelpers = require("./cli-helpers");
|
|
47
|
+
var C = require("./constants");
|
|
48
|
+
var bCrypto = require("./crypto");
|
|
49
|
+
var dev = require("./dev");
|
|
50
|
+
var fileType = require("./file-type");
|
|
51
|
+
var guardRegex = require("./guard-regex");
|
|
52
|
+
var migrations = require("./migrations");
|
|
53
|
+
var passwordModule = require("./auth/password");
|
|
54
|
+
var requestHelpers = require("./request-helpers");
|
|
55
|
+
var restore = require("./restore");
|
|
56
|
+
var restoreBundle = require("./restore-bundle");
|
|
57
|
+
var restoreRollback = require("./restore-rollback");
|
|
58
|
+
var seeders = require("./seeders");
|
|
59
|
+
var vaultPassphraseOps = require("./vault/passphrase-ops");
|
|
60
|
+
var { defineClass } = require("./framework-error");
|
|
61
|
+
|
|
62
|
+
var CliError = defineClass("CliError", { alwaysPermanent: true });
|
|
63
|
+
|
|
64
|
+
// Maximum length for an operator-supplied --ignore regex pattern. Caps
|
|
65
|
+
// ReDoS surface area: a multi-megabyte pattern compiled to a regex
|
|
66
|
+
// would already be a footgun, so refuse anything beyond the cap.
|
|
67
|
+
var MAX_IGNORE_PATTERN_LENGTH = 0x100;
|
|
68
|
+
|
|
69
|
+
var DEFAULT_MIG_DIR = "./migrations";
|
|
70
|
+
var DEFAULT_SEED_DIR = "./seeders";
|
|
71
|
+
|
|
72
|
+
function _writeLine(stream, line) {
|
|
73
|
+
if (!stream || typeof stream.write !== "function") return;
|
|
74
|
+
stream.write(line + "\n");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Minimal argv parser: positional args + flag map. Supports both
|
|
78
|
+
// `--flag value` and `--flag=value`. Single-dash forms (-v) treated
|
|
79
|
+
// as long aliases to keep the surface predictable. Routed through the
|
|
80
|
+
// reusable b.argParser.parseRaw primitive — every subcommand's hand-
|
|
81
|
+
// written flag validation continues to read the same { pos, flags }
|
|
82
|
+
// shape the cli has always exposed.
|
|
83
|
+
function _parseArgs(argv) {
|
|
84
|
+
return argParser.parseRaw(argv);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function _resolvePath(p, cwd) {
|
|
88
|
+
if (!p) return p;
|
|
89
|
+
if (nodePath.isAbsolute(p)) return p;
|
|
90
|
+
return nodePath.resolve(cwd || process.cwd(), p);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function _openSqlite(dbPath) {
|
|
94
|
+
// Lazy-required so the CLI doesn't crash on `blamejs version` or
|
|
95
|
+
// `blamejs help` if node:sqlite isn't usable for some reason.
|
|
96
|
+
var { DatabaseSync } = require("node:sqlite");
|
|
97
|
+
return new DatabaseSync(dbPath);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ---- Subcommand: migrate ----
|
|
101
|
+
|
|
102
|
+
var MIGRATE_USAGE = [
|
|
103
|
+
"Usage: blamejs migrate <subcommand> [flags]",
|
|
104
|
+
"",
|
|
105
|
+
"Subcommands:",
|
|
106
|
+
" up Apply all pending migrations",
|
|
107
|
+
" down Roll back the most-recent applied migration",
|
|
108
|
+
" status Print applied + pending migrations",
|
|
109
|
+
"",
|
|
110
|
+
"Flags:",
|
|
111
|
+
" --db <path> Path to the SQLite database file (required)",
|
|
112
|
+
" --dir <path> Path to migrations directory (default ./migrations)",
|
|
113
|
+
" --steps <N> For down: number of migrations to revert (default 1)",
|
|
114
|
+
].join("\n");
|
|
115
|
+
|
|
116
|
+
async function _runMigrate(args, ctx) {
|
|
117
|
+
if (args.pos.length === 0) {
|
|
118
|
+
_writeLine(ctx.stderr, MIGRATE_USAGE);
|
|
119
|
+
return 2;
|
|
120
|
+
}
|
|
121
|
+
var sub = args.pos[0];
|
|
122
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
123
|
+
_writeLine(ctx.stdout, MIGRATE_USAGE);
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
if (sub !== "up" && sub !== "down" && sub !== "status") {
|
|
127
|
+
_writeLine(ctx.stderr, "blamejs migrate: unknown subcommand '" + sub + "'");
|
|
128
|
+
_writeLine(ctx.stderr, MIGRATE_USAGE);
|
|
129
|
+
return 2;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var dbPath = args.flags.db;
|
|
133
|
+
if (!dbPath || dbPath === true) {
|
|
134
|
+
_writeLine(ctx.stderr, "blamejs migrate " + sub + ": --db <path> is required");
|
|
135
|
+
return 2;
|
|
136
|
+
}
|
|
137
|
+
dbPath = _resolvePath(String(dbPath), ctx.cwd);
|
|
138
|
+
|
|
139
|
+
var dir = _resolvePath(String(args.flags.dir || DEFAULT_MIG_DIR), ctx.cwd);
|
|
140
|
+
|
|
141
|
+
var db;
|
|
142
|
+
try { db = _openSqlite(dbPath); }
|
|
143
|
+
catch (e) {
|
|
144
|
+
_writeLine(ctx.stderr, "blamejs migrate: cannot open db at " + dbPath +
|
|
145
|
+
": " + ((e && e.message) || String(e)));
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
var runner = migrations.create({ db: db, dir: dir });
|
|
151
|
+
|
|
152
|
+
if (sub === "status") {
|
|
153
|
+
var s = runner.status();
|
|
154
|
+
_writeLine(ctx.stdout, "applied: " + s.applied.length + " / " + s.total);
|
|
155
|
+
for (var i = 0; i < s.applied.length; i++) {
|
|
156
|
+
_writeLine(ctx.stdout, " ✓ " + s.applied[i].name +
|
|
157
|
+
" (applied " + s.applied[i].appliedAt + ")");
|
|
158
|
+
}
|
|
159
|
+
_writeLine(ctx.stdout, "pending: " + s.pending.length);
|
|
160
|
+
for (var j = 0; j < s.pending.length; j++) {
|
|
161
|
+
_writeLine(ctx.stdout, " · " + s.pending[j]);
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (sub === "up") {
|
|
167
|
+
var r = runner.up();
|
|
168
|
+
if (r.applied.length === 0) {
|
|
169
|
+
_writeLine(ctx.stdout, "no pending migrations (" + r.skipped.length + " already applied)");
|
|
170
|
+
} else {
|
|
171
|
+
_writeLine(ctx.stdout, "applied " + r.applied.length + " migration(s):");
|
|
172
|
+
for (var k = 0; k < r.applied.length; k++) {
|
|
173
|
+
_writeLine(ctx.stdout, " ✓ " + r.applied[k]);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (sub === "down") {
|
|
180
|
+
var steps = args.flags.steps === undefined ? 1 : Number(args.flags.steps);
|
|
181
|
+
if (!Number.isFinite(steps) || steps < 1 || Math.floor(steps) !== steps) {
|
|
182
|
+
_writeLine(ctx.stderr, "blamejs migrate down: --steps must be a positive integer");
|
|
183
|
+
return 2;
|
|
184
|
+
}
|
|
185
|
+
var rd = runner.down({ steps: steps });
|
|
186
|
+
if (rd.reverted.length === 0) {
|
|
187
|
+
_writeLine(ctx.stdout, "nothing to revert");
|
|
188
|
+
} else {
|
|
189
|
+
_writeLine(ctx.stdout, "reverted " + rd.reverted.length + " migration(s):");
|
|
190
|
+
for (var m = 0; m < rd.reverted.length; m++) {
|
|
191
|
+
_writeLine(ctx.stdout, " ↶ " + rd.reverted[m]);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
} catch (e) {
|
|
197
|
+
var msg = (e && e.message) || String(e);
|
|
198
|
+
var code = (e && e.code) || "ERROR";
|
|
199
|
+
_writeLine(ctx.stderr, "blamejs migrate " + sub + ": " + code + ": " + msg);
|
|
200
|
+
return 1;
|
|
201
|
+
} finally {
|
|
202
|
+
try { db.close(); } catch (_e) { /* close best-effort */ }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ---- Subcommand: seed ----
|
|
209
|
+
|
|
210
|
+
var SEED_USAGE = [
|
|
211
|
+
"Usage: blamejs seed <subcommand> [flags]",
|
|
212
|
+
"",
|
|
213
|
+
"Subcommands:",
|
|
214
|
+
" run Apply pending seeds for the given env",
|
|
215
|
+
" status Print applied + pending seeds for the given env",
|
|
216
|
+
"",
|
|
217
|
+
"Flags:",
|
|
218
|
+
" --db <path> Path to the SQLite database file [required]",
|
|
219
|
+
" --env <name> Environment to seed (dev / test / prod / ...) [required]",
|
|
220
|
+
" --dir <path> Path to seeders directory (default ./seeders)",
|
|
221
|
+
" --only <name> Apply just one seed by filename (run subcommand only)",
|
|
222
|
+
" --force Re-apply already-applied seeds (operator-explicit)",
|
|
223
|
+
].join("\n");
|
|
224
|
+
|
|
225
|
+
async function _runSeed(args, ctx) {
|
|
226
|
+
if (args.pos.length === 0) {
|
|
227
|
+
_writeLine(ctx.stderr, SEED_USAGE);
|
|
228
|
+
return 2;
|
|
229
|
+
}
|
|
230
|
+
var sub = args.pos[0];
|
|
231
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
232
|
+
_writeLine(ctx.stdout, SEED_USAGE);
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
if (sub !== "run" && sub !== "status") {
|
|
236
|
+
_writeLine(ctx.stderr, "blamejs seed: unknown subcommand '" + sub + "'");
|
|
237
|
+
_writeLine(ctx.stderr, SEED_USAGE);
|
|
238
|
+
return 2;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
var dbPath = args.flags.db;
|
|
242
|
+
if (!dbPath || dbPath === true) {
|
|
243
|
+
_writeLine(ctx.stderr, "blamejs seed " + sub + ": --db <path> is required");
|
|
244
|
+
return 2;
|
|
245
|
+
}
|
|
246
|
+
dbPath = _resolvePath(String(dbPath), ctx.cwd);
|
|
247
|
+
|
|
248
|
+
var env = args.flags.env;
|
|
249
|
+
if (!env || env === true) {
|
|
250
|
+
_writeLine(ctx.stderr, "blamejs seed " + sub + ": --env <name> is required");
|
|
251
|
+
return 2;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
var dir = _resolvePath(String(args.flags.dir || DEFAULT_SEED_DIR), ctx.cwd);
|
|
255
|
+
|
|
256
|
+
var db;
|
|
257
|
+
try { db = _openSqlite(dbPath); }
|
|
258
|
+
catch (e) {
|
|
259
|
+
_writeLine(ctx.stderr, "blamejs seed: cannot open db at " + dbPath +
|
|
260
|
+
": " + ((e && e.message) || String(e)));
|
|
261
|
+
return 1;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
var runner = seeders.create({ db: db, dir: dir });
|
|
266
|
+
|
|
267
|
+
if (sub === "status") {
|
|
268
|
+
var s = await runner.status({ env: String(env) });
|
|
269
|
+
_writeLine(ctx.stdout, "env: " + s.env);
|
|
270
|
+
_writeLine(ctx.stdout, "applied: " + s.applied.length + " / " + s.total);
|
|
271
|
+
for (var i = 0; i < s.applied.length; i++) {
|
|
272
|
+
_writeLine(ctx.stdout, " ✓ " + s.applied[i].name +
|
|
273
|
+
" (applied " + s.applied[i].appliedAt + ")");
|
|
274
|
+
}
|
|
275
|
+
_writeLine(ctx.stdout, "pending: " + s.pending.length);
|
|
276
|
+
for (var j = 0; j < s.pending.length; j++) {
|
|
277
|
+
_writeLine(ctx.stdout, " · " + s.pending[j]);
|
|
278
|
+
}
|
|
279
|
+
if (s.rerunnable.length > 0) {
|
|
280
|
+
_writeLine(ctx.stdout, "rerunnable: " + s.rerunnable.length);
|
|
281
|
+
for (var k = 0; k < s.rerunnable.length; k++) {
|
|
282
|
+
_writeLine(ctx.stdout, " ↻ " + s.rerunnable[k]);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (sub === "run") {
|
|
289
|
+
var only = args.flags.only ? String(args.flags.only) : undefined;
|
|
290
|
+
var force = !!args.flags.force;
|
|
291
|
+
var r = await runner.run({ env: String(env), only: only, force: force });
|
|
292
|
+
if (r.applied.length === 0) {
|
|
293
|
+
_writeLine(ctx.stdout, "no seeds applied (" + r.skipped.length + " skipped)");
|
|
294
|
+
} else {
|
|
295
|
+
_writeLine(ctx.stdout, "applied " + r.applied.length + " seed(s):");
|
|
296
|
+
for (var m = 0; m < r.applied.length; m++) {
|
|
297
|
+
_writeLine(ctx.stdout, " ✓ " + r.applied[m]);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (r.skipped.length > 0) {
|
|
301
|
+
_writeLine(ctx.stdout, "skipped " + r.skipped.length + " (already applied)");
|
|
302
|
+
}
|
|
303
|
+
return 0;
|
|
304
|
+
}
|
|
305
|
+
} catch (e) {
|
|
306
|
+
var msg = (e && e.message) || String(e);
|
|
307
|
+
var code = (e && e.code) || "ERROR";
|
|
308
|
+
_writeLine(ctx.stderr, "blamejs seed " + sub + ": " + code + ": " + msg);
|
|
309
|
+
return 1;
|
|
310
|
+
} finally {
|
|
311
|
+
try { db.close(); } catch (_e) { /* close best-effort */ }
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return 0;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ---- Subcommand: dev ----
|
|
318
|
+
|
|
319
|
+
var DEV_USAGE = [
|
|
320
|
+
"Usage: blamejs dev --command <cmd> [args] [flags]",
|
|
321
|
+
"",
|
|
322
|
+
"Spawn a child process and restart it on file changes.",
|
|
323
|
+
"",
|
|
324
|
+
"Flags:",
|
|
325
|
+
" --command <cmd> Program to spawn (e.g. node) [required]",
|
|
326
|
+
" --arg <value> Argument for the spawned program (repeatable)",
|
|
327
|
+
" --watch <dir> Directory to watch (repeatable; default '.')",
|
|
328
|
+
" --ignore <pattern> Glob/regex fragment to ignore (repeatable)",
|
|
329
|
+
" --grace-ms <N> Debounce window in ms (default 250)",
|
|
330
|
+
" --kill-signal <S> Signal to send on restart (default SIGTERM)",
|
|
331
|
+
"",
|
|
332
|
+
"Example:",
|
|
333
|
+
" blamejs dev --command node --arg ./server.js --watch ./routes --watch ./views",
|
|
334
|
+
].join("\n");
|
|
335
|
+
|
|
336
|
+
function _coerceList(val) {
|
|
337
|
+
if (val === undefined || val === null) return [];
|
|
338
|
+
return Array.isArray(val) ? val.slice() : [val];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function _runDev(args, ctx) {
|
|
342
|
+
if (args.flags.help || args.flags.h) {
|
|
343
|
+
_writeLine(ctx.stdout, DEV_USAGE);
|
|
344
|
+
return 0;
|
|
345
|
+
}
|
|
346
|
+
var command = args.flags.command;
|
|
347
|
+
if (!command || command === true) {
|
|
348
|
+
_writeLine(ctx.stderr, "blamejs dev: --command <cmd> is required");
|
|
349
|
+
_writeLine(ctx.stderr, DEV_USAGE);
|
|
350
|
+
return 2;
|
|
351
|
+
}
|
|
352
|
+
var argList = _coerceList(args.flags.arg).map(String);
|
|
353
|
+
var watchList = _coerceList(args.flags.watch).map(String);
|
|
354
|
+
var ignoreList = _coerceList(args.flags.ignore).map(function (s) {
|
|
355
|
+
var str = String(s);
|
|
356
|
+
if (str.length > MAX_IGNORE_PATTERN_LENGTH) {
|
|
357
|
+
throw new CliError("cli/bad-ignore-pattern",
|
|
358
|
+
"blamejs dev: --ignore pattern exceeds max length " +
|
|
359
|
+
MAX_IGNORE_PATTERN_LENGTH + " (got " + str.length + ")");
|
|
360
|
+
}
|
|
361
|
+
// ReDoS / catastrophic-backtracking defense — refuses nested-quant
|
|
362
|
+
// (CVE-2024-21538 class), consecutive-* (CVE-2026-26996), nested
|
|
363
|
+
// extglob (CVE-2026-33671), and lookaround-quant shapes before the
|
|
364
|
+
// pattern reaches RegExp(). Operator typo / hostile-input identical
|
|
365
|
+
// shape from here on — both want the same refusal.
|
|
366
|
+
try {
|
|
367
|
+
guardRegex.sanitize(str, { profile: "strict" });
|
|
368
|
+
} catch (e) {
|
|
369
|
+
throw new CliError("cli/bad-ignore-pattern",
|
|
370
|
+
"blamejs dev: --ignore pattern refused by guardRegex: " +
|
|
371
|
+
((e && e.message) || String(e)));
|
|
372
|
+
}
|
|
373
|
+
return RegExp(str);
|
|
374
|
+
});
|
|
375
|
+
var graceMs = args.flags["grace-ms"] !== undefined ? Number(args.flags["grace-ms"]) : undefined;
|
|
376
|
+
if (graceMs !== undefined && (!Number.isFinite(graceMs) || graceMs < 0)) {
|
|
377
|
+
_writeLine(ctx.stderr, "blamejs dev: --grace-ms must be a non-negative number");
|
|
378
|
+
return 2;
|
|
379
|
+
}
|
|
380
|
+
var killSignal = args.flags["kill-signal"];
|
|
381
|
+
|
|
382
|
+
var d = dev.create({
|
|
383
|
+
command: String(command),
|
|
384
|
+
args: argList,
|
|
385
|
+
watch: watchList.length ? watchList : undefined,
|
|
386
|
+
ignore: ignoreList.length ? ignoreList : undefined,
|
|
387
|
+
graceMs: graceMs,
|
|
388
|
+
killSignal: typeof killSignal === "string" ? killSignal : undefined,
|
|
389
|
+
cwd: ctx.cwd,
|
|
390
|
+
env: ctx.env,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Forward parent SIGINT/SIGTERM to the child via stop()
|
|
394
|
+
var stopped = false;
|
|
395
|
+
function shutdown() {
|
|
396
|
+
if (stopped) return;
|
|
397
|
+
stopped = true;
|
|
398
|
+
d.stop().then(function () { /* exit naturally */ });
|
|
399
|
+
}
|
|
400
|
+
process.once("SIGINT", shutdown);
|
|
401
|
+
process.once("SIGTERM", shutdown);
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
await d.start();
|
|
405
|
+
} catch (e) {
|
|
406
|
+
_writeLine(ctx.stderr, "blamejs dev: " + ((e && e.message) || String(e)));
|
|
407
|
+
return 1;
|
|
408
|
+
}
|
|
409
|
+
// The dev loop runs until the operator interrupts. Resolve a
|
|
410
|
+
// never-settling promise so main() awaits forever; the SIGINT handler
|
|
411
|
+
// above flips stopped+resolves on Ctrl-C.
|
|
412
|
+
await new Promise(function (resolve) {
|
|
413
|
+
var iv = setInterval(function () {
|
|
414
|
+
if (stopped) { clearInterval(iv); resolve(); }
|
|
415
|
+
}, 250);
|
|
416
|
+
if (typeof iv.unref === "function") iv.unref();
|
|
417
|
+
});
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ---- Subcommand: api-snapshot ----
|
|
422
|
+
|
|
423
|
+
var API_SNAPSHOT_USAGE = [
|
|
424
|
+
"Usage: blamejs api-snapshot <subcommand> [flags]",
|
|
425
|
+
"",
|
|
426
|
+
"Subcommands:",
|
|
427
|
+
" capture Walk the framework's public surface and write a snapshot",
|
|
428
|
+
" compare Diff the current surface against a saved snapshot",
|
|
429
|
+
"",
|
|
430
|
+
"Flags:",
|
|
431
|
+
" --file <path> Snapshot file path (default ./api-snapshot.json)",
|
|
432
|
+
" --module <path> Module to inspect (default require('@blamejs/core'))",
|
|
433
|
+
"",
|
|
434
|
+
"Exit codes:",
|
|
435
|
+
" 0 no changes (compare) or write succeeded (capture)",
|
|
436
|
+
" 1 breaking changes detected (compare)",
|
|
437
|
+
" 2 bad invocation",
|
|
438
|
+
].join("\n");
|
|
439
|
+
|
|
440
|
+
function _resolveTargetModule(modulePath, ctx) {
|
|
441
|
+
// Default: load index.js from the framework root (one level up from lib/cli.js).
|
|
442
|
+
// Dynamic require by design — the CLI loads either the framework root index.js
|
|
443
|
+
// or an operator-supplied module path from the command line. Operator-
|
|
444
|
+
// extensibility surfaces by definition can't be statically traced by a
|
|
445
|
+
// bundler — anyone bundling this CLI surface into SEA/pkg accepts that
|
|
446
|
+
// runtime --module=<path> arguments won't resolve. Internal framework
|
|
447
|
+
// code never reaches this nodePath.
|
|
448
|
+
if (!modulePath) {
|
|
449
|
+
var root = nodePath.resolve(__dirname, "..");
|
|
450
|
+
return require(nodePath.join(root, "index.js")); // allow:dynamic-require — operator-extensibility entry point
|
|
451
|
+
}
|
|
452
|
+
var abs = nodePath.isAbsolute(modulePath) ? modulePath : nodePath.resolve(ctx.cwd, modulePath);
|
|
453
|
+
delete require.cache[require.resolve(abs)];
|
|
454
|
+
return require(abs); // allow:dynamic-require — operator-extensibility entry point
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function _runApiSnapshot(args, ctx) {
|
|
458
|
+
if (args.flags.help || args.flags.h) {
|
|
459
|
+
_writeLine(ctx.stdout, API_SNAPSHOT_USAGE);
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
462
|
+
if (args.pos.length === 0) {
|
|
463
|
+
_writeLine(ctx.stderr, API_SNAPSHOT_USAGE);
|
|
464
|
+
return 2;
|
|
465
|
+
}
|
|
466
|
+
var sub = args.pos[0];
|
|
467
|
+
var file = String(args.flags.file || "./api-snapshot.json");
|
|
468
|
+
var filePath = nodePath.isAbsolute(file) ? file : nodePath.resolve(ctx.cwd, file);
|
|
469
|
+
var modulePathOpt = typeof args.flags.module === "string" ? args.flags.module : null;
|
|
470
|
+
|
|
471
|
+
if (sub === "capture") {
|
|
472
|
+
var target;
|
|
473
|
+
try { target = _resolveTargetModule(modulePathOpt, ctx); }
|
|
474
|
+
catch (e) {
|
|
475
|
+
_writeLine(ctx.stderr, "blamejs api-snapshot capture: cannot load module: " +
|
|
476
|
+
((e && e.message) || String(e)));
|
|
477
|
+
return 1;
|
|
478
|
+
}
|
|
479
|
+
var snap;
|
|
480
|
+
try { snap = apiSnapshot.capture(target); }
|
|
481
|
+
catch (e) {
|
|
482
|
+
_writeLine(ctx.stderr, "blamejs api-snapshot capture: " +
|
|
483
|
+
((e && e.message) || String(e)));
|
|
484
|
+
return 1;
|
|
485
|
+
}
|
|
486
|
+
apiSnapshot.write(snap, filePath);
|
|
487
|
+
_writeLine(ctx.stdout, "wrote snapshot to " + filePath +
|
|
488
|
+
" (frameworkVersion " + snap.frameworkVersion + ")");
|
|
489
|
+
return 0;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (sub === "compare") {
|
|
493
|
+
var loaded;
|
|
494
|
+
try { loaded = apiSnapshot.read(filePath); }
|
|
495
|
+
catch (e) {
|
|
496
|
+
_writeLine(ctx.stderr, "blamejs api-snapshot compare: " +
|
|
497
|
+
((e && e.message) || String(e)));
|
|
498
|
+
return 1;
|
|
499
|
+
}
|
|
500
|
+
var current;
|
|
501
|
+
try {
|
|
502
|
+
var t = _resolveTargetModule(modulePathOpt, ctx);
|
|
503
|
+
current = apiSnapshot.capture(t);
|
|
504
|
+
} catch (e) {
|
|
505
|
+
_writeLine(ctx.stderr, "blamejs api-snapshot compare: cannot capture current surface: " +
|
|
506
|
+
((e && e.message) || String(e)));
|
|
507
|
+
return 1;
|
|
508
|
+
}
|
|
509
|
+
var diff = apiSnapshot.compare(loaded, current);
|
|
510
|
+
_writeLine(ctx.stdout, apiSnapshot.formatDiff(diff));
|
|
511
|
+
if (diff.breaking.length > 0) return 1;
|
|
512
|
+
return 0;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
_writeLine(ctx.stderr, "blamejs api-snapshot: unknown subcommand '" + sub + "'");
|
|
516
|
+
_writeLine(ctx.stderr, API_SNAPSHOT_USAGE);
|
|
517
|
+
return 2;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// ---- Subcommand: audit ----
|
|
521
|
+
//
|
|
522
|
+
// Operator tooling on top of the audit chain. Programmatic API is at
|
|
523
|
+
// b.auditTools — the CLI is a thin wrapper that's easier to script
|
|
524
|
+
// against from operator runbooks (cron, retention pipelines, etc.).
|
|
525
|
+
|
|
526
|
+
var AUDIT_USAGE = [
|
|
527
|
+
"Usage: blamejs audit <subcommand> [flags]",
|
|
528
|
+
"",
|
|
529
|
+
"Subcommands:",
|
|
530
|
+
" archive Bundle audit rows older than --before into a verified archive",
|
|
531
|
+
" export Auditor evidence bundle for a date range",
|
|
532
|
+
" verify-bundle Round-trip integrity check on an archive or export bundle",
|
|
533
|
+
" verify-chain Walk the live audit chain end-to-end; reports tampering",
|
|
534
|
+
" purge Delete live rows already captured in a verified archive",
|
|
535
|
+
"",
|
|
536
|
+
"Common flags:",
|
|
537
|
+
" --out <path> Output bundle directory (must NOT exist)",
|
|
538
|
+
" --in <path> Input bundle directory (verify-bundle, purge)",
|
|
539
|
+
" --passphrase <string> Bundle passphrase (or env BLAMEJS_AUDIT_PASSPHRASE)",
|
|
540
|
+
"",
|
|
541
|
+
"archive flags:",
|
|
542
|
+
" --before <date> Archive rows with recordedAt < this date (ISO-8601 or epoch ms)",
|
|
543
|
+
"",
|
|
544
|
+
"export flags:",
|
|
545
|
+
" --from <date> Earliest recordedAt (inclusive)",
|
|
546
|
+
" --to <date> Latest recordedAt (inclusive)",
|
|
547
|
+
" --action <name> Restrict to a single audit action",
|
|
548
|
+
"",
|
|
549
|
+
"verify-chain flags:",
|
|
550
|
+
" --db <path> SQLite database path (required)",
|
|
551
|
+
" --table <name> Audit table name (default audit_log)",
|
|
552
|
+
" --max-rows <N> Stop after walking N rows (default: walk all)",
|
|
553
|
+
"",
|
|
554
|
+
"purge flags:",
|
|
555
|
+
" --confirm REQUIRED — operator acknowledgement of destructive op",
|
|
556
|
+
"",
|
|
557
|
+
"Exit codes:",
|
|
558
|
+
" 0 success (or chain verified ok)",
|
|
559
|
+
" 1 operation failed (or chain tampered)",
|
|
560
|
+
" 2 bad invocation",
|
|
561
|
+
].join("\n");
|
|
562
|
+
|
|
563
|
+
function _resolvePassphrase(args, ctx) {
|
|
564
|
+
if (typeof args.flags.passphrase === "string" && args.flags.passphrase.length > 0) {
|
|
565
|
+
return args.flags.passphrase;
|
|
566
|
+
}
|
|
567
|
+
var env = ctx.env && ctx.env.BLAMEJS_AUDIT_PASSPHRASE;
|
|
568
|
+
if (typeof env === "string" && env.length > 0) return env;
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function _resolveOutPath(p, ctx) {
|
|
573
|
+
if (!p) return null;
|
|
574
|
+
return nodePath.isAbsolute(p) ? p : nodePath.resolve(ctx.cwd, p);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
async function _runAudit(args, ctx) {
|
|
578
|
+
if (args.flags.help || args.flags.h) {
|
|
579
|
+
_writeLine(ctx.stdout, AUDIT_USAGE);
|
|
580
|
+
return 0;
|
|
581
|
+
}
|
|
582
|
+
if (args.pos.length === 0) {
|
|
583
|
+
_writeLine(ctx.stderr, AUDIT_USAGE);
|
|
584
|
+
return 2;
|
|
585
|
+
}
|
|
586
|
+
var sub = args.pos[0];
|
|
587
|
+
var passphrase = _resolvePassphrase(args, ctx);
|
|
588
|
+
// verify-chain reads the live DB, no bundle passphrase needed.
|
|
589
|
+
var passRequired = sub === "archive" || sub === "export" ||
|
|
590
|
+
sub === "verify-bundle" || sub === "purge";
|
|
591
|
+
if (passRequired && !passphrase) {
|
|
592
|
+
_writeLine(ctx.stderr, "blamejs audit " + sub +
|
|
593
|
+
": --passphrase or BLAMEJS_AUDIT_PASSPHRASE is required");
|
|
594
|
+
return 2;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (sub === "archive") {
|
|
598
|
+
var out = _resolveOutPath(args.flags.out, ctx);
|
|
599
|
+
var before = args.flags.before;
|
|
600
|
+
if (!out) { _writeLine(ctx.stderr, "blamejs audit archive: --out is required"); return 2; }
|
|
601
|
+
if (!before) { _writeLine(ctx.stderr, "blamejs audit archive: --before is required"); return 2; }
|
|
602
|
+
try {
|
|
603
|
+
var r = await auditTools.archive({
|
|
604
|
+
before: before, out: out, passphrase: passphrase,
|
|
605
|
+
});
|
|
606
|
+
_writeLine(ctx.stdout, "wrote archive bundle to " + r.outDir +
|
|
607
|
+
" (rowCount=" + r.rowCount +
|
|
608
|
+
", counters=" + r.range.firstCounter + ".." + r.range.lastCounter + ")");
|
|
609
|
+
return 0;
|
|
610
|
+
} catch (e) {
|
|
611
|
+
_writeLine(ctx.stderr, "blamejs audit archive: " + ((e && e.message) || String(e)));
|
|
612
|
+
return 1;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (sub === "export") {
|
|
617
|
+
var outE = _resolveOutPath(args.flags.out, ctx);
|
|
618
|
+
var from = args.flags.from;
|
|
619
|
+
var to = args.flags.to;
|
|
620
|
+
var action = args.flags.action;
|
|
621
|
+
if (!outE) { _writeLine(ctx.stderr, "blamejs audit export: --out is required"); return 2; }
|
|
622
|
+
if (!from && !to && !action) {
|
|
623
|
+
_writeLine(ctx.stderr, "blamejs audit export: at least one of --from / --to / --action is required");
|
|
624
|
+
return 2;
|
|
625
|
+
}
|
|
626
|
+
try {
|
|
627
|
+
var r2 = await auditTools.exportSlice({
|
|
628
|
+
from: from, to: to, action: action,
|
|
629
|
+
out: outE, passphrase: passphrase,
|
|
630
|
+
});
|
|
631
|
+
_writeLine(ctx.stdout, "wrote export bundle to " + r2.outDir +
|
|
632
|
+
" (rowCount=" + r2.rowCount +
|
|
633
|
+
", counters=" + r2.range.firstCounter + ".." + r2.range.lastCounter + ")");
|
|
634
|
+
return 0;
|
|
635
|
+
} catch (e) {
|
|
636
|
+
_writeLine(ctx.stderr, "blamejs audit export: " + ((e && e.message) || String(e)));
|
|
637
|
+
return 1;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (sub === "verify-bundle") {
|
|
642
|
+
var inV = _resolveOutPath(args.flags.in, ctx);
|
|
643
|
+
if (!inV) { _writeLine(ctx.stderr, "blamejs audit verify-bundle: --in is required"); return 2; }
|
|
644
|
+
try {
|
|
645
|
+
var v = await auditTools.verifyBundle({ in: inV, passphrase: passphrase });
|
|
646
|
+
if (v.ok) {
|
|
647
|
+
_writeLine(ctx.stdout, "OK — bundle verified" +
|
|
648
|
+
" (kind=" + v.kind +
|
|
649
|
+
", rowsVerified=" + v.rowsVerified +
|
|
650
|
+
", counters=" + v.range.firstCounter + ".." + v.range.lastCounter + ")");
|
|
651
|
+
return 0;
|
|
652
|
+
}
|
|
653
|
+
_writeLine(ctx.stderr, "FAIL — " + v.reason);
|
|
654
|
+
return 1;
|
|
655
|
+
} catch (e) {
|
|
656
|
+
_writeLine(ctx.stderr, "blamejs audit verify-bundle: " + ((e && e.message) || String(e)));
|
|
657
|
+
return 1;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (sub === "verify-chain") {
|
|
662
|
+
var dbPathV = args.flags.db;
|
|
663
|
+
if (!dbPathV || dbPathV === true) {
|
|
664
|
+
_writeLine(ctx.stderr, "blamejs audit verify-chain: --db <path> is required");
|
|
665
|
+
return 2;
|
|
666
|
+
}
|
|
667
|
+
dbPathV = _resolvePath(String(dbPathV), ctx.cwd);
|
|
668
|
+
var tableV = args.flags.table ? String(args.flags.table) : "audit_log";
|
|
669
|
+
var maxRows = args.flags["max-rows"];
|
|
670
|
+
var maxRowsN = maxRows === undefined ? undefined : Number(maxRows);
|
|
671
|
+
if (maxRowsN !== undefined && (!Number.isFinite(maxRowsN) || maxRowsN < 1)) {
|
|
672
|
+
_writeLine(ctx.stderr, "blamejs audit verify-chain: --max-rows must be a positive integer");
|
|
673
|
+
return 2;
|
|
674
|
+
}
|
|
675
|
+
var dbV;
|
|
676
|
+
try { dbV = _openSqlite(dbPathV); }
|
|
677
|
+
catch (e) {
|
|
678
|
+
_writeLine(ctx.stderr, "blamejs audit verify-chain: cannot open db at " + dbPathV +
|
|
679
|
+
": " + ((e && e.message) || String(e)));
|
|
680
|
+
return 1;
|
|
681
|
+
}
|
|
682
|
+
try {
|
|
683
|
+
var queryAllAsync = async function (sql, params) {
|
|
684
|
+
var stmt = dbV.prepare(sql);
|
|
685
|
+
return Array.isArray(params) ? stmt.all.apply(stmt, params) : stmt.all();
|
|
686
|
+
};
|
|
687
|
+
var vc = await auditChain.verifyChain(queryAllAsync, tableV,
|
|
688
|
+
maxRowsN ? { maxRows: maxRowsN } : {});
|
|
689
|
+
if (vc.ok) {
|
|
690
|
+
_writeLine(ctx.stdout, "OK — chain verified" +
|
|
691
|
+
" (table=" + vc.table +
|
|
692
|
+
", rowsVerified=" + vc.rowsVerified + ")");
|
|
693
|
+
return 0;
|
|
694
|
+
}
|
|
695
|
+
_writeLine(ctx.stderr, "FAIL — " + vc.reason +
|
|
696
|
+
" (table=" + vc.table +
|
|
697
|
+
", rowsVerified=" + vc.rowsVerified +
|
|
698
|
+
", breakAt=" + vc.breakAt +
|
|
699
|
+
", breakRowId=" + vc.breakRowId + ")");
|
|
700
|
+
_writeLine(ctx.stderr, " expected prevHash: " + vc.expected);
|
|
701
|
+
_writeLine(ctx.stderr, " actual: " + vc.actual);
|
|
702
|
+
return 1;
|
|
703
|
+
} catch (e) {
|
|
704
|
+
_writeLine(ctx.stderr, "blamejs audit verify-chain: " + ((e && e.message) || String(e)));
|
|
705
|
+
return 1;
|
|
706
|
+
} finally {
|
|
707
|
+
try { dbV.close(); } catch (_e) { /* close best-effort */ }
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (sub === "purge") {
|
|
712
|
+
var inP = _resolveOutPath(args.flags.archive || args.flags.in, ctx);
|
|
713
|
+
if (!inP) {
|
|
714
|
+
_writeLine(ctx.stderr, "blamejs audit purge: --archive (path to verified archive bundle) is required");
|
|
715
|
+
return 2;
|
|
716
|
+
}
|
|
717
|
+
if (args.flags.confirm !== true && args.flags.confirm !== "true") {
|
|
718
|
+
_writeLine(ctx.stderr, "blamejs audit purge: --confirm is REQUIRED — destructive operation");
|
|
719
|
+
return 2;
|
|
720
|
+
}
|
|
721
|
+
try {
|
|
722
|
+
var p = await auditTools.purge({
|
|
723
|
+
archive: inP, passphrase: passphrase, confirm: true,
|
|
724
|
+
});
|
|
725
|
+
_writeLine(ctx.stdout, "OK — purged " + p.rowsDeleted + " rows" +
|
|
726
|
+
" (counters ≤ " + p.lastPurgedCounter + ")");
|
|
727
|
+
return 0;
|
|
728
|
+
} catch (e) {
|
|
729
|
+
_writeLine(ctx.stderr, "blamejs audit purge: " + ((e && e.message) || String(e)));
|
|
730
|
+
return 1;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
_writeLine(ctx.stderr, "blamejs audit: unknown subcommand '" + sub + "'");
|
|
735
|
+
_writeLine(ctx.stderr, AUDIT_USAGE);
|
|
736
|
+
return 2;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// ---- Subcommand: restore ----
|
|
740
|
+
//
|
|
741
|
+
// Operator workflow on top of b.restore: list bundles in storage,
|
|
742
|
+
// inspect a specific one, do a live in-place restore (with rollback
|
|
743
|
+
// preservation), and roll back to a previous restore point. Wraps the
|
|
744
|
+
// restore primitive's run / inspect / list / rollback / list-rollbacks
|
|
745
|
+
// surface; uses b.backup.diskStorage as the storage adapter (the same
|
|
746
|
+
// adapter that wrote the bundles).
|
|
747
|
+
//
|
|
748
|
+
// Two ways to identify a bundle for inspect / apply:
|
|
749
|
+
// --bundle <dir> point at an extracted bundle directory
|
|
750
|
+
// (parent dir is treated as storage root,
|
|
751
|
+
// dir basename as bundle id — matches the
|
|
752
|
+
// shape `blamejs backup extract` produces)
|
|
753
|
+
// --storage-root <root> --bundle-id <id> use a multi-bundle root
|
|
754
|
+
|
|
755
|
+
var RESTORE_USAGE = [
|
|
756
|
+
"Usage: blamejs restore <subcommand> [flags]",
|
|
757
|
+
"",
|
|
758
|
+
"Subcommands:",
|
|
759
|
+
" list List bundles available in storage",
|
|
760
|
+
" inspect Read a bundle manifest summary (no live changes)",
|
|
761
|
+
" apply Live in-place restore with rollback preserved",
|
|
762
|
+
" rollback Revert the most-recent (or named) restore",
|
|
763
|
+
" list-rollbacks List preserved rollback points",
|
|
764
|
+
"",
|
|
765
|
+
"Common flags:",
|
|
766
|
+
" --data-dir <path> Live data directory (apply / rollback / list-rollbacks)",
|
|
767
|
+
" --storage-root <path> Directory containing bundle subdirs (list)",
|
|
768
|
+
" --bundle <dir> Extracted bundle directory (inspect / apply)",
|
|
769
|
+
" --bundle-id <id> Alternative: pass id with --storage-root",
|
|
770
|
+
" --rollback-root <path> Override rollback dir (default <data-dir>.rollbacks)",
|
|
771
|
+
" --passphrase <string> Bundle passphrase (or env BLAMEJS_BACKUP_PASSPHRASE)",
|
|
772
|
+
"",
|
|
773
|
+
"apply flags:",
|
|
774
|
+
" --max-pulled-bytes <N> Refuse a bundle whose pulled bytes exceed N (default 4 GiB)",
|
|
775
|
+
" --max-pulled-files <N> Refuse a bundle whose pulled file count exceeds N (default 100K)",
|
|
776
|
+
" --no-audit Suppress audit emission (default ON)",
|
|
777
|
+
"",
|
|
778
|
+
"rollback flags:",
|
|
779
|
+
" --rollback <pathOrId> Specific rollback point to restore (default: most recent)",
|
|
780
|
+
"",
|
|
781
|
+
"Exit codes:",
|
|
782
|
+
" 0 success",
|
|
783
|
+
" 1 operation failed",
|
|
784
|
+
" 2 bad invocation",
|
|
785
|
+
].join("\n");
|
|
786
|
+
|
|
787
|
+
// Resolve {storageRoot, bundleId} from either --bundle <dir> OR
|
|
788
|
+
// --storage-root <root> --bundle-id <id>. Returns null + writes an
|
|
789
|
+
// error on the report when neither shape works.
|
|
790
|
+
function _resolveRestoreBundleSelector(args, ctx, report, requireBundle) {
|
|
791
|
+
var bundleFlag = args.flags.bundle;
|
|
792
|
+
var storageRootFlag = args.flags["storage-root"];
|
|
793
|
+
var bundleIdFlag = args.flags["bundle-id"];
|
|
794
|
+
if (bundleFlag && bundleFlag !== true) {
|
|
795
|
+
var bundlePath = _resolvePath(String(bundleFlag), ctx.cwd);
|
|
796
|
+
return {
|
|
797
|
+
storageRoot: nodePath.dirname(bundlePath),
|
|
798
|
+
bundleId: nodePath.basename(bundlePath),
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
if (storageRootFlag && storageRootFlag !== true) {
|
|
802
|
+
var sr = _resolvePath(String(storageRootFlag), ctx.cwd);
|
|
803
|
+
if (requireBundle) {
|
|
804
|
+
if (!bundleIdFlag || bundleIdFlag === true) {
|
|
805
|
+
report.error("--bundle-id is required when using --storage-root", 2);
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
return { storageRoot: sr, bundleId: String(bundleIdFlag) };
|
|
809
|
+
}
|
|
810
|
+
return { storageRoot: sr, bundleId: null };
|
|
811
|
+
}
|
|
812
|
+
if (requireBundle) {
|
|
813
|
+
report.error("--bundle <dir> OR --storage-root <root> --bundle-id <id> is required", 2);
|
|
814
|
+
} else {
|
|
815
|
+
report.error("--storage-root <root> is required", 2);
|
|
816
|
+
}
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
async function _runRestore(args, ctx) {
|
|
821
|
+
if (args.pos.length === 0) {
|
|
822
|
+
return cliHelpers.makeReporter(ctx, "blamejs restore").usage(RESTORE_USAGE);
|
|
823
|
+
}
|
|
824
|
+
var sub = args.pos[0];
|
|
825
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs restore " + sub);
|
|
826
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
827
|
+
return report.helpStdout(RESTORE_USAGE);
|
|
828
|
+
}
|
|
829
|
+
if (["list", "inspect", "apply", "rollback", "list-rollbacks"].indexOf(sub) === -1) {
|
|
830
|
+
cliHelpers.makeReporter(ctx, "blamejs restore").error("unknown subcommand '" + sub + "'", 2);
|
|
831
|
+
return cliHelpers.makeReporter(ctx, "blamejs restore").usage(RESTORE_USAGE);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// list / inspect / apply all need a storage root + (for inspect/apply) a bundle id.
|
|
835
|
+
// rollback / list-rollbacks only need data-dir.
|
|
836
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
837
|
+
function _requireDataDir() {
|
|
838
|
+
if (!dataDirFlag || dataDirFlag === true) {
|
|
839
|
+
report.error("--data-dir <path> is required", 2);
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
842
|
+
return _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (sub === "list") {
|
|
846
|
+
var sel = _resolveRestoreBundleSelector(args, ctx, report, false);
|
|
847
|
+
if (!sel) return 2;
|
|
848
|
+
try {
|
|
849
|
+
var storage = backup.diskStorage({ root: sel.storageRoot });
|
|
850
|
+
var bundles = await storage.listBundles();
|
|
851
|
+
if (bundles.length === 0) {
|
|
852
|
+
report.write("no bundles in " + sel.storageRoot);
|
|
853
|
+
return report.ok();
|
|
854
|
+
}
|
|
855
|
+
report.write("bundles in " + sel.storageRoot + ": " + bundles.length);
|
|
856
|
+
for (var i = 0; i < bundles.length; i++) {
|
|
857
|
+
var b = bundles[i];
|
|
858
|
+
report.write(" " + b.bundleId +
|
|
859
|
+
" size=" + (b.size != null ? b.size + "B" : "?") +
|
|
860
|
+
" createdAt=" + (b.createdAt || "?"));
|
|
861
|
+
}
|
|
862
|
+
return report.ok();
|
|
863
|
+
} catch (e) {
|
|
864
|
+
return report.error((e && e.message) || String(e));
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (sub === "inspect") {
|
|
869
|
+
var selI = _resolveRestoreBundleSelector(args, ctx, report, true);
|
|
870
|
+
if (!selI) return 2;
|
|
871
|
+
try {
|
|
872
|
+
var storageI = backup.diskStorage({ root: selI.storageRoot });
|
|
873
|
+
// restore.create needs a passphrase + dataDir even for inspect because
|
|
874
|
+
// its closure captures them; pass placeholders since inspect doesn't
|
|
875
|
+
// touch them.
|
|
876
|
+
var rI = restore.create({
|
|
877
|
+
dataDir: nodePath.join(os.tmpdir(), "blamejs-restore-inspect-noop"),
|
|
878
|
+
storage: storageI,
|
|
879
|
+
passphrase: "inspect-only-not-used",
|
|
880
|
+
audit: false,
|
|
881
|
+
});
|
|
882
|
+
var manifest = await rI.inspect(selI.bundleId);
|
|
883
|
+
var totalBytesI = 0;
|
|
884
|
+
for (var ix = 0; ix < manifest.files.length; ix++) {
|
|
885
|
+
totalBytesI += manifest.files[ix].encryptedSize || 0;
|
|
886
|
+
}
|
|
887
|
+
report.write("bundle: " + selI.bundleId);
|
|
888
|
+
report.write("storage root: " + selI.storageRoot);
|
|
889
|
+
report.write("manifest: v" + (manifest.manifestVersion || manifest.version || "unknown"));
|
|
890
|
+
report.write("created: " + (manifest.createdAt || "unknown"));
|
|
891
|
+
report.write("files: " + manifest.files.length);
|
|
892
|
+
report.write("encrypted size: " + totalBytesI + " bytes");
|
|
893
|
+
return report.ok();
|
|
894
|
+
} catch (e) {
|
|
895
|
+
return report.error((e && e.message) || String(e));
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (sub === "apply") {
|
|
900
|
+
var dd = _requireDataDir();
|
|
901
|
+
if (!dd) return 2;
|
|
902
|
+
var selA = _resolveRestoreBundleSelector(args, ctx, report, true);
|
|
903
|
+
if (!selA) return 2;
|
|
904
|
+
var pp = cliHelpers.resolvePassphrase(args, ctx, {
|
|
905
|
+
flag: "passphrase", envVar: "BLAMEJS_BACKUP_PASSPHRASE",
|
|
906
|
+
});
|
|
907
|
+
if (!pp) {
|
|
908
|
+
return report.error("--passphrase or BLAMEJS_BACKUP_PASSPHRASE is required", 2);
|
|
909
|
+
}
|
|
910
|
+
var rollbackRootA = args.flags["rollback-root"]
|
|
911
|
+
? _resolvePath(String(args.flags["rollback-root"]), ctx.cwd) : undefined;
|
|
912
|
+
var maxBytes = args.flags["max-pulled-bytes"];
|
|
913
|
+
var maxFiles = args.flags["max-pulled-files"];
|
|
914
|
+
if (maxBytes !== undefined && (!Number.isFinite(Number(maxBytes)) || Number(maxBytes) <= 0)) {
|
|
915
|
+
return report.error("--max-pulled-bytes must be a positive number", 2);
|
|
916
|
+
}
|
|
917
|
+
if (maxFiles !== undefined && (!Number.isFinite(Number(maxFiles)) || Number(maxFiles) <= 0)) {
|
|
918
|
+
return report.error("--max-pulled-files must be a positive number", 2);
|
|
919
|
+
}
|
|
920
|
+
try {
|
|
921
|
+
var storageA = backup.diskStorage({ root: selA.storageRoot });
|
|
922
|
+
var rA = restore.create({
|
|
923
|
+
dataDir: dd,
|
|
924
|
+
storage: storageA,
|
|
925
|
+
passphrase: pp,
|
|
926
|
+
rollbackRoot: rollbackRootA,
|
|
927
|
+
audit: args.flags["no-audit"] !== true,
|
|
928
|
+
maxPulledBytes: maxBytes !== undefined ? Number(maxBytes) : undefined,
|
|
929
|
+
maxPulledFiles: maxFiles !== undefined ? Number(maxFiles) : undefined,
|
|
930
|
+
});
|
|
931
|
+
var summary = await rA.run({ bundleId: selA.bundleId });
|
|
932
|
+
report.write("OK — restored");
|
|
933
|
+
report.write(" bundle: " + summary.bundleId);
|
|
934
|
+
report.write(" files: " + summary.fileCount);
|
|
935
|
+
report.write(" bytes: " + summary.totalBytes);
|
|
936
|
+
report.write(" rollback at: " + summary.rollbackPath);
|
|
937
|
+
report.write(" duration ms: " + summary.durationMs);
|
|
938
|
+
report.write("");
|
|
939
|
+
report.write("Stop and start the app fresh against " + dd + " to pick up the restored state.");
|
|
940
|
+
report.write("Roll back with: blamejs restore rollback --data-dir " + dd);
|
|
941
|
+
return report.ok();
|
|
942
|
+
} catch (e) {
|
|
943
|
+
return report.error((e && e.message) || String(e));
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (sub === "rollback") {
|
|
948
|
+
var ddR = _requireDataDir();
|
|
949
|
+
if (!ddR) return 2;
|
|
950
|
+
var rollbackRootR = args.flags["rollback-root"]
|
|
951
|
+
? _resolvePath(String(args.flags["rollback-root"]), ctx.cwd)
|
|
952
|
+
: (ddR + ".rollbacks");
|
|
953
|
+
var rollbackTarget = args.flags.rollback;
|
|
954
|
+
var targetPath = null;
|
|
955
|
+
if (rollbackTarget && rollbackTarget !== true) {
|
|
956
|
+
// operator can pass either a full path or just the basename inside rollback-root
|
|
957
|
+
var rt = String(rollbackTarget);
|
|
958
|
+
targetPath = nodePath.isAbsolute(rt) ? rt : nodePath.resolve(rollbackRootR, rt);
|
|
959
|
+
} else {
|
|
960
|
+
// Default to most-recent rollback point (mirrors restore.create().rollback()).
|
|
961
|
+
var ptsR;
|
|
962
|
+
try { ptsR = restoreRollback.list({ rollbackRoot: rollbackRootR }); }
|
|
963
|
+
catch (e) {
|
|
964
|
+
return report.error("listing rollbacks at " + rollbackRootR + ": " + ((e && e.message) || String(e)));
|
|
965
|
+
}
|
|
966
|
+
if (!ptsR || ptsR.length === 0) {
|
|
967
|
+
return report.error("no rollback points at " + rollbackRootR + " — pass --rollback <pathOrId> explicitly", 2);
|
|
968
|
+
}
|
|
969
|
+
targetPath = ptsR[0].rollbackPath;
|
|
970
|
+
}
|
|
971
|
+
try {
|
|
972
|
+
var rR = await restoreRollback.rollback({
|
|
973
|
+
dataDir: ddR,
|
|
974
|
+
rollbackPath: targetPath,
|
|
975
|
+
rollbackRoot: rollbackRootR,
|
|
976
|
+
});
|
|
977
|
+
report.write("OK — rolled back");
|
|
978
|
+
report.write(" data dir: " + ddR);
|
|
979
|
+
report.write(" used: " + (targetPath || "most-recent rollback point"));
|
|
980
|
+
report.write(" discarded at: " + (rR.discardedAt || "(unknown)"));
|
|
981
|
+
return report.ok();
|
|
982
|
+
} catch (e) {
|
|
983
|
+
return report.error((e && e.message) || String(e));
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (sub === "list-rollbacks") {
|
|
988
|
+
var ddL = _requireDataDir();
|
|
989
|
+
if (!ddL) return 2;
|
|
990
|
+
var rollbackRootL = args.flags["rollback-root"]
|
|
991
|
+
? _resolvePath(String(args.flags["rollback-root"]), ctx.cwd)
|
|
992
|
+
: (ddL + ".rollbacks");
|
|
993
|
+
try {
|
|
994
|
+
var pts = restoreRollback.list({ rollbackRoot: rollbackRootL });
|
|
995
|
+
if (pts.length === 0) {
|
|
996
|
+
report.write("no rollback points at " + rollbackRootL);
|
|
997
|
+
return report.ok();
|
|
998
|
+
}
|
|
999
|
+
report.write("rollback points at " + rollbackRootL + ": " + pts.length);
|
|
1000
|
+
for (var p = 0; p < pts.length; p++) {
|
|
1001
|
+
var pt = pts[p];
|
|
1002
|
+
report.write(" " + (pt.rollbackPath || pt) +
|
|
1003
|
+
(pt.recordedAt ? " recordedAt=" + pt.recordedAt : "") +
|
|
1004
|
+
(pt.bundleId ? " bundleId=" + pt.bundleId : ""));
|
|
1005
|
+
}
|
|
1006
|
+
return report.ok();
|
|
1007
|
+
} catch (e) {
|
|
1008
|
+
return report.error((e && e.message) || String(e));
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
return 2;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// ---- Top-level help ----
|
|
1016
|
+
|
|
1017
|
+
// ---- Subcommand: api-key ----
|
|
1018
|
+
|
|
1019
|
+
var API_KEY_USAGE = [
|
|
1020
|
+
"Usage: blamejs api-key <subcommand> [flags]",
|
|
1021
|
+
"",
|
|
1022
|
+
"Subcommands:",
|
|
1023
|
+
" issue Issue a new API key under a namespace. Prints the",
|
|
1024
|
+
" composite key + id. The plaintext secret is shown",
|
|
1025
|
+
" ONCE and cannot be recovered after the command exits.",
|
|
1026
|
+
" revoke Revoke an issued key by its composite id (namespace:idHex).",
|
|
1027
|
+
" list List active keys for a given owner under a namespace.",
|
|
1028
|
+
" rotate Issue a new secret for an existing id while leaving the",
|
|
1029
|
+
" old secret valid for opts.gracePeriodMs (default 0 — immediate).",
|
|
1030
|
+
" verify Verify a token string and print the resolved metadata.",
|
|
1031
|
+
" Useful for debugging an integration that's seeing 401s.",
|
|
1032
|
+
"",
|
|
1033
|
+
"Flags (all subcommands):",
|
|
1034
|
+
" --data-dir <path> Path to the app's data dir (required)",
|
|
1035
|
+
" --namespace <name> API-key namespace (required) — typically matches the",
|
|
1036
|
+
" operator's b.apiKey.create({ namespace }) at boot",
|
|
1037
|
+
" --vault-mode <mode> plaintext | wrapped (default wrapped). When wrapped,",
|
|
1038
|
+
" BLAMEJS_VAULT_PASSPHRASE must be set.",
|
|
1039
|
+
"",
|
|
1040
|
+
"Subcommand flags:",
|
|
1041
|
+
" issue: --owner-id <id> --scopes <comma-separated> [--label <text>] [--expires-ms <ms>]",
|
|
1042
|
+
" revoke: --id <idHex>",
|
|
1043
|
+
" list: --owner-id <id>",
|
|
1044
|
+
" rotate: --id <idHex> [--grace-ms <ms>]",
|
|
1045
|
+
" verify: --token <key>",
|
|
1046
|
+
].join("\n");
|
|
1047
|
+
|
|
1048
|
+
async function _runApiKey(args, ctx) {
|
|
1049
|
+
if (args.pos.length === 0) {
|
|
1050
|
+
return cliHelpers.makeReporter(ctx, "blamejs api-key").usage(API_KEY_USAGE);
|
|
1051
|
+
}
|
|
1052
|
+
var sub = args.pos[0];
|
|
1053
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs api-key " + sub);
|
|
1054
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1055
|
+
return report.helpStdout(API_KEY_USAGE);
|
|
1056
|
+
}
|
|
1057
|
+
if (["issue", "revoke", "list", "rotate", "verify"].indexOf(sub) === -1) {
|
|
1058
|
+
cliHelpers.makeReporter(ctx, "blamejs api-key").error("unknown subcommand '" + sub + "'", 2);
|
|
1059
|
+
return cliHelpers.makeReporter(ctx, "blamejs api-key").usage(API_KEY_USAGE);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
1063
|
+
if (!dataDirFlag || dataDirFlag === true) {
|
|
1064
|
+
return report.error("--data-dir <path> is required", 2);
|
|
1065
|
+
}
|
|
1066
|
+
var dataDir = _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
1067
|
+
|
|
1068
|
+
var namespace = args.flags.namespace;
|
|
1069
|
+
if (!namespace || namespace === true) {
|
|
1070
|
+
return report.error("--namespace <name> is required", 2);
|
|
1071
|
+
}
|
|
1072
|
+
namespace = String(namespace);
|
|
1073
|
+
|
|
1074
|
+
var vaultMode = args.flags["vault-mode"] || "wrapped";
|
|
1075
|
+
if (vaultMode !== "wrapped" && vaultMode !== "plaintext") {
|
|
1076
|
+
return report.error("--vault-mode must be 'wrapped' or 'plaintext'", 2);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
var booted;
|
|
1080
|
+
try {
|
|
1081
|
+
booted = await cliHelpers.bootApp({
|
|
1082
|
+
dataDir: dataDir,
|
|
1083
|
+
vaultMode: vaultMode,
|
|
1084
|
+
env: ctx.env,
|
|
1085
|
+
});
|
|
1086
|
+
} catch (e) {
|
|
1087
|
+
return report.error("boot failed: " + ((e && e.message) || String(e)));
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
try {
|
|
1091
|
+
var registry = booted.b.apiKey.create({
|
|
1092
|
+
namespace: namespace,
|
|
1093
|
+
audit: booted.b.audit,
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
if (sub === "issue") {
|
|
1097
|
+
var ownerId = args.flags["owner-id"];
|
|
1098
|
+
var scopes = args.flags.scopes;
|
|
1099
|
+
if (!ownerId || ownerId === true) return report.error("--owner-id <id> is required", 2);
|
|
1100
|
+
if (!scopes || scopes === true) return report.error("--scopes <comma-separated> is required", 2);
|
|
1101
|
+
var scopeList = requestHelpers.parseListHeader(scopes);
|
|
1102
|
+
if (scopeList.length === 0) {
|
|
1103
|
+
return report.error("--scopes must contain at least one non-empty scope", 2);
|
|
1104
|
+
}
|
|
1105
|
+
var label = typeof args.flags.label === "string" ? args.flags.label : null;
|
|
1106
|
+
var expiresMs = args.flags["expires-ms"];
|
|
1107
|
+
var issued = await registry.issue({
|
|
1108
|
+
ownerId: String(ownerId),
|
|
1109
|
+
scopes: scopeList,
|
|
1110
|
+
metadata: label ? { label: label } : null,
|
|
1111
|
+
expiresMs: expiresMs && expiresMs !== true ? Number(expiresMs) : undefined,
|
|
1112
|
+
});
|
|
1113
|
+
report.write("id: " + issued.id);
|
|
1114
|
+
report.write("key: " + issued.key);
|
|
1115
|
+
report.write("scopes: " + issued.scopes.join(", "));
|
|
1116
|
+
if (issued.expiresAt) report.write("expires: " + new Date(issued.expiresAt).toISOString());
|
|
1117
|
+
return report.ok("\nThe plaintext secret is shown ONCE — copy it now.");
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (sub === "revoke") {
|
|
1121
|
+
var revokeId = args.flags.id;
|
|
1122
|
+
if (!revokeId || revokeId === true) return report.error("--id <idHex> is required", 2);
|
|
1123
|
+
var revoked = await registry.revoke(String(revokeId));
|
|
1124
|
+
return revoked
|
|
1125
|
+
? report.ok("revoked: " + revokeId)
|
|
1126
|
+
: report.error("no-op: " + revokeId + " not found or already revoked");
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
if (sub === "list") {
|
|
1130
|
+
var listOwnerId = args.flags["owner-id"];
|
|
1131
|
+
if (!listOwnerId || listOwnerId === true) return report.error("--owner-id <id> is required", 2);
|
|
1132
|
+
var rows = await registry.listForOwner(String(listOwnerId));
|
|
1133
|
+
report.write("owner: " + listOwnerId + " (" + rows.length + " active keys)");
|
|
1134
|
+
for (var i = 0; i < rows.length; i++) {
|
|
1135
|
+
var r = rows[i];
|
|
1136
|
+
var scope = Array.isArray(r.scopes) ? r.scopes.join(",") : "";
|
|
1137
|
+
report.write(" " + r.id + " scopes=[" + scope + "]" +
|
|
1138
|
+
(r.expiresAt ? " expires=" + new Date(r.expiresAt).toISOString() : ""));
|
|
1139
|
+
}
|
|
1140
|
+
return report.ok();
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
if (sub === "rotate") {
|
|
1144
|
+
var rotateId = args.flags.id;
|
|
1145
|
+
if (!rotateId || rotateId === true) return report.error("--id <idHex> is required", 2);
|
|
1146
|
+
var graceMs = args.flags["grace-ms"];
|
|
1147
|
+
var rotated = await registry.rotate(String(rotateId), {
|
|
1148
|
+
gracePeriodMs: graceMs && graceMs !== true ? Number(graceMs) : 0,
|
|
1149
|
+
});
|
|
1150
|
+
report.write("id: " + rotated.id);
|
|
1151
|
+
report.write("key (new): " + rotated.key);
|
|
1152
|
+
return report.ok("\nUpdate your integration to the new key, then revoke the old secret " +
|
|
1153
|
+
"(or wait gracePeriodMs for it to expire).");
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
if (sub === "verify") {
|
|
1157
|
+
var token = args.flags.token;
|
|
1158
|
+
if (!token || token === true) return report.error("--token <key> is required", 2);
|
|
1159
|
+
var v = await registry.verify(String(token));
|
|
1160
|
+
if (!v) return report.error("rejected: token does not verify (bad format, unknown id, revoked, or expired)");
|
|
1161
|
+
report.write("id: " + v.id);
|
|
1162
|
+
report.write("ownerId: " + v.ownerId);
|
|
1163
|
+
report.write("scopes: " + (v.scopes || []).join(", "));
|
|
1164
|
+
if (v.lastUsedAt) report.write("last-used: " + new Date(v.lastUsedAt).toISOString());
|
|
1165
|
+
if (v.expiresAt) report.write("expires: " + new Date(v.expiresAt).toISOString());
|
|
1166
|
+
return report.ok();
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
return 2;
|
|
1170
|
+
} catch (e) {
|
|
1171
|
+
return report.error((e && e.message) || String(e));
|
|
1172
|
+
} finally {
|
|
1173
|
+
try { await booted.app.shutdown(); } catch (_e) { /* best-effort */ }
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// ---- Subcommand: backup ----
|
|
1178
|
+
|
|
1179
|
+
var BACKUP_USAGE = [
|
|
1180
|
+
"Usage: blamejs backup <subcommand> [flags]",
|
|
1181
|
+
"",
|
|
1182
|
+
"Subcommands:",
|
|
1183
|
+
" inspect Read a bundle's manifest without decrypting and",
|
|
1184
|
+
" print a summary (file count, total bytes, kinds,",
|
|
1185
|
+
" timestamp). No passphrase required — useful for",
|
|
1186
|
+
" pre-flight before a restore.",
|
|
1187
|
+
" verify Decrypt + verify the bundle in a temp directory,",
|
|
1188
|
+
" discard the output. Confirms passphrase is correct",
|
|
1189
|
+
" and every encrypted blob's HMAC validates against",
|
|
1190
|
+
" the manifest, without committing a restore.",
|
|
1191
|
+
" extract Decrypt + verify into the target staging directory.",
|
|
1192
|
+
" The staging directory is the operator's responsibility",
|
|
1193
|
+
" to inspect and then move into place; this command",
|
|
1194
|
+
" never touches the live data dir.",
|
|
1195
|
+
"",
|
|
1196
|
+
"Flags:",
|
|
1197
|
+
" --bundle <dir> Path to a bundle directory (must contain manifest.json)",
|
|
1198
|
+
" --to <stagingDir> For extract — fresh directory to decrypt into (must not exist)",
|
|
1199
|
+
" --passphrase <string> Backup passphrase (or env BLAMEJS_BACKUP_PASSPHRASE)",
|
|
1200
|
+
].join("\n");
|
|
1201
|
+
|
|
1202
|
+
async function _runBackup(args, ctx) {
|
|
1203
|
+
if (args.pos.length === 0) {
|
|
1204
|
+
return cliHelpers.makeReporter(ctx, "blamejs backup").usage(BACKUP_USAGE);
|
|
1205
|
+
}
|
|
1206
|
+
var sub = args.pos[0];
|
|
1207
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs backup " + sub);
|
|
1208
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1209
|
+
return report.helpStdout(BACKUP_USAGE);
|
|
1210
|
+
}
|
|
1211
|
+
if (["inspect", "verify", "extract"].indexOf(sub) === -1) {
|
|
1212
|
+
cliHelpers.makeReporter(ctx, "blamejs backup").error("unknown subcommand '" + sub + "'", 2);
|
|
1213
|
+
return cliHelpers.makeReporter(ctx, "blamejs backup").usage(BACKUP_USAGE);
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
var bundleFlag = args.flags.bundle;
|
|
1217
|
+
if (!bundleFlag || bundleFlag === true) {
|
|
1218
|
+
return report.error("--bundle <dir> is required", 2);
|
|
1219
|
+
}
|
|
1220
|
+
var bundleDir = _resolvePath(String(bundleFlag), ctx.cwd);
|
|
1221
|
+
|
|
1222
|
+
if (sub === "inspect") {
|
|
1223
|
+
try {
|
|
1224
|
+
var m = restoreBundle.inspect({ bundleDir: bundleDir });
|
|
1225
|
+
var totalBytes = 0;
|
|
1226
|
+
for (var i = 0; i < m.files.length; i++) totalBytes += m.files[i].encryptedSize || 0;
|
|
1227
|
+
report.write("bundle: " + bundleDir);
|
|
1228
|
+
report.write("manifest: v" + (m.manifestVersion || m.version || "unknown"));
|
|
1229
|
+
report.write("created: " + (m.createdAt || "unknown"));
|
|
1230
|
+
report.write("files: " + m.files.length);
|
|
1231
|
+
report.write("encrypted size: " + totalBytes + " bytes");
|
|
1232
|
+
var kinds = {};
|
|
1233
|
+
for (var k = 0; k < m.files.length; k++) {
|
|
1234
|
+
var kind = m.files[k].kind || "unknown";
|
|
1235
|
+
kinds[kind] = (kinds[kind] || 0) + 1;
|
|
1236
|
+
}
|
|
1237
|
+
// Stable kind ordering for the human-readable report — same
|
|
1238
|
+
// sort the framework's canonical-json walker uses for object
|
|
1239
|
+
// keys. Pulled out as a sortKeys() helper so this single sorted
|
|
1240
|
+
// walk in cli matches the canonical-json discipline elsewhere.
|
|
1241
|
+
var ks = canonicalJson.sortKeys(kinds);
|
|
1242
|
+
for (var ki = 0; ki < ks.length; ki++) {
|
|
1243
|
+
report.write(" " + ks[ki] + ": " + kinds[ks[ki]]);
|
|
1244
|
+
}
|
|
1245
|
+
return report.ok();
|
|
1246
|
+
} catch (e) {
|
|
1247
|
+
return report.error((e && e.message) || String(e));
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// verify + extract both decrypt — both need a passphrase.
|
|
1252
|
+
var pp = cliHelpers.resolvePassphrase(args, ctx, {
|
|
1253
|
+
flag: "passphrase", envVar: "BLAMEJS_BACKUP_PASSPHRASE",
|
|
1254
|
+
});
|
|
1255
|
+
if (!pp) {
|
|
1256
|
+
return report.error("--passphrase or BLAMEJS_BACKUP_PASSPHRASE is required", 2);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
if (sub === "verify") {
|
|
1260
|
+
var stagingDir = nodePath.join(os.tmpdir(),
|
|
1261
|
+
"blamejs-backup-verify-" + bCrypto.generateToken(C.BYTES.bytes(8)));
|
|
1262
|
+
try {
|
|
1263
|
+
var r = await restoreBundle.extract({
|
|
1264
|
+
bundleDir: bundleDir,
|
|
1265
|
+
stagingDir: stagingDir,
|
|
1266
|
+
passphrase: pp,
|
|
1267
|
+
});
|
|
1268
|
+
report.write("verified: " + (r && r.fileCount != null ? r.fileCount : "n/a") + " files");
|
|
1269
|
+
report.write("passphrase decrypts the vault-key wrap");
|
|
1270
|
+
report.write("every blob's HMAC validates against the manifest");
|
|
1271
|
+
return report.ok();
|
|
1272
|
+
} catch (e) {
|
|
1273
|
+
return report.error((e && e.message) || String(e));
|
|
1274
|
+
} finally {
|
|
1275
|
+
try { nodeFs.rmSync(stagingDir, { recursive: true, force: true }); } catch (_e) { /* best-effort */ }
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (sub === "extract") {
|
|
1280
|
+
var toFlag = args.flags.to;
|
|
1281
|
+
if (!toFlag || toFlag === true) {
|
|
1282
|
+
return report.error("--to <stagingDir> is required", 2);
|
|
1283
|
+
}
|
|
1284
|
+
var stagingDir2 = _resolvePath(String(toFlag), ctx.cwd);
|
|
1285
|
+
try {
|
|
1286
|
+
var rr = await restoreBundle.extract({
|
|
1287
|
+
bundleDir: bundleDir,
|
|
1288
|
+
stagingDir: stagingDir2,
|
|
1289
|
+
passphrase: pp,
|
|
1290
|
+
});
|
|
1291
|
+
report.write("extracted: " + (rr && rr.fileCount != null ? rr.fileCount : "n/a") +
|
|
1292
|
+
" files → " + stagingDir2);
|
|
1293
|
+
report.write("");
|
|
1294
|
+
report.write("Inspect the staging directory before moving any files into your live data dir.");
|
|
1295
|
+
report.write("blamejs does NOT auto-promote — that's an operator decision.");
|
|
1296
|
+
return report.ok();
|
|
1297
|
+
} catch (e) {
|
|
1298
|
+
return report.error((e && e.message) || String(e));
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
return 2;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// ---- Subcommand: mtls ----
|
|
1306
|
+
|
|
1307
|
+
var MTLS_USAGE = [
|
|
1308
|
+
"Usage: blamejs mtls <subcommand> [flags]",
|
|
1309
|
+
"",
|
|
1310
|
+
"Subcommands:",
|
|
1311
|
+
" status Print CA state — exists / generation / sealed-mode.",
|
|
1312
|
+
" No engine required.",
|
|
1313
|
+
" show-cert Print the CA certificate PEM to stdout. Operators",
|
|
1314
|
+
" paste this into client truststores. No engine required.",
|
|
1315
|
+
" init Generate a fresh CA keypair + self-signed cert and",
|
|
1316
|
+
" write to data-dir. Requires opts.engine — see note below.",
|
|
1317
|
+
" issue Issue a leaf client certificate signed by the CA.",
|
|
1318
|
+
" Requires opts.engine + --subject. Prints cert + key PEM.",
|
|
1319
|
+
" issue-p12 Issue + package as PKCS#12 with --password. Useful for",
|
|
1320
|
+
" importing into browsers / OS keychains. Requires engine.",
|
|
1321
|
+
"",
|
|
1322
|
+
"Flags:",
|
|
1323
|
+
" --data-dir <path> Path to the app's data dir (required)",
|
|
1324
|
+
" --vault-mode <mode> plaintext | wrapped (default wrapped). When wrapped,",
|
|
1325
|
+
" BLAMEJS_VAULT_PASSPHRASE must be set.",
|
|
1326
|
+
" --sealed-mode <mode> auto | required | disabled (default auto). 'required'",
|
|
1327
|
+
" seals the CA key under the vault before writing it",
|
|
1328
|
+
" to disk; 'disabled' keeps it plaintext on disk;",
|
|
1329
|
+
" 'auto' loads whichever form exists.",
|
|
1330
|
+
"",
|
|
1331
|
+
"Subcommand flags:",
|
|
1332
|
+
" issue: --subject <CN> [--days <N>]",
|
|
1333
|
+
" issue-p12: --subject <CN> --password <pkcs12-passphrase> [--days <N>] [--out <path>]",
|
|
1334
|
+
"",
|
|
1335
|
+
"Cert issuance ('init', 'issue', 'issue-p12') uses the framework's",
|
|
1336
|
+
"bundled pure-JS engine (lib/mtls-engine-default.js, ECDSA P-384",
|
|
1337
|
+
"signatures, AES-256-CBC + HMAC-SHA-512 PBKDF2 PKCS#12 with 2,000,000",
|
|
1338
|
+
"iterations). Operators with custom requirements pass a different",
|
|
1339
|
+
"engine via b.mtlsCa.create({ engine: ... }) when wiring their app;",
|
|
1340
|
+
"the CLI always uses the default.",
|
|
1341
|
+
].join("\n");
|
|
1342
|
+
|
|
1343
|
+
async function _runMtls(args, ctx) {
|
|
1344
|
+
if (args.pos.length === 0) {
|
|
1345
|
+
return cliHelpers.makeReporter(ctx, "blamejs mtls").usage(MTLS_USAGE);
|
|
1346
|
+
}
|
|
1347
|
+
var sub = args.pos[0];
|
|
1348
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs mtls " + sub);
|
|
1349
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1350
|
+
return report.helpStdout(MTLS_USAGE);
|
|
1351
|
+
}
|
|
1352
|
+
if (["status", "show-cert", "init", "issue", "issue-p12"].indexOf(sub) === -1) {
|
|
1353
|
+
cliHelpers.makeReporter(ctx, "blamejs mtls").error("unknown subcommand '" + sub + "'", 2);
|
|
1354
|
+
return cliHelpers.makeReporter(ctx, "blamejs mtls").usage(MTLS_USAGE);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
1358
|
+
if (!dataDirFlag || dataDirFlag === true) {
|
|
1359
|
+
return report.error("--data-dir <path> is required", 2);
|
|
1360
|
+
}
|
|
1361
|
+
var dataDir = _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
1362
|
+
|
|
1363
|
+
var vaultMode = args.flags["vault-mode"] || "wrapped";
|
|
1364
|
+
if (vaultMode !== "wrapped" && vaultMode !== "plaintext") {
|
|
1365
|
+
return report.error("--vault-mode must be 'wrapped' or 'plaintext'", 2);
|
|
1366
|
+
}
|
|
1367
|
+
var sealedMode = args.flags["sealed-mode"] || "required";
|
|
1368
|
+
if (["required", "disabled"].indexOf(sealedMode) === -1) {
|
|
1369
|
+
return report.error("--sealed-mode must be 'required' or 'disabled'", 2);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
var booted;
|
|
1373
|
+
try {
|
|
1374
|
+
booted = await cliHelpers.bootApp({
|
|
1375
|
+
dataDir: dataDir,
|
|
1376
|
+
vaultMode: vaultMode,
|
|
1377
|
+
env: ctx.env,
|
|
1378
|
+
});
|
|
1379
|
+
} catch (e) {
|
|
1380
|
+
return report.error("boot failed: " + ((e && e.message) || String(e)));
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
try {
|
|
1384
|
+
var ca = booted.b.mtlsCa.create({
|
|
1385
|
+
dataDir: dataDir,
|
|
1386
|
+
vault: booted.b.vault,
|
|
1387
|
+
caKeySealedMode: sealedMode,
|
|
1388
|
+
// No engine passed — b.mtlsCa falls back to the bundled default
|
|
1389
|
+
// (lib/mtls-engine-default.js).
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
if (sub === "status") {
|
|
1393
|
+
var s = ca.status();
|
|
1394
|
+
report.write("data-dir: " + dataDir);
|
|
1395
|
+
report.write("CA exists: " + (s.exists ? "yes" : "no"));
|
|
1396
|
+
if (s.exists) {
|
|
1397
|
+
report.write("generation: " + s.generation +
|
|
1398
|
+
(s.isLegacy ? " (LEGACY — current is " + s.current + ", rotate via init)" : ""));
|
|
1399
|
+
report.write("ca-key-sealed-mode: " + ca.caKeySealedMode);
|
|
1400
|
+
report.write("paths:");
|
|
1401
|
+
report.write(" cert: " + ca.paths.caCert);
|
|
1402
|
+
report.write(" key: " + ca.paths.caKey);
|
|
1403
|
+
report.write(" key-sealed: " + ca.paths.caKeySealed);
|
|
1404
|
+
} else {
|
|
1405
|
+
report.write("(run 'blamejs mtls init' to generate a CA)");
|
|
1406
|
+
}
|
|
1407
|
+
return report.ok();
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
if (sub === "show-cert") {
|
|
1411
|
+
if (!ca.exists()) {
|
|
1412
|
+
return report.error("no CA on disk at " + ca.paths.caCert + " — run 'blamejs mtls init' first");
|
|
1413
|
+
}
|
|
1414
|
+
try {
|
|
1415
|
+
var pem = ca.loadCert().toString("utf8");
|
|
1416
|
+
report.write(pem.trim());
|
|
1417
|
+
return report.ok();
|
|
1418
|
+
} catch (e) {
|
|
1419
|
+
return report.error("could not load CA cert: " + ((e && e.message) || String(e)));
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
if (sub === "init") {
|
|
1424
|
+
try {
|
|
1425
|
+
await ca.initCA();
|
|
1426
|
+
report.write("ca-cert: " + ca.paths.caCert);
|
|
1427
|
+
report.write("ca-key: " + (ca.caKeySealedMode === "required" ? ca.paths.caKeySealed : ca.paths.caKey));
|
|
1428
|
+
return report.ok("CA generated. Distribute ca-cert to clients via 'blamejs mtls show-cert'.");
|
|
1429
|
+
} catch (e) {
|
|
1430
|
+
return report.error((e && e.message) || String(e));
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
if (sub === "issue") {
|
|
1435
|
+
var subject = args.flags.subject;
|
|
1436
|
+
if (!subject || subject === true) return report.error("--subject <CN> is required", 2);
|
|
1437
|
+
var days = args.flags.days && args.flags.days !== true ? Number(args.flags.days) : undefined;
|
|
1438
|
+
try {
|
|
1439
|
+
var leaf = await ca.generateClientCert({ cn: String(subject), validityDays: days });
|
|
1440
|
+
report.write("# certificate");
|
|
1441
|
+
report.write(leaf.cert.trim());
|
|
1442
|
+
report.write("");
|
|
1443
|
+
report.write("# private key");
|
|
1444
|
+
report.write(leaf.key.trim());
|
|
1445
|
+
// Framework-canonical fingerprint via b.crypto.sha3Hash. Computed
|
|
1446
|
+
// here over the leaf cert PEM bytes so the audit trail is
|
|
1447
|
+
// independent of whatever fingerprint format the operator-
|
|
1448
|
+
// supplied engine returns. Operators wanting the X.509-
|
|
1449
|
+
// conventional SHA-256 fingerprint (browsers, openssl) can run
|
|
1450
|
+
// `openssl x509 -fingerprint -sha256 -in cert.pem` separately.
|
|
1451
|
+
report.write("");
|
|
1452
|
+
report.write("# fingerprint (sha3-512): " + booted.b.crypto.sha3Hash(Buffer.from(leaf.cert, "utf8")));
|
|
1453
|
+
if (leaf.expiresAt) report.write("# expires: " + new Date(leaf.expiresAt).toISOString());
|
|
1454
|
+
return report.ok();
|
|
1455
|
+
} catch (e) {
|
|
1456
|
+
return report.error((e && e.message) || String(e));
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
if (sub === "issue-p12") {
|
|
1461
|
+
var subjectP = args.flags.subject;
|
|
1462
|
+
var password = args.flags.password;
|
|
1463
|
+
if (!subjectP || subjectP === true) return report.error("--subject <CN> is required", 2);
|
|
1464
|
+
if (!password || password === true) return report.error("--password <pkcs12-passphrase> is required", 2);
|
|
1465
|
+
var daysP = args.flags.days && args.flags.days !== true ? Number(args.flags.days) : undefined;
|
|
1466
|
+
var outPath = args.flags.out && args.flags.out !== true
|
|
1467
|
+
? _resolvePath(String(args.flags.out), ctx.cwd)
|
|
1468
|
+
: null;
|
|
1469
|
+
try {
|
|
1470
|
+
var p12 = await ca.generateClientP12({
|
|
1471
|
+
cn: String(subjectP),
|
|
1472
|
+
password: String(password),
|
|
1473
|
+
validityDays: daysP,
|
|
1474
|
+
});
|
|
1475
|
+
if (outPath) {
|
|
1476
|
+
nodeFs.writeFileSync(outPath, p12.p12, { mode: 0o600 });
|
|
1477
|
+
report.write("p12 written: " + outPath);
|
|
1478
|
+
} else {
|
|
1479
|
+
// No --out: stream the bytes to stdout for piping. Operators
|
|
1480
|
+
// can `blamejs mtls issue-p12 ... > client.p12`.
|
|
1481
|
+
if (ctx.stdout && typeof ctx.stdout.write === "function") {
|
|
1482
|
+
ctx.stdout.write(p12.p12);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
// Framework-canonical fingerprint via b.crypto.sha3Hash over
|
|
1486
|
+
// the embedded cert PEM, same posture as the issue path above.
|
|
1487
|
+
// Independent of the engine's fingerprint format.
|
|
1488
|
+
if (p12.certPem) {
|
|
1489
|
+
report.write("# fingerprint (sha3-512): " + booted.b.crypto.sha3Hash(Buffer.from(p12.certPem, "utf8")));
|
|
1490
|
+
}
|
|
1491
|
+
if (p12.expiresAt) report.write("# expires: " + new Date(p12.expiresAt).toISOString());
|
|
1492
|
+
return report.ok();
|
|
1493
|
+
} catch (e) {
|
|
1494
|
+
return report.error((e && e.message) || String(e));
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
return 2;
|
|
1499
|
+
} finally {
|
|
1500
|
+
try { await booted.app.shutdown(); } catch (_e) { /* best-effort */ }
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// ---- Subcommand: vault ----
|
|
1505
|
+
|
|
1506
|
+
var VAULT_USAGE = [
|
|
1507
|
+
"Usage: blamejs vault <subcommand> [flags]",
|
|
1508
|
+
"",
|
|
1509
|
+
"Subcommands:",
|
|
1510
|
+
" status Report whether vault.key (plaintext) and/or",
|
|
1511
|
+
" vault.key.sealed (wrapped) exist under <data-dir>",
|
|
1512
|
+
" seal Wrap a plaintext vault.key into a passphrase-",
|
|
1513
|
+
" sealed vault.key.sealed (Argon2id KDF +",
|
|
1514
|
+
" XChaCha20-Poly1305). Crash-safe: writes to .tmp",
|
|
1515
|
+
" + fsync + atomic rename, leaves the original",
|
|
1516
|
+
" untouched on any failure.",
|
|
1517
|
+
" unseal Reverse — write a plaintext vault.key from a",
|
|
1518
|
+
" sealed file. For audits / migration to a new",
|
|
1519
|
+
" machine; remove the plaintext file as soon as",
|
|
1520
|
+
" you're done.",
|
|
1521
|
+
" rotate Re-wrap a sealed vault.key.sealed under a new",
|
|
1522
|
+
" passphrase. The old passphrase is required to",
|
|
1523
|
+
" unwrap; the new passphrase wraps. The keypair",
|
|
1524
|
+
" itself is unchanged (use `b.vault.rotateKey()`",
|
|
1525
|
+
" at runtime if you want to rotate the keypair).",
|
|
1526
|
+
"",
|
|
1527
|
+
"Flags:",
|
|
1528
|
+
" --data-dir <path> Path to the app's data dir (default ./data)",
|
|
1529
|
+
" --passphrase <string> Passphrase to wrap with (or env",
|
|
1530
|
+
" BLAMEJS_VAULT_PASSPHRASE). For `rotate`,",
|
|
1531
|
+
" this is the OLD passphrase; pair with",
|
|
1532
|
+
" --new-passphrase / BLAMEJS_VAULT_PASSPHRASE_NEW.",
|
|
1533
|
+
" --new-passphrase <s> Rotate-only — the NEW passphrase to re-wrap",
|
|
1534
|
+
" under. Or env BLAMEJS_VAULT_PASSPHRASE_NEW.",
|
|
1535
|
+
" --keep-plaintext For `seal` — retain the plaintext vault.key",
|
|
1536
|
+
" file (default: delete it after sealing).",
|
|
1537
|
+
].join("\n");
|
|
1538
|
+
|
|
1539
|
+
async function _runVault(args, ctx) {
|
|
1540
|
+
if (args.pos.length === 0) {
|
|
1541
|
+
return cliHelpers.makeReporter(ctx, "blamejs vault").usage(VAULT_USAGE);
|
|
1542
|
+
}
|
|
1543
|
+
var sub = args.pos[0];
|
|
1544
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs vault " + sub);
|
|
1545
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1546
|
+
return report.helpStdout(VAULT_USAGE);
|
|
1547
|
+
}
|
|
1548
|
+
if (["status", "seal", "unseal", "rotate"].indexOf(sub) === -1) {
|
|
1549
|
+
cliHelpers.makeReporter(ctx, "blamejs vault").error("unknown subcommand '" + sub + "'", 2);
|
|
1550
|
+
return cliHelpers.makeReporter(ctx, "blamejs vault").usage(VAULT_USAGE);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
var dataDir = _resolvePath(String(args.flags["data-dir"] || "./data"), ctx.cwd);
|
|
1554
|
+
|
|
1555
|
+
if (sub === "status") {
|
|
1556
|
+
var pre = vaultPassphraseOps.preflightSealable({ dataDir: dataDir });
|
|
1557
|
+
var unsealable = vaultPassphraseOps.preflightUnsealable
|
|
1558
|
+
? vaultPassphraseOps.preflightUnsealable({ dataDir: dataDir })
|
|
1559
|
+
: null;
|
|
1560
|
+
report.write("data-dir: " + dataDir);
|
|
1561
|
+
report.write("vault.key (plaintext): " +
|
|
1562
|
+
(pre.ok ? "present (sealable)" : "absent — " + (pre.reason || "n/a")));
|
|
1563
|
+
if (unsealable) {
|
|
1564
|
+
report.write("vault.key.sealed (wrapped): " +
|
|
1565
|
+
(unsealable.ok ? "present" : "absent — " + (unsealable.reason || "n/a")));
|
|
1566
|
+
}
|
|
1567
|
+
return report.ok();
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
if (sub === "seal") {
|
|
1571
|
+
var pp = cliHelpers.resolvePassphrase(args, ctx, {
|
|
1572
|
+
flag: "passphrase", envVar: "BLAMEJS_VAULT_PASSPHRASE",
|
|
1573
|
+
});
|
|
1574
|
+
if (!pp) {
|
|
1575
|
+
return report.error("--passphrase or BLAMEJS_VAULT_PASSPHRASE is required", 2);
|
|
1576
|
+
}
|
|
1577
|
+
try {
|
|
1578
|
+
var r = await vaultPassphraseOps.seal({
|
|
1579
|
+
dataDir: dataDir,
|
|
1580
|
+
passphrase: pp,
|
|
1581
|
+
keepPlaintext: !!args.flags["keep-plaintext"],
|
|
1582
|
+
});
|
|
1583
|
+
report.write("sealed: " + r.sealedPath);
|
|
1584
|
+
report.write(r.plaintextDeleted
|
|
1585
|
+
? "removed plaintext vault.key"
|
|
1586
|
+
: "kept plaintext vault.key (--keep-plaintext set)");
|
|
1587
|
+
report.write("");
|
|
1588
|
+
report.write("Set BLAMEJS_VAULT_PASSPHRASE in the runtime environment and");
|
|
1589
|
+
return report.ok("boot the app with vault: { mode: \"wrapped\" }.");
|
|
1590
|
+
} catch (e) {
|
|
1591
|
+
return report.error((e && e.message) || String(e));
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
if (sub === "unseal") {
|
|
1596
|
+
var pp2 = cliHelpers.resolvePassphrase(args, ctx, {
|
|
1597
|
+
flag: "passphrase", envVar: "BLAMEJS_VAULT_PASSPHRASE",
|
|
1598
|
+
});
|
|
1599
|
+
if (!pp2) {
|
|
1600
|
+
return report.error("--passphrase or BLAMEJS_VAULT_PASSPHRASE is required", 2);
|
|
1601
|
+
}
|
|
1602
|
+
try {
|
|
1603
|
+
var u = await vaultPassphraseOps.unseal({ dataDir: dataDir, passphrase: pp2 });
|
|
1604
|
+
report.write("unsealed: " + u.plaintextPath);
|
|
1605
|
+
report.write("");
|
|
1606
|
+
report.write("WARNING: vault.key is now plaintext on disk. Re-seal as soon");
|
|
1607
|
+
return report.ok("as you're done auditing or migrating.");
|
|
1608
|
+
} catch (e) {
|
|
1609
|
+
return report.error((e && e.message) || String(e));
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
if (sub === "rotate") {
|
|
1614
|
+
var oldPp = cliHelpers.resolvePassphrase(args, ctx, {
|
|
1615
|
+
flag: "passphrase", envVar: "BLAMEJS_VAULT_PASSPHRASE",
|
|
1616
|
+
});
|
|
1617
|
+
var newPp = cliHelpers.resolvePassphrase(args, ctx, {
|
|
1618
|
+
flag: "new-passphrase", envVar: "BLAMEJS_VAULT_PASSPHRASE_NEW",
|
|
1619
|
+
});
|
|
1620
|
+
if (!oldPp || !newPp) {
|
|
1621
|
+
report.error("both --passphrase (old) and --new-passphrase are required", 2);
|
|
1622
|
+
report.writeErr("(or BLAMEJS_VAULT_PASSPHRASE + BLAMEJS_VAULT_PASSPHRASE_NEW)");
|
|
1623
|
+
return 2;
|
|
1624
|
+
}
|
|
1625
|
+
try {
|
|
1626
|
+
var rr = await vaultPassphraseOps.rotate({
|
|
1627
|
+
dataDir: dataDir,
|
|
1628
|
+
oldPassphrase: oldPp,
|
|
1629
|
+
newPassphrase: newPp,
|
|
1630
|
+
});
|
|
1631
|
+
report.write("rotated: " + rr.sealedPath);
|
|
1632
|
+
return report.ok("Update BLAMEJS_VAULT_PASSPHRASE in the runtime environment to the new value.");
|
|
1633
|
+
} catch (e) {
|
|
1634
|
+
return report.error((e && e.message) || String(e));
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
return 2;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
// ---- Subcommand: security ----------------------------------------
|
|
1642
|
+
//
|
|
1643
|
+
// Runs b.security.assertProduction against the live framework. Useful
|
|
1644
|
+
// out-of-band: ops can re-check posture without rebooting the app.
|
|
1645
|
+
// Boots the framework so resolvers see the actual vault / db / audit-
|
|
1646
|
+
// signing modes; reports pass / fail with the failure-code list.
|
|
1647
|
+
|
|
1648
|
+
var SECURITY_USAGE = [
|
|
1649
|
+
"Usage: blamejs security <subcommand> [flags]",
|
|
1650
|
+
"",
|
|
1651
|
+
"Subcommands:",
|
|
1652
|
+
" assert Run b.security.assertProduction against the framework's",
|
|
1653
|
+
" live posture (vault / dbAtRest / auditSigning / NTP / env",
|
|
1654
|
+
" vars / dataDir POSIX-mode / NODE_ENV). Exit 0 = clean,",
|
|
1655
|
+
" exit 1 = one or more assertions failed.",
|
|
1656
|
+
"",
|
|
1657
|
+
"Flags:",
|
|
1658
|
+
" --data-dir <path> Required for `assert` (the boot dir)",
|
|
1659
|
+
" --vault-mode <mode> plaintext | wrapped (default wrapped)",
|
|
1660
|
+
" --no-ntp-strict Skip the BLAMEJS_NTP_STRICT check",
|
|
1661
|
+
" --require-env <KEY,KEY,...> Comma-separated env vars that MUST be set",
|
|
1662
|
+
" --forbid-env <KEY,KEY,...> Comma-separated env vars that must NOT be set",
|
|
1663
|
+
" --no-vault Skip vault posture check",
|
|
1664
|
+
" --no-db-at-rest Skip dbAtRest posture check",
|
|
1665
|
+
" --no-audit-signing Skip auditSigning posture check",
|
|
1666
|
+
].join("\n");
|
|
1667
|
+
|
|
1668
|
+
async function _runSecurity(args, ctx) {
|
|
1669
|
+
if (args.pos.length === 0) {
|
|
1670
|
+
return cliHelpers.makeReporter(ctx, "blamejs security").usage(SECURITY_USAGE);
|
|
1671
|
+
}
|
|
1672
|
+
var sub = args.pos[0];
|
|
1673
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs security " + sub);
|
|
1674
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1675
|
+
return report.helpStdout(SECURITY_USAGE);
|
|
1676
|
+
}
|
|
1677
|
+
if (sub !== "assert") {
|
|
1678
|
+
cliHelpers.makeReporter(ctx, "blamejs security").error("unknown subcommand '" + sub + "'", 2);
|
|
1679
|
+
return cliHelpers.makeReporter(ctx, "blamejs security").usage(SECURITY_USAGE);
|
|
1680
|
+
}
|
|
1681
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
1682
|
+
if (!dataDirFlag || dataDirFlag === true) {
|
|
1683
|
+
return report.error("--data-dir <path> is required", 2);
|
|
1684
|
+
}
|
|
1685
|
+
var dataDir = _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
1686
|
+
var vaultMode = args.flags["vault-mode"] || "wrapped";
|
|
1687
|
+
if (vaultMode !== "wrapped" && vaultMode !== "plaintext") {
|
|
1688
|
+
return report.error("--vault-mode must be 'wrapped' or 'plaintext'", 2);
|
|
1689
|
+
}
|
|
1690
|
+
var booted;
|
|
1691
|
+
try {
|
|
1692
|
+
booted = await cliHelpers.bootApp({ dataDir: dataDir, vaultMode: vaultMode, env: ctx.env });
|
|
1693
|
+
} catch (e) {
|
|
1694
|
+
return report.error("boot failed: " + ((e && e.message) || String(e)));
|
|
1695
|
+
}
|
|
1696
|
+
try {
|
|
1697
|
+
var assertOpts = {
|
|
1698
|
+
audit: booted.b.audit,
|
|
1699
|
+
dataDir: dataDir,
|
|
1700
|
+
vault: args.flags["no-vault"] ? false : "wrapped",
|
|
1701
|
+
dbAtRest: args.flags["no-db-at-rest"] ? false : "encrypted",
|
|
1702
|
+
auditSigning: args.flags["no-audit-signing"] ? false : "wrapped",
|
|
1703
|
+
ntpStrict: !args.flags["no-ntp-strict"],
|
|
1704
|
+
};
|
|
1705
|
+
if (args.flags["require-env"] && args.flags["require-env"] !== true) {
|
|
1706
|
+
assertOpts.requireEnv = requestHelpers.parseListHeader(args.flags["require-env"]);
|
|
1707
|
+
}
|
|
1708
|
+
if (args.flags["forbid-env"] && args.flags["forbid-env"] !== true) {
|
|
1709
|
+
assertOpts.forbidEnv = requestHelpers.parseListHeader(args.flags["forbid-env"]);
|
|
1710
|
+
}
|
|
1711
|
+
try {
|
|
1712
|
+
await booted.b.security.assertProduction(assertOpts);
|
|
1713
|
+
return report.ok("production posture clean");
|
|
1714
|
+
} catch (e) {
|
|
1715
|
+
if (e && e.isSecurityAssertError && Array.isArray(e.failures)) {
|
|
1716
|
+
report.write("FAIL: " + e.failures.length + " assertion(s):");
|
|
1717
|
+
for (var fi = 0; fi < e.failures.length; fi++) {
|
|
1718
|
+
report.write(" - " + e.failures[fi].code + ": " + e.failures[fi].message);
|
|
1719
|
+
}
|
|
1720
|
+
return 1;
|
|
1721
|
+
}
|
|
1722
|
+
return report.error((e && e.message) || String(e));
|
|
1723
|
+
}
|
|
1724
|
+
} finally {
|
|
1725
|
+
try { await booted.app.shutdown(); } catch (_e) { /* best-effort */ }
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
// ---- Subcommand: config-drift -------------------------------------
|
|
1730
|
+
//
|
|
1731
|
+
// Inspect / verify the b.configDrift sidecar without rebooting. The
|
|
1732
|
+
// sidecar is signed with the audit-signing key, so we boot the
|
|
1733
|
+
// framework to access it. `inspect` prints the full snapshot;
|
|
1734
|
+
// `verify` only reports the verified flag (exit 0 = signed +
|
|
1735
|
+
// untampered, exit 1 = tampered or missing).
|
|
1736
|
+
|
|
1737
|
+
var CONFIG_DRIFT_USAGE = [
|
|
1738
|
+
"Usage: blamejs config-drift <subcommand> [flags]",
|
|
1739
|
+
"",
|
|
1740
|
+
"Subcommands:",
|
|
1741
|
+
" inspect Print the sidecar's snapshot + capturedAt + verified flag",
|
|
1742
|
+
" verify Verify the sidecar's signature (exit code reflects status)",
|
|
1743
|
+
"",
|
|
1744
|
+
"Flags:",
|
|
1745
|
+
" --data-dir <path> Required (sidecar location)",
|
|
1746
|
+
" --baseline <name> Multi-baseline name (default: \"default\")",
|
|
1747
|
+
" --vault-mode <mode> plaintext | wrapped (default wrapped)",
|
|
1748
|
+
" --json inspect: print machine-readable JSON",
|
|
1749
|
+
].join("\n");
|
|
1750
|
+
|
|
1751
|
+
async function _runConfigDrift(args, ctx) {
|
|
1752
|
+
if (args.pos.length === 0) {
|
|
1753
|
+
return cliHelpers.makeReporter(ctx, "blamejs config-drift").usage(CONFIG_DRIFT_USAGE);
|
|
1754
|
+
}
|
|
1755
|
+
var sub = args.pos[0];
|
|
1756
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs config-drift " + sub);
|
|
1757
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1758
|
+
return report.helpStdout(CONFIG_DRIFT_USAGE);
|
|
1759
|
+
}
|
|
1760
|
+
if (["inspect", "verify"].indexOf(sub) === -1) {
|
|
1761
|
+
cliHelpers.makeReporter(ctx, "blamejs config-drift").error("unknown subcommand '" + sub + "'", 2);
|
|
1762
|
+
return cliHelpers.makeReporter(ctx, "blamejs config-drift").usage(CONFIG_DRIFT_USAGE);
|
|
1763
|
+
}
|
|
1764
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
1765
|
+
if (!dataDirFlag || dataDirFlag === true) {
|
|
1766
|
+
return report.error("--data-dir <path> is required", 2);
|
|
1767
|
+
}
|
|
1768
|
+
var dataDir = _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
1769
|
+
var vaultMode = args.flags["vault-mode"] || "wrapped";
|
|
1770
|
+
var booted;
|
|
1771
|
+
try {
|
|
1772
|
+
booted = await cliHelpers.bootApp({ dataDir: dataDir, vaultMode: vaultMode, env: ctx.env });
|
|
1773
|
+
} catch (e) {
|
|
1774
|
+
return report.error("boot failed: " + ((e && e.message) || String(e)));
|
|
1775
|
+
}
|
|
1776
|
+
try {
|
|
1777
|
+
var driftOpts = { dataDir: dataDir, audit: booted.b.audit };
|
|
1778
|
+
if (args.flags.baseline && args.flags.baseline !== true) {
|
|
1779
|
+
driftOpts.baseline = String(args.flags.baseline);
|
|
1780
|
+
}
|
|
1781
|
+
var drift = booted.b.configDrift.create(driftOpts);
|
|
1782
|
+
var sidecar = drift.read();
|
|
1783
|
+
if (!sidecar) {
|
|
1784
|
+
report.write("no sidecar present at " + drift.sidecarPath);
|
|
1785
|
+
return sub === "verify" ? 1 : 0;
|
|
1786
|
+
}
|
|
1787
|
+
if (sub === "verify") {
|
|
1788
|
+
if (sidecar.verified) {
|
|
1789
|
+
return report.ok("sidecar verified at " + new Date(sidecar.capturedAt).toISOString());
|
|
1790
|
+
}
|
|
1791
|
+
report.error("sidecar tamper detected: " + sidecar.tamperReason);
|
|
1792
|
+
return 1;
|
|
1793
|
+
}
|
|
1794
|
+
if (args.flags.json) {
|
|
1795
|
+
report.write(JSON.stringify({
|
|
1796
|
+
capturedAt: sidecar.capturedAt,
|
|
1797
|
+
digestHex: sidecar.digestHex,
|
|
1798
|
+
verified: sidecar.verified,
|
|
1799
|
+
tamperReason: sidecar.tamperReason,
|
|
1800
|
+
snapshot: sidecar.snapshot,
|
|
1801
|
+
}, null, 2));
|
|
1802
|
+
} else {
|
|
1803
|
+
report.write("sidecar: " + drift.sidecarPath);
|
|
1804
|
+
report.write("capturedAt: " + new Date(sidecar.capturedAt).toISOString());
|
|
1805
|
+
report.write("digestHex: " + sidecar.digestHex);
|
|
1806
|
+
report.write("verified: " + (sidecar.verified ? "yes" : "no — " + sidecar.tamperReason));
|
|
1807
|
+
report.write("snapshot:");
|
|
1808
|
+
report.write(JSON.stringify(sidecar.snapshot, null, 2));
|
|
1809
|
+
}
|
|
1810
|
+
return sidecar.verified ? 0 : 1;
|
|
1811
|
+
} finally {
|
|
1812
|
+
try { await booted.app.shutdown(); } catch (_e) { /* best-effort */ }
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// ---- Subcommand: file-type ---------------------------------------
|
|
1817
|
+
//
|
|
1818
|
+
// Pure utility — magic-byte content classification. No framework
|
|
1819
|
+
// boot. Useful for upload debugging ("the user said this was a PDF
|
|
1820
|
+
// but is it really?") and as a CI-side sanity check.
|
|
1821
|
+
|
|
1822
|
+
var FILE_TYPE_USAGE = [
|
|
1823
|
+
"Usage: blamejs file-type detect <file> [flags]",
|
|
1824
|
+
"",
|
|
1825
|
+
"Inspects the leading bytes of <file> against the b.fileType signature",
|
|
1826
|
+
"registry. Prints the detected mime / extension / category; exit 1 when",
|
|
1827
|
+
"no signature matches (the actual format is unknown to the registry).",
|
|
1828
|
+
"",
|
|
1829
|
+
"Flags:",
|
|
1830
|
+
" --json Print machine-readable JSON",
|
|
1831
|
+
" --allowlist <list> Comma-separated mime / category list — exits 1",
|
|
1832
|
+
" when the detected type is NOT in the allowlist",
|
|
1833
|
+
" (mirrors b.fileType.assertOneOf).",
|
|
1834
|
+
].join("\n");
|
|
1835
|
+
|
|
1836
|
+
function _runFileType(args, ctx) {
|
|
1837
|
+
if (args.pos.length === 0) {
|
|
1838
|
+
return cliHelpers.makeReporter(ctx, "blamejs file-type").usage(FILE_TYPE_USAGE);
|
|
1839
|
+
}
|
|
1840
|
+
var sub = args.pos[0];
|
|
1841
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs file-type " + sub);
|
|
1842
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1843
|
+
return report.helpStdout(FILE_TYPE_USAGE);
|
|
1844
|
+
}
|
|
1845
|
+
if (sub !== "detect") {
|
|
1846
|
+
cliHelpers.makeReporter(ctx, "blamejs file-type").error("unknown subcommand '" + sub + "'", 2);
|
|
1847
|
+
return cliHelpers.makeReporter(ctx, "blamejs file-type").usage(FILE_TYPE_USAGE);
|
|
1848
|
+
}
|
|
1849
|
+
var file = args.pos[1];
|
|
1850
|
+
if (!file) return report.error("file path is required (positional arg after 'detect')", 2);
|
|
1851
|
+
var resolved = _resolvePath(String(file), ctx.cwd);
|
|
1852
|
+
var buf;
|
|
1853
|
+
try { buf = nodeFs.readFileSync(resolved); }
|
|
1854
|
+
catch (e) {
|
|
1855
|
+
return report.error("read failed: " + ((e && e.message) || String(e)));
|
|
1856
|
+
}
|
|
1857
|
+
if (args.flags.allowlist && args.flags.allowlist !== true) {
|
|
1858
|
+
var allowed = requestHelpers.parseListHeader(args.flags.allowlist);
|
|
1859
|
+
try {
|
|
1860
|
+
var det = fileType.assertOneOf(buf, allowed);
|
|
1861
|
+
if (args.flags.json) report.write(JSON.stringify(det));
|
|
1862
|
+
else {
|
|
1863
|
+
report.write("mime: " + det.mime);
|
|
1864
|
+
report.write("extension: " + det.extension);
|
|
1865
|
+
report.write("category: " + det.category);
|
|
1866
|
+
report.write("name: " + det.name);
|
|
1867
|
+
}
|
|
1868
|
+
return report.ok("matched allowlist " + JSON.stringify(allowed));
|
|
1869
|
+
} catch (e) {
|
|
1870
|
+
return report.error(e.code + ": " + e.message);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
var detected = fileType.detect(buf);
|
|
1874
|
+
if (!detected) {
|
|
1875
|
+
if (args.flags.json) report.write("null");
|
|
1876
|
+
return report.error("unknown — no signature matched the leading bytes (" +
|
|
1877
|
+
buf.length + " bytes read)");
|
|
1878
|
+
}
|
|
1879
|
+
if (args.flags.json) {
|
|
1880
|
+
report.write(JSON.stringify(detected));
|
|
1881
|
+
} else {
|
|
1882
|
+
report.write("mime: " + detected.mime);
|
|
1883
|
+
report.write("extension: " + detected.extension);
|
|
1884
|
+
report.write("category: " + detected.category);
|
|
1885
|
+
report.write("name: " + detected.name);
|
|
1886
|
+
}
|
|
1887
|
+
return report.ok();
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// ---- Subcommand: password ----------------------------------------
|
|
1891
|
+
//
|
|
1892
|
+
// Test b.auth.password.policy from the CLI without rebooting the app.
|
|
1893
|
+
// Useful for ops dashboards that want to surface "your policy
|
|
1894
|
+
// requires X" or for CI checks of operator-supplied passwords.
|
|
1895
|
+
|
|
1896
|
+
var PASSWORD_USAGE = [
|
|
1897
|
+
"Usage: blamejs password check [flags]",
|
|
1898
|
+
"",
|
|
1899
|
+
"Runs b.auth.password.policy({ profile, ... }).check(plaintext, context).",
|
|
1900
|
+
"Exit 0 = ok, exit 1 = policy rejected, exit 2 = bad args.",
|
|
1901
|
+
"",
|
|
1902
|
+
"Flags:",
|
|
1903
|
+
" --plaintext <s> REQUIRED — the plaintext to test (or use stdin)",
|
|
1904
|
+
" --stdin Read the plaintext from stdin (newline-trimmed)",
|
|
1905
|
+
" --profile <name> Named profile: nist-aal2 | pci-4.0 | hipaa-aal2",
|
|
1906
|
+
" --min-length <n> Override the profile minLength",
|
|
1907
|
+
" --max-length <n> Override the profile maxLength",
|
|
1908
|
+
" --breach-check Enable HaveIBeenPwned k-anonymity check (NETWORK)",
|
|
1909
|
+
" --fail-closed With --breach-check: HIBP outage → fail (default ok)",
|
|
1910
|
+
" --email <addr> Context for the deny-context-substrings check",
|
|
1911
|
+
" --username <name> Context for the deny-context-substrings check",
|
|
1912
|
+
" --json Print machine-readable JSON",
|
|
1913
|
+
].join("\n");
|
|
1914
|
+
|
|
1915
|
+
async function _runPassword(args, ctx) {
|
|
1916
|
+
if (args.pos.length === 0) {
|
|
1917
|
+
return cliHelpers.makeReporter(ctx, "blamejs password").usage(PASSWORD_USAGE);
|
|
1918
|
+
}
|
|
1919
|
+
var sub = args.pos[0];
|
|
1920
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs password " + sub);
|
|
1921
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
1922
|
+
return report.helpStdout(PASSWORD_USAGE);
|
|
1923
|
+
}
|
|
1924
|
+
if (sub !== "check") {
|
|
1925
|
+
cliHelpers.makeReporter(ctx, "blamejs password").error("unknown subcommand '" + sub + "'", 2);
|
|
1926
|
+
return cliHelpers.makeReporter(ctx, "blamejs password").usage(PASSWORD_USAGE);
|
|
1927
|
+
}
|
|
1928
|
+
var plaintext;
|
|
1929
|
+
if (args.flags.stdin) {
|
|
1930
|
+
try { plaintext = nodeFs.readFileSync(0, "utf8").replace(/\r?\n$/, ""); }
|
|
1931
|
+
catch (e) { return report.error("stdin read failed: " + ((e && e.message) || String(e))); }
|
|
1932
|
+
} else if (args.flags.plaintext && args.flags.plaintext !== true) {
|
|
1933
|
+
plaintext = String(args.flags.plaintext);
|
|
1934
|
+
} else {
|
|
1935
|
+
return report.error("--plaintext <s> or --stdin is required", 2);
|
|
1936
|
+
}
|
|
1937
|
+
var policyOpts = {};
|
|
1938
|
+
if (args.flags.profile && args.flags.profile !== true) policyOpts.profile = String(args.flags.profile);
|
|
1939
|
+
if (args.flags["min-length"] && args.flags["min-length"] !== true) {
|
|
1940
|
+
policyOpts.minLength = Number(args.flags["min-length"]);
|
|
1941
|
+
}
|
|
1942
|
+
if (args.flags["max-length"] && args.flags["max-length"] !== true) {
|
|
1943
|
+
policyOpts.maxLength = Number(args.flags["max-length"]);
|
|
1944
|
+
}
|
|
1945
|
+
if (args.flags["breach-check"]) {
|
|
1946
|
+
policyOpts.breachCheck = "haveibeenpwned";
|
|
1947
|
+
if (args.flags["fail-closed"]) policyOpts.failClosed = true;
|
|
1948
|
+
}
|
|
1949
|
+
var policy;
|
|
1950
|
+
try { policy = passwordModule.policy(policyOpts); }
|
|
1951
|
+
catch (e) { return report.error("bad policy: " + ((e && e.message) || String(e)), 2); }
|
|
1952
|
+
var context = {};
|
|
1953
|
+
if (args.flags.email && args.flags.email !== true) context.email = String(args.flags.email);
|
|
1954
|
+
if (args.flags.username && args.flags.username !== true) context.username = String(args.flags.username);
|
|
1955
|
+
var verdict;
|
|
1956
|
+
try { verdict = await policy.check(plaintext, context); }
|
|
1957
|
+
catch (e) { return report.error("check threw: " + ((e && e.message) || String(e))); }
|
|
1958
|
+
if (args.flags.json) {
|
|
1959
|
+
report.write(JSON.stringify(verdict));
|
|
1960
|
+
return verdict.ok ? 0 : 1;
|
|
1961
|
+
}
|
|
1962
|
+
if (verdict.ok) {
|
|
1963
|
+
report.write("ok");
|
|
1964
|
+
if (verdict.breachCheckSkipped) {
|
|
1965
|
+
report.write(" (HIBP skipped: " + verdict.breachCheckSkipReason + ")");
|
|
1966
|
+
} else if (typeof verdict.breachCheckCount === "number") {
|
|
1967
|
+
report.write(" (HIBP breach count: " + verdict.breachCheckCount + ")");
|
|
1968
|
+
}
|
|
1969
|
+
return 0;
|
|
1970
|
+
}
|
|
1971
|
+
report.write("REJECTED: " + verdict.code);
|
|
1972
|
+
report.write(" " + verdict.message);
|
|
1973
|
+
return 1;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
// ---- Subcommand: erase -------------------------------------------
|
|
1977
|
+
//
|
|
1978
|
+
// Cryptographic-erasure of a single row. The right tool for one-off
|
|
1979
|
+
// GDPR Art. 17 / right-to-erasure flows that don't fit the periodic
|
|
1980
|
+
// retention sweep. Replaces every sealed column + derived hash with
|
|
1981
|
+
// NULL, sets __erasedAt, and writes the row back. Cleartext is
|
|
1982
|
+
// unrecoverable even with the vault key.
|
|
1983
|
+
|
|
1984
|
+
var ERASE_USAGE = [
|
|
1985
|
+
"Usage: blamejs erase --table <table> --row-id <id> [flags]",
|
|
1986
|
+
"",
|
|
1987
|
+
"Tombstones a single row's sealed columns + derived hashes. Used for",
|
|
1988
|
+
"one-off compliance erasure (GDPR Art. 17). The row stays in the table",
|
|
1989
|
+
"(referential integrity) but the cleartext is unrecoverable.",
|
|
1990
|
+
"",
|
|
1991
|
+
"Flags:",
|
|
1992
|
+
" --data-dir <path> Required",
|
|
1993
|
+
" --table <name> Required — the table containing the row",
|
|
1994
|
+
" --row-id <id> Required — the _id of the row to erase",
|
|
1995
|
+
" --vault-mode <mode> plaintext | wrapped (default wrapped)",
|
|
1996
|
+
" --reason <text> Reason recorded on the audit row (recommended)",
|
|
1997
|
+
" --confirm Required — confirms the erase is intentional",
|
|
1998
|
+
].join("\n");
|
|
1999
|
+
|
|
2000
|
+
async function _runErase(args, ctx) {
|
|
2001
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs erase");
|
|
2002
|
+
if (args.flags.help || args.flags.h) {
|
|
2003
|
+
return report.helpStdout(ERASE_USAGE);
|
|
2004
|
+
}
|
|
2005
|
+
var table = args.flags.table;
|
|
2006
|
+
var rowId = args.flags["row-id"];
|
|
2007
|
+
if (!table || table === true) return report.error("--table <name> is required", 2);
|
|
2008
|
+
if (!rowId || rowId === true) return report.error("--row-id <id> is required", 2);
|
|
2009
|
+
if (!args.flags.confirm) {
|
|
2010
|
+
return report.error("--confirm is required (this operation is irreversible)", 2);
|
|
2011
|
+
}
|
|
2012
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
2013
|
+
if (!dataDirFlag || dataDirFlag === true) {
|
|
2014
|
+
return report.error("--data-dir <path> is required", 2);
|
|
2015
|
+
}
|
|
2016
|
+
var dataDir = _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
2017
|
+
var vaultMode = args.flags["vault-mode"] || "wrapped";
|
|
2018
|
+
var reason = (args.flags.reason && args.flags.reason !== true) ? String(args.flags.reason) : null;
|
|
2019
|
+
var booted;
|
|
2020
|
+
try {
|
|
2021
|
+
booted = await cliHelpers.bootApp({ dataDir: dataDir, vaultMode: vaultMode, env: ctx.env });
|
|
2022
|
+
} catch (e) {
|
|
2023
|
+
return report.error("boot failed: " + ((e && e.message) || String(e)));
|
|
2024
|
+
}
|
|
2025
|
+
try {
|
|
2026
|
+
var b = booted.b;
|
|
2027
|
+
var safeTable = String(table).replace(/[^A-Za-z0-9_]/g, "");
|
|
2028
|
+
if (safeTable !== String(table) || safeTable.length === 0) {
|
|
2029
|
+
return report.error("--table must be a valid identifier (got " + JSON.stringify(table) + ")", 2);
|
|
2030
|
+
}
|
|
2031
|
+
var row;
|
|
2032
|
+
try {
|
|
2033
|
+
row = b.db.prepare("SELECT * FROM \"" + safeTable + "\" WHERE _id = ?").get(String(rowId));
|
|
2034
|
+
} catch (e) {
|
|
2035
|
+
return report.error("row lookup failed: " + ((e && e.message) || String(e)));
|
|
2036
|
+
}
|
|
2037
|
+
if (!row) {
|
|
2038
|
+
return report.error("no row with _id=" + JSON.stringify(rowId) + " in table " + safeTable);
|
|
2039
|
+
}
|
|
2040
|
+
var schema = b.cryptoField.getSchema(safeTable);
|
|
2041
|
+
var sealedFields = schema && Array.isArray(schema.sealedFields) ? schema.sealedFields : [];
|
|
2042
|
+
var derivedHashes = schema && schema.derivedHashes ? Object.keys(schema.derivedHashes) : [];
|
|
2043
|
+
if (sealedFields.length === 0 && derivedHashes.length === 0) {
|
|
2044
|
+
return report.error("table " + safeTable + " has no sealed columns or derived hashes; " +
|
|
2045
|
+
"use a regular DELETE for non-sealed rows");
|
|
2046
|
+
}
|
|
2047
|
+
var setClauses = [];
|
|
2048
|
+
var values = [];
|
|
2049
|
+
for (var si = 0; si < sealedFields.length; si++) {
|
|
2050
|
+
setClauses.push('"' + sealedFields[si] + '" = ?');
|
|
2051
|
+
values.push(null);
|
|
2052
|
+
}
|
|
2053
|
+
for (var di = 0; di < derivedHashes.length; di++) {
|
|
2054
|
+
setClauses.push('"' + derivedHashes[di] + '" = ?');
|
|
2055
|
+
values.push(null);
|
|
2056
|
+
}
|
|
2057
|
+
values.push(String(rowId));
|
|
2058
|
+
try {
|
|
2059
|
+
var upd = b.db.prepare("UPDATE \"" + safeTable + "\" SET " + setClauses.join(", ") + " WHERE _id = ?");
|
|
2060
|
+
upd.run.apply(upd, values);
|
|
2061
|
+
} catch (e) {
|
|
2062
|
+
return report.error("UPDATE failed: " + ((e && e.message) || String(e)));
|
|
2063
|
+
}
|
|
2064
|
+
try {
|
|
2065
|
+
b.audit.safeEmit({
|
|
2066
|
+
action: "system.erase",
|
|
2067
|
+
outcome: "success",
|
|
2068
|
+
resource: { kind: "row.erase", id: safeTable + "/" + String(rowId) },
|
|
2069
|
+
reason: reason,
|
|
2070
|
+
metadata: {
|
|
2071
|
+
table: safeTable, rowId: String(rowId),
|
|
2072
|
+
sealedFieldCount: sealedFields.length,
|
|
2073
|
+
derivedHashCount: derivedHashes.length,
|
|
2074
|
+
},
|
|
2075
|
+
});
|
|
2076
|
+
} catch (_e) { /* audit best-effort */ }
|
|
2077
|
+
report.write("erased: " + safeTable + "/" + String(rowId));
|
|
2078
|
+
report.write(" sealed columns nulled: " + sealedFields.join(", "));
|
|
2079
|
+
if (derivedHashes.length > 0) {
|
|
2080
|
+
report.write(" derived hashes nulled: " + derivedHashes.join(", "));
|
|
2081
|
+
}
|
|
2082
|
+
return report.ok();
|
|
2083
|
+
} finally {
|
|
2084
|
+
try { await booted.app.shutdown(); } catch (_e) { /* best-effort */ }
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// ---- Subcommand: retention ---------------------------------------
|
|
2089
|
+
//
|
|
2090
|
+
// Run / preview an ad-hoc retention rule from the CLI. Operators
|
|
2091
|
+
// supply the rule shape on the command line — table + ageField +
|
|
2092
|
+
// ttlMs + action — for one-off cleanups outside the scheduler-
|
|
2093
|
+
// driven sweep wired in lib code.
|
|
2094
|
+
|
|
2095
|
+
var RETENTION_USAGE = [
|
|
2096
|
+
"Usage: blamejs retention <subcommand> [flags]",
|
|
2097
|
+
"",
|
|
2098
|
+
"Subcommands:",
|
|
2099
|
+
" preview Dry-run: report what WOULD be processed without acting",
|
|
2100
|
+
" run Run the rule once (acts on the rows it finds)",
|
|
2101
|
+
"",
|
|
2102
|
+
"Flags (all subcommands):",
|
|
2103
|
+
" --data-dir <path> Required",
|
|
2104
|
+
" --vault-mode <mode> plaintext | wrapped (default wrapped)",
|
|
2105
|
+
" --table <name> Required — table to sweep",
|
|
2106
|
+
" --age-field <col> Required — column holding the ms-epoch timestamp",
|
|
2107
|
+
" --ttl-ms <ms> Required — rows older than (now - ttlMs) are matched",
|
|
2108
|
+
" --action <a> erase (default) | delete | soft-delete",
|
|
2109
|
+
" --soft-delete-field <col>",
|
|
2110
|
+
" For action=soft-delete — column to write the",
|
|
2111
|
+
" deletion timestamp into (required when action=soft-delete)",
|
|
2112
|
+
" --legal-hold-field <col>",
|
|
2113
|
+
" Per-row legal-hold exemption column; rows where this",
|
|
2114
|
+
" is truthy are skipped",
|
|
2115
|
+
" --batch-size <n> Rows per batch (default 500)",
|
|
2116
|
+
" --json Print machine-readable JSON summary",
|
|
2117
|
+
].join("\n");
|
|
2118
|
+
|
|
2119
|
+
async function _runRetention(args, ctx) {
|
|
2120
|
+
if (args.pos.length === 0) {
|
|
2121
|
+
return cliHelpers.makeReporter(ctx, "blamejs retention").usage(RETENTION_USAGE);
|
|
2122
|
+
}
|
|
2123
|
+
var sub = args.pos[0];
|
|
2124
|
+
var report = cliHelpers.makeReporter(ctx, "blamejs retention " + sub);
|
|
2125
|
+
if (sub === "help" || args.flags.help || args.flags.h) {
|
|
2126
|
+
return report.helpStdout(RETENTION_USAGE);
|
|
2127
|
+
}
|
|
2128
|
+
if (["preview", "run"].indexOf(sub) === -1) {
|
|
2129
|
+
cliHelpers.makeReporter(ctx, "blamejs retention").error("unknown subcommand '" + sub + "'", 2);
|
|
2130
|
+
return cliHelpers.makeReporter(ctx, "blamejs retention").usage(RETENTION_USAGE);
|
|
2131
|
+
}
|
|
2132
|
+
var dataDirFlag = args.flags["data-dir"];
|
|
2133
|
+
if (!dataDirFlag || dataDirFlag === true) return report.error("--data-dir <path> is required", 2);
|
|
2134
|
+
var table = args.flags.table;
|
|
2135
|
+
var ageField = args.flags["age-field"];
|
|
2136
|
+
var ttlMs = args.flags["ttl-ms"];
|
|
2137
|
+
if (!table || table === true) return report.error("--table <name> is required", 2);
|
|
2138
|
+
if (!ageField || ageField === true) return report.error("--age-field <col> is required", 2);
|
|
2139
|
+
if (!ttlMs || ttlMs === true) return report.error("--ttl-ms <ms> is required", 2);
|
|
2140
|
+
var ttlMsNum = Number(ttlMs);
|
|
2141
|
+
if (!isFinite(ttlMsNum) || ttlMsNum <= 0) {
|
|
2142
|
+
return report.error("--ttl-ms must be a positive finite number", 2);
|
|
2143
|
+
}
|
|
2144
|
+
var action = args.flags.action ? String(args.flags.action) : "erase";
|
|
2145
|
+
if (["erase", "delete", "soft-delete"].indexOf(action) === -1) {
|
|
2146
|
+
return report.error("--action must be erase / delete / soft-delete", 2);
|
|
2147
|
+
}
|
|
2148
|
+
if (action === "soft-delete" &&
|
|
2149
|
+
(!args.flags["soft-delete-field"] || args.flags["soft-delete-field"] === true)) {
|
|
2150
|
+
return report.error("--soft-delete-field <col> required when --action=soft-delete", 2);
|
|
2151
|
+
}
|
|
2152
|
+
var batchSize = args.flags["batch-size"] && args.flags["batch-size"] !== true
|
|
2153
|
+
? Number(args.flags["batch-size"]) : 500;
|
|
2154
|
+
var dataDir = _resolvePath(String(dataDirFlag), ctx.cwd);
|
|
2155
|
+
var vaultMode = args.flags["vault-mode"] || "wrapped";
|
|
2156
|
+
var booted;
|
|
2157
|
+
try {
|
|
2158
|
+
booted = await cliHelpers.bootApp({ dataDir: dataDir, vaultMode: vaultMode, env: ctx.env });
|
|
2159
|
+
} catch (e) {
|
|
2160
|
+
return report.error("boot failed: " + ((e && e.message) || String(e)));
|
|
2161
|
+
}
|
|
2162
|
+
try {
|
|
2163
|
+
var rules = booted.b.retention.create({ db: booted.b.db, audit: booted.b.audit });
|
|
2164
|
+
var ruleSpec = {
|
|
2165
|
+
name: "cli-" + String(table) + "-" + Date.now(),
|
|
2166
|
+
table: String(table),
|
|
2167
|
+
ageField: String(ageField),
|
|
2168
|
+
ttlMs: ttlMsNum,
|
|
2169
|
+
action: action,
|
|
2170
|
+
batchSize: batchSize,
|
|
2171
|
+
};
|
|
2172
|
+
if (args.flags["soft-delete-field"] && args.flags["soft-delete-field"] !== true) {
|
|
2173
|
+
ruleSpec.softDeleteField = String(args.flags["soft-delete-field"]);
|
|
2174
|
+
}
|
|
2175
|
+
if (args.flags["legal-hold-field"] && args.flags["legal-hold-field"] !== true) {
|
|
2176
|
+
ruleSpec.legalHoldField = String(args.flags["legal-hold-field"]);
|
|
2177
|
+
}
|
|
2178
|
+
rules.declare(ruleSpec);
|
|
2179
|
+
var summary = await rules.run(ruleSpec.name, { dryRun: sub === "preview" });
|
|
2180
|
+
if (args.flags.json) {
|
|
2181
|
+
report.write(JSON.stringify(summary, null, 2));
|
|
2182
|
+
} else {
|
|
2183
|
+
report.write((sub === "preview" ? "DRY-RUN " : "") + "rule: " + ruleSpec.name);
|
|
2184
|
+
report.write("table: " + ruleSpec.table);
|
|
2185
|
+
report.write("scanned: " + summary.scanned);
|
|
2186
|
+
report.write("processed:" + summary.processed);
|
|
2187
|
+
report.write("skipped: " + summary.skipped);
|
|
2188
|
+
report.write("legalHoldsHonored: " + summary.legalHoldsHonored);
|
|
2189
|
+
if (summary.errors && summary.errors.length > 0) {
|
|
2190
|
+
report.write("errors: " + summary.errors.length);
|
|
2191
|
+
for (var ei = 0; ei < Math.min(summary.errors.length, 5); ei++) {
|
|
2192
|
+
report.write(" - " + (summary.errors[ei].rowId || "?") + ": " + summary.errors[ei].reason);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
report.write("durationMs: " + summary.durationMs);
|
|
2196
|
+
}
|
|
2197
|
+
return summary.errors && summary.errors.length > 0 ? 1 : 0;
|
|
2198
|
+
} catch (e) {
|
|
2199
|
+
return report.error((e && e.message) || String(e));
|
|
2200
|
+
} finally {
|
|
2201
|
+
try { await booted.app.shutdown(); } catch (_e) { /* best-effort */ }
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
var TOP_USAGE = [
|
|
2206
|
+
"Usage: blamejs <command> [args]",
|
|
2207
|
+
"",
|
|
2208
|
+
"Commands:",
|
|
2209
|
+
" migrate Manage database migrations (up / down / status)",
|
|
2210
|
+
" seed Apply seed-data fixtures by env (run / status)",
|
|
2211
|
+
" dev Run an app with file-watch + auto-restart",
|
|
2212
|
+
" api-snapshot Capture / compare the public API surface (CI gate)",
|
|
2213
|
+
" api-key Issue / revoke / list / rotate / verify API keys for a namespace",
|
|
2214
|
+
" audit Operator tooling on top of the audit chain (archive / export / verify / purge)",
|
|
2215
|
+
" backup Inspect / verify / extract a backup bundle from disk",
|
|
2216
|
+
" restore Live in-place restore from a bundle (list / inspect / apply / rollback / list-rollbacks)",
|
|
2217
|
+
" mtls Inspect or generate the in-box mTLS CA + leaf certs (status / show-cert / init / issue / issue-p12)",
|
|
2218
|
+
" vault Seal / unseal / rotate the on-disk vault keypair (plaintext ↔ wrapped)",
|
|
2219
|
+
" security Run b.security.assertProduction against the live framework",
|
|
2220
|
+
" config-drift Inspect / verify the b.configDrift signed sidecar",
|
|
2221
|
+
" file-type Magic-byte content classification (b.fileType.detect)",
|
|
2222
|
+
" password Test b.auth.password.policy against a candidate plaintext",
|
|
2223
|
+
" erase Cryptographically erase a single row's sealed columns (GDPR Art. 17)",
|
|
2224
|
+
" retention Run / preview an ad-hoc b.retention rule",
|
|
2225
|
+
" version Print framework version",
|
|
2226
|
+
" help [<command>] Show this message or details for a command",
|
|
2227
|
+
].join("\n");
|
|
2228
|
+
|
|
2229
|
+
function _printTopHelp(ctx) { _writeLine(ctx.stdout, TOP_USAGE); }
|
|
2230
|
+
|
|
2231
|
+
// ---- Dispatch ----
|
|
2232
|
+
|
|
2233
|
+
async function main(argv, opts) {
|
|
2234
|
+
opts = opts || {};
|
|
2235
|
+
var ctx = {
|
|
2236
|
+
stdout: opts.stdout || process.stdout,
|
|
2237
|
+
stderr: opts.stderr || process.stderr,
|
|
2238
|
+
env: opts.env || process.env,
|
|
2239
|
+
cwd: opts.cwd || process.cwd(),
|
|
2240
|
+
};
|
|
2241
|
+
if (!Array.isArray(argv)) argv = [];
|
|
2242
|
+
var args = _parseArgs(argv);
|
|
2243
|
+
|
|
2244
|
+
// Top-level flags handled before subcommand dispatch
|
|
2245
|
+
if (args.flags.version || args.flags.v) {
|
|
2246
|
+
_writeLine(ctx.stdout, C.version);
|
|
2247
|
+
return 0;
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
var cmd = args.pos[0];
|
|
2251
|
+
|
|
2252
|
+
// --help routing:
|
|
2253
|
+
// `blamejs --help` → top-level help
|
|
2254
|
+
// `blamejs <cmd> --help` → that command's USAGE (via the
|
|
2255
|
+
// existing `help <cmd>` dispatch
|
|
2256
|
+
// block below). Synthesizing the
|
|
2257
|
+
// positional form keeps every
|
|
2258
|
+
// subcommand's per-command usage
|
|
2259
|
+
// reachable via `--help` without
|
|
2260
|
+
// each handler having to special-case
|
|
2261
|
+
// the flag-only-no-subcommand nodePath.
|
|
2262
|
+
if (cmd === undefined) { _printTopHelp(ctx); return 0; }
|
|
2263
|
+
if (args.flags.help || args.flags.h) {
|
|
2264
|
+
args = _parseArgs(["help", cmd]);
|
|
2265
|
+
cmd = "help";
|
|
2266
|
+
}
|
|
2267
|
+
if (cmd === "help") {
|
|
2268
|
+
var subTopic = args.pos[1];
|
|
2269
|
+
if (subTopic === "migrate") { _writeLine(ctx.stdout, MIGRATE_USAGE); return 0; }
|
|
2270
|
+
if (subTopic === "seed") { _writeLine(ctx.stdout, SEED_USAGE); return 0; }
|
|
2271
|
+
if (subTopic === "dev") { _writeLine(ctx.stdout, DEV_USAGE); return 0; }
|
|
2272
|
+
if (subTopic === "api-snapshot") { _writeLine(ctx.stdout, API_SNAPSHOT_USAGE); return 0; }
|
|
2273
|
+
if (subTopic === "api-key") { _writeLine(ctx.stdout, API_KEY_USAGE); return 0; }
|
|
2274
|
+
if (subTopic === "audit") { _writeLine(ctx.stdout, AUDIT_USAGE); return 0; }
|
|
2275
|
+
if (subTopic === "backup") { _writeLine(ctx.stdout, BACKUP_USAGE); return 0; }
|
|
2276
|
+
if (subTopic === "restore") { _writeLine(ctx.stdout, RESTORE_USAGE); return 0; }
|
|
2277
|
+
if (subTopic === "mtls") { _writeLine(ctx.stdout, MTLS_USAGE); return 0; }
|
|
2278
|
+
if (subTopic === "vault") { _writeLine(ctx.stdout, VAULT_USAGE); return 0; }
|
|
2279
|
+
if (subTopic === "security") { _writeLine(ctx.stdout, SECURITY_USAGE); return 0; }
|
|
2280
|
+
if (subTopic === "config-drift") { _writeLine(ctx.stdout, CONFIG_DRIFT_USAGE); return 0; }
|
|
2281
|
+
if (subTopic === "file-type") { _writeLine(ctx.stdout, FILE_TYPE_USAGE); return 0; }
|
|
2282
|
+
if (subTopic === "password") { _writeLine(ctx.stdout, PASSWORD_USAGE); return 0; }
|
|
2283
|
+
if (subTopic === "erase") { _writeLine(ctx.stdout, ERASE_USAGE); return 0; }
|
|
2284
|
+
if (subTopic === "retention") { _writeLine(ctx.stdout, RETENTION_USAGE); return 0; }
|
|
2285
|
+
_printTopHelp(ctx);
|
|
2286
|
+
return 0;
|
|
2287
|
+
}
|
|
2288
|
+
if (cmd === "version") { _writeLine(ctx.stdout, C.version); return 0; }
|
|
2289
|
+
|
|
2290
|
+
var rest = { pos: args.pos.slice(1), flags: args.flags };
|
|
2291
|
+
if (cmd === "migrate") return await _runMigrate(rest, ctx);
|
|
2292
|
+
if (cmd === "seed") return await _runSeed(rest, ctx);
|
|
2293
|
+
if (cmd === "dev") return await _runDev(rest, ctx);
|
|
2294
|
+
if (cmd === "api-snapshot") return _runApiSnapshot(rest, ctx);
|
|
2295
|
+
if (cmd === "api-key") return await _runApiKey(rest, ctx);
|
|
2296
|
+
if (cmd === "audit") return await _runAudit(rest, ctx);
|
|
2297
|
+
if (cmd === "backup") return await _runBackup(rest, ctx);
|
|
2298
|
+
if (cmd === "restore") return await _runRestore(rest, ctx);
|
|
2299
|
+
if (cmd === "mtls") return await _runMtls(rest, ctx);
|
|
2300
|
+
if (cmd === "vault") return await _runVault(rest, ctx);
|
|
2301
|
+
if (cmd === "security") return await _runSecurity(rest, ctx);
|
|
2302
|
+
if (cmd === "config-drift") return await _runConfigDrift(rest, ctx);
|
|
2303
|
+
if (cmd === "file-type") return _runFileType(rest, ctx);
|
|
2304
|
+
if (cmd === "password") return await _runPassword(rest, ctx);
|
|
2305
|
+
if (cmd === "erase") return await _runErase(rest, ctx);
|
|
2306
|
+
if (cmd === "retention") return await _runRetention(rest, ctx);
|
|
2307
|
+
|
|
2308
|
+
_writeLine(ctx.stderr, "blamejs: unknown command '" + cmd + "'");
|
|
2309
|
+
_printTopHelp(ctx);
|
|
2310
|
+
return 2;
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
module.exports = {
|
|
2314
|
+
main: main,
|
|
2315
|
+
// Internal helpers exposed so tests can drive the parser without
|
|
2316
|
+
// running the full dispatch.
|
|
2317
|
+
_parseArgs: _parseArgs,
|
|
2318
|
+
TOP_USAGE: TOP_USAGE,
|
|
2319
|
+
MIGRATE_USAGE: MIGRATE_USAGE,
|
|
2320
|
+
DEV_USAGE: DEV_USAGE,
|
|
2321
|
+
API_SNAPSHOT_USAGE: API_SNAPSHOT_USAGE,
|
|
2322
|
+
API_KEY_USAGE: API_KEY_USAGE,
|
|
2323
|
+
AUDIT_USAGE: AUDIT_USAGE,
|
|
2324
|
+
BACKUP_USAGE: BACKUP_USAGE,
|
|
2325
|
+
RESTORE_USAGE: RESTORE_USAGE,
|
|
2326
|
+
MTLS_USAGE: MTLS_USAGE,
|
|
2327
|
+
VAULT_USAGE: VAULT_USAGE,
|
|
2328
|
+
};
|