fix(stack-drizzle): preserve per-column types in extractEncryptionSch… #351
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Integration — Drizzle (EQL v3) | |
| # Real ZeroKMS ciphertext against a real Postgres, on BOTH database variants. | |
| # | |
| # The Drizzle adapter talks straight to the database, so it does not need | |
| # PostgREST — but it does need to work on managed Postgres, where the `postgres` | |
| # role is not a superuser, the EQL install takes its self-skipping path, and the | |
| # ORE domains cannot hold data. The Supabase compose file brings up PostgREST | |
| # too; the Drizzle suites simply ignore it. | |
| # | |
| # Separate from `tests.yml` on purpose: these suites need CipherStash credentials | |
| # and a database, and they THROW rather than skip when unconfigured. Keeping them | |
| # out of the unit job is what lets `pnpm test` stay runnable with neither. | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'packages/stack/src/eql/v3/**' | |
| - 'packages/stack-drizzle/**' | |
| # Source layers the adapter's encoding/round-trip rests on: a break here | |
| # (not just under src/eql/v3) can produce wrong rows, so trigger the live | |
| # suite that would catch it. | |
| - 'packages/stack/src/encryption/**' | |
| - 'packages/stack/src/schema/**' | |
| - 'packages/stack/integration/**' | |
| # The WASM family suite (integration/wasm/**) exercises this entry: | |
| - 'packages/stack/src/wasm-inline.ts' | |
| # The DynamoDB adapter, and the entry/type modules the suites import | |
| # directly. `integration/shared/v2-decrypt-compat` and its | |
| # `integration/wasm/` twin (both selected below) are the repo's only live | |
| # EQL v2 read coverage, and they exercise the DynamoDB legacy path, so a | |
| # change here must run them. Pinned by | |
| # scripts/__tests__/integration-workflow-paths.test.mjs. | |
| - 'packages/stack/src/dynamodb/**' | |
| - 'packages/stack/src/index.ts' | |
| - 'packages/stack/src/types.ts' | |
| # Those same v2 suites mint their fixtures by importing | |
| # `@cipherstash/protect-ffi` directly. A native-module bump is the change | |
| # most able to break v2 payload deserialization and it touches NO source | |
| # directory, so without these two entries the only suites that would catch | |
| # it never start. They are the files a bump actually edits: exact pins | |
| # (`protect-ffi`, `@cipherstash/eql`) live in the package manifest, | |
| # `catalog:` ones (`@cipherstash/auth`, which moves in lockstep with | |
| # protect-ffi for the WASM entry) in the workspace catalog. | |
| # | |
| # `pnpm-lock.yaml` is deliberately NOT listed. It changes on roughly every | |
| # dependency bump in the monorepo — far more often than either file here — | |
| # and these are credentialed, database-backed jobs. Nothing is lost: a | |
| # protect-ffi or auth version change cannot reach the lockfile without | |
| # editing one of the two manifests below first. | |
| - 'packages/stack/package.json' | |
| - 'pnpm-workspace.yaml' | |
| - 'packages/test-kit/**' | |
| - 'packages/cli/src/installer/**' | |
| - 'local/docker-compose.postgres.yml' | |
| - 'local/docker-compose.supabase.yml' | |
| - 'local/supabase-init.sql' | |
| - '.github/workflows/integration-drizzle.yml' | |
| - '.github/actions/integration-setup/**' | |
| - '.github/actions/integration-db/**' | |
| pull_request: | |
| branches: ['**'] | |
| # Repeated verbatim: GitHub Actions does not support YAML anchors/aliases. | |
| paths: | |
| - 'packages/stack/src/eql/v3/**' | |
| - 'packages/stack-drizzle/**' | |
| # Source layers the adapter's encoding/round-trip rests on: a break here | |
| # (not just under src/eql/v3) can produce wrong rows, so trigger the live | |
| # suite that would catch it. | |
| - 'packages/stack/src/encryption/**' | |
| - 'packages/stack/src/schema/**' | |
| - 'packages/stack/integration/**' | |
| # The WASM family suite (integration/wasm/**) exercises this entry: | |
| - 'packages/stack/src/wasm-inline.ts' | |
| # The DynamoDB adapter, and the entry/type modules the suites import | |
| # directly. `integration/shared/v2-decrypt-compat` and its | |
| # `integration/wasm/` twin (both selected below) are the repo's only live | |
| # EQL v2 read coverage, and they exercise the DynamoDB legacy path, so a | |
| # change here must run them. Pinned by | |
| # scripts/__tests__/integration-workflow-paths.test.mjs. | |
| - 'packages/stack/src/dynamodb/**' | |
| - 'packages/stack/src/index.ts' | |
| - 'packages/stack/src/types.ts' | |
| # Those same v2 suites mint their fixtures by importing | |
| # `@cipherstash/protect-ffi` directly. A native-module bump is the change | |
| # most able to break v2 payload deserialization and it touches NO source | |
| # directory, so without these two entries the only suites that would catch | |
| # it never start. They are the files a bump actually edits: exact pins | |
| # (`protect-ffi`, `@cipherstash/eql`) live in the package manifest, | |
| # `catalog:` ones (`@cipherstash/auth`, which moves in lockstep with | |
| # protect-ffi for the WASM entry) in the workspace catalog. | |
| # | |
| # `pnpm-lock.yaml` is deliberately NOT listed. It changes on roughly every | |
| # dependency bump in the monorepo — far more often than either file here — | |
| # and these are credentialed, database-backed jobs. Nothing is lost: a | |
| # protect-ffi or auth version change cannot reach the lockfile without | |
| # editing one of the two manifests below first. | |
| - 'packages/stack/package.json' | |
| - 'pnpm-workspace.yaml' | |
| - 'packages/test-kit/**' | |
| - 'packages/cli/src/installer/**' | |
| - 'local/docker-compose.postgres.yml' | |
| - 'local/docker-compose.supabase.yml' | |
| - 'local/supabase-init.sql' | |
| - '.github/workflows/integration-drizzle.yml' | |
| - '.github/actions/integration-setup/**' | |
| - '.github/actions/integration-db/**' | |
| jobs: | |
| integration: | |
| name: Drizzle v3 integration (db=${{ matrix.db }}) | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| # No concurrency group: `integration-db` gives each job its own compose | |
| # project and ephemeral host ports, so live-DB jobs no longer contend and do | |
| # not need serialising. See that action for why the old | |
| # `integration-live-db-<db>` group had to go (it cancelled a third | |
| # contender rather than queueing it). | |
| # | |
| # Fork PRs have no secrets. Skip cleanly rather than fail on something the | |
| # contributor cannot fix — `tests.yml` still gives them a green signal. | |
| if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }} | |
| strategy: | |
| fail-fast: false | |
| # Drizzle talks straight to Postgres, so it runs against BOTH databases. | |
| # The Supabase variant is not a formality: its `postgres` role is not a | |
| # superuser, so the EQL install takes its self-skipping path and the ORE | |
| # domains become unusable. A suite that passes on a superuser database can | |
| # still fail there. | |
| # (The supabase compose file starts PostgREST anyway. Drizzle does not use | |
| # it, but `integration-db` supplies the URL regardless, which lets the | |
| # harness assert the `anon` path on the database it is actually running | |
| # against.) | |
| matrix: | |
| db: [postgres, supabase] | |
| env: | |
| CS_WORKSPACE_CRN: ${{ vars.CS_WORKSPACE_CRN }} | |
| CS_CLIENT_ID: ${{ vars.CS_CLIENT_ID }} | |
| CS_CLIENT_KEY: ${{ secrets.CS_CLIENT_KEY }} | |
| CS_CLIENT_ACCESS_KEY: ${{ secrets.CS_CLIENT_ACCESS_KEY }} | |
| # The identity suites federate a freshly-minted Clerk M2M JWT into a CTS | |
| # token. Only they read these; the other suites ignore them. If one is | |
| # unset the relevant suite fails loudly (throw, never skip) rather than | |
| # taking the whole job down, so they are NOT in the require-cs-secrets | |
| # preflight. `_B` is a SECOND machine (a distinct `sub`) in the same Clerk | |
| # instance, used only by the cross-identity test. | |
| CLERK_MACHINE_TOKEN: ${{ secrets.CLERK_MACHINE_TOKEN }} | |
| CLERK_MACHINE_TOKEN_B: ${{ secrets.CLERK_MACHINE_TOKEN_B }} | |
| # EXPLICIT, never inferred. The variant decides whether EQL is installed | |
| # with `--supabase` (and therefore whether the role grants are applied). | |
| # Inferring it from `PGRST_URL` reported `postgres` for this job's Supabase | |
| # cell and silently skipped the grants. | |
| CS_IT_DB_VARIANT: ${{ matrix.db }} | |
| # Scoped by directory, never by named file, so a renamed suite cannot | |
| # silently drop from CI. `integration/shared/` holds the adapter-agnostic | |
| # suites (harness, bloom, ope-term, the crypto/SQL matrices); | |
| # `integration/identity/` holds the Clerk-federated lock-context suites | |
| # (they need CLERK_MACHINE_TOKEN + a workspace with the Clerk issuer | |
| # registered); the Supabase adapter suites are not run here — they have | |
| # their own job. | |
| # The Drizzle adapter suites (incl. the Clerk-federated lock-context one) | |
| # now live in @cipherstash/stack-drizzle (run below via its own | |
| # test:integration). This glob scopes what still lives in @cipherstash/stack: | |
| # the adapter-agnostic `shared/` core suites, the model-path | |
| # `identity/matrix-identity` suite, and the `wasm/` family suite (the | |
| # `@cipherstash/stack/wasm-inline` adapter over the shared v3 matrix). | |
| CS_IT_SUITE: >- | |
| integration/shared/**/*.integration.test.ts, | |
| integration/identity/**/*.integration.test.ts, | |
| integration/wasm/**/*.integration.test.ts | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: ./.github/actions/integration-setup | |
| # Fast pre-flight: fail in seconds if a secret was rotated or cleared, | |
| # before the docker pull. The in-test `requireIntegrationEnv` is the | |
| # correctness guarantee; this is the cheap one. | |
| - name: Require CipherStash secrets | |
| uses: ./.github/actions/require-cs-secrets | |
| with: | |
| workspace-crn: ${{ vars.CS_WORKSPACE_CRN }} | |
| client-id: ${{ vars.CS_CLIENT_ID }} | |
| client-key: ${{ secrets.CS_CLIENT_KEY }} | |
| client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }} | |
| # No pre-`up` cleanup step any more: the project name is unique per job, so | |
| # a container leaked by a hard-killed prior run cannot hold this job's | |
| # name or its (ephemeral) port. Blanket-pruning would now be actively | |
| # unsafe — without the concurrency group, another job's stack may be live | |
| # on this runner. | |
| - name: Start ${{ matrix.db }} | |
| id: db | |
| uses: ./.github/actions/integration-db | |
| with: | |
| db: ${{ matrix.db }} | |
| # `globalSetup` installs EQL v3 by shelling out to the real | |
| # `stash eql install --eql-version 3`, so an installer regression fails | |
| # here rather than hiding behind a test-only SQL apply. | |
| # | |
| # Step env, not a `.env` file: `dotenv/config` does not override an | |
| # already-set `process.env`, so these win and no secret is written to disk. | |
| # Through turbo, not a bare `pnpm --filter`: `test:integration` declares | |
| # `dependsOn: ["^build", "build"]`, and the only build in this job is the | |
| # setup action's `--filter stash`, which reaches these packages purely by | |
| # coincidence of stash's own dependency graph. `--env-mode=loose` because | |
| # turbo defaults to strict and would otherwise withhold the step env below | |
| # from the test process (#787 review follow-up). | |
| - name: Drizzle v3 integration suites | |
| run: pnpm exec turbo run test:integration --filter @cipherstash/stack-drizzle --env-mode=loose | |
| env: | |
| DATABASE_URL: ${{ steps.db.outputs.database-url }} | |
| PGRST_URL: ${{ steps.db.outputs.pgrest-url }} | |
| # A second vitest invocation (stack's shared/ + identity suites live in a | |
| # different package now). Its globalSetup calls the same EQL v3 install, but | |
| # `isInstalled` short-circuits against the DB the first invocation already | |
| # provisioned — a fast no-op check, not a second schema apply. | |
| - name: Shared core + identity + wasm integration suites | |
| run: pnpm exec turbo run test:integration --filter @cipherstash/stack --env-mode=loose | |
| env: | |
| DATABASE_URL: ${{ steps.db.outputs.database-url }} | |
| PGRST_URL: ${{ steps.db.outputs.pgrest-url }} | |
| # Guarded on the project being set: if the stack never came up, there is | |
| # nothing to tear down and an unguarded `-p ""` would fail the job with a | |
| # confusing error that masks the real one. | |
| - name: Stop ${{ matrix.db }} | |
| if: always() && env.CS_COMPOSE_PROJECT != '' | |
| run: docker compose -p "$CS_COMPOSE_PROJECT" -f "$CS_COMPOSE_FILE" down -v |