@blamejs/blamejs-shop 0.4.30 → 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 +4 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/checkout.js +8 -0
- package/lib/order.js +71 -11
- 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,517 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Live test of the catalog claim that the tamper-evident, signed audit
|
|
4
|
+
* hash-chain "runs on the operator's external Postgres in cluster mode"
|
|
5
|
+
* (b.audit / b.clusterStorage / b.frameworkSchema). Driver: a docker-exec
|
|
6
|
+
* psql shim that replicates a real node-postgres driver's coercions
|
|
7
|
+
* EXACTLY — the point of the test:
|
|
8
|
+
*
|
|
9
|
+
* - unquoted camelCase columns come back LOWERCASED in the result keys
|
|
10
|
+
* (Postgres folds unquoted identifiers; node-postgres returns the
|
|
11
|
+
* server's reported names verbatim → `rowhash`, `prevhash`,
|
|
12
|
+
* `monotoniccounter`, …),
|
|
13
|
+
* - BIGINT (int8) comes back as a JS STRING (node-postgres default to
|
|
14
|
+
* avoid >2^53 precision loss),
|
|
15
|
+
* - BYTEA comes back as a Node Buffer.
|
|
16
|
+
*
|
|
17
|
+
* What this proves (or refutes), end-to-end against the live server:
|
|
18
|
+
*
|
|
19
|
+
* 1. frameworkSchema.ensureSchema creates _blamejs_audit_log + the
|
|
20
|
+
* append-only WORM triggers on real Postgres (the chain's home in
|
|
21
|
+
* cluster mode).
|
|
22
|
+
*
|
|
23
|
+
* 2. Build a KNOWN-VALID chain with the framework's OWN hash math
|
|
24
|
+
* (b.auditChain.computeRowHash), INSERT the rows into the live
|
|
25
|
+
* _blamejs_audit_log via the driver, then run the framework's own
|
|
26
|
+
* verifier (b.auditChain.verifyChain, the exact reader b.audit.verify
|
|
27
|
+
* uses) against the live table. A correct framework returns ok:true.
|
|
28
|
+
* THIS IS THE CORE PROOF and it asserts the CORRECT behavior so a
|
|
29
|
+
* regression / pre-existing gap surfaces as a failure.
|
|
30
|
+
*
|
|
31
|
+
* 3. The BIGINT→string + BYTEA→Buffer coercion of the hash-preimage
|
|
32
|
+
* columns (monotonicCounter, recordedAt, nonce) must not break a
|
|
33
|
+
* valid chain's verification.
|
|
34
|
+
*
|
|
35
|
+
* 4. TAMPER a hashed column directly via the driver → verify must
|
|
36
|
+
* report ok:false.
|
|
37
|
+
*
|
|
38
|
+
* 5. cluster.init leadership acquisition over the real Postgres lease
|
|
39
|
+
* provider — the gate every chain append passes through.
|
|
40
|
+
*
|
|
41
|
+
* MySQL note: frameworkSchema only emits DDL for postgres / sqlite
|
|
42
|
+
* (lib/framework-schema.js _types() throws on "mysql"; the module
|
|
43
|
+
* docstring states MySQL is not supported). There is no MySQL audit-chain
|
|
44
|
+
* path to exercise — the test asserts the framework refuses MySQL rather
|
|
45
|
+
* than fabricating a MySQL chain.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
var spawn = require("node:child_process").spawn;
|
|
49
|
+
var execFileSync = require("node:child_process").execFileSync;
|
|
50
|
+
var helpers = require("../helpers");
|
|
51
|
+
var check = helpers.check;
|
|
52
|
+
var services = require("../helpers/services");
|
|
53
|
+
var b = require("../../");
|
|
54
|
+
|
|
55
|
+
var CONTAINER = "blamejs-test-postgres";
|
|
56
|
+
var NULL_SENTINEL = "__BJNULL__";
|
|
57
|
+
var PSQL_ARGS = "psql -U blamejs -d blamejs_test -A " +
|
|
58
|
+
"-v ON_ERROR_STOP=0 -P null=__BJNULL__ 2>&1";
|
|
59
|
+
|
|
60
|
+
// ---- one-shot psql (setup / teardown / out-of-band tamper + asserts) ----
|
|
61
|
+
function _psql(sql) {
|
|
62
|
+
var prelude = "\\pset fieldsep '\\t'\n";
|
|
63
|
+
var out = execFileSync(
|
|
64
|
+
"docker",
|
|
65
|
+
["exec", "-i", CONTAINER, "sh", "-c",
|
|
66
|
+
"psql -U blamejs -d blamejs_test -qtA -P null=__BJNULL__ 2>&1"],
|
|
67
|
+
{ input: prelude + sql + "\n", stdio: ["pipe", "pipe", "pipe"] }
|
|
68
|
+
).toString("utf8");
|
|
69
|
+
if (/^ERROR:/m.test(out)) {
|
|
70
|
+
throw new Error("psql setup failed for [" + sql + "]:\n" + out);
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---- persistent-session docker-exec psql driver (faithful to pg) ----
|
|
76
|
+
var _seq = 0;
|
|
77
|
+
function _makeDockerPgDriver() {
|
|
78
|
+
return {
|
|
79
|
+
connect: function () {
|
|
80
|
+
return new Promise(function (resolve, reject) {
|
|
81
|
+
var child = spawn(
|
|
82
|
+
"docker",
|
|
83
|
+
["exec", "-i", CONTAINER, "sh", "-c",
|
|
84
|
+
PSQL_ARGS + " ; echo __BLAMEJS_PSQL_EXIT__"],
|
|
85
|
+
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
86
|
+
);
|
|
87
|
+
var client = { child: child, buf: "", pending: null, closed: false };
|
|
88
|
+
child.on("error", function (e) {
|
|
89
|
+
if (client.pending) { var p = client.pending; client.pending = null; p.reject(e); }
|
|
90
|
+
});
|
|
91
|
+
child.on("close", function () {
|
|
92
|
+
client.closed = true;
|
|
93
|
+
if (client.pending) {
|
|
94
|
+
var p = client.pending; client.pending = null;
|
|
95
|
+
p.reject(new Error("psql session closed mid-statement"));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
child.stdout.on("data", function (chunk) {
|
|
99
|
+
client.buf += chunk.toString("utf8");
|
|
100
|
+
_drain(client);
|
|
101
|
+
});
|
|
102
|
+
var primeSentinel = "__BJ_PRIME__";
|
|
103
|
+
client.pending = {
|
|
104
|
+
sentinel: primeSentinel,
|
|
105
|
+
resolve: function () { resolve(client); },
|
|
106
|
+
reject: reject,
|
|
107
|
+
};
|
|
108
|
+
client.child.stdin.write(
|
|
109
|
+
"\\pset fieldsep '\\t'\n\\pset footer off\n\\set VERBOSITY verbose\n" +
|
|
110
|
+
"SET bytea_output = 'hex';\n" +
|
|
111
|
+
"\\echo " + primeSentinel + "\n");
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
query: function (client, sql, params) {
|
|
116
|
+
params = params || [];
|
|
117
|
+
var bound = _bindParams(sql, params);
|
|
118
|
+
var sentinel = "__BJ_EOR_" + (++_seq) + "__";
|
|
119
|
+
return new Promise(function (resolve, reject) {
|
|
120
|
+
if (client.closed) { reject(new Error("psql session is closed")); return; }
|
|
121
|
+
client.pending = { sentinel: sentinel, resolve: resolve, reject: reject };
|
|
122
|
+
client.child.stdin.write(bound + "\n;\n\\echo " + sentinel + "\n");
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
close: function (client) {
|
|
127
|
+
return new Promise(function (resolve) {
|
|
128
|
+
if (client.closed) { resolve(); return; }
|
|
129
|
+
try { client.child.stdin.end("\\q\n"); } catch (_e) { /* best effort */ }
|
|
130
|
+
var done = false;
|
|
131
|
+
client.child.on("close", function () { if (!done) { done = true; resolve(); } });
|
|
132
|
+
setTimeout(function () {
|
|
133
|
+
if (done) return;
|
|
134
|
+
done = true;
|
|
135
|
+
try { client.child.kill("SIGKILL"); } catch (_e) {}
|
|
136
|
+
resolve();
|
|
137
|
+
}, 2000);
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
dialect: "postgres",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function _drain(client) {
|
|
146
|
+
if (!client.pending) return;
|
|
147
|
+
var sentinel = client.pending.sentinel;
|
|
148
|
+
var marker = "\n" + sentinel + "\n";
|
|
149
|
+
var idx = client.buf.indexOf(marker);
|
|
150
|
+
var startAtZero = client.buf.indexOf(sentinel + "\n") === 0;
|
|
151
|
+
var block;
|
|
152
|
+
if (idx !== -1) {
|
|
153
|
+
block = client.buf.slice(0, idx);
|
|
154
|
+
client.buf = client.buf.slice(idx + marker.length);
|
|
155
|
+
} else if (startAtZero) {
|
|
156
|
+
block = "";
|
|
157
|
+
client.buf = client.buf.slice((sentinel + "\n").length);
|
|
158
|
+
} else {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
var p = client.pending;
|
|
162
|
+
client.pending = null;
|
|
163
|
+
var parsed;
|
|
164
|
+
try { parsed = _parseBlock(block); }
|
|
165
|
+
catch (e) { return p.reject(e); }
|
|
166
|
+
if (parsed.error) return p.reject(parsed.error);
|
|
167
|
+
p.resolve({ rows: parsed.rows, rowCount: parsed.rowCount });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Inline params: Buffers as bytea hex literals (byte-faithful round-trip),
|
|
171
|
+
// numbers raw, everything else single-quote-escaped.
|
|
172
|
+
var BYTEA_LITERAL_PREFIX = "'" + "\\" + "x";
|
|
173
|
+
function _bindParams(sql, params) {
|
|
174
|
+
return sql.replace(/\$(\d+)/g, function (_m, n) {
|
|
175
|
+
var i = Number(n) - 1;
|
|
176
|
+
if (i < 0 || i >= params.length) {
|
|
177
|
+
throw new Error("placeholder $" + n + " has no matching param");
|
|
178
|
+
}
|
|
179
|
+
var v = params[i];
|
|
180
|
+
if (v === null || v === undefined) return "NULL";
|
|
181
|
+
if (Buffer.isBuffer(v)) return BYTEA_LITERAL_PREFIX + v.toString("hex") + "'::bytea";
|
|
182
|
+
if (typeof v === "number") return String(v);
|
|
183
|
+
if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
|
|
184
|
+
return "'" + String(v).replace(/'/g, "''") + "'";
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
var _CMD_TAG_RE = /^(INSERT|UPDATE|DELETE|MERGE|SELECT|COPY|MOVE)\b(?:\s+\d+)*\s*$/;
|
|
189
|
+
var _CTRL_TAG_RE = /^(BEGIN|COMMIT|ROLLBACK|SET|RESET|SAVEPOINT|RELEASE|START|CREATE|DROP|ALTER|GRANT|REVOKE|TRUNCATE|COMMENT|DO|CALL|VACUUM|ANALYZE|EXPLAIN|TABLE|SHOW|DISCARD)\b/;
|
|
190
|
+
|
|
191
|
+
// Columns the framework reads as Buffers (real pg returns bytea as Buffer).
|
|
192
|
+
var _BYTEA_COLUMNS = { nonce: true, signature: true };
|
|
193
|
+
|
|
194
|
+
function _parseBlock(block) {
|
|
195
|
+
var lines = block.split(/\r?\n/);
|
|
196
|
+
while (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
197
|
+
|
|
198
|
+
for (var i = 0; i < lines.length; i++) {
|
|
199
|
+
var em = /^ERROR:\s+([0-9A-Za-z]{5}):\s*(.*)$/.exec(lines[i]);
|
|
200
|
+
if (em) {
|
|
201
|
+
var err = new Error("Postgres " + em[1] + ": " + em[2]);
|
|
202
|
+
err.code = em[1];
|
|
203
|
+
return { error: err };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
var affected = null;
|
|
208
|
+
var dataLines = [];
|
|
209
|
+
for (var j = 0; j < lines.length; j++) {
|
|
210
|
+
var ln = lines[j];
|
|
211
|
+
if (/^(NOTICE|WARNING|DETAIL|HINT|LINE|LOCATION|CONTEXT|STATEMENT):/.test(ln)) continue;
|
|
212
|
+
var tm = _CMD_TAG_RE.exec(ln);
|
|
213
|
+
if (tm) {
|
|
214
|
+
var nums = ln.trim().split(/\s+/).slice(1).map(Number);
|
|
215
|
+
if (nums.length) affected = nums[nums.length - 1];
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (_CTRL_TAG_RE.test(ln) && ln.indexOf("\t") === -1) continue;
|
|
219
|
+
dataLines.push(ln);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
var rows = [];
|
|
223
|
+
if (dataLines.length >= 1) {
|
|
224
|
+
// dataLines[0] is the header row (column names AS POSTGRES REPORTS
|
|
225
|
+
// THEM — lowercase for unquoted identifiers). We deliberately keep
|
|
226
|
+
// them verbatim, exactly as node-postgres would key the row object.
|
|
227
|
+
var headers = dataLines[0].split("\t");
|
|
228
|
+
for (var k = 1; k < dataLines.length; k++) {
|
|
229
|
+
var cells = dataLines[k].split("\t");
|
|
230
|
+
var row = {};
|
|
231
|
+
for (var c = 0; c < headers.length; c++) {
|
|
232
|
+
var cell = cells[c];
|
|
233
|
+
var hdr = headers[c];
|
|
234
|
+
if (cell === NULL_SENTINEL || cell === undefined) { row[hdr] = null; continue; }
|
|
235
|
+
if (_BYTEA_COLUMNS[hdr] === true) {
|
|
236
|
+
var hex = cell.charAt(0) === "\\" && cell.charAt(1) === "x"
|
|
237
|
+
? cell.slice(2) : cell;
|
|
238
|
+
row[hdr] = Buffer.from(hex, "hex");
|
|
239
|
+
} else {
|
|
240
|
+
// STRING — including BIGINT columns (node-postgres int8 default).
|
|
241
|
+
row[hdr] = cell;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
rows.push(row);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
var rowCount = (affected !== null) ? affected : rows.length;
|
|
248
|
+
return { rows: rows, rowCount: rowCount, error: null };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Audit_log column set that ensureSchema creates (camelCase in DDL —
|
|
252
|
+
// Postgres folds the stored names to lowercase). We INSERT with these
|
|
253
|
+
// names quoted so the values land in the right physical columns; the
|
|
254
|
+
// READBACK is what surfaces the lowercase keys.
|
|
255
|
+
var AUDIT_COLS = [
|
|
256
|
+
"_id", "recordedAt", "monotonicCounter",
|
|
257
|
+
"actorUserId", "actorUserIdHash", "actorIp",
|
|
258
|
+
"actorUserAgent", "actorSessionId",
|
|
259
|
+
"action", "resourceKind", "resourceId", "resourceIdHash",
|
|
260
|
+
"outcome", "reason", "metadata", "requestId",
|
|
261
|
+
"prevHash", "rowHash", "nonce", "fencingToken",
|
|
262
|
+
];
|
|
263
|
+
// Columns that feed the chain-hash preimage (must match what the
|
|
264
|
+
// framework's chain-writer hashes: every audit column except the chain
|
|
265
|
+
// bookkeeping prevHash/rowHash/nonce/fencingToken).
|
|
266
|
+
var HASHABLE_COLS = [
|
|
267
|
+
"_id", "recordedAt", "monotonicCounter",
|
|
268
|
+
"actorUserId", "actorUserIdHash", "actorIp",
|
|
269
|
+
"actorUserAgent", "actorSessionId",
|
|
270
|
+
"action", "resourceKind", "resourceId", "resourceIdHash",
|
|
271
|
+
"outcome", "reason", "metadata", "requestId",
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
// Build the framework-faithful logical row + its rowHash, exactly as
|
|
275
|
+
// chain-writer would: materialize null for every hashable column so the
|
|
276
|
+
// canonicalizer sees the same key set at write- and verify-time, then
|
|
277
|
+
// computeRowHash(prevHash, hashableFields, nonce).
|
|
278
|
+
function _buildChainRow(driverClient, driver, counter, prevHash, logical) {
|
|
279
|
+
var crypto = require("../../lib/crypto");
|
|
280
|
+
var nonce = crypto.generateBytes(16);
|
|
281
|
+
var full = Object.assign({
|
|
282
|
+
_id: "row-" + counter,
|
|
283
|
+
recordedAt: 1700000000000 + counter,
|
|
284
|
+
monotonicCounter: counter,
|
|
285
|
+
}, logical);
|
|
286
|
+
// Hashable view: every hashable column present, null-filled.
|
|
287
|
+
var hashable = {};
|
|
288
|
+
for (var i = 0; i < HASHABLE_COLS.length; i++) {
|
|
289
|
+
var col = HASHABLE_COLS[i];
|
|
290
|
+
hashable[col] = (full[col] === undefined) ? null : full[col];
|
|
291
|
+
}
|
|
292
|
+
var rowHash = b.auditChain.computeRowHash(prevHash, hashable, nonce);
|
|
293
|
+
var rowForInsert = Object.assign({}, hashable, {
|
|
294
|
+
prevHash: prevHash, rowHash: rowHash, nonce: nonce, fencingToken: 0,
|
|
295
|
+
});
|
|
296
|
+
return { rowForInsert: rowForInsert, rowHash: rowHash };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Insert a chain row using the EXACT SQL shape the framework's
|
|
300
|
+
// chain-writer emits: identifiers quoted via safeSql.quoteIdentifier
|
|
301
|
+
// (double-quoted, case-PRESERVING camelCase). This is what
|
|
302
|
+
// b.audit.record → chain-writer → clusterStorage actually runs against
|
|
303
|
+
// the external Postgres backend, so a failure here is the framework's
|
|
304
|
+
// real failure, not a test artifact.
|
|
305
|
+
var safeSql = require("../../lib/safe-sql");
|
|
306
|
+
async function _insertChainRow(driver, driverClient, rowForInsert) {
|
|
307
|
+
var quoted = AUDIT_COLS.map(function (c) { return safeSql.quoteIdentifier(c); }).join(", ");
|
|
308
|
+
var ph = AUDIT_COLS.map(function (_c, i) { return "$" + (i + 1); }).join(", ");
|
|
309
|
+
var vals = AUDIT_COLS.map(function (c) {
|
|
310
|
+
return rowForInsert[c] === undefined ? null : rowForInsert[c];
|
|
311
|
+
});
|
|
312
|
+
await driver.query(driverClient,
|
|
313
|
+
'INSERT INTO ' + safeSql.quoteIdentifier("_blamejs_audit_log") +
|
|
314
|
+
' (' + quoted + ') VALUES (' + ph + ')', vals);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function run() {
|
|
318
|
+
var pg = await services.requireService("postgres");
|
|
319
|
+
if (!pg.ok) throw new Error("postgres unreachable: " + pg.reason);
|
|
320
|
+
|
|
321
|
+
var DROP_ALL = [
|
|
322
|
+
"_blamejs_audit_log", "_blamejs_consent_log", "_blamejs_audit_checkpoints",
|
|
323
|
+
"_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
|
|
324
|
+
"_blamejs_scheduler_ticks", "_blamejs_rate_limit_counters",
|
|
325
|
+
"_blamejs_pubsub_messages", "_blamejs_api_encrypt_nonces", "_blamejs_api_keys",
|
|
326
|
+
"_blamejs_sessions", "_blamejs_jobs", "_blamejs_cache", "_blamejs_cache_tags",
|
|
327
|
+
"_blamejs_seeders", "_blamejs_seeders_lock", "_blamejs_break_glass_policies",
|
|
328
|
+
"_blamejs_break_glass_grants", "_blamejs_leader", "_blamejs_cluster_state",
|
|
329
|
+
].map(function (t) { return "DROP TABLE IF EXISTS " + t + " CASCADE;"; }).join("\n");
|
|
330
|
+
_psql(DROP_ALL);
|
|
331
|
+
|
|
332
|
+
b.cluster._resetForTest();
|
|
333
|
+
b.audit._resetForTest();
|
|
334
|
+
b.externalDb._resetForTest();
|
|
335
|
+
|
|
336
|
+
var driver = _makeDockerPgDriver();
|
|
337
|
+
b.externalDb.init({
|
|
338
|
+
backends: {
|
|
339
|
+
ops: {
|
|
340
|
+
connect: driver.connect, query: driver.query, close: driver.close,
|
|
341
|
+
dialect: "postgres",
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// ---- 1. framework audit schema on the live server ----
|
|
347
|
+
var report = await b.frameworkSchema.ensureSchema({
|
|
348
|
+
externalDbBackend: "ops",
|
|
349
|
+
dialect: "postgres",
|
|
350
|
+
});
|
|
351
|
+
check("ensureSchema created _blamejs_audit_log on real Postgres",
|
|
352
|
+
report.tables.indexOf("_blamejs_audit_log") !== -1);
|
|
353
|
+
var tblCheck = _psql(
|
|
354
|
+
"SELECT count(*) AS n FROM information_schema.tables " +
|
|
355
|
+
"WHERE table_name = '_blamejs_audit_log';");
|
|
356
|
+
check("_blamejs_audit_log table is present on the server", /\b1\b/.test(tblCheck.trim()));
|
|
357
|
+
|
|
358
|
+
// ---- 2. build a KNOWN-VALID chain with the framework's own hash math,
|
|
359
|
+
// INSERT it into the live table, verify with the framework's
|
|
360
|
+
// own verifier (b.auditChain.verifyChain → the reader
|
|
361
|
+
// b.audit.verify uses). A correct framework returns ok:true. ----
|
|
362
|
+
var driverClient = await driver.connect();
|
|
363
|
+
|
|
364
|
+
var logicalRows = [
|
|
365
|
+
{ action: "system.boot", outcome: "success" },
|
|
366
|
+
{ action: "auth.login.success", outcome: "success", actorUserId: "u-1", actorIp: "10.0.0.7" },
|
|
367
|
+
{ action: "consent.granted", outcome: "success", actorUserId: "u-2",
|
|
368
|
+
resourceKind: "purpose", resourceId: "marketing", metadata: '{"region":"eu"}' },
|
|
369
|
+
{ action: "system.shutdown", outcome: "success" },
|
|
370
|
+
];
|
|
371
|
+
var prevHash = b.auditChain.ZERO_HASH;
|
|
372
|
+
var insertErr = null;
|
|
373
|
+
try {
|
|
374
|
+
for (var i = 0; i < logicalRows.length; i++) {
|
|
375
|
+
var built = _buildChainRow(driverClient, driver, i + 1, prevHash, logicalRows[i]);
|
|
376
|
+
await _insertChainRow(driver, driverClient, built.rowForInsert);
|
|
377
|
+
prevHash = built.rowHash;
|
|
378
|
+
}
|
|
379
|
+
} catch (e) { insertErr = e; }
|
|
380
|
+
|
|
381
|
+
// The framework's chain-writer INSERT must land rows in the external
|
|
382
|
+
// Postgres table. ensureSchema created the columns UNQUOTED (Postgres
|
|
383
|
+
// folds them to lowercase: recordedat / monotoniccounter / rowhash …)
|
|
384
|
+
// while chain-writer INSERTs into safeSql.quoteIdentifier()-quoted,
|
|
385
|
+
// case-PRESERVING camelCase columns ("recordedAt" …). On real Postgres
|
|
386
|
+
// those names don't match → the append fails.
|
|
387
|
+
check("framework chain-writer INSERT lands audit rows on real Postgres " +
|
|
388
|
+
"(the columns it writes must exist on the ensureSchema-created table)",
|
|
389
|
+
insertErr === null);
|
|
390
|
+
if (insertErr) {
|
|
391
|
+
check("WRITE-PATH DETAIL: " + ((insertErr && insertErr.message) || String(insertErr)) +
|
|
392
|
+
" — ensureSchema DDL creates UNQUOTED (lowercase-folded) columns " +
|
|
393
|
+
"but chain-writer INSERTs safeSql.quoteIdentifier-quoted camelCase " +
|
|
394
|
+
'columns ("recordedAt"…); the audit chain cannot be written to ' +
|
|
395
|
+
"the operator's external Postgres", false);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
var countOnServer = _psql("SELECT count(*) AS n FROM _blamejs_audit_log;");
|
|
399
|
+
check("known-valid chain rows are physically in _blamejs_audit_log",
|
|
400
|
+
new RegExp("\\b" + logicalRows.length + "\\b").test(countOnServer.trim()));
|
|
401
|
+
|
|
402
|
+
// The verifier the framework ships: walk the live chain and recompute.
|
|
403
|
+
// queryAll routes through the SAME driver the framework's clusterStorage
|
|
404
|
+
// uses, so the row objects are keyed exactly as node-postgres keys them.
|
|
405
|
+
async function liveQueryAll(sql, params) {
|
|
406
|
+
var r = await driver.query(driverClient, sql, params || []);
|
|
407
|
+
return r.rows;
|
|
408
|
+
}
|
|
409
|
+
var v1 = await b.auditChain.verifyChain(liveQueryAll, "_blamejs_audit_log", {});
|
|
410
|
+
check("audit chain verifies ok:true on real Postgres " +
|
|
411
|
+
"(a valid chain stored on the operator's external DB must verify)",
|
|
412
|
+
v1.ok === true);
|
|
413
|
+
check("verifyChain walked every stored row (rowsVerified === " + logicalRows.length + ")",
|
|
414
|
+
v1.ok === true && v1.rowsVerified === logicalRows.length);
|
|
415
|
+
if (!v1.ok) {
|
|
416
|
+
check("FALSE-TAMPER DETAIL: verifyChain reports '" + v1.reason +
|
|
417
|
+
"' at row " + v1.breakAt + " on an UNTAMPERED chain — " +
|
|
418
|
+
"expected=" + String(v1.expected).slice(0, 20) +
|
|
419
|
+
"… actual=" + String(v1.actual).slice(0, 20) + "…", false);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// ---- 3. coercion fidelity: confirm the readback IS real-pg-shaped
|
|
423
|
+
// (lowercase keys, BIGINT→string, BYTEA→Buffer). This is the
|
|
424
|
+
// shape the framework's reader must handle. ----
|
|
425
|
+
var sample = (await liveQueryAll(
|
|
426
|
+
'SELECT * FROM _blamejs_audit_log ORDER BY "monotonicCounter" ASC LIMIT 1', []))[0];
|
|
427
|
+
var keys = sample ? Object.keys(sample) : [];
|
|
428
|
+
check("readback row carries the chain columns (some hash + nonce key present)",
|
|
429
|
+
keys.length >= 18);
|
|
430
|
+
check("BYTEA nonce coerced to a Buffer (real-pg shape)",
|
|
431
|
+
sample && Buffer.isBuffer(sample.nonce));
|
|
432
|
+
// The framework reader expects camelCase (row.rowHash / row.monotonicCounter);
|
|
433
|
+
// these assertions document what real pg actually returns.
|
|
434
|
+
var hasCamelRowHash = sample && typeof sample.rowHash === "string";
|
|
435
|
+
var hasLowerRowHash = sample && typeof sample.rowhash === "string";
|
|
436
|
+
check("readback exposes rowHash under the key the framework reader uses " +
|
|
437
|
+
"(row.rowHash) — NOT only the Postgres-folded lowercase key",
|
|
438
|
+
hasCamelRowHash === true);
|
|
439
|
+
if (!hasCamelRowHash && hasLowerRowHash) {
|
|
440
|
+
check("CASE-FOLD DETAIL: Postgres returns the column as 'rowhash' " +
|
|
441
|
+
"(lowercase) but verifyChain reads row.rowHash → undefined; " +
|
|
442
|
+
"monotonicCounter is keyed 'monotoniccounter' as " +
|
|
443
|
+
(typeof sample.monotoniccounter) + " value " +
|
|
444
|
+
JSON.stringify(sample.monotoniccounter), false);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// ---- 4. tamper a hashed column → verify must report ok:false ----
|
|
448
|
+
// Drop the WORM triggers (simulate a privileged DB-write attacker) then
|
|
449
|
+
// mutate the action of the row at counter 2.
|
|
450
|
+
_psql([
|
|
451
|
+
"DROP TRIGGER IF EXISTS no_update__blamejs_audit_log ON _blamejs_audit_log;",
|
|
452
|
+
"DROP TRIGGER IF EXISTS no_delete__blamejs_audit_log ON _blamejs_audit_log;",
|
|
453
|
+
].join("\n"));
|
|
454
|
+
_psql("UPDATE _blamejs_audit_log SET action = 'auth.login.tampered' " +
|
|
455
|
+
'WHERE "monotonicCounter" = 2;');
|
|
456
|
+
var vTampered = await b.auditChain.verifyChain(liveQueryAll, "_blamejs_audit_log", {});
|
|
457
|
+
check("verifyChain returns ok:false after a hashed column is tampered",
|
|
458
|
+
vTampered.ok === false);
|
|
459
|
+
// The tamper detection is only MEANINGFUL if verify passed on the clean
|
|
460
|
+
// chain (else ok:false is a false positive that happens to coincide).
|
|
461
|
+
check("tamper detection is meaningful (clean chain had verified ok:true)",
|
|
462
|
+
v1.ok === true && vTampered.ok === false);
|
|
463
|
+
|
|
464
|
+
// ---- 5. cluster leadership over the real Postgres lease provider ----
|
|
465
|
+
// Every chain append in cluster mode passes cluster.requireLeader().
|
|
466
|
+
// Confirm a single node can actually acquire leadership on real Postgres.
|
|
467
|
+
_psql(["DROP TABLE IF EXISTS _blamejs_leader CASCADE;",
|
|
468
|
+
"DROP TABLE IF EXISTS _blamejs_cluster_state CASCADE;"].join("\n"));
|
|
469
|
+
var clusterErr = null;
|
|
470
|
+
try {
|
|
471
|
+
await b.cluster.init({
|
|
472
|
+
nodeId: "audit-ext-node",
|
|
473
|
+
role: "leader",
|
|
474
|
+
externalDbBackend: "ops",
|
|
475
|
+
dialect: "postgres",
|
|
476
|
+
});
|
|
477
|
+
} catch (e) { clusterErr = e; }
|
|
478
|
+
check("cluster.init completed without throwing on real Postgres",
|
|
479
|
+
clusterErr === null);
|
|
480
|
+
check("cluster node acquired leadership on real Postgres " +
|
|
481
|
+
"(required for EVERY audit-chain append in cluster mode)",
|
|
482
|
+
clusterErr === null && b.cluster.isLeader() === true);
|
|
483
|
+
if (clusterErr === null && b.cluster.isLeader() !== true) {
|
|
484
|
+
var leaderRow = _psql(
|
|
485
|
+
'SELECT "nodeId", "expiresAt" FROM _blamejs_leader WHERE scope=\'leader\';');
|
|
486
|
+
check("LEADERSHIP DETAIL: a leader row WAS written to the server [" +
|
|
487
|
+
leaderRow.trim() + "] but acquireLease returned no in-memory " +
|
|
488
|
+
"lease (provider read row.expiresAt/row.nodeId but the live " +
|
|
489
|
+
"row keys are lowercase expiresat/nodeid) → isLeader()=false → " +
|
|
490
|
+
"every audit append would throw NotLeaderError", false);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// ---- MySQL audit-chain coverage ----
|
|
494
|
+
// MySQL is a first-class audit-chain backend: the framework-schema
|
|
495
|
+
// reconciler emits MySQL DDL and the hash chain appends and verifies
|
|
496
|
+
// against it. The end-to-end proof (ensureSchema + audit.record →
|
|
497
|
+
// chain-writer._insertRow + audit.verify ok:true against a real MySQL
|
|
498
|
+
// server) lives in audit-stack-mysql.test.js. This Postgres-focused file
|
|
499
|
+
// does not re-probe MySQL through the Postgres "ops" connection.
|
|
500
|
+
|
|
501
|
+
// ---- teardown ----
|
|
502
|
+
try { await driver.close(driverClient); } catch (_e) {}
|
|
503
|
+
try { await b.cluster.shutdown(); } catch (_e) {}
|
|
504
|
+
await b.externalDb.shutdown();
|
|
505
|
+
b.cluster._resetForTest();
|
|
506
|
+
b.audit._resetForTest();
|
|
507
|
+
_psql(DROP_ALL);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
module.exports = { run: run };
|
|
511
|
+
|
|
512
|
+
if (require.main === module) {
|
|
513
|
+
run().then(
|
|
514
|
+
function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
|
|
515
|
+
function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
|
|
516
|
+
);
|
|
517
|
+
}
|