-
Notifications
You must be signed in to change notification settings - Fork 6
244 lines (232 loc) · 12.5 KB
/
Copy pathintegration-supabase.yml
File metadata and controls
244 lines (232 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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/**'
# The DynamoDB adapter, and the entry/type modules the suites import
# directly. `integration/shared/v2-decrypt-compat` is the repo's only live
# EQL v2 read coverage for the native entry (the `integration/wasm/` twin
# runs on the Drizzle job) and it exercises the DynamoDB legacy path, so a
# change here must run it. Pinned by
# scripts/__tests__/integration-workflow-paths.test.mjs.
- 'packages/stack/src/dynamodb/**'
- 'packages/stack/src/index.ts'
- 'packages/stack/src/types.ts'
# That v2 suite mints its 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`) 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.supabase.yml'
- 'local/supabase-init.sql'
- '.github/workflows/integration-supabase.yml'
- '.github/actions/integration-setup/**'
- '.github/actions/integration-db/**'
- '.github/actions/build-ffi-binding/**'
# The Rust that produces every EQL payload these suites round-trip.
# Absorbing protect-ffi put it in-tree, so a crate change can now
# break them in a PR that touches no TypeScript at all.
#
# The manifests are here for the same reason as the sources: a
# dependency bump in Cargo.lock changes the compiled encryption core
# without touching a .rs file, and package.json / mise.toml carry the
# build scripts and the toolchain pin. Matching the filter in
# tests-rust.yml, which already covers all four.
- 'packages/protect-ffi/crates/**'
- 'packages/protect-ffi/src/**'
- 'packages/protect-ffi/Cargo.toml'
- 'packages/protect-ffi/Cargo.lock'
- 'packages/protect-ffi/package.json'
- 'packages/protect-ffi/mise.toml'
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/**'
# The DynamoDB adapter, and the entry/type modules the suites import
# directly. `integration/shared/v2-decrypt-compat` is the repo's only live
# EQL v2 read coverage for the native entry (the `integration/wasm/` twin
# runs on the Drizzle job) and it exercises the DynamoDB legacy path, so a
# change here must run it. Pinned by
# scripts/__tests__/integration-workflow-paths.test.mjs.
- 'packages/stack/src/dynamodb/**'
- 'packages/stack/src/index.ts'
- 'packages/stack/src/types.ts'
# That v2 suite mints its 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`) 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.supabase.yml'
- 'local/supabase-init.sql'
- '.github/workflows/integration-supabase.yml'
- '.github/actions/integration-setup/**'
- '.github/actions/integration-db/**'
- '.github/actions/build-ffi-binding/**'
# The Rust that produces every EQL payload these suites round-trip.
# Absorbing protect-ffi put it in-tree, so a crate change can now
# break them in a PR that touches no TypeScript at all.
#
# The manifests are here for the same reason as the sources: a
# dependency bump in Cargo.lock changes the compiled encryption core
# without touching a .rs file, and package.json / mise.toml carry the
# build scripts and the toolchain pin. Matching the filter in
# tests-rust.yml, which already covers all four.
- 'packages/protect-ffi/crates/**'
- 'packages/protect-ffi/src/**'
- 'packages/protect-ffi/Cargo.toml'
- 'packages/protect-ffi/Cargo.lock'
- 'packages/protect-ffi/package.json'
- 'packages/protect-ffi/mise.toml'
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.
# Every OTHER event runs, which is why this gates on "not a fork PR" rather
# than listing the event names allowed through: the listing form skipped
# the job on `workflow_dispatch` in integration-protect-ffi.yml, making a
# declared manual trigger do nothing. Enforced by
# scripts/__tests__/workflow-dispatch-job-conditions.test.mjs.
if: ${{ github.event_name != 'pull_request' || 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 the binding build and before paying for the ~2 GB
# supabase/postgres pull. The in-test `requireIntegrationEnv` is the
# correctness guarantee; this is the cheap one, so nothing expensive may
# be ordered ahead of it.
- 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 `wasm: true` — this job's CS_IT_SUITE is `integration/shared/**`
# only, which goes through the native binding.
- name: Build the protect-ffi binding
uses: ./.github/actions/build-ffi-binding
# 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 exec turbo run test:integration --filter @cipherstash/stack-supabase --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/ 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 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