@blamejs/blamejs-shop 0.5.12 → 0.5.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +632 -416
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
- package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/.gitignore +2 -0
- package/lib/vendor/blamejs/CHANGELOG.md +122 -0
- package/lib/vendor/blamejs/NOTICE +26 -1
- package/lib/vendor/blamejs/SECURITY.md +1 -1
- package/lib/vendor/blamejs/api-snapshot.json +207 -5
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
- package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
- package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
- package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
- package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
- package/lib/vendor/blamejs/index.js +6 -0
- package/lib/vendor/blamejs/lib/a2a.js +4 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
- package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
- package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
- package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
- package/lib/vendor/blamejs/lib/archive-read.js +8 -0
- package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
- package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
- package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
- package/lib/vendor/blamejs/lib/audit.js +71 -8
- package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
- package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
- package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
- package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
- package/lib/vendor/blamejs/lib/backup/index.js +16 -5
- package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
- package/lib/vendor/blamejs/lib/base32.js +21 -0
- package/lib/vendor/blamejs/lib/break-glass.js +19 -10
- package/lib/vendor/blamejs/lib/bundler.js +5 -1
- package/lib/vendor/blamejs/lib/cache-status.js +3 -7
- package/lib/vendor/blamejs/lib/calendar.js +21 -1
- package/lib/vendor/blamejs/lib/cbor.js +12 -1
- package/lib/vendor/blamejs/lib/cert.js +29 -11
- package/lib/vendor/blamejs/lib/cli.js +94 -24
- package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
- package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
- package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
- package/lib/vendor/blamejs/lib/content-digest.js +2 -1
- package/lib/vendor/blamejs/lib/cookies.js +13 -3
- package/lib/vendor/blamejs/lib/cose.js +31 -16
- package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
- package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
- package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
- package/lib/vendor/blamejs/lib/crypto.js +314 -19
- package/lib/vendor/blamejs/lib/csp.js +11 -3
- package/lib/vendor/blamejs/lib/daemon.js +270 -24
- package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
- package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
- package/lib/vendor/blamejs/lib/db-query.js +34 -7
- package/lib/vendor/blamejs/lib/db.js +18 -6
- package/lib/vendor/blamejs/lib/dbsc.js +17 -0
- package/lib/vendor/blamejs/lib/dev.js +21 -2
- package/lib/vendor/blamejs/lib/dsr.js +157 -102
- package/lib/vendor/blamejs/lib/external-db.js +41 -2
- package/lib/vendor/blamejs/lib/file-upload.js +25 -7
- package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
- package/lib/vendor/blamejs/lib/forms.js +113 -27
- package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
- package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
- package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
- package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
- package/lib/vendor/blamejs/lib/guard-html.js +26 -53
- package/lib/vendor/blamejs/lib/guard-image.js +24 -5
- package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
- package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
- package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
- package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
- package/lib/vendor/blamejs/lib/guard-time.js +1 -1
- package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
- package/lib/vendor/blamejs/lib/html-balance.js +3 -3
- package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
- package/lib/vendor/blamejs/lib/http-client.js +39 -7
- package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
- package/lib/vendor/blamejs/lib/i18n.js +35 -21
- package/lib/vendor/blamejs/lib/incident-report.js +8 -1
- package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
- package/lib/vendor/blamejs/lib/json-path.js +23 -1
- package/lib/vendor/blamejs/lib/jwk.js +20 -3
- package/lib/vendor/blamejs/lib/link-header.js +2 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream.js +8 -3
- package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
- package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
- package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
- package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
- package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
- package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
- package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
- package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
- package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
- package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
- package/lib/vendor/blamejs/lib/mail.js +15 -5
- package/lib/vendor/blamejs/lib/metrics.js +268 -63
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
- package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
- package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
- package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
- package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
- package/lib/vendor/blamejs/lib/network-dns.js +21 -2
- package/lib/vendor/blamejs/lib/network-tls.js +69 -7
- package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
- package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
- package/lib/vendor/blamejs/lib/outbox.js +1 -1
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
- package/lib/vendor/blamejs/lib/permissions.js +6 -3
- package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
- package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
- package/lib/vendor/blamejs/lib/pubsub.js +20 -9
- package/lib/vendor/blamejs/lib/queue-local.js +8 -1
- package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
- package/lib/vendor/blamejs/lib/redact.js +54 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
- package/lib/vendor/blamejs/lib/restore.js +19 -0
- package/lib/vendor/blamejs/lib/retention.js +12 -4
- package/lib/vendor/blamejs/lib/router.js +60 -6
- package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
- package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
- package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
- package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
- package/lib/vendor/blamejs/lib/safe-object.js +80 -0
- package/lib/vendor/blamejs/lib/safe-path.js +52 -4
- package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
- package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
- package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
- package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
- package/lib/vendor/blamejs/lib/scheduler.js +8 -1
- package/lib/vendor/blamejs/lib/security-assert.js +6 -6
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
- package/lib/vendor/blamejs/lib/self-update.js +517 -87
- package/lib/vendor/blamejs/lib/server-timing.js +2 -4
- package/lib/vendor/blamejs/lib/session.js +34 -12
- package/lib/vendor/blamejs/lib/sql.js +15 -1
- package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
- package/lib/vendor/blamejs/lib/static.js +55 -13
- package/lib/vendor/blamejs/lib/storage.js +8 -2
- package/lib/vendor/blamejs/lib/subject.js +6 -1
- package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
- package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
- package/lib/vendor/blamejs/lib/tsa.js +34 -13
- package/lib/vendor/blamejs/lib/uri-template.js +8 -1
- package/lib/vendor/blamejs/lib/vault/index.js +13 -0
- package/lib/vendor/blamejs/lib/vc.js +44 -5
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
- package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
- package/lib/vendor/blamejs/lib/watcher.js +89 -17
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
- package/lib/vendor/blamejs/lib/webhook.js +12 -2
- package/lib/vendor/blamejs/lib/ws-client.js +32 -1
- package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
- package/lib/vendor/blamejs/package-lock.json +2 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
- package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
- package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
- package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
- package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
- package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
- package/lib/vendor/blamejs/socket.yml +94 -0
- package/lib/vendor/blamejs/test/00-primitives.js +605 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
- package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
- package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
- package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
- package/lib/vendor/blamejs/test/smoke.js +2 -0
- package/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
- package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
- package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
- package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
- package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
- package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
|
@@ -57,7 +57,6 @@ var nodeCrypto = require("node:crypto");
|
|
|
57
57
|
var numericBounds = require("./numeric-bounds");
|
|
58
58
|
var atomicFile = require("./atomic-file");
|
|
59
59
|
var validateOpts = require("./validate-opts");
|
|
60
|
-
var bCrypto = require("./crypto");
|
|
61
60
|
var guardRegex = require("./guard-regex");
|
|
62
61
|
var httpClient = require("./http-client");
|
|
63
62
|
var safeJson = require("./safe-json");
|
|
@@ -301,6 +300,60 @@ function _matchAsset(name, pattern, fallback) {
|
|
|
301
300
|
return fallback ? fallback.test(name) : false;
|
|
302
301
|
}
|
|
303
302
|
|
|
303
|
+
// Detached-signature suffixes. A release's detached signature is conventionally
|
|
304
|
+
// the asset name plus one of these (asset.tar.gz.sig / .asc / .sig.bin).
|
|
305
|
+
var _SIG_SUFFIXES = [".sig", ".asc", ".sig.bin"];
|
|
306
|
+
var _SIG_SHAPE = /\.sig$|\.asc$|\.sig\.bin$/i;
|
|
307
|
+
|
|
308
|
+
function _assetObj(a) {
|
|
309
|
+
return {
|
|
310
|
+
name: a.name,
|
|
311
|
+
url: a.browser_download_url,
|
|
312
|
+
size: a.size || null,
|
|
313
|
+
digest: typeof a.digest === "string" ? a.digest : null,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function _findEntryByName(entries, name) {
|
|
318
|
+
for (var i = 0; i < entries.length; i++) {
|
|
319
|
+
if (entries[i].name === name) return entries[i];
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// _selectSignatureFor — pick the detached signature OF `assetName`, not a
|
|
325
|
+
// first-match-wins signature that may sign a DIFFERENT sidecar. Selecting the
|
|
326
|
+
// asset first and DERIVING the expected signature name from it is the pairing
|
|
327
|
+
// contract: a returned { asset, signature } is guaranteed to be an asset and
|
|
328
|
+
// the signature over exactly that asset. Falls back to a lone signature-shaped
|
|
329
|
+
// asset only when the release ships exactly one (the common one-asset-one-sig
|
|
330
|
+
// case); anything ambiguous fails closed (null) rather than pairing a signature
|
|
331
|
+
// that may not sign the returned asset.
|
|
332
|
+
function _selectSignatureFor(assetName, entries, signaturePattern) {
|
|
333
|
+
// (a) Strong pairing: the asset name plus a signature suffix.
|
|
334
|
+
for (var s = 0; s < _SIG_SUFFIXES.length; s++) {
|
|
335
|
+
var hit = _findEntryByName(entries, assetName + _SIG_SUFFIXES[s]);
|
|
336
|
+
// When the operator constrained signaturePattern, the derived name must
|
|
337
|
+
// also satisfy it; otherwise the derived name is authoritative.
|
|
338
|
+
if (hit && (signaturePattern === undefined || _matchAsset(hit.name, signaturePattern, null))) {
|
|
339
|
+
return _assetObj(hit);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// (b) Operator signaturePattern, no derived hit: accept only a pattern match
|
|
343
|
+
// that ALSO references the asset stem, and only when unambiguous — else fail
|
|
344
|
+
// closed (never pair a pattern hit that may sign a different asset).
|
|
345
|
+
if (signaturePattern !== undefined) {
|
|
346
|
+
var stemMatches = entries.filter(function (e) {
|
|
347
|
+
return e.name.indexOf(assetName) === 0 && _matchAsset(e.name, signaturePattern, null);
|
|
348
|
+
});
|
|
349
|
+
return stemMatches.length === 1 ? _assetObj(stemMatches[0]) : null;
|
|
350
|
+
}
|
|
351
|
+
// (c) No operator pattern, no derived hit: accept a lone signature-shaped
|
|
352
|
+
// asset (single-sig release), else null.
|
|
353
|
+
var sigShaped = entries.filter(function (e) { return _SIG_SHAPE.test(e.name); });
|
|
354
|
+
return sigShaped.length === 1 ? _assetObj(sigShaped[0]) : null;
|
|
355
|
+
}
|
|
356
|
+
|
|
304
357
|
/**
|
|
305
358
|
* @primitive b.selfUpdate.poll
|
|
306
359
|
* @signature b.selfUpdate.poll(opts)
|
|
@@ -378,6 +431,15 @@ async function poll(opts) {
|
|
|
378
431
|
allowedHosts: opts.allowedHosts,
|
|
379
432
|
allowedProtocols: opts.allowedProtocols,
|
|
380
433
|
allowInternal: opts.allowInternal,
|
|
434
|
+
// poll() owns status handling — the branches below distinguish a 304
|
|
435
|
+
// If-None-Match "fast no-update" hit from a real non-2xx refusal and a
|
|
436
|
+
// 2xx feed to parse. Without always-resolve, httpClient.request rejects
|
|
437
|
+
// EVERY non-2xx (304 included) as HTTP_ERROR before poll can inspect
|
|
438
|
+
// res.statusCode, which made the documented conditional-poll fast-path
|
|
439
|
+
// and the selfupdate/poll-non-2xx branch dead code — a conditional poll
|
|
440
|
+
// that correctly received a 304 threw selfupdate/poll-failed instead of
|
|
441
|
+
// reporting "no update".
|
|
442
|
+
responseMode: "always-resolve",
|
|
381
443
|
errorClass: SelfUpdateError,
|
|
382
444
|
});
|
|
383
445
|
} catch (e) {
|
|
@@ -465,21 +527,27 @@ async function poll(opts) {
|
|
|
465
527
|
}
|
|
466
528
|
|
|
467
529
|
var assets = Array.isArray(latest.assets) ? latest.assets : [];
|
|
468
|
-
|
|
469
|
-
var
|
|
530
|
+
// Collect the well-formed asset entries once, preserving feed order.
|
|
531
|
+
var entries = [];
|
|
470
532
|
for (var i = 0; i < assets.length; i++) {
|
|
471
533
|
var a = assets[i] || {};
|
|
472
534
|
if (typeof a.name !== "string" || typeof a.browser_download_url !== "string") continue;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
535
|
+
entries.push(a);
|
|
536
|
+
}
|
|
537
|
+
// Select the runtime asset FIRST, then derive its detached signature — so the
|
|
538
|
+
// returned signature is the sig OF the returned asset, never a first-match-wins
|
|
539
|
+
// sig that may belong to a different sidecar (#497).
|
|
540
|
+
var assetMatch = null;
|
|
541
|
+
var signatureMatch = null;
|
|
542
|
+
for (var j = 0; j < entries.length; j++) {
|
|
543
|
+
if (_matchAsset(entries[j].name, opts.assetPattern, /\.(tar\.gz|tgz|zip|node|exe|bin)$/i)) {
|
|
544
|
+
assetMatch = _assetObj(entries[j]);
|
|
545
|
+
break;
|
|
481
546
|
}
|
|
482
547
|
}
|
|
548
|
+
if (assetMatch) {
|
|
549
|
+
signatureMatch = _selectSignatureFor(assetMatch.name, entries, opts.signaturePattern);
|
|
550
|
+
}
|
|
483
551
|
|
|
484
552
|
_safeAuditEmit("selfupdate.poll.checked", "success", {
|
|
485
553
|
releasesUrl: opts.releasesUrl,
|
|
@@ -530,13 +598,20 @@ function _validateVerifyOpts(opts) {
|
|
|
530
598
|
* @since 0.6.0
|
|
531
599
|
* @related b.selfUpdate.poll, b.selfUpdate.swap, b.crypto.verify
|
|
532
600
|
*
|
|
533
|
-
* Verify a detached signature over the asset bytes. The
|
|
534
|
-
* auto-detected from `opts.pubkeyPem` (ML-DSA-87 / Ed25519
|
|
535
|
-
* P-384)
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
601
|
+
* Verify a detached signature over the asset bytes. The signature
|
|
602
|
+
* algorithm is auto-detected from `opts.pubkeyPem` (ML-DSA-87 / Ed25519
|
|
603
|
+
* / ECDSA P-384). Verification routes through the framework's own
|
|
604
|
+
* `standaloneVerifier`, which streams the asset (no whole-file buffer),
|
|
605
|
+
* commits to a SHA3-512 digest, and dispatches the ECDSA signature
|
|
606
|
+
* encoding by structure (DER SEQUENCE vs raw IEEE-P1363) — so a release
|
|
607
|
+
* sidecar signed SHA3-512-then-sign with either encoding verifies, and
|
|
608
|
+
* the accept set is identical to `b.selfUpdate.standaloneVerifier.verify`
|
|
609
|
+
* (no verifier divergence between the install-pipeline and installed
|
|
610
|
+
* paths). Reports the asset's hash alongside the verified flag for SBOM /
|
|
611
|
+
* audit correlation; the supported digest algorithms are sha3-512
|
|
612
|
+
* (default), sha-256, sha-512, and shake256. Throws SelfUpdateError on a
|
|
613
|
+
* missing file, a verify-time exception, or a signature that does not
|
|
614
|
+
* verify.
|
|
540
615
|
*
|
|
541
616
|
* @opts
|
|
542
617
|
* assetPath: string, // required — path to the downloaded asset
|
|
@@ -556,56 +631,67 @@ function _validateVerifyOpts(opts) {
|
|
|
556
631
|
* e.code; // → "selfupdate/read-failed"
|
|
557
632
|
* }
|
|
558
633
|
*/
|
|
634
|
+
// _mapStandaloneKind — translate a standaloneVerifier `.kind` into this
|
|
635
|
+
// module's typed selfupdate/* code. File-availability / size-cap failures are
|
|
636
|
+
// read-failed; a cryptographic non-verification is signature-mismatch; a
|
|
637
|
+
// structural / key / encoding problem is verify-failed. Keeping the mapping
|
|
638
|
+
// structural (off `.kind`, not English message text) means a message reword in
|
|
639
|
+
// the zero-dep verifier never silently reclassifies a failure here.
|
|
640
|
+
function _mapStandaloneKind(kind) {
|
|
641
|
+
switch (kind) {
|
|
642
|
+
case "asset-not-found":
|
|
643
|
+
case "sig-not-found":
|
|
644
|
+
case "sig-too-large":
|
|
645
|
+
case "asset-too-large":
|
|
646
|
+
case "size-race":
|
|
647
|
+
return "selfupdate/read-failed";
|
|
648
|
+
case "verify-failed":
|
|
649
|
+
return "selfupdate/signature-mismatch";
|
|
650
|
+
default: // bad-input / bad-pubkey / unsupported-key / sig-empty / bad-sig-encoding
|
|
651
|
+
return "selfupdate/verify-failed";
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
559
655
|
async function verify(opts) {
|
|
560
656
|
_validateVerifyOpts(opts);
|
|
561
657
|
var alg = opts.hashAlgo || DEFAULT_HASH_ALG;
|
|
658
|
+
var maxBytes = typeof opts.maxBytes === "number" ? opts.maxBytes : C.BYTES.gib(1);
|
|
659
|
+
// The default sha3-512 / sha-256 reported digests are already produced by the
|
|
660
|
+
// standalone verifier's single pass; only a non-default reported alg needs an
|
|
661
|
+
// extra digest folded into that same stream (no second read of the asset).
|
|
662
|
+
var extraDigests = (alg === "sha3-512" || alg === "sha-256") ? [] : [alg];
|
|
562
663
|
|
|
563
|
-
var
|
|
564
|
-
var sigBytes;
|
|
664
|
+
var result;
|
|
565
665
|
try {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
666
|
+
// Route the signature verification through the framework's own
|
|
667
|
+
// standaloneVerifier so the installed path and the copy-into-install-pipeline
|
|
668
|
+
// path share ONE verifier — SHA3-512 digest, DER/IEEE-P1363 structural
|
|
669
|
+
// dispatch, streamed (no whole-asset in-memory buffer). It fails closed on a
|
|
670
|
+
// wrong key, truncated / empty signature, or size-cap breach.
|
|
671
|
+
result = standaloneVerifier.verify(opts.assetPath, opts.signaturePath, opts.pubkeyPem, {
|
|
672
|
+
maxAssetBytes: maxBytes,
|
|
673
|
+
extraDigests: extraDigests,
|
|
571
674
|
});
|
|
572
675
|
} catch (e) {
|
|
676
|
+
var code = _mapStandaloneKind(e && e.kind);
|
|
573
677
|
_safeAuditEmit("selfupdate.verify.failed", "denied", {
|
|
574
678
|
assetPath: opts.assetPath, signaturePath: opts.signaturePath,
|
|
575
|
-
reason: "
|
|
679
|
+
reason: (e && e.kind) || "verify-error", message: (e && e.message) || String(e),
|
|
576
680
|
});
|
|
577
|
-
throw new SelfUpdateError(
|
|
578
|
-
"selfUpdate.verify:
|
|
681
|
+
throw new SelfUpdateError(code,
|
|
682
|
+
"selfUpdate.verify: " + ((e && e.message) || String(e)));
|
|
579
683
|
}
|
|
580
684
|
|
|
581
|
-
var
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
_safeAuditEmit("selfupdate.verify.failed", "denied", {
|
|
585
|
-
assetPath: opts.assetPath, signaturePath: opts.signaturePath,
|
|
586
|
-
reason: "verify-threw", message: (e && e.message) || String(e),
|
|
587
|
-
});
|
|
588
|
-
throw new SelfUpdateError("selfupdate/verify-failed",
|
|
589
|
-
"selfUpdate.verify: signature verify threw: " + ((e && e.message) || String(e)));
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
var hashHex = nodeCrypto.createHash(alg).update(assetBytes).digest("hex");
|
|
593
|
-
|
|
594
|
-
if (!ok) {
|
|
595
|
-
_safeAuditEmit("selfupdate.verify.failed", "denied", {
|
|
596
|
-
assetPath: opts.assetPath, signaturePath: opts.signaturePath,
|
|
597
|
-
alg: alg, hash: hashHex, reason: "signature-mismatch",
|
|
598
|
-
});
|
|
599
|
-
throw new SelfUpdateError("selfupdate/signature-mismatch",
|
|
600
|
-
"selfUpdate.verify: signature did not verify against the supplied public key");
|
|
601
|
-
}
|
|
685
|
+
var hashHex = alg === "sha3-512" ? result.sha3_512
|
|
686
|
+
: alg === "sha-256" ? result.sha256
|
|
687
|
+
: result.digests[alg];
|
|
602
688
|
|
|
603
689
|
_safeAuditEmit("selfupdate.verify.passed", "success", {
|
|
604
690
|
assetPath: opts.assetPath, signaturePath: opts.signaturePath,
|
|
605
|
-
alg: alg, hash: hashHex, bytes:
|
|
691
|
+
alg: alg, hash: hashHex, bytes: result.bytes,
|
|
606
692
|
});
|
|
607
693
|
log("selfUpdate.verify passed asset=" + opts.assetPath + " alg=" + alg);
|
|
608
|
-
return { verified: true, hash: hashHex, alg: alg, bytes:
|
|
694
|
+
return { verified: true, hash: hashHex, alg: alg, bytes: result.bytes };
|
|
609
695
|
}
|
|
610
696
|
|
|
611
697
|
// ---- swap ----
|
|
@@ -630,6 +716,15 @@ function _validateSwapOpts(opts, label) {
|
|
|
630
716
|
"selfUpdate.swap: opts.hashAlgo must be one of " + ALLOWED_HASH_ALGS.join(", "));
|
|
631
717
|
}
|
|
632
718
|
};
|
|
719
|
+
// swap re-reads the from-bytes to re-hash them (closing the verify->swap
|
|
720
|
+
// window); its cap must be declarable so it matches the maxBytes an
|
|
721
|
+
// operator passed to selfUpdate.verify for the same asset — otherwise swap
|
|
722
|
+
// would refuse a large binary that verify accepted. Optional; defaults to
|
|
723
|
+
// the same C.BYTES.gib(1) cap the body applies.
|
|
724
|
+
schema.maxBytes = function (value) {
|
|
725
|
+
numericBounds.requirePositiveFiniteIntIfPresent(value,
|
|
726
|
+
"selfUpdate.swap: opts.maxBytes", SelfUpdateError, "selfupdate/bad-max-bytes");
|
|
727
|
+
};
|
|
633
728
|
}
|
|
634
729
|
schema.to = { rule: "required-string", code: "selfupdate/bad-to",
|
|
635
730
|
label: "selfUpdate." + label + ": opts.to" };
|
|
@@ -638,25 +733,47 @@ function _validateSwapOpts(opts, label) {
|
|
|
638
733
|
validateOpts.shape(opts, schema, "selfUpdate." + label, SelfUpdateError, "selfupdate/bad-opts");
|
|
639
734
|
}
|
|
640
735
|
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
//
|
|
644
|
-
//
|
|
645
|
-
// `
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
|
|
649
|
-
|
|
736
|
+
// _relocateFile — move `src` -> `dst`, preferring an atomic rename. A rename
|
|
737
|
+
// moves even a locked, RUNNING image on Windows (which refuses an in-place
|
|
738
|
+
// replace of a mapped executable but allows a rename/move) and needs no second
|
|
739
|
+
// copy; on EXDEV (cross-volume) it falls back to copy + unlink. This one
|
|
740
|
+
// primitive backs BOTH "move the outgoing `to` aside to its backup before an
|
|
741
|
+
// install" and "restore the backup over `to` on rollback", so the locked-image
|
|
742
|
+
// path is handled identically in the install and rollback directions.
|
|
743
|
+
async function _relocateFile(src, dst, fileMode) {
|
|
744
|
+
try {
|
|
745
|
+
atomicFile.renameWithRetry(src, dst);
|
|
746
|
+
return;
|
|
747
|
+
} catch (e) {
|
|
748
|
+
if (!e || e.code !== "EXDEV") throw e;
|
|
749
|
+
// Cross-volume: a rename can't cross the device boundary. Preserve the
|
|
750
|
+
// bytes by copy, then remove the source (best-effort — a locked cross-volume
|
|
751
|
+
// source is the documented limitation of this rare fallback).
|
|
752
|
+
await atomicFile.copy(src, dst, { fileMode: fileMode });
|
|
753
|
+
try { nodeFs.unlinkSync(src); } catch (_u) { /* cross-vol source cleanup — operator-cleanable */ }
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// _safeRollback — best-effort restore of `to` from `backupTo` during the swap
|
|
758
|
+
// failure paths. Routes through _relocateFile so the moved-aside backup is
|
|
759
|
+
// renamed back over the (now-absent) `to` — a rename that succeeds even where an
|
|
760
|
+
// in-place copy-replace would be blocked by a lock. Returns null on success (or
|
|
761
|
+
// when no backup existed); returns the rollback Error otherwise so the caller
|
|
762
|
+
// can throw a distinct `selfupdate/swap-rollback-failed`. Emits the
|
|
763
|
+
// `selfupdate.swap.rollback_failed` audit event when rollback fails (the prior
|
|
764
|
+
// best-effort catch dropped this signal silently — operators with no audit row
|
|
765
|
+
// for `rollback_failed` couldn't tell a successful swap-with-rollback from a
|
|
766
|
+
// failed both-binaries-lost scenario). SSDF RV.1.
|
|
650
767
|
async function _safeRollback(backupTo, to, hadOriginal) {
|
|
651
768
|
if (!hadOriginal) return null;
|
|
652
769
|
try {
|
|
653
|
-
await
|
|
770
|
+
await _relocateFile(backupTo, to, 0o600);
|
|
654
771
|
return null;
|
|
655
772
|
} catch (re) {
|
|
656
773
|
var err = re instanceof Error ? re : new Error(String(re));
|
|
657
774
|
_safeAuditEmit("selfupdate.swap.rollback_failed", "denied", {
|
|
658
775
|
to: to, backupTo: backupTo,
|
|
659
|
-
reason: "rollback-
|
|
776
|
+
reason: "rollback-restore-failed",
|
|
660
777
|
message: err.message,
|
|
661
778
|
});
|
|
662
779
|
return err;
|
|
@@ -666,29 +783,33 @@ async function _safeRollback(backupTo, to, hadOriginal) {
|
|
|
666
783
|
// Atomic swap of `from` -> `to` with rollback on failure. Steps:
|
|
667
784
|
//
|
|
668
785
|
// 1. ensure `to` and `backupTo` parents exist
|
|
669
|
-
// 2. if `to` exists —
|
|
670
|
-
//
|
|
671
|
-
//
|
|
672
|
-
//
|
|
786
|
+
// 2. if `to` exists — MOVE it aside to `backupTo` via a rename (this both
|
|
787
|
+
// frees `to` and IS the backup). A rename moves even a locked, running
|
|
788
|
+
// image on Windows, where an in-place replace of a mapped exe is refused;
|
|
789
|
+
// cross-volume (EXDEV) falls back to copy + unlink.
|
|
790
|
+
// 3. write the verified in-memory bytes to the now-free `to` (a create, not
|
|
791
|
+
// a replace of a locked file)
|
|
673
792
|
// 4. fsync both directories (best-effort across platforms)
|
|
674
793
|
//
|
|
675
|
-
// If step
|
|
676
|
-
//
|
|
794
|
+
// If step 2 fails the original `to` is intact (surfaced as backup-failed); if
|
|
795
|
+
// step 3 fails the moved-aside backup is renamed back over `to` (rollback); if
|
|
796
|
+
// step 4 fails the swap is considered complete (operator can audit).
|
|
677
797
|
/**
|
|
678
798
|
* @primitive b.selfUpdate.swap
|
|
679
799
|
* @signature b.selfUpdate.swap(opts)
|
|
680
800
|
* @since 0.6.0
|
|
681
|
-
* @related b.selfUpdate.verify, b.selfUpdate.rollback, b.atomicFile.
|
|
801
|
+
* @related b.selfUpdate.verify, b.selfUpdate.rollback, b.atomicFile.write
|
|
682
802
|
*
|
|
683
803
|
* Atomic install: re-hash `from` and refuse unless it matches `expectedHash`
|
|
684
804
|
* (the hash selfUpdate.verify returned — this binds the installed bytes to the
|
|
685
|
-
* signature-verified bytes and closes the verify→swap window),
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
805
|
+
* signature-verified bytes and closes the verify→swap window), MOVE the existing
|
|
806
|
+
* `to` aside to `backupTo` with a rename (which succeeds on a locked, running
|
|
807
|
+
* image where an in-place replace is refused, and IS the backup), write the
|
|
808
|
+
* verified bytes to the now-free `to`, then fsync both directories. `backupTo`
|
|
809
|
+
* must be on the same volume as `to`; a cross-volume backup (EXDEV) falls back to
|
|
810
|
+
* copy + replace. On an install-write failure after the move-aside, the backup is
|
|
811
|
+
* restored over `to`. Throws SelfUpdateError on a missing `from`, an expectedHash
|
|
812
|
+
* mismatch, a move-aside/backup failure, or an install-write failure.
|
|
692
813
|
*
|
|
693
814
|
* @opts
|
|
694
815
|
* from: string, // required — newly-installed asset path
|
|
@@ -696,6 +817,8 @@ async function _safeRollback(backupTo, to, hadOriginal) {
|
|
|
696
817
|
* backupTo: string, // required — backup path for the existing `to`
|
|
697
818
|
* expectedHash: string, // required — the hash selfUpdate.verify returned
|
|
698
819
|
* hashAlgo: string, // sha3-512 (default) | sha-256 | sha-512 | shake256
|
|
820
|
+
* maxBytes: number, // from-bytes re-hash cap (default 1 GiB) — set to
|
|
821
|
+
* // the same value passed to selfUpdate.verify
|
|
699
822
|
*
|
|
700
823
|
* @example
|
|
701
824
|
* var v = await b.selfUpdate.verify({ assetPath, signaturePath, pubkeyPem });
|
|
@@ -757,26 +880,31 @@ async function swap(opts) {
|
|
|
757
880
|
atomicFile.ensureDir(toDir);
|
|
758
881
|
atomicFile.ensureDir(backupDir);
|
|
759
882
|
|
|
760
|
-
// Step 2 —
|
|
761
|
-
//
|
|
883
|
+
// Step 2 — move the outgoing `to` ASIDE to `backupTo` via a rename. A rename
|
|
884
|
+
// frees the path even when `to` is a locked, running image (Windows refuses an
|
|
885
|
+
// in-place replace of a mapped executable but allows the move), and the moved
|
|
886
|
+
// file IS the backup — so no separate copy of the old bytes is needed. The
|
|
887
|
+
// move-aside failing leaves the original `to` intact (surfaced as backup-failed).
|
|
762
888
|
var hadOriginal = nodeFs.existsSync(to);
|
|
763
889
|
if (hadOriginal) {
|
|
764
890
|
try {
|
|
765
|
-
await
|
|
891
|
+
await _relocateFile(to, backupTo, 0o600);
|
|
766
892
|
} catch (e) {
|
|
767
893
|
throw new SelfUpdateError("selfupdate/backup-failed",
|
|
768
|
-
"selfUpdate.swap: failed to
|
|
894
|
+
"selfUpdate.swap: failed to move " + to + " aside to " + backupTo + ": " +
|
|
769
895
|
((e && e.message) || String(e)));
|
|
770
896
|
}
|
|
771
897
|
}
|
|
772
898
|
|
|
773
|
-
// Step 3 — install the verified in-memory bytes via an
|
|
774
|
-
// rename
|
|
775
|
-
//
|
|
776
|
-
//
|
|
777
|
-
//
|
|
778
|
-
//
|
|
779
|
-
//
|
|
899
|
+
// Step 3 — install the verified in-memory bytes at the now-free `to` via an
|
|
900
|
+
// atomic temp+fsync+rename (atomicFile.write). With `to` moved aside (or never
|
|
901
|
+
// present), this rename is a CREATE at a free path, not a replace of a locked
|
|
902
|
+
// file — so it succeeds on a running Windows image. The installed object is
|
|
903
|
+
// exactly the bytes just hashed (installed from memory), so there is no by-path
|
|
904
|
+
// re-read to race and no symlinked source to move into place. On failure the
|
|
905
|
+
// moved-aside backup is renamed back over `to`; a rollback failure surfaces as
|
|
906
|
+
// a DISTINCT error class + audit event so operators don't silently lose both
|
|
907
|
+
// binaries (SSDF RV.1).
|
|
780
908
|
try {
|
|
781
909
|
await atomicFile.write(to, fromBytes, { fileMode: fromMode, overwrite: true });
|
|
782
910
|
} catch (e) {
|
|
@@ -862,11 +990,313 @@ async function rollback(opts) {
|
|
|
862
990
|
return { ok: true, restoredAt: Date.now(), to: to, backupTo: backupTo };
|
|
863
991
|
}
|
|
864
992
|
|
|
993
|
+
// ---- probation / auto-rollback orchestration ----
|
|
994
|
+
//
|
|
995
|
+
// A swap installs the new binary; probation gives it a bounded window to prove
|
|
996
|
+
// itself before the install is considered final. The new binary (or the
|
|
997
|
+
// operator's shutdown hook) calls confirmHealthy() once it is up + healthy,
|
|
998
|
+
// which clears the marker — the "clean / healthy" signal. On the next boot
|
|
999
|
+
// evaluateOnBoot() reads the marker: still inside the window means a clean stop /
|
|
1000
|
+
// restart (NOT a crash) so it keeps; past the window with no confirmHealthy means
|
|
1001
|
+
// the binary never became healthy so it rolls the known-good backup back over the
|
|
1002
|
+
// target. Rollback re-verifies first (the installed bytes must still hash to the
|
|
1003
|
+
// probationary expectedHash and the backup must exist) so a marker left behind by
|
|
1004
|
+
// a swap that FAILED — where the new binary was never installed — never triggers
|
|
1005
|
+
// a phantom rollback.
|
|
1006
|
+
|
|
1007
|
+
var PROBATION_MARKER_SUFFIX = ".blamejs-probation.json";
|
|
1008
|
+
var PROBATION_MARKER_MAX = C.BYTES.kib(64); // marker is a small JSON record
|
|
1009
|
+
|
|
1010
|
+
function _resolveMarkerPath(opts) {
|
|
1011
|
+
if (typeof opts.markerPath === "string" && opts.markerPath.length > 0) return opts.markerPath;
|
|
1012
|
+
return opts.to + PROBATION_MARKER_SUFFIX;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
function _probationHashAlgo(value, method) {
|
|
1016
|
+
if (value !== undefined && (typeof value !== "string" || ALLOWED_HASH_ALGS.indexOf(value) === -1)) {
|
|
1017
|
+
throw new SelfUpdateError("selfupdate/bad-hash-algo",
|
|
1018
|
+
"selfUpdate." + method + ": opts.hashAlgo must be one of " + ALLOWED_HASH_ALGS.join(", "));
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Field-descriptor builders for the probation validators — the required/optional
|
|
1023
|
+
// string field shape composes from one definition instead of repeating an inline
|
|
1024
|
+
// `{ rule, code, label }` object per field across the three validators.
|
|
1025
|
+
function _reqStr(code, label) { return { rule: "required-string", code: code, label: label }; }
|
|
1026
|
+
function _optStr(code, label) { return { rule: "optional-string", code: code, label: label }; }
|
|
1027
|
+
function _probationLabel(method, field) { return "selfUpdate." + method + ": opts." + field; }
|
|
1028
|
+
|
|
1029
|
+
function _validateProbationBeginOpts(opts) {
|
|
1030
|
+
validateOpts.shape(opts, {
|
|
1031
|
+
to: _reqStr("selfupdate/bad-to", _probationLabel("beginProbation", "to")),
|
|
1032
|
+
backupTo: _reqStr("selfupdate/bad-backup", _probationLabel("beginProbation", "backupTo")),
|
|
1033
|
+
expectedHash: _reqStr("selfupdate/bad-expected-hash", _probationLabel("beginProbation", "expectedHash")),
|
|
1034
|
+
windowMs: function (value) {
|
|
1035
|
+
numericBounds.requirePositiveFiniteIntIfPresent(value,
|
|
1036
|
+
_probationLabel("beginProbation", "windowMs"), SelfUpdateError, "selfupdate/bad-window");
|
|
1037
|
+
},
|
|
1038
|
+
hashAlgo: function (value) { _probationHashAlgo(value, "beginProbation"); },
|
|
1039
|
+
markerPath: _optStr("selfupdate/bad-marker-path", _probationLabel("beginProbation", "markerPath")),
|
|
1040
|
+
}, "selfUpdate.beginProbation", SelfUpdateError, "selfupdate/bad-opts");
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
function _validateConfirmOpts(opts) {
|
|
1044
|
+
validateOpts.shape(opts, {
|
|
1045
|
+
to: _reqStr("selfupdate/bad-to", _probationLabel("confirmHealthy", "to")),
|
|
1046
|
+
markerPath: _optStr("selfupdate/bad-marker-path", _probationLabel("confirmHealthy", "markerPath")),
|
|
1047
|
+
}, "selfUpdate.confirmHealthy", SelfUpdateError, "selfupdate/bad-opts");
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function _validateEvaluateOpts(opts) {
|
|
1051
|
+
validateOpts.shape(opts, {
|
|
1052
|
+
to: _reqStr("selfupdate/bad-to", _probationLabel("evaluateOnBoot", "to")),
|
|
1053
|
+
backupTo: _optStr("selfupdate/bad-backup", _probationLabel("evaluateOnBoot", "backupTo")),
|
|
1054
|
+
markerPath: _optStr("selfupdate/bad-marker-path", _probationLabel("evaluateOnBoot", "markerPath")),
|
|
1055
|
+
now: function (value) {
|
|
1056
|
+
numericBounds.requirePositiveFiniteIntIfPresent(value,
|
|
1057
|
+
_probationLabel("evaluateOnBoot", "now"), SelfUpdateError, "selfupdate/bad-now");
|
|
1058
|
+
},
|
|
1059
|
+
}, "selfUpdate.evaluateOnBoot", SelfUpdateError, "selfupdate/bad-opts");
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
function _probationKeep(reason, to, markerPath) {
|
|
1063
|
+
// A boot with no probation marker is the steady-state no-op — don't audit it
|
|
1064
|
+
// every boot. Every other keep reason is a real probation transition.
|
|
1065
|
+
if (reason !== "no-probation-active") {
|
|
1066
|
+
_safeAuditEmit("selfupdate.probation.kept", "success", {
|
|
1067
|
+
to: to, markerPath: markerPath, reason: reason,
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
return { action: "keep", reason: reason };
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* @primitive b.selfUpdate.beginProbation
|
|
1075
|
+
* @signature b.selfUpdate.beginProbation(opts)
|
|
1076
|
+
* @since 0.17.13
|
|
1077
|
+
* @status stable
|
|
1078
|
+
* @related b.selfUpdate.confirmHealthy, b.selfUpdate.evaluateOnBoot, b.selfUpdate.swap
|
|
1079
|
+
*
|
|
1080
|
+
* Arm a bounded post-install probation for a freshly-swapped binary. Writes an
|
|
1081
|
+
* atomic marker (`to` + `.blamejs-probation.json`, or `opts.markerPath`)
|
|
1082
|
+
* recording the target, the known-good backup, the installed bytes' hash, and an
|
|
1083
|
+
* `expiresAt` = now + `windowMs`. The new binary calls `confirmHealthy` once it
|
|
1084
|
+
* is up and healthy (clearing the marker); if the window elapses with no such
|
|
1085
|
+
* confirmation, the next `evaluateOnBoot` rolls the backup back over the target.
|
|
1086
|
+
*
|
|
1087
|
+
* The marker is written via `b.atomicFile.writeJson` (temp + fsync + rename), so
|
|
1088
|
+
* a process that dies mid-write leaves either the previous complete marker or
|
|
1089
|
+
* none — never a half-written record a boot could misread.
|
|
1090
|
+
*
|
|
1091
|
+
* @opts
|
|
1092
|
+
* to: string, // required — installed binary path (the probationary target)
|
|
1093
|
+
* backupTo: string, // required — known-good backup restored on a failed probation
|
|
1094
|
+
* expectedHash: string, // required — hash of the installed bytes (selfUpdate.verify/swap's hash)
|
|
1095
|
+
* windowMs: number, // probation window in ms; default 10 minutes
|
|
1096
|
+
* hashAlgo: string, // sha3-512 (default) | sha-256 | sha-512 | shake256
|
|
1097
|
+
* markerPath: string, // override marker path (default: `to` + ".blamejs-probation.json")
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* var v = await b.selfUpdate.verify({ assetPath, signaturePath, pubkeyPem });
|
|
1101
|
+
* await b.selfUpdate.swap({ from, to, backupTo, expectedHash: v.hash });
|
|
1102
|
+
* var p = await b.selfUpdate.beginProbation({ to, backupTo, expectedHash: v.hash });
|
|
1103
|
+
* p.expiresAt; // → epoch ms the probation window closes
|
|
1104
|
+
*/
|
|
1105
|
+
async function beginProbation(opts) {
|
|
1106
|
+
_validateProbationBeginOpts(opts);
|
|
1107
|
+
var markerPath = _resolveMarkerPath(opts);
|
|
1108
|
+
var windowMs = typeof opts.windowMs === "number" ? opts.windowMs : C.TIME.minutes(10);
|
|
1109
|
+
var hashAlgo = opts.hashAlgo || DEFAULT_HASH_ALG;
|
|
1110
|
+
var installedAt = Date.now();
|
|
1111
|
+
var expiresAt = installedAt + windowMs;
|
|
1112
|
+
|
|
1113
|
+
// Carry a monotonically increasing generation across successive probations of
|
|
1114
|
+
// the same target — each install supersedes the prior probation record.
|
|
1115
|
+
var generation = 1;
|
|
1116
|
+
try {
|
|
1117
|
+
var prior = await atomicFile.readJson(markerPath, { maxBytes: PROBATION_MARKER_MAX });
|
|
1118
|
+
if (prior && typeof prior.generation === "number" && isFinite(prior.generation)) {
|
|
1119
|
+
generation = prior.generation + 1;
|
|
1120
|
+
}
|
|
1121
|
+
} catch (_p) { /* no prior marker (or unreadable) — first generation */ }
|
|
1122
|
+
|
|
1123
|
+
var marker = {
|
|
1124
|
+
schema: 1,
|
|
1125
|
+
installedAt: installedAt,
|
|
1126
|
+
expiresAt: expiresAt,
|
|
1127
|
+
windowMs: windowMs,
|
|
1128
|
+
to: opts.to,
|
|
1129
|
+
backupTo: opts.backupTo,
|
|
1130
|
+
expectedHash: opts.expectedHash,
|
|
1131
|
+
hashAlgo: hashAlgo,
|
|
1132
|
+
generation: generation,
|
|
1133
|
+
};
|
|
1134
|
+
var written = await atomicFile.writeJson(markerPath, marker, { computeHash: true, fileMode: 0o600 });
|
|
1135
|
+
|
|
1136
|
+
_safeAuditEmit("selfupdate.probation.begin", "success", {
|
|
1137
|
+
to: opts.to, backupTo: opts.backupTo, markerPath: markerPath,
|
|
1138
|
+
expiresAt: expiresAt, generation: generation, markerHash: written.hash,
|
|
1139
|
+
});
|
|
1140
|
+
log("selfUpdate.beginProbation to=" + opts.to + " expiresAt=" + expiresAt + " gen=" + generation);
|
|
1141
|
+
return { markerPath: markerPath, installedAt: installedAt, expiresAt: expiresAt, generation: generation };
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
/**
|
|
1145
|
+
* @primitive b.selfUpdate.confirmHealthy
|
|
1146
|
+
* @signature b.selfUpdate.confirmHealthy(opts)
|
|
1147
|
+
* @since 0.17.13
|
|
1148
|
+
* @status stable
|
|
1149
|
+
* @related b.selfUpdate.beginProbation, b.selfUpdate.evaluateOnBoot
|
|
1150
|
+
*
|
|
1151
|
+
* Clear the probation marker — the explicit clean / healthy signal. The new
|
|
1152
|
+
* binary calls this once its own startup health checks pass (and an operator's
|
|
1153
|
+
* graceful-shutdown hook may call it too, marking a clean stop). With the marker
|
|
1154
|
+
* gone, a later `evaluateOnBoot` finds no probation and keeps the binary. Absence
|
|
1155
|
+
* of this signal at the next boot past the window is what `evaluateOnBoot` reads
|
|
1156
|
+
* as a failed probation. Idempotent: a missing marker returns `cleared: false`.
|
|
1157
|
+
*
|
|
1158
|
+
* @opts
|
|
1159
|
+
* to: string, // required — the probationary target (locates the marker)
|
|
1160
|
+
* markerPath: string, // override marker path (must match beginProbation)
|
|
1161
|
+
*
|
|
1162
|
+
* @example
|
|
1163
|
+
* // in the new binary, after startup health checks pass:
|
|
1164
|
+
* var r = await b.selfUpdate.confirmHealthy({ to: "/opt/app/app.bin" });
|
|
1165
|
+
* r.cleared; // → true (marker removed)
|
|
1166
|
+
*/
|
|
1167
|
+
async function confirmHealthy(opts) {
|
|
1168
|
+
_validateConfirmOpts(opts);
|
|
1169
|
+
var markerPath = _resolveMarkerPath(opts);
|
|
1170
|
+
var cleared = false;
|
|
1171
|
+
if (nodeFs.existsSync(markerPath)) {
|
|
1172
|
+
try {
|
|
1173
|
+
nodeFs.unlinkSync(markerPath);
|
|
1174
|
+
cleared = true;
|
|
1175
|
+
} catch (e) {
|
|
1176
|
+
throw new SelfUpdateError("selfupdate/probation-confirm-failed",
|
|
1177
|
+
"selfUpdate.confirmHealthy: failed to clear probation marker " + markerPath + ": " +
|
|
1178
|
+
((e && e.message) || String(e)));
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
_safeAuditEmit("selfupdate.probation.confirmed", "success", {
|
|
1182
|
+
to: opts.to, markerPath: markerPath, cleared: cleared,
|
|
1183
|
+
});
|
|
1184
|
+
log("selfUpdate.confirmHealthy to=" + opts.to + " cleared=" + cleared);
|
|
1185
|
+
return { ok: true, cleared: cleared, markerPath: markerPath };
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* @primitive b.selfUpdate.evaluateOnBoot
|
|
1190
|
+
* @signature b.selfUpdate.evaluateOnBoot(opts)
|
|
1191
|
+
* @since 0.17.13
|
|
1192
|
+
* @status stable
|
|
1193
|
+
* @related b.selfUpdate.beginProbation, b.selfUpdate.confirmHealthy, b.selfUpdate.rollback
|
|
1194
|
+
*
|
|
1195
|
+
* Decide, at process start, whether a probationary install should be kept or
|
|
1196
|
+
* rolled back. Returns `{ action: "keep" | "rollback", reason }`. No marker, or a
|
|
1197
|
+
* marker still inside its window, keeps (a clean stop / restart within the window
|
|
1198
|
+
* is not a crash). A marker past its window with no `confirmHealthy` means the
|
|
1199
|
+
* binary never became healthy → the known-good backup is restored over the
|
|
1200
|
+
* target and the marker cleared.
|
|
1201
|
+
*
|
|
1202
|
+
* Before restoring, it RE-VERIFIES: the bytes currently at `to` must still hash
|
|
1203
|
+
* to the marker's `expectedHash` (so a marker left by a swap that FAILED — where
|
|
1204
|
+
* the probationary binary was never installed — never triggers a phantom
|
|
1205
|
+
* rollback), and the backup must exist (otherwise it keeps and defers to the
|
|
1206
|
+
* operator rather than destroying the only present binary). A corrupt / malformed
|
|
1207
|
+
* marker keeps, never rolls back.
|
|
1208
|
+
*
|
|
1209
|
+
* @opts
|
|
1210
|
+
* to: string, // required — the probationary target
|
|
1211
|
+
* backupTo: string, // override the marker's backup path
|
|
1212
|
+
* markerPath: string, // override marker path (must match beginProbation)
|
|
1213
|
+
* now: number, // override the wall clock (epoch ms) for deterministic evaluation
|
|
1214
|
+
*
|
|
1215
|
+
* @example
|
|
1216
|
+
* // at process start, before serving traffic:
|
|
1217
|
+
* var d = await b.selfUpdate.evaluateOnBoot({ to: "/opt/app/app.bin" });
|
|
1218
|
+
* if (d.action === "rollback") process.exit(1); // restart onto the restored binary
|
|
1219
|
+
*/
|
|
1220
|
+
async function evaluateOnBoot(opts) {
|
|
1221
|
+
_validateEvaluateOpts(opts);
|
|
1222
|
+
var markerPath = _resolveMarkerPath(opts);
|
|
1223
|
+
var to = opts.to;
|
|
1224
|
+
var now = typeof opts.now === "number" ? opts.now : Date.now();
|
|
1225
|
+
|
|
1226
|
+
if (!nodeFs.existsSync(markerPath)) {
|
|
1227
|
+
return _probationKeep("no-probation-active", to, markerPath);
|
|
1228
|
+
}
|
|
1229
|
+
var marker;
|
|
1230
|
+
try {
|
|
1231
|
+
marker = await atomicFile.readJson(markerPath, { maxBytes: PROBATION_MARKER_MAX });
|
|
1232
|
+
} catch (_e) {
|
|
1233
|
+
// A corrupt / unreadable marker must not phantom-rollback.
|
|
1234
|
+
return _probationKeep("marker-unreadable", to, markerPath);
|
|
1235
|
+
}
|
|
1236
|
+
if (!marker || typeof marker.expiresAt !== "number" || typeof marker.expectedHash !== "string") {
|
|
1237
|
+
return _probationKeep("marker-malformed", to, markerPath);
|
|
1238
|
+
}
|
|
1239
|
+
// Inside the window — a clean stop / restart is not a crash.
|
|
1240
|
+
if (now < marker.expiresAt) {
|
|
1241
|
+
return _probationKeep("within-probation-window", to, markerPath);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// Expired with no confirmHealthy. Re-verify before restoring.
|
|
1245
|
+
var backupTo = typeof opts.backupTo === "string" ? opts.backupTo : marker.backupTo;
|
|
1246
|
+
var alg = ALLOWED_HASH_ALGS.indexOf(marker.hashAlgo) !== -1 ? marker.hashAlgo : DEFAULT_HASH_ALG;
|
|
1247
|
+
|
|
1248
|
+
// The probationary binary must actually be the one installed at `to`; if `to`
|
|
1249
|
+
// is absent or holds different bytes (a swap that failed and left the old
|
|
1250
|
+
// binary), rolling back would be a phantom.
|
|
1251
|
+
var currentHash = null;
|
|
1252
|
+
try {
|
|
1253
|
+
var curBytes = atomicFile.fdSafeReadSync(to, { maxBytes: C.BYTES.gib(1) });
|
|
1254
|
+
currentHash = nodeCrypto.createHash(alg).update(curBytes).digest("hex");
|
|
1255
|
+
} catch (_r) { currentHash = null; }
|
|
1256
|
+
if (currentHash !== marker.expectedHash) {
|
|
1257
|
+
return _probationKeep("installed-binary-not-probationary", to, markerPath);
|
|
1258
|
+
}
|
|
1259
|
+
if (typeof backupTo !== "string" || !nodeFs.existsSync(backupTo)) {
|
|
1260
|
+
// No backup to restore — keep the current binary and defer to the operator
|
|
1261
|
+
// rather than leaving the target with nothing.
|
|
1262
|
+
return _probationKeep("backup-unavailable", to, markerPath);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
// Restore the known-good backup over the failed probationary binary. On boot
|
|
1266
|
+
// the target is not yet running, so an atomic write-replace is safe.
|
|
1267
|
+
try {
|
|
1268
|
+
var backupBytes = atomicFile.fdSafeReadSync(backupTo, { maxBytes: C.BYTES.gib(1) });
|
|
1269
|
+
var restoreMode;
|
|
1270
|
+
try { restoreMode = (nodeFs.statSync(to).mode & 0o777); } catch (_sm) { restoreMode = 0o600; }
|
|
1271
|
+
await atomicFile.write(to, backupBytes, { fileMode: restoreMode, overwrite: true });
|
|
1272
|
+
} catch (e) {
|
|
1273
|
+
_safeAuditEmit("selfupdate.probation.rollback_failed", "denied", {
|
|
1274
|
+
to: to, backupTo: backupTo, markerPath: markerPath,
|
|
1275
|
+
reason: "restore-failed", message: (e && e.message) || String(e),
|
|
1276
|
+
});
|
|
1277
|
+
throw new SelfUpdateError("selfupdate/probation-rollback-failed",
|
|
1278
|
+
"selfUpdate.evaluateOnBoot: probation rollback restore of " + to + " failed: " +
|
|
1279
|
+
((e && e.message) || String(e)));
|
|
1280
|
+
}
|
|
1281
|
+
atomicFile.fsyncDir(nodePath.dirname(to));
|
|
1282
|
+
try { nodeFs.unlinkSync(markerPath); } catch (_u) { /* marker cleanup best-effort */ }
|
|
1283
|
+
|
|
1284
|
+
_safeAuditEmit("selfupdate.probation.rolled_back", "success", {
|
|
1285
|
+
to: to, backupTo: backupTo, markerPath: markerPath, generation: marker.generation,
|
|
1286
|
+
});
|
|
1287
|
+
log("selfUpdate.evaluateOnBoot rolled back to=" + to + " from=" + backupTo);
|
|
1288
|
+
return { action: "rollback", reason: "probation-window-elapsed-without-confirmation",
|
|
1289
|
+
to: to, backupTo: backupTo, generation: marker.generation };
|
|
1290
|
+
}
|
|
1291
|
+
|
|
865
1292
|
module.exports = {
|
|
866
1293
|
poll: poll,
|
|
867
1294
|
verify: verify,
|
|
868
1295
|
swap: swap,
|
|
869
1296
|
rollback: rollback,
|
|
1297
|
+
beginProbation: beginProbation,
|
|
1298
|
+
confirmHealthy: confirmHealthy,
|
|
1299
|
+
evaluateOnBoot: evaluateOnBoot,
|
|
870
1300
|
// Standalone verifier — zero-dep companion for install-pipeline
|
|
871
1301
|
// contexts that run BEFORE the framework is installed (Dockerfile
|
|
872
1302
|
// build stages, install.sh, update.sh). See the module's intro for
|