@blamejs/blamejs-shop 0.4.31 → 0.4.33
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 +4 -0
- package/README.md +1 -1
- package/lib/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +400 -282
- package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
- package/lib/vendor/blamejs/.gitignore +6 -0
- package/lib/vendor/blamejs/CHANGELOG.md +28 -0
- package/lib/vendor/blamejs/MIGRATING.md +55 -0
- package/lib/vendor/blamejs/README.md +8 -6
- package/lib/vendor/blamejs/SECURITY.md +19 -3
- package/lib/vendor/blamejs/api-snapshot.json +2190 -664
- package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
- package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
- package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
- package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
- package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
- package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
- package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
- package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
- package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
- package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
- package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
- package/lib/vendor/blamejs/index.js +4 -0
- package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
- package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
- package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
- package/lib/vendor/blamejs/lib/api-key.js +158 -77
- package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
- package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
- package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
- package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
- package/lib/vendor/blamejs/lib/audit.js +259 -123
- package/lib/vendor/blamejs/lib/auth/elevation-grant.js +6 -2
- package/lib/vendor/blamejs/lib/auth/oauth.js +66 -9
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
- package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +36 -7
- package/lib/vendor/blamejs/lib/backup/index.js +45 -10
- package/lib/vendor/blamejs/lib/break-glass.js +355 -147
- package/lib/vendor/blamejs/lib/cache.js +174 -105
- package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
- package/lib/vendor/blamejs/lib/cli.js +19 -14
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
- package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
- package/lib/vendor/blamejs/lib/cluster.js +119 -71
- package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
- package/lib/vendor/blamejs/lib/compliance.js +210 -4
- package/lib/vendor/blamejs/lib/consent.js +82 -29
- package/lib/vendor/blamejs/lib/constants.js +27 -11
- package/lib/vendor/blamejs/lib/credential-hash.js +9 -0
- package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
- package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
- package/lib/vendor/blamejs/lib/db-query.js +882 -260
- package/lib/vendor/blamejs/lib/db-schema.js +228 -44
- package/lib/vendor/blamejs/lib/db.js +249 -99
- package/lib/vendor/blamejs/lib/dsr.js +385 -55
- package/lib/vendor/blamejs/lib/error-page.js +14 -1
- package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
- package/lib/vendor/blamejs/lib/external-db.js +549 -34
- package/lib/vendor/blamejs/lib/file-upload.js +52 -7
- package/lib/vendor/blamejs/lib/framework-error.js +20 -1
- package/lib/vendor/blamejs/lib/framework-files.js +73 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
- package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
- package/lib/vendor/blamejs/lib/guard-all.js +1 -0
- package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
- package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
- package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
- package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
- package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
- package/lib/vendor/blamejs/lib/guard-email.js +47 -69
- package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
- package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
- package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
- package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
- package/lib/vendor/blamejs/lib/guard-html.js +53 -108
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
- package/lib/vendor/blamejs/lib/guard-image.js +46 -103
- package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
- package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
- package/lib/vendor/blamejs/lib/guard-json.js +38 -108
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
- package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
- package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
- package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
- package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
- package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
- package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
- package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
- package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
- package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
- package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
- package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
- package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
- package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
- package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
- package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
- package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
- package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
- package/lib/vendor/blamejs/lib/guard-template.js +35 -172
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
- package/lib/vendor/blamejs/lib/guard-time.js +32 -154
- package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
- package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
- package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
- package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
- package/lib/vendor/blamejs/lib/http-client.js +37 -9
- package/lib/vendor/blamejs/lib/inbox.js +120 -107
- package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
- package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
- package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
- package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
- package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
- package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
- package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
- package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
- package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
- package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
- package/lib/vendor/blamejs/lib/mail-store.js +293 -154
- package/lib/vendor/blamejs/lib/mail.js +8 -4
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
- package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
- package/lib/vendor/blamejs/lib/migrations.js +108 -66
- package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
- package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
- package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
- package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
- package/lib/vendor/blamejs/lib/observability.js +124 -0
- package/lib/vendor/blamejs/lib/otel-export.js +12 -3
- package/lib/vendor/blamejs/lib/outbox.js +184 -83
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
- package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
- package/lib/vendor/blamejs/lib/queue-local.js +225 -140
- package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
- package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
- package/lib/vendor/blamejs/lib/queue.js +7 -0
- package/lib/vendor/blamejs/lib/redact.js +68 -11
- package/lib/vendor/blamejs/lib/redis-client.js +160 -31
- package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
- package/lib/vendor/blamejs/lib/retention.js +117 -42
- package/lib/vendor/blamejs/lib/router.js +212 -5
- package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
- package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
- package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
- package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
- package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
- package/lib/vendor/blamejs/lib/safe-url.js +170 -3
- package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
- package/lib/vendor/blamejs/lib/scheduler.js +47 -12
- package/lib/vendor/blamejs/lib/seeders.js +122 -74
- package/lib/vendor/blamejs/lib/session-stores.js +42 -14
- package/lib/vendor/blamejs/lib/session.js +175 -77
- package/lib/vendor/blamejs/lib/sql.js +3842 -0
- package/lib/vendor/blamejs/lib/sse.js +26 -0
- package/lib/vendor/blamejs/lib/ssrf-guard.js +169 -4
- package/lib/vendor/blamejs/lib/static.js +177 -34
- package/lib/vendor/blamejs/lib/subject.js +96 -49
- package/lib/vendor/blamejs/lib/vault/index.js +3 -2
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
- package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
- package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
- package/lib/vendor/blamejs/lib/websocket.js +35 -5
- package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
- package/lib/vendor/blamejs/package.json +2 -2
- package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
- package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
- package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
- package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
- package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
- package/lib/vendor/blamejs/release-notes/v0.15.7.json +43 -0
- package/lib/vendor/blamejs/scripts/check-services.js +21 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +67 -0
- package/lib/vendor/blamejs/scripts/release.js +398 -38
- package/lib/vendor/blamejs/test/00-primitives.js +168 -0
- package/lib/vendor/blamejs/test/10-state.js +140 -14
- package/lib/vendor/blamejs/test/20-db.js +65 -2
- package/lib/vendor/blamejs/test/helpers/db.js +9 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
- package/lib/vendor/blamejs/test/helpers/services.js +21 -0
- package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
- package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
- package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
- package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
- package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
- package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
- package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
- package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
- package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
- package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
- package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
- package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
- package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
- package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
- package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
- package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
- package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
- package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
- package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
- package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
- package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
- package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
- package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
- package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1196 -14
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +362 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-watchdog-stale-settle.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
- package/lib/vendor/blamejs/test/smoke.js +79 -21
- package/package.json +2 -2
- package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
- package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
- package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
- package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
- package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
- package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
- package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
- package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
- package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
- package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
- package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
- package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
- package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
- package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
- package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
- package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
- package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
- package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
|
@@ -283,7 +283,7 @@ This is the minimum-viable security posture for a production deployment. The fra
|
|
|
283
283
|
- [ ] Confirm `vault: { mode: "wrapped" }` in the app's config (not `"plaintext"`)
|
|
284
284
|
- [ ] Store the passphrase in a secret manager (1Password / Vault / AWS Secrets Manager / sops) — never in git, never in shell history
|
|
285
285
|
- [ ] Rotate the vault passphrase quarterly: `blamejs vault rotate`
|
|
286
|
-
- [ ] When rotating the vault *keypair* (not just the passphrase) with `b.vaultRotate.rotate`, first re-seal every AAD-backed store you use via its hook (`b.agent.idempotency.reseal` / `b.agent.orchestrator.reseal` / `b.agent.snapshot.reseal` / the `b.agent.tenant` `AAD_ROTATION` reseal paths) and re-wrap tenant archives with `b.archive.rewrapTenant`, then pass `externalAadResealed` naming each re-sealed store (or `true` if you use none of them). Rotation refuses rather than silently orphaning a store it cannot reach, and its round-trip verify decrypts AAD-sealed cells under the new keypair and flags any that still open under the old one. Declare the rotation to each cluster node with `acceptVaultKeyRotation: true` so the membership adopts the new fingerprint instead of reporting `VAULT_KEY_DRIFT`
|
|
286
|
+
- [ ] When rotating the vault *keypair* (not just the passphrase) with `b.vaultRotate.rotate`, first re-seal every AAD-backed store you use via its hook (`b.agent.idempotency.reseal` / `b.agent.orchestrator.reseal` / `b.agent.snapshot.reseal` / the `b.agent.tenant` `AAD_ROTATION` reseal paths / `b.dsr.reseal` for a database-backed DSR ticket store) and re-wrap tenant archives with `b.archive.rewrapTenant`, then pass `externalAadResealed` naming each re-sealed store (or `true` if you use none of them). Rotation refuses rather than silently orphaning a store it cannot reach, and its round-trip verify decrypts AAD-sealed cells under the new keypair and flags any that still open under the old one. Declare the rotation to each cluster node with `acceptVaultKeyRotation: true` so the membership adopts the new fingerprint instead of reporting `VAULT_KEY_DRIFT`
|
|
287
287
|
- [ ] In FIPS / regulated deployments, run `b.crypto.selfTest()` at start-up as a power-on integrity gate — it KATs SHA3/SHAKE against NIST FIPS 202 vectors and pairwise-tests ML-KEM-1024 / ML-DSA-87 / SLH-DSA-SHAKE-256f, throwing `crypto/self-test-failed` (fail closed) if the crypto stack is broken
|
|
288
288
|
|
|
289
289
|
**Audit chain**
|
|
@@ -335,16 +335,18 @@ This is the minimum-viable security posture for a production deployment. The fra
|
|
|
335
335
|
- [ ] For destructive operations (data purge, key rotation, financial close), wire `b.dualControl.create({ minApprovers: 2, consumeLockMs: C.TIME.minutes(2), approverRoles: ["security-officer"], minReasonLength: 20 })` and gate the consumer on `consume(grantId).ready`
|
|
336
336
|
- [ ] For Postgres backends serving narrowed views or row-level-security policies, mount `b.middleware.dbRoleFor` so the request-time DB role is bound from the actor's permissions role; pair `b.db.declareRowPolicy` migrations with `b.externalDb.transaction({ sessionGucs })` for per-tenant binding
|
|
337
337
|
- [ ] For password-using auth: configure `b.auth.password.policy({ profile: "pci-4.0" })` (or `nist-aal2` / `hipaa-aal2`) and call `policy.check()` on every signup AND password change; pass `policy.shouldRotate(passwordSetAt)` through the login response so the UI can prompt rotation; pass the user's last-N stored hashes to `policy.reuseProhibited()` on change flows
|
|
338
|
-
- [ ] For session security: pass `{ req }` to `b.session.create()` and `b.session.verify()` so the IP / UA fingerprint is captured and checked; for high-value sessions (admin, finance) set `requireFingerprintMatch: true` OR `maxAnomalyScore: 0.7` with an operator-supplied `scorer(input)` function (impossible-travel detection, geo-distance, etc.)
|
|
338
|
+
- [ ] For session security: pass `{ req }` to `b.session.create()` and `b.session.verify()` so the IP / UA fingerprint is captured and checked; for high-value sessions (admin, finance) set `requireFingerprintMatch: true` OR `maxAnomalyScore: 0.7` with an operator-supplied `scorer(input)` function (impossible-travel detection, geo-distance, etc.). When rotating a session at a privilege boundary (login, MFA, role change), pass the same `{ req, fingerprintFields }` to `b.session.rotate()` so the device binding re-keys to the new session id — a fingerprint-bound session rotated without `req` is refused, because the binding cannot follow the new id and would otherwise silently break or false-drift the user out on the next request
|
|
339
|
+
- [ ] For RFC 9449 DPoP proof-of-possession deployments: wire `b.middleware.dpop` with a `replayStore` (a `b.nonceStore`-shaped `{ checkAndInsert }`, e.g. `b.nonceStore.create({ backend })`) — it is required at mount time, so single-use jti-replay defense is always enforced. Mounting the middleware without the store (or with one lacking `checkAndInsert`) throws at config time rather than failing open at request time with no replay defense (RFC 9449 §11.1)
|
|
339
340
|
- [ ] For inbound admin paths reachable on the public network: mount `b.middleware.networkAllowlist({ paths: ["/admin"], allowedCidrs: [...] })` as the in-process CIDR fence above the application-layer auth gate
|
|
340
341
|
- [ ] For outbound integrations: pin destination hosts via `b.httpClient.request({ allowedHosts: ["api.partner.com", ".internal.example.com"] })` so a compromised process can't reach arbitrary upstreams
|
|
341
342
|
- [ ] For test suites that mount a mock server on `127.0.0.1` to exercise `b.httpClient` / `b.wsClient` against deterministic fixtures: keep the SSRF gate ON in production code, then in tests inject an explicit `allowInternal: true` (per-call) alongside the mock-server URL. The opt-in is loud and audited, the production posture is unchanged, and operators reviewing the test grep see exactly which call sites talk to internal addresses. Cloud-metadata IPs (`169.254.169.254` etc.) stay hard-deny under any `allowInternal` value
|
|
343
|
+
- [ ] Before comparing a URL against an allowlist/denylist, building a cache/dedup key from one, or deciding whether a host is internal: canonicalize it with `b.safeUrl.canonicalize(url)` (or `b.ssrfGuard.canonicalizeHost(host)` for the host alone) first. It collapses obfuscated host + IP spellings — decimal / octal / hex / dotted IPv4, zero-compressed IPv6, IDN → punycode (rejecting confusable hosts), default ports, trailing-dot hosts (every count), path percent-encoding — to one comparable string, so `0177.0.0.1`, `0x7f.1`, `2130706433`, and `127.0.0.1` can't slip past a check that only string-matched the literal. An IPv4-mapped IPv6 host (`::ffff:1.2.3.4`) folds to its embedded IPv4 so a dual-stack peer unifies with a dotted-IPv4 entry, and credentials are dropped from the canonical form (NAT64 / 6to4 stay IPv6 so canonicalize-then-classify agrees with the SSRF classifier). Pair it with the `b.ssrfGuard` DNS-resolving gate, which still runs at fetch time
|
|
342
344
|
- [ ] For file-upload routes: gate on magic bytes via `b.fileType.assertOneOf(buffer, ["image", "application/pdf"])` — never trust the client-supplied `Content-Type` alone
|
|
343
345
|
- [ ] For routes that emit or accept CSV (operator exports, user-supplied uploads, mail attachments, object-store deliverables): wire `b.guardCsv.gate({ profile: "strict" })` into `b.staticServe.create({ contentSafety: { ".csv": gate } })` and `b.fileUpload.create({ contentSafety: gate })` — strict profile applies the OWASP-recommended `prefix-tab` formula-injection mitigation, the dangerous-function denylist (HYPERLINK / WEBSERVICE / IMAGE / IMPORT* / RTD / DDE / CALL), bidi / homoglyph / control / null-byte / BOM detection, dialect-ambiguity refusal, and CSV-bomb size caps; pick `compliancePosture: "hipaa" | "pci-dss" | "gdpr" | "soc2"` instead of (or layered over) the profile when the workload is regulated
|
|
344
346
|
- [ ] For routes that accept YAML (config uploads, CI/CD pipelines, infra-as-code, document-import flows — ANY operator-supplied YAML the server parses): `b.guardYaml.gate({ profile: "strict" })` is wired by default into `b.fileUpload` + `b.staticServe` as of v0.7.12. For inbound YAML bodies that don't go through those primitives, wire `b.guardYaml.parse(body, { profile: "strict" })` before passing the parsed structure to operator handlers — strict refuses deserialization-tag RCE (defends CVE-2026-24009 Docling/PyYAML, CVE-2022-1471 SnakeYAML, CVE-2017-18342 PyYAML class), billion-laughs alias recursion (CVE-2026-27807 MarkUs class), Norway-problem implicit booleans, multi-document streams, leading-zero octals, duplicate keys, merge-key anchor-chains, bidi/null/control chars. Unlike JSON, YAML's threat surface includes language-specific deserialization triggers — `!!python/object/new:...` / `!!java.util.HashMap` / `!!ruby/object` etc. — which the source-level scan catches before any downstream parser (PyYAML / SnakeYAML / js-yaml) sees them
|
|
345
347
|
- [ ] For routes that accept JSON bodies (REST APIs / webhook receivers / config uploads — ANY operator-supplied JSON the server parses): `b.guardJson.gate({ profile: "strict" })` is wired by default into `b.fileUpload` + `b.staticServe` as of v0.7.12. For inbound JSON request bodies that don't go through those primitives, wire `b.guardJson.parse(body, { profile: "strict" })` before passing the parsed structure to operator handlers — strict refuses prototype pollution at source level (catches `__proto__` / `constructor` / `prototype` keys before any parser sees the input — defends CVE-2025-55182 React Server Functions RCE class), duplicate keys (RFC 8259 SHOULD-unique smuggling), NaN/Infinity, comments, JSON5 syntax, BOM, bidi/null/control chars, numeric precision-loss, depth + breadth + array-length + string-length caps. Pair with `topLevelKeyAllowlist: [...]` for routes with a known shape so unauthorized keys refuse before validation
|
|
346
348
|
- [ ] For routes that accept email (inbound webhooks from mail providers, .eml uploads, mailbox imports, message-archival flows, customer-support-ticket-by-email — ANY operator-supplied RFC 822/5322 message the server processes): `b.guardEmail.gate({ profile: "strict" })` is wired by default into `b.fileUpload` + `b.staticServe` as of v0.7.17. For inbound message bytes that don't go through those primitives, wire `b.guardEmail.validateMessage(bytes, { profile: "strict" })` BEFORE the parser sees the message — strict refuses SMTP smuggling (bare CR / bare LF outside CRLF pairs combined with embedded SMTP verbs `MAIL FROM`/`RCPT TO`/`DATA`/`EHLO`/`HELO`/`RSET`/`QUIT` — defends CVE-2023-51764 Postfix / CVE-2023-51765 Sendmail / CVE-2023-51766 Exim / CVE-2026-32178 .NET System.Net.Mail class), CRLF header injection in single-line headers (defends From/Bcc/body smuggling), IDN homograph mixed-script domains in address-bearing headers (Cyrillic / Greek / Armenian / Cherokee codepoints overlapping Latin — operator opts in to legitimate non-Latin via `allowedScripts: ["latin", "cyrillic"]`), Punycode `xn--` labels, display-name spoofing (`"support@apple.com" <attacker@evil>` — display contains @-address that doesn't match envelope domain), IP-literal addresses (`user@[1.2.3.4]` — bypasses DNS/DMARC alignment), RFC 5322 comment syntax in addresses, multiple @ characters, RFC 5321 length caps (local-part 64 / domain 255 / address 320), RFC 5322 line cap (998), BOM injection, bidi/null/control chars in addresses + headers. For per-address validation outside a full message context (form-submitted email, signup, MX-host validation), wire `b.guardEmail.validateAddress(addr, { profile: "strict" })`. Pair with operator's DMARC / SPF / DKIM verifier for envelope-alignment checks — guardEmail is the source-level gate, not the authentication-result interpreter
|
|
347
|
-
- [ ] For an inbound `b.mail.server.mx` listener, wire the connection-level gate cascade so the anti-abuse controls actually run: `helo: b.mail.helo` (FCrDNS / HELO-shape / self-name spoofing → 550), `rbl: b.mail.rbl.create({ providers: [...] })` (connecting-IP DNS blocklist → 554, evaluated once per connection), and `greylist: b.mail.greylist.create({ store })` (first-seen (ip, sender, recipient) → 450 tempfail). A gate you don't wire is skipped, not synthesized — so an unwired RBL is no protection, not a default-allow surprise. SPF/DKIM/DMARC
|
|
349
|
+
- [ ] For an inbound `b.mail.server.mx` listener, wire the connection-level gate cascade so the anti-abuse controls actually run: `helo: b.mail.helo` (FCrDNS / HELO-shape / self-name spoofing → 550), `rbl: b.mail.rbl.create({ providers: [...] })` (connecting-IP DNS blocklist → 554, evaluated once per connection), and `greylist: b.mail.greylist.create({ store })` (first-seen (ip, sender, recipient) → 450 tempfail). A gate you don't wire is skipped, not synthesized — so an unwired RBL is no protection, not a default-allow surprise. Wire `guardEnvelope: true` (or a config object) to run the DATA-phase SPF/DKIM/DMARC gate (`b.mail.inbound.verify`): enforce mode refuses with 550 5.7.26 (RFC 7372) when the sender's published DMARC policy says reject and with 550 5.7.1 on the RFC 7489 §6.6.1 multi-From spoofing shape, defers with 451 4.7.0 on DNS temperror or pipeline timeout, strips any sender-forged Authentication-Results header carrying your authserv-id before prepending the computed one (RFC 8601 §5), and hands the verdict to the agent as `auth` — start with `mode: "monitor"` to observe verdicts on live traffic before enforcing
|
|
348
350
|
- [ ] For routes that accept markdown (rich-text editors, comment systems, README rendering, documentation submission, GitHub-style wikis, mail-rendered markdown, document-import flows — ANY operator-supplied markdown the server renders): `b.guardMarkdown.gate({ profile: "strict" })` is wired by default into `b.fileUpload` + `b.staticServe` as of v0.7.16. For inbound markdown bodies that don't go through those primitives, wire `b.guardMarkdown.validate(body, { profile: "strict" })` BEFORE passing the source to any markdown renderer (marked / markdown-it / commonmark / remark / parsedown — all of them) — strict refuses dangerous URL schemes in inline links + images + autolinks + reference-link definitions (defends CVE-2025-9540 Markup Markdown class, CVE-2025-24981 MDC class, NuGetGallery GHSA-gwjh-c548-f787, Joplin GHSA-hff8-hjwv-j9q7), whitespace-tolerant dangerous-tag matching (`<script\n>` / `<script\t>` — defends CVE-2026-30838 CommonMark DisallowedRawHtml bypass class), HTML-entity scheme bypass (`javascript:` / `javascript:` decoded BEFORE scheme matching), reference-link smuggling (`[label]: javascript:...`), front-matter YAML/TOML blocks, HTML comments, code-fence language injection (language tag containing `<>"' `` blocks attribute breakout), catastrophic emphasis runs (CVE-2025-6493 CodeMirror Markdown class, CVE-2025-7969 markdown-it class), inline DOCTYPE, bidi/null/control chars, total-bytes + line + link + image + autolink + ref-def + list-depth + blockquote-depth caps. **Layer with `b.guardHtml`**: source-level guardMarkdown then render then output-level guardHtml together close the residual bypass surface that either alone misses (markdown engines surprise; sanitizers also surprise — defense in depth)
|
|
349
351
|
- [ ] For routes that accept XML (SOAP endpoints, sitemap submissions, RSS / Atom feeds, OAI-PMH harvesters, SAML / WS-Federation receivers, document-import flows — ANY operator-supplied XML the server parses): `b.guardXml.gate({ profile: "strict" })` is wired by default into `b.fileUpload` + `b.staticServe` as of v0.7.15. For inbound XML bodies that don't go through those primitives, wire `b.guardXml.validate(body, { profile: "strict" })` before passing the document to any XML parser — strict refuses DOCTYPE declarations unconditionally (XXE + billion-laughs vector — defends CVE-2026-24400 AssertJ class, CVE-2024-8176 libexpat recursive-entity stack-overflow class), `<!ENTITY>` declarations including parameter entities (out-of-band exfiltration vector), external entity references (SYSTEM / PUBLIC with file:// / http:// / ftp:// schemes — local file read + SSRF), `<xi:include>` remote inclusion (CVE-2024-25062 libxml2 use-after-free class), `xsi:schemaLocation` operator-controlled schema fetch, processing instructions (`<?xml-stylesheet ?>` CSS-injection vector), CDATA sections (often used to hide payloads from naive scanners), XML signature wrapping (xmldsig surface), bidi/null/control chars in element text + attribute values, and applies depth + element + per-attribute-value caps. DOCTYPE remains refused at every profile level (strict / balanced / permissive) because billion-laughs is universal. Operators integrating with legacy SOAP that requires DTDs must instead route through a separately-firewalled XML processor with explicit allowlist — the gate has no knob to relax DOCTYPE
|
|
350
352
|
- [ ] **For ZIP-shaped uploads specifically**, reach for `b.safeArchive.extract({ source, destination, guardProfile: "strict" })` — the one-liner composes `b.archive.read.zip`'s random-access reader (LFH/CD skew defense + CD-walk validation), `b.guardArchive.zipBombPolicy` defaults (per-entry + per-archive + ratio caps), `b.guardArchive.entryTypePolicy` defaults (symlink / hardlink / device / fifo / socket entries refused), and `b.guardFilename.verifyExtractionPath`'s dual-check (string-normalize + `fs.realpath`-agreement; refuses pre-resolve names exceeding PATH_MAX=4096 to defend the CVE-2025-4517 TOCTOU class; and refuses per-segment Windows write-target hazards — reserved device names like `CON`/`NUL`, NTFS alternate-data-stream `name:stream` syntax, and trailing-dot/whitespace that Windows strips into a sibling overwrite — platform-unconditionally, since the extracting host may differ from the verifying host). The fs-coupled realpath check is the depth above `b.guardArchive.checkExtractionPath`'s portable string-only gate; operators with their own extract loop call both. Default refuses ZIP encrypted entries (v0.12.10/11 add the encryption read paths). For tar / gzip / 7z / rar / zstd, the read-side primitives land in v0.12.8 / v0.12.9; until then use the legacy guard-only path below
|
|
@@ -366,6 +368,7 @@ This is the minimum-viable security posture for a production deployment. The fra
|
|
|
366
368
|
- [ ] For data with a TTL (GDPR Art. 17, PCI 3.1, retention windows): declare retention rules via `b.retention.create({ db, audit }).declare({ name, table, ageField, ttlMs, action: "erase" })` and run on a `b.scheduler` cadence; honour legal-hold via `legalHoldField`
|
|
367
369
|
- [ ] For write-once-read-many object archives (SEC 17a-4, FINRA, HIPAA-shaped retention): create the bucket with `b.objectStore.bucketOps.create(name, { objectLockEnabled: true })` (Object Lock can ONLY be flipped at create time), apply a default retention via `setObjectLockConfiguration(name, { mode: "COMPLIANCE", years })`, and pin individual objects with `setObjectRetention(name, key, { mode, retainUntil })` or `setObjectLegalHold(name, key, "ON")` — `COMPLIANCE` cannot be shortened or bypassed by anyone (including root); pick deliberately
|
|
368
370
|
- [ ] At boot, before any outbound socket opens: call `b.network.bootFromEnv({ env: process.env, audit: b.audit })` so operator-supplied NTP / DNS / proxy / DPI-trust / TCP socket settings (`BLAMEJS_NTP_*`, `BLAMEJS_DNS_*`, `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`, `BLAMEJS_EXTRA_CA_CERTS`, `BLAMEJS_SOCKET_*`) apply uniformly
|
|
371
|
+
- [ ] If you ship spans/metrics to an OTLP collector through a custom exporter (rather than the framework's `b.otelExport` / `b.logStream`, which already do this): run every span / metric / resource attribute **value** through `b.observability.redactAttrs(attrs)` before serialization. Telemetry is a first-class egress sink — an attribute value holding a bearer token, password, or PII is otherwise shipped to the collector verbatim (CWE-532). `redactAttrs` composes `b.redact.redact`, drops any attribute whose redactor throws (fail toward dropping), and honours an operator override installed via `b.observability.setRedactor`
|
|
369
372
|
- [ ] If the deployment sits behind a deep-packet-inspection proxy with its own re-signing CA: install the CA via `b.network.tls.addCa("/path/to/corp-ca.pem", { label: "corp-mitm" })` and pass `allowDpiTrust: true` to `b.security.assertProduction` — every CA addition audits with subject + fingerprint so a forensic review can reconstruct the trust path
|
|
370
373
|
- [ ] For authenticated time (HIPAA / PCI / FIPS shops): use `b.network.ntp.nts.query({ host: ntsKeServer })` (RFC 8915) instead of plain SNTP; set `BLAMEJS_NTS_REQUIRE=1` to fail closed on negotiation failure
|
|
371
374
|
- [ ] When a DNS answer drives a trust decision (DANE / TLSA pinning, SSHFP, CAA enforcement, OPENPGPKEY lookup) and the upstream resolver isn't itself trusted: verify the answer's DNSSEC signature with `b.network.dns.dnssec.verifyRrset(...)` rather than trusting the resolver's AD bit — an on-path or compromised resolver can set AD on a forged answer, but cannot forge the RRSIG. Validate the whole delegation chain root→TLD→zone with `b.network.dns.dnssec.verifyChain(...)` (default-pinned to the IANA root KSKs, or `trustAnchors` for a private root) so trust is anchored, not borrowed from the resolver. `verifyChain` bounds KeyTrap (CVE-2023-50387) amplification with non-configurable caps (≤4 same-tag candidate keys per RRSIG, ≤64 DNSKEYs/zone, ≤16 DS/delegation, ≤128 chain links, and a signature-validation budget that scales with chain depth so deep delegations validate while bounded collisions stay bounded) and caps NSEC3 iterations at 150 (CVE-2023-50868) — a hostile zone is refused, not allowed to exhaust CPU. For a negative answer that drives a fail-closed decision (an allowlist lookup, a revocation check), verify the NSEC / NSEC3 proof with `b.network.dns.dnssec.verifyDenial(...)` so a forged NXDOMAIN cannot suppress a record; keep the default Opt-Out refusal unless the zone's opt-out spans are acceptable for that decision. For DANE / TLSA, once the TLSA RRset is DNSSEC-verified, pin the peer certificate with `b.network.dns.dane.matchCertificate(...)` — a DANE-EE(3) match authenticates the key with no public CA, while PKIX usages are flagged as still needing PKIX
|
|
@@ -425,6 +428,7 @@ The framework's audit + consent chains are append-only at the application layer
|
|
|
425
428
|
|
|
426
429
|
**Residency & replication**
|
|
427
430
|
|
|
431
|
+
- [ ] For tables holding mixed-region personal data under a cross-border regulated posture (GDPR / UK-GDPR / DPDP / PIPL / LGPD / APPI / PDPA): declare per-row residency (`b.cryptoField.declarePerRowResidency(table, { residencyColumn, allowedTags })`) so local writes refuse rows whose tag falls outside the deployment's `dataResidency` region set, and pass `rowResidencyTag` on `b.externalDb.query` / `transaction` DML so a tagged backend refuses mismatched rows at the wire (refusals + cross-border replica reads land in the audit chain). Tag columns with `b.cryptoField.declareColumnResidency` for the column-scoped version of the same gate
|
|
428
432
|
- [ ] WAL archive / streaming replicas MUST stay within the declared `b.db.getDataResidency().region`. Cross-region WAL ship (Aurora Global, RDS cross-region read replica, pg_basebackup over public internet) silently moves audit + consent rows out of the residency boundary even when the framework's `b.externalDb.residencyTag` enforcement is correct. Confirm replication topology + log-shipping path before flipping `personal` classification onto an externalDb backend
|
|
429
433
|
- [ ] For point-in-time recovery: bound the PITR window with the framework's retention floor (`b.retention.complianceFloor`) — restoring a snapshot older than the consent-erasure timestamp re-materializes deleted personal data and creates a new GDPR Art. 17 violation. Pair PITR replay with a `b.retention` re-run before re-opening the restored DB to traffic
|
|
430
434
|
- [ ] Backup encryption key MUST differ from the framework `BLAMEJS_VAULT_PASSPHRASE` — a single-key compromise that exfiltrates the running vault should not also unlock every backup bundle
|
|
@@ -435,6 +439,18 @@ The framework's audit + consent chains are append-only at the application layer
|
|
|
435
439
|
- [ ] Enable `log_min_duration_statement` at the cluster level (typically `1000ms`) so slow queries land in the operator-managed log stream alongside the framework's `db.query.slow` observability events. The framework emits the `1s` / `5s` / `30s` buckets; the cluster log captures the SQL text the framework intentionally redacts from audit metadata
|
|
436
440
|
- [ ] For roles that issue DDL (migration runner, framework boot): set `log_statement = ddl` so a forensic review can correlate the framework's `db.ddl.executed` audit row with the cluster log's verbatim DDL text — closes the trust gap between "framework says it ran X" and "cluster log shows X actually ran"
|
|
437
441
|
|
|
442
|
+
## Per-row-key crypto-shred advisory (fixed in v0.14.25)
|
|
443
|
+
|
|
444
|
+
Tables opted into per-row keying (`b.cryptoField.declarePerRowKey`) advertise crypto-erasure: `b.subject.eraseHard` / `b.retention` destroy a row's wrapped key so WAL / replica / backup residual ciphertext for that row becomes mathematically undecryptable. Before v0.14.25 that guarantee did not hold:
|
|
445
|
+
|
|
446
|
+
- **The row key was re-derivable from disk.** `K_row` was derived deterministically from `vault.getDerivedHashSalt()` — a value stored in **plaintext** on disk — plus the table name and row id. An attacker with read access to the data directory could recompute `K_row` for any row, so deleting the wrapped-key entry shredded nothing.
|
|
447
|
+
- **The wrapped key was sealed without AAD.** Despite the documented copy-row protection, the wrap carried no Additional Authenticated Data, so a database-write attacker could move a wrapped key (and the ciphertext it opens) between rows.
|
|
448
|
+
- **The key was never materialized on write.** The materialize-on-INSERT path was never wired, so the feature was inert — no row ever actually carried a per-row key.
|
|
449
|
+
|
|
450
|
+
v0.14.25 makes the guarantee real: each keyed row's secret is a fresh 32-byte CSPRNG value (never a function of any on-disk salt), stored AEAD-sealed and bound to `(table, rowId, column, schemaVersion)`; sealed columns on keyed rows are encrypted under the row key (`vault.row:` cells) and bound to the same tuple; and the key is materialized at the write boundary on every INSERT/UPDATE and destroyed by `eraseHard` / `retention`. A vault keypair rotation re-seals the wrapped secret old-root → new-root.
|
|
451
|
+
|
|
452
|
+
**Operator action.** The per-row-key registry was empty in prior deployments (the path never ran), so there is no legacy ciphertext to migrate — keyed tables become correct from their first write under v0.14.25. If you scripted a parallel re-derivation of `K_row` from `getDerivedHashSalt()` outside the framework, remove it; the derivation input is now the sealed random secret. The same plaintext-salt class was corrected for the idempotency-middleware fingerprint HMAC (`b.middleware.idempotencyKey` with `fingerprintSeal`), which now seeds off the sealed `vault.getDerivedHashMacKey()`; cached fingerprints from before the upgrade are treated as a mismatch (replayed requests re-execute once), which is the safe behavior.
|
|
453
|
+
|
|
438
454
|
## Watch list
|
|
439
455
|
|
|
440
456
|
CVE classes the framework tracks but does not currently ship a primitive for — operator awareness items:
|