refactor(stack): inject the FFI binding into the encryption operations (#798, stages 1-3) #243
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 — Supabase (EQL v3) | |
| # Real ZeroKMS ciphertext, a real PostgREST, and `supabase/postgres` — the only | |
| # job that proves the Supabase v3 adapter's queries return the right rows. The | |
| # unit suites drive a mock that records strings; they cannot. | |
| # | |
| # 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-supabase/**' | |
| - 'packages/stack/src/eql/v3/**' | |
| # Source layers the adapter's encoding/round-trip rests on: a break here | |
| # (not just under src/supabase) can produce wrong wire output or rows, so | |
| # trigger the live suite that would catch it. | |
| - 'packages/stack/src/encryption/**' | |
| - 'packages/stack/src/schema/**' | |
| - 'packages/stack/integration/**' | |
| - 'packages/test-kit/**' | |
| - 'packages/cli/src/installer/**' | |
| - 'local/docker-compose.supabase.yml' | |
| - 'local/supabase-init.sql' | |
| - '.github/workflows/integration-supabase.yml' | |
| - '.github/actions/integration-setup/**' | |
| - '.github/actions/integration-db/**' | |
| pull_request: | |
| branches: ['**'] | |
| paths: | |
| - 'packages/stack-supabase/**' | |
| - 'packages/stack/src/eql/v3/**' | |
| # Source layers the adapter's encoding/round-trip rests on: a break here | |
| # (not just under src/supabase) can produce wrong wire output or rows, so | |
| # trigger the live suite that would catch it. | |
| - 'packages/stack/src/encryption/**' | |
| - 'packages/stack/src/schema/**' | |
| - 'packages/stack/integration/**' | |
| - 'packages/test-kit/**' | |
| - 'packages/cli/src/installer/**' | |
| - 'local/docker-compose.supabase.yml' | |
| - 'local/supabase-init.sql' | |
| - '.github/workflows/integration-supabase.yml' | |
| - '.github/actions/integration-setup/**' | |
| - '.github/actions/integration-db/**' | |
| jobs: | |
| integration: | |
| name: Supabase 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 loudly 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: | |
| # A one-element matrix, not a cross-product: the Supabase adapter only ever | |
| # runs against the Supabase variant. Kept as a matrix so adding a second | |
| # database is a one-line change. | |
| matrix: | |
| db: [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 }} | |
| # `DATABASE_URL` / `PGRST_URL` are set per step from the `integration-db` | |
| # outputs — the host ports are assigned by Docker at start-up, so they | |
| # cannot be written down here. The role that URL connects as (`postgres`) | |
| # is deliberately NOT a superuser on this image, which is what makes the | |
| # EQL install, the grants, and the ORE opclass skip behave as they do on a | |
| # real Supabase project. | |
| # | |
| # EXPLICIT, never inferred from `PGRST_URL` — see `dbVariant()`. | |
| 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, the ope-term tripwire for THIS job's `col->op` | |
| # ordering path, and the crypto/SQL matrices); the Drizzle suites talk to | |
| # plain Postgres and get their own job. | |
| # | |
| # `integration/identity/` runs on the Drizzle job (it needs Postgres + | |
| # Drizzle, not PostgREST), so it is intentionally not listed here. | |
| # The Supabase adapter suites now live in @cipherstash/stack-supabase (run | |
| # below via its own test:integration). This glob scopes the adapter-agnostic | |
| # `shared/` core suites that still live in @cipherstash/stack and run against | |
| # this job's Postgres too. | |
| CS_IT_SUITE: >- | |
| integration/shared/**/*.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 paying for the ~2 GB supabase/postgres 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 --supabase --direct`, 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. | |
| - name: Supabase v3 integration suites | |
| run: pnpm --filter @cipherstash/stack-supabase run test:integration | |
| env: | |
| DATABASE_URL: ${{ steps.db.outputs.database-url }} | |
| PGRST_URL: ${{ steps.db.outputs.pgrest-url }} | |
| # A second vitest invocation (stack's shared/ 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 — so this is a fast no-op check, not a second schema apply. | |
| - name: Shared core integration suites (against Supabase Postgres) | |
| run: pnpm --filter @cipherstash/stack run test:integration | |
| 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 |