@blamejs/blamejs-shop 0.4.31 → 0.4.32
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 +392 -278
- 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 +26 -0
- package/lib/vendor/blamejs/MIGRATING.md +43 -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/oauth.js +53 -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 +31 -5
- 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 +206 -4
- package/lib/vendor/blamejs/lib/consent.js +82 -29
- package/lib/vendor/blamejs/lib/constants.js +27 -11
- 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 +101 -40
- 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 +35 -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 +151 -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/scripts/check-services.js +21 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
- package/lib/vendor/blamejs/scripts/release.js +398 -38
- package/lib/vendor/blamejs/test/00-primitives.js +117 -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 +1120 -14
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -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/router-use-path-scope.test.js +255 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -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/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 +1 -1
- 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
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Live b.sql sqlite-FTS5 + catalog/pragma test against a real node:sqlite
|
|
4
|
+
* DatabaseSync handle (no docker - sqlite is the built-in dialect).
|
|
5
|
+
*
|
|
6
|
+
* Exercises the sqlite-only builders the mail store + the at-rest key-
|
|
7
|
+
* rotation pipeline drive, end to end against a live engine so the emitted
|
|
8
|
+
* SQL is proven to PARSE + RUN + return the right rows, not just match a
|
|
9
|
+
* string shape:
|
|
10
|
+
*
|
|
11
|
+
* 1. createVirtualTable -> CREATE VIRTUAL TABLE ... USING fts5(...) runs;
|
|
12
|
+
* whereMatch -> `<fts> MATCH ?` returns exactly the rows whose tokens
|
|
13
|
+
* match, with the query string bound (never interpolated).
|
|
14
|
+
* 2. whereInJsonEach -> `<col> IN (SELECT value FROM json_each(?))`
|
|
15
|
+
* unrolls a JSON-array string bind to a membership filter.
|
|
16
|
+
* 3. The catalog sub-API (listTables / tableExists / tableInfo /
|
|
17
|
+
* sampleRandom / changes) + pragma (journal_mode / synchronous /
|
|
18
|
+
* wal_checkpoint) emit statements the engine accepts, returning the
|
|
19
|
+
* real catalog metadata.
|
|
20
|
+
* 4. A bound MATCH operand carrying SQL metacharacters stays a literal
|
|
21
|
+
* FTS query term - it cannot break out of the placeholder.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
var { DatabaseSync } = require("node:sqlite");
|
|
25
|
+
var helpers = require("../helpers");
|
|
26
|
+
var check = helpers.check;
|
|
27
|
+
var b = require("../../");
|
|
28
|
+
|
|
29
|
+
function _all(db, built) {
|
|
30
|
+
var st = db.prepare(built.sql);
|
|
31
|
+
return built.params.length > 0 ? st.all.apply(st, built.params) : st.all();
|
|
32
|
+
}
|
|
33
|
+
function _get(db, built) {
|
|
34
|
+
var st = db.prepare(built.sql);
|
|
35
|
+
return built.params.length > 0 ? st.get.apply(st, built.params) : st.get();
|
|
36
|
+
}
|
|
37
|
+
function _run(db, built) {
|
|
38
|
+
var st = db.prepare(built.sql);
|
|
39
|
+
return built.params.length > 0 ? st.run.apply(st, built.params) : st.run();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function run() {
|
|
43
|
+
var sql = b.sql;
|
|
44
|
+
var db = new DatabaseSync(":memory:");
|
|
45
|
+
try {
|
|
46
|
+
// ---- 1. FTS5 virtual table + MATCH ----
|
|
47
|
+
_run(db, sql.createVirtualTable("mail_fts", {
|
|
48
|
+
columns: [{ name: "objectid", unindexed: true }, "subject_toks", "body_toks"],
|
|
49
|
+
tokenize: "unicode61 remove_diacritics 2",
|
|
50
|
+
quoteName: true,
|
|
51
|
+
}));
|
|
52
|
+
check("createVirtualTable: CREATE VIRTUAL TABLE USING fts5 runs", true);
|
|
53
|
+
|
|
54
|
+
function ins(oid, subj, body) {
|
|
55
|
+
_run(db, sql.insert("mail_fts", { quoteName: true })
|
|
56
|
+
.columns(["objectid", "subject_toks", "body_toks"])
|
|
57
|
+
.values({ objectid: oid, subject_toks: subj, body_toks: body }).toSql());
|
|
58
|
+
}
|
|
59
|
+
ins("m1", "alpha bravo", "charlie delta");
|
|
60
|
+
ins("m2", "bravo", "echo");
|
|
61
|
+
ins("m3", "zulu", "delta foxtrot");
|
|
62
|
+
|
|
63
|
+
// `<fts> MATCH ?` inside the IN-subquery shape the mail store uses -
|
|
64
|
+
// bind the query string, never interpolate.
|
|
65
|
+
var matchSub = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
|
|
66
|
+
.columns(["objectid"]).whereMatch("mail_fts", "bravo").toSql();
|
|
67
|
+
var bravoRows = _all(db, matchSub).map(function (r) { return r.objectid; }).sort();
|
|
68
|
+
check("whereMatch 'bravo' returns m1 + m2 (token in subject of both)",
|
|
69
|
+
bravoRows.length === 2 && bravoRows[0] === "m1" && bravoRows[1] === "m2");
|
|
70
|
+
|
|
71
|
+
var deltaSub = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
|
|
72
|
+
.columns(["objectid"]).whereMatch("mail_fts", "delta").toSql();
|
|
73
|
+
var deltaRows = _all(db, deltaSub).map(function (r) { return r.objectid; }).sort();
|
|
74
|
+
check("whereMatch 'delta' returns m1 + m3 (token in body of both)",
|
|
75
|
+
deltaRows.length === 2 && deltaRows[0] === "m1" && deltaRows[1] === "m3");
|
|
76
|
+
|
|
77
|
+
// The MATCH operand binds: a query carrying a token that does not exist
|
|
78
|
+
// returns nothing (and a metacharacter-laden operand stays a literal
|
|
79
|
+
// FTS term, never a statement break - the engine parses it as a query).
|
|
80
|
+
var noneSub = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
|
|
81
|
+
.columns(["objectid"]).whereMatch("mail_fts", "nonexistenttoken").toSql();
|
|
82
|
+
check("whereMatch unknown token returns no rows", _all(db, noneSub).length === 0);
|
|
83
|
+
|
|
84
|
+
// ---- 2. json_each membership ----
|
|
85
|
+
db.prepare('CREATE TABLE "msgs" ("objectid" TEXT, "folder_id" INTEGER)').run();
|
|
86
|
+
db.prepare('INSERT INTO "msgs" VALUES (?,?),(?,?),(?,?)')
|
|
87
|
+
.run("m1", 1, "m2", 1, "m3", 2);
|
|
88
|
+
var jeBuilt = sql.select("msgs", { dialect: "sqlite", quoteName: true })
|
|
89
|
+
.columns(["objectid", "folder_id"])
|
|
90
|
+
.where("folder_id", 1)
|
|
91
|
+
.whereInJsonEach("objectid", JSON.stringify(["m1", "m3"]))
|
|
92
|
+
.toSql();
|
|
93
|
+
var jeRows = _all(db, jeBuilt).map(function (r) { return r.objectid; });
|
|
94
|
+
check("whereInJsonEach: folder=1 AND objectid IN json_each(['m1','m3']) -> only m1",
|
|
95
|
+
jeRows.length === 1 && jeRows[0] === "m1");
|
|
96
|
+
|
|
97
|
+
// ---- 3. catalog sub-API ----
|
|
98
|
+
var tables = _all(db, sql.catalog.listTables()).map(function (r) { return r.name; });
|
|
99
|
+
check("catalog.listTables lists the user tables (msgs present, no sqlite_ internal)",
|
|
100
|
+
tables.indexOf("msgs") !== -1 && tables.every(function (n) { return n.indexOf("sqlite_") !== 0; }));
|
|
101
|
+
check("catalog.tableExists true for a real table",
|
|
102
|
+
!!_get(db, sql.catalog.tableExists("msgs")));
|
|
103
|
+
check("catalog.tableExists false for a missing table",
|
|
104
|
+
!_get(db, sql.catalog.tableExists("no_such_table")));
|
|
105
|
+
var info = _all(db, sql.catalog.tableInfo("msgs")).map(function (c) { return c.name; }).sort();
|
|
106
|
+
check("catalog.tableInfo returns the column names",
|
|
107
|
+
info.length === 2 && info[0] === "folder_id" && info[1] === "objectid");
|
|
108
|
+
var sample = _all(db, sql.catalog.sampleRandom("msgs", ["objectid"], { limit: 2 }));
|
|
109
|
+
check("catalog.sampleRandom ORDER BY RANDOM LIMIT ? returns <= limit rows",
|
|
110
|
+
sample.length <= 2 && sample.length >= 1);
|
|
111
|
+
|
|
112
|
+
// catalog.changes reports the row count of the last write on this conn.
|
|
113
|
+
db.prepare('UPDATE "msgs" SET "folder_id" = 9 WHERE "folder_id" = 2').run();
|
|
114
|
+
var changed = _get(db, sql.catalog.changes());
|
|
115
|
+
check("catalog.changes reports last-write rowcount", changed && changed.c === 1);
|
|
116
|
+
|
|
117
|
+
// ---- 4. pragma sub-API ----
|
|
118
|
+
var jm = _get(db, sql.pragma("journal_mode", "WAL"));
|
|
119
|
+
check("pragma journal_mode=WAL runs (returns a mode row)", !!jm);
|
|
120
|
+
_run(db, sql.pragma("synchronous", "NORMAL"));
|
|
121
|
+
check("pragma synchronous=NORMAL runs", true);
|
|
122
|
+
_run(db, sql.pragma("wal_checkpoint", "TRUNCATE"));
|
|
123
|
+
check("pragma wal_checkpoint(TRUNCATE) runs", true);
|
|
124
|
+
|
|
125
|
+
// ---- 5. metacharacter operand stays bound (no breakout) ----
|
|
126
|
+
// A would-be-injection MATCH operand is a literal FTS query term: the
|
|
127
|
+
// FTS5 parser treats it as a (possibly zero-match) query, never a
|
|
128
|
+
// statement. The row count is whatever matches; the point is the
|
|
129
|
+
// statement does not error out / stack a second statement.
|
|
130
|
+
var safeMatch = sql.select("mail_fts", { dialect: "sqlite", quoteName: true })
|
|
131
|
+
.columns(["objectid"]).whereMatch("mail_fts", "alpha").toSql();
|
|
132
|
+
var injBuilt = { sql: safeMatch.sql, params: ['alpha"; DROP TABLE "msgs'] };
|
|
133
|
+
var injErr = null;
|
|
134
|
+
try { _all(db, injBuilt); } catch (e) { injErr = e; }
|
|
135
|
+
var msgsStill = !!_get(db, sql.catalog.tableExists("msgs"));
|
|
136
|
+
check("bound MATCH operand with metacharacters does not drop a table",
|
|
137
|
+
msgsStill);
|
|
138
|
+
// The metachar query either matches nothing or errors as a malformed
|
|
139
|
+
// FTS expression - either way "msgs" survived (no statement breakout).
|
|
140
|
+
check("metachar MATCH operand stayed a single bound statement",
|
|
141
|
+
injErr === null || msgsStill);
|
|
142
|
+
} finally {
|
|
143
|
+
db.close();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = { run: run };
|
|
148
|
+
|
|
149
|
+
if (require.main === module) {
|
|
150
|
+
run().then(
|
|
151
|
+
function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
|
|
152
|
+
function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
|
|
153
|
+
);
|
|
154
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Live proof of the outbound-TLS classical-downgrade audit. When an outbound
|
|
4
|
+
* connection negotiates classical X25519 (the peer offers no ML-KEM hybrid),
|
|
5
|
+
* the framework emits a `tls.classical_downgrade` audit event; when it
|
|
6
|
+
* negotiates a hybrid, it does not. Azurite (its OpenSSL has no ML-KEM)
|
|
7
|
+
* forces the classical fallback; MinIO-tls (OpenSSL 3.5) negotiates the
|
|
8
|
+
* hybrid. Runs over TLS with the test CA (NODE_EXTRA_CA_CERTS), no bypass.
|
|
9
|
+
*/
|
|
10
|
+
var helpers = require("../helpers");
|
|
11
|
+
var b = helpers.b;
|
|
12
|
+
var check = helpers.check;
|
|
13
|
+
var services = require("../helpers/services");
|
|
14
|
+
var httpClient = require("../../lib/http-client");
|
|
15
|
+
var setupTestDb = require("../helpers/db").setupTestDb;
|
|
16
|
+
var teardownTestDb = require("../helpers/db").teardownTestDb;
|
|
17
|
+
var fs = require("node:fs"), os = require("node:os"), path = require("node:path");
|
|
18
|
+
|
|
19
|
+
async function downgradeRows(sinceMs) {
|
|
20
|
+
await b.audit.flush();
|
|
21
|
+
var rows = await b.audit.query({ action: "tls.classical_downgrade", from: sinceMs - 1000, limit: 100 });
|
|
22
|
+
return (rows || []).map(function (r) {
|
|
23
|
+
var md = r.metadata;
|
|
24
|
+
if (typeof md === "string") { try { md = JSON.parse(md); } catch (_e) { md = {}; } }
|
|
25
|
+
return md || {};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function run() {
|
|
30
|
+
var azu = await services.requireService("azurite");
|
|
31
|
+
if (!azu.ok) throw new Error("azurite unreachable: " + azu.reason);
|
|
32
|
+
var mio = await services.requireService("minioTls");
|
|
33
|
+
if (!mio.ok) throw new Error("minio-tls unreachable: " + mio.reason);
|
|
34
|
+
|
|
35
|
+
var dir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-tlsdown-"));
|
|
36
|
+
try {
|
|
37
|
+
await setupTestDb(dir, []);
|
|
38
|
+
|
|
39
|
+
// Classical peer (Azurite — no ML-KEM hybrid). The HTTP response is
|
|
40
|
+
// irrelevant (an unauthenticated GET may 400); the downgrade audit fires
|
|
41
|
+
// on the TLS handshake regardless.
|
|
42
|
+
var t0 = Date.now();
|
|
43
|
+
try { await httpClient.request({ url: "https://127.0.0.1:10000/", method: "GET", allowInternal: true }); } catch (_e) {}
|
|
44
|
+
var afterAzu = await downgradeRows(t0);
|
|
45
|
+
var azuHit = afterAzu.filter(function (m) { return String(m.port) === "10000"; });
|
|
46
|
+
check("classical peer (Azurite) emitted a tls.classical_downgrade audit", azuHit.length >= 1);
|
|
47
|
+
check("downgrade audit names the classical group + host",
|
|
48
|
+
azuHit.some(function (m) { return m.group === "X25519" && m.host === "127.0.0.1"; }));
|
|
49
|
+
|
|
50
|
+
// PQC peer (MinIO-tls — negotiates the ML-KEM hybrid). No downgrade for it.
|
|
51
|
+
var t1 = Date.now();
|
|
52
|
+
try { await httpClient.request({ url: "https://127.0.0.1:9443/", method: "GET", allowInternal: true }); } catch (_e) {}
|
|
53
|
+
var afterMio = await downgradeRows(t1);
|
|
54
|
+
var mioHit = afterMio.filter(function (m) { return String(m.port) === "9443"; });
|
|
55
|
+
check("PQC peer (MinIO-tls) emitted NO downgrade audit (hybrid negotiated)", mioHit.length === 0);
|
|
56
|
+
|
|
57
|
+
await teardownTestDb(dir);
|
|
58
|
+
} finally {
|
|
59
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_e) {}
|
|
60
|
+
}
|
|
61
|
+
console.log("OK — " + helpers.getChecks() + " checks passed");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { run: run };
|
|
65
|
+
|
|
66
|
+
if (require.main === module) {
|
|
67
|
+
run().then(
|
|
68
|
+
function () { process.exit(0); },
|
|
69
|
+
function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
var helpers = require("../helpers");
|
|
4
4
|
var b = helpers.b;
|
|
5
5
|
var check = helpers.check;
|
|
6
|
+
var fs = helpers.fs;
|
|
7
|
+
var os = helpers.os;
|
|
8
|
+
var path = helpers.path;
|
|
9
|
+
|
|
10
|
+
// The shape-only tests below run single-process with no vault, so they
|
|
11
|
+
// pass requireMac:false (the documented escape hatch). The keyed-MAC
|
|
12
|
+
// envelope authentication (M6) is exercised against a real vault in the
|
|
13
|
+
// testEnvelopeMac* tests at the bottom of this file.
|
|
14
|
+
function _tmp() { return fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-evbus-")); }
|
|
6
15
|
|
|
7
16
|
function _fakePubsub() {
|
|
8
17
|
var subs = new Map();
|
|
@@ -43,7 +52,7 @@ function testSurface() {
|
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
async function testRegisterPublishSubscribe() {
|
|
46
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
55
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
47
56
|
bus.registerTopic("mail.scan.malware-detected", {
|
|
48
57
|
schema: { source: "string", confidence: "number" },
|
|
49
58
|
});
|
|
@@ -58,7 +67,7 @@ async function testRegisterPublishSubscribe() {
|
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
async function testUnknownTopic() {
|
|
61
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
70
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
62
71
|
await expectRejection("publish refuses unknown topic",
|
|
63
72
|
bus.publish("mail.unknown.event", {}),
|
|
64
73
|
"agent-event-bus/unknown-topic");
|
|
@@ -68,7 +77,7 @@ async function testUnknownTopic() {
|
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
async function testDuplicateTopic() {
|
|
71
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
80
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
72
81
|
bus.registerTopic("mail.a.b", { schema: { x: "string" } });
|
|
73
82
|
var threw = null;
|
|
74
83
|
try { bus.registerTopic("mail.a.b", { schema: { x: "string" } }); }
|
|
@@ -78,7 +87,7 @@ async function testDuplicateTopic() {
|
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
async function testBadTopicShape() {
|
|
81
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
90
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
82
91
|
var threw = null;
|
|
83
92
|
try { bus.registerTopic("malware", { schema: { x: "string" } }); }
|
|
84
93
|
catch (e) { threw = e; }
|
|
@@ -87,7 +96,7 @@ async function testBadTopicShape() {
|
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
async function testSchemaValidation() {
|
|
90
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
99
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
91
100
|
bus.registerTopic("mail.scan.detected", {
|
|
92
101
|
schema: { source: "string", confidence: "number" },
|
|
93
102
|
});
|
|
@@ -113,7 +122,7 @@ async function testPermissions() {
|
|
|
113
122
|
},
|
|
114
123
|
auditFailures: false, auditSuccess: false,
|
|
115
124
|
});
|
|
116
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), permissions: perms });
|
|
125
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), permissions: perms, requireMac: false });
|
|
117
126
|
bus.registerTopic("mail.scan.detected", {
|
|
118
127
|
schema: { source: "string" },
|
|
119
128
|
permissions: { publish: ["mail-scan:write"], subscribe: ["mail-mx:write"] },
|
|
@@ -134,7 +143,7 @@ async function testPermissions() {
|
|
|
134
143
|
}
|
|
135
144
|
|
|
136
145
|
async function testTenantScope() {
|
|
137
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
146
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
138
147
|
bus.registerTopic("mail.tenant.event", {
|
|
139
148
|
schema: { source: "string" },
|
|
140
149
|
tenantScope: true,
|
|
@@ -156,7 +165,7 @@ async function testTenantScope() {
|
|
|
156
165
|
}
|
|
157
166
|
|
|
158
167
|
async function testTenantScopeRefusesSubscriberWithoutTenantId() {
|
|
159
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
168
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
160
169
|
bus.registerTopic("mail.scoped.event", {
|
|
161
170
|
schema: { source: "string" },
|
|
162
171
|
tenantScope: true,
|
|
@@ -172,7 +181,7 @@ async function testTenantScopeRefusesSubscriberWithoutTenantId() {
|
|
|
172
181
|
}
|
|
173
182
|
|
|
174
183
|
async function testAsyncHandlerErrors() {
|
|
175
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
184
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
176
185
|
bus.registerTopic("mail.async.event", { schema: { x: "string" } });
|
|
177
186
|
var crashed = false;
|
|
178
187
|
var origHandler = process.listeners("unhandledRejection").slice();
|
|
@@ -196,7 +205,7 @@ async function testRefusesBadOpts() {
|
|
|
196
205
|
}
|
|
197
206
|
|
|
198
207
|
async function testListTopics() {
|
|
199
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
208
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
200
209
|
bus.registerTopic("mail.a.b", { schema: { x: "string" }, posture: "soc2" });
|
|
201
210
|
bus.registerTopic("mail.c.d", { schema: { y: "number" } });
|
|
202
211
|
var list = bus.listTopics({});
|
|
@@ -208,7 +217,7 @@ async function testPublishRefusesUntenantedOnTenantTopic() {
|
|
|
208
217
|
// SUBSTRATE-6 — tenant-scoped topic refuses publish without
|
|
209
218
|
// actor.tenantId so the durable bus never accumulates untenanted
|
|
210
219
|
// entries that get filtered out at subscribe-time.
|
|
211
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
220
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
212
221
|
bus.registerTopic("mail.scan.malware", {
|
|
213
222
|
schema: { source: "string" }, tenantScope: true,
|
|
214
223
|
});
|
|
@@ -226,7 +235,7 @@ async function testPublishRefusesUntenantedOnTenantTopic() {
|
|
|
226
235
|
async function testUnregisterTopic() {
|
|
227
236
|
// SUBSTRATE-22 / BUG-12 — unregisterTopic exists; the kind filter
|
|
228
237
|
// matches because register captures the kind.
|
|
229
|
-
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub() });
|
|
238
|
+
var bus = b.agent.eventBus.create({ pubsub: _fakePubsub(), requireMac: false });
|
|
230
239
|
bus.registerTopic("mail.scan.A", { schema: { x: "string" } });
|
|
231
240
|
bus.registerTopic("mail.scan.B", { schema: { y: "number" } });
|
|
232
241
|
bus.registerTopic("ai.classify.C", { schema: { z: "boolean" } });
|
|
@@ -242,6 +251,154 @@ async function testUnregisterTopic() {
|
|
|
242
251
|
check("SUBSTRATE-22: re-register after unregister", bus.listTopics({}).length === 3);
|
|
243
252
|
}
|
|
244
253
|
|
|
254
|
+
// ---- M6 — keyed-MAC envelope authentication (real vault) ----
|
|
255
|
+
//
|
|
256
|
+
// A pubsub-write attacker can set _tenantId to a victim's tenant + a
|
|
257
|
+
// schema-valid payload and forge a cross-tenant event; the tenant/schema
|
|
258
|
+
// checks prove SHAPE, not authenticity. The keyed MAC over the envelope's
|
|
259
|
+
// authority-bearing fields, verified at the consumer BEFORE the tenant
|
|
260
|
+
// check, refuses the forgery and any in-flight tamper. requireMac is on
|
|
261
|
+
// by default; these tests use the default with a real vault.
|
|
262
|
+
|
|
263
|
+
// A pubsub that captures the published envelope AND exposes the
|
|
264
|
+
// subscriber handler, so a test can deliver an arbitrary (forged /
|
|
265
|
+
// tampered) envelope directly to the consumer — exactly a pubsub-write
|
|
266
|
+
// attacker's capability.
|
|
267
|
+
function _capturingPubsub() {
|
|
268
|
+
var handlers = new Map();
|
|
269
|
+
var published = [];
|
|
270
|
+
return {
|
|
271
|
+
publish: async function (channel, envelope) {
|
|
272
|
+
published.push({ channel: channel, envelope: envelope });
|
|
273
|
+
(handlers.get(channel) || []).forEach(function (h) { h(envelope, { source: "fake" }); });
|
|
274
|
+
},
|
|
275
|
+
subscribe: async function (channel, handler) {
|
|
276
|
+
var list = handlers.get(channel) || [];
|
|
277
|
+
list.push(handler);
|
|
278
|
+
handlers.set(channel, list);
|
|
279
|
+
return function () {};
|
|
280
|
+
},
|
|
281
|
+
unsubscribe: function () {},
|
|
282
|
+
// Test affordance: deliver an attacker-controlled envelope straight to
|
|
283
|
+
// the consumer, bypassing publish() (the bus's own MAC mint).
|
|
284
|
+
_deliver: function (channel, envelope) {
|
|
285
|
+
(handlers.get(channel) || []).forEach(function (h) { h(envelope, { source: "attacker" }); });
|
|
286
|
+
},
|
|
287
|
+
_lastEnvelope: function () { return published.length ? published[published.length - 1].envelope : null; },
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function testEnvelopeMacForgedRefused() {
|
|
292
|
+
var tmpDir = _tmp();
|
|
293
|
+
await helpers.setupVaultOnly(tmpDir);
|
|
294
|
+
try {
|
|
295
|
+
var pubsub = _capturingPubsub();
|
|
296
|
+
var bus = b.agent.eventBus.create({ pubsub: pubsub }); // requireMac default ON
|
|
297
|
+
bus.registerTopic("mail.tenant.event", { schema: { source: "string" }, tenantScope: true });
|
|
298
|
+
var received = [];
|
|
299
|
+
await bus.subscribe("mail.tenant.event", function (p) { received.push(p); }, {
|
|
300
|
+
actor: { id: "victim", tenantId: "globex" },
|
|
301
|
+
});
|
|
302
|
+
// Attacker forges an envelope: victim's tenant, schema-valid payload,
|
|
303
|
+
// NO valid MAC. Delivered straight onto the bus (pubsub-write access).
|
|
304
|
+
pubsub._deliver("mail.tenant.event", {
|
|
305
|
+
_topic: "mail.tenant.event",
|
|
306
|
+
_posture: undefined,
|
|
307
|
+
_tenantId: "globex", // victim's tenant — forged
|
|
308
|
+
_publishedAt: Date.now(),
|
|
309
|
+
payload: { source: "attacker-injected" },
|
|
310
|
+
_mac: "AAAA", // bogus MAC
|
|
311
|
+
});
|
|
312
|
+
await helpers.passiveObserve(25, "M6: forged envelope must NOT be delivered");
|
|
313
|
+
check("forged cross-tenant envelope refused at consumer (MAC invalid)", received.length === 0);
|
|
314
|
+
} finally {
|
|
315
|
+
helpers.teardownVaultOnly(tmpDir);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function testEnvelopeMacHonestDelivered() {
|
|
320
|
+
var tmpDir = _tmp();
|
|
321
|
+
await helpers.setupVaultOnly(tmpDir);
|
|
322
|
+
try {
|
|
323
|
+
var pubsub = _capturingPubsub();
|
|
324
|
+
var bus = b.agent.eventBus.create({ pubsub: pubsub });
|
|
325
|
+
bus.registerTopic("mail.tenant.event", { schema: { source: "string" }, tenantScope: true });
|
|
326
|
+
var received = [];
|
|
327
|
+
await bus.subscribe("mail.tenant.event", function (p) { received.push(p); }, {
|
|
328
|
+
actor: { id: "u-acme", tenantId: "acme" },
|
|
329
|
+
});
|
|
330
|
+
// Honest publish through the bus — it mints a valid MAC.
|
|
331
|
+
await bus.publish("mail.tenant.event", { source: "legit" }, {
|
|
332
|
+
actor: { id: "p1", tenantId: "acme" },
|
|
333
|
+
});
|
|
334
|
+
await helpers.waitUntil(function () { return received.length >= 1; }, {
|
|
335
|
+
timeoutMs: 5000, label: "M6: honestly-published event delivered",
|
|
336
|
+
});
|
|
337
|
+
check("honestly-published event delivered (valid MAC)", received.length === 1);
|
|
338
|
+
check("honest event payload intact", received[0].source === "legit");
|
|
339
|
+
} finally {
|
|
340
|
+
helpers.teardownVaultOnly(tmpDir);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function testEnvelopeMacTamperFails() {
|
|
345
|
+
var tmpDir = _tmp();
|
|
346
|
+
await helpers.setupVaultOnly(tmpDir);
|
|
347
|
+
try {
|
|
348
|
+
var pubsub = _capturingPubsub();
|
|
349
|
+
var bus = b.agent.eventBus.create({ pubsub: pubsub });
|
|
350
|
+
bus.registerTopic("mail.scan.event", { schema: { source: "string" }, posture: "soc2" });
|
|
351
|
+
var receivedTopic = [];
|
|
352
|
+
await bus.subscribe("mail.scan.event", function (p) { receivedTopic.push(p); });
|
|
353
|
+
|
|
354
|
+
// Capture a genuine envelope, then tamper each authority field and
|
|
355
|
+
// re-deliver — every tamper must fail the MAC.
|
|
356
|
+
await bus.publish("mail.scan.event", { source: "ok" }, { actor: { id: "p1" } });
|
|
357
|
+
await helpers.waitUntil(function () { return receivedTopic.length >= 1; }, {
|
|
358
|
+
timeoutMs: 5000, label: "M6: baseline honest delivery",
|
|
359
|
+
});
|
|
360
|
+
var genuine = pubsub._lastEnvelope();
|
|
361
|
+
check("baseline honest envelope carries a MAC", typeof genuine._mac === "string" && genuine._mac.length > 0);
|
|
362
|
+
|
|
363
|
+
function _clone(env) { return JSON.parse(JSON.stringify(env)); }
|
|
364
|
+
|
|
365
|
+
// Tamper _posture (posture downgrade attempt).
|
|
366
|
+
var gotPosture = [];
|
|
367
|
+
await bus.subscribe("mail.scan.event", function (p) { gotPosture.push(p); });
|
|
368
|
+
var tPosture = _clone(genuine); tPosture._posture = "none"; tPosture.payload = { source: "ok" };
|
|
369
|
+
pubsub._deliver("mail.scan.event", tPosture);
|
|
370
|
+
|
|
371
|
+
// Tamper _topic.
|
|
372
|
+
var tTopic = _clone(genuine); tTopic._topic = "mail.scan.event"; tTopic.payload = { source: "ok" };
|
|
373
|
+
tTopic._tenantId = "injected"; // change a signed field
|
|
374
|
+
pubsub._deliver("mail.scan.event", tTopic);
|
|
375
|
+
|
|
376
|
+
// Tamper payload.
|
|
377
|
+
var tPayload = _clone(genuine); tPayload.payload = { source: "tampered" };
|
|
378
|
+
pubsub._deliver("mail.scan.event", tPayload);
|
|
379
|
+
|
|
380
|
+
await helpers.passiveObserve(40, "M6: tampered envelopes must NOT reach the second subscriber");
|
|
381
|
+
check("tampered _posture / _tenantId / payload all fail the MAC (none delivered)",
|
|
382
|
+
gotPosture.length === 0);
|
|
383
|
+
} finally {
|
|
384
|
+
helpers.teardownVaultOnly(tmpDir);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function testEnvelopeMacPublishFailsClosedWithoutVault() {
|
|
389
|
+
// requireMac default ON + no vault → publish refuses (fail-closed)
|
|
390
|
+
// rather than emitting an unauthenticatable envelope.
|
|
391
|
+
b.vault._resetForTest();
|
|
392
|
+
if (b.agent.postureChain && b.agent.postureChain._resetForTest) b.agent.postureChain._resetForTest();
|
|
393
|
+
var bus = b.agent.eventBus.create({ pubsub: _capturingPubsub() });
|
|
394
|
+
bus.registerTopic("mail.scan.noVault", { schema: { source: "string" } });
|
|
395
|
+
var threw = null;
|
|
396
|
+
try { await bus.publish("mail.scan.noVault", { source: "x" }, { actor: { id: "p1" } }); }
|
|
397
|
+
catch (e) { threw = e; }
|
|
398
|
+
check("publish fails closed when no MAC key (requireMac default)",
|
|
399
|
+
threw && (threw.code || "").indexOf("agent-event-bus/envelope-mac-unavailable") !== -1);
|
|
400
|
+
}
|
|
401
|
+
|
|
245
402
|
async function run() {
|
|
246
403
|
testSurface();
|
|
247
404
|
await testRegisterPublishSubscribe();
|
|
@@ -257,6 +414,12 @@ async function run() {
|
|
|
257
414
|
await testRefusesBadOpts();
|
|
258
415
|
await testListTopics();
|
|
259
416
|
await testUnregisterTopic();
|
|
417
|
+
// M6 — keyed-MAC envelope authentication (real vault). The no-vault
|
|
418
|
+
// fail-closed test runs LAST (it tears the vault down).
|
|
419
|
+
await testEnvelopeMacForgedRefused();
|
|
420
|
+
await testEnvelopeMacHonestDelivered();
|
|
421
|
+
await testEnvelopeMacTamperFails();
|
|
422
|
+
await testEnvelopeMacPublishFailsClosedWithoutVault();
|
|
260
423
|
}
|
|
261
424
|
|
|
262
425
|
module.exports = { run: run };
|