Skip to content

test(stack): EQL v3 integration harness + shared test kit, and two Supabase adapter fixes (PR1 of 4) #1621

test(stack): EQL v3 integration harness + shared test kit, and two Supabase adapter fixes (PR1 of 4)

test(stack): EQL v3 integration harness + shared test kit, and two Supabase adapter fixes (PR1 of 4) #1621

Workflow file for this run

name: Test JS
on:
push:
branches:
- 'main'
pull_request:
branches:
- "**"
jobs:
run-tests:
name: Run Tests (Node ${{ matrix.node-version }})
runs-on: blacksmith-4vcpu-ubuntu-2404
strategy:
matrix:
node-version: [22, 24]
# Postgres + EQL for the integration tests. Official EQL image —
# PostgreSQL 17 with EQL pre-installed via /docker-entrypoint-initdb.d.
# Pinned to eql-2.3.1 to match the EQL payload format the code emits
# (protect-ffi 0.23.x); bump in lockstep with the protect-ffi upgrade.
services:
postgres:
image: ghcr.io/cipherstash/postgres-eql:17-2.3.1
env:
POSTGRES_USER: cipherstash
POSTGRES_PASSWORD: password
POSTGRES_DB: cipherstash
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U cipherstash -d cipherstash"
--health-interval 2s
--health-timeout 5s
--health-retries 20
steps:
- name: Checkout Repo
uses: actions/checkout@v6
- uses: pnpm/action-setup@v6.0.8
name: Install pnpm
with:
run_install: false
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
# node-pty's install hook falls back to `node-gyp rebuild` when no
# linux-x64 prebuild matches. pnpm/action-setup v6 no longer ships
# node-gyp on PATH, so install it explicitly.
- name: Install node-gyp
run: npm install -g node-gyp
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Fail loudly if any live-test credential is missing, so the v3 live
# matrix (and every other `describeLive` suite) can't silently skip.
- name: Require CipherStash secrets
uses: ./.github/actions/require-cs-secrets
with:
workspace-crn: ${{ secrets.CS_WORKSPACE_CRN }}
client-id: ${{ secrets.CS_CLIENT_ID }}
client-key: ${{ secrets.CS_CLIENT_KEY }}
client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
- name: Type tests (stack)
run: pnpm --filter @cipherstash/stack run test:types
# The v3 domain catalog lives in the test kit, and its
# `satisfies Record<EqlV3TypeName, DomainSpec>` is what forces a new SDK
# domain to be covered. That check only fires under `tsc`, so without this
# step a domain added to stack would slip through untested.
- name: Type tests (test-kit — enforces v3 domain coverage)
run: pnpm --filter @cipherstash/test-kit run test:types
- name: Lint — no hardcoded package-manager runners
run: pnpm run lint:runners
- name: Test — lint script self-tests
run: pnpm run test:scripts
# The EQL v3 bundle in packages/cli/src/sql is vendored from the pinned
# @cipherstash/eql package (sha256-verified by gen:eql-v3-sql).
# Regenerate and fail on any diff so the pin and the shipped bundle
# cannot drift silently.
- name: Check — vendored EQL v3 SQL bundle is in sync
run: |
pnpm --filter stash run gen:eql-v3-sql
git diff --exit-code -- packages/cli/src/sql/cipherstash-encrypt-v3.sql
- name: Create .env file in ./packages/protect/
run: |
touch ./packages/protect/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/protect/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/protect/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/protect/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/protect/.env
echo "DATABASE_URL=postgres://cipherstash:password@localhost:5432/cipherstash" >> ./packages/protect/.env
- name: Create .env file in ./packages/stack/
run: |
touch ./packages/stack/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/stack/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/stack/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/stack/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/stack/.env
echo "DATABASE_URL=postgres://cipherstash:password@localhost:5432/cipherstash" >> ./packages/stack/.env
- name: Create .env file in ./packages/protect-dynamodb/
run: |
touch ./packages/protect-dynamodb/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/protect-dynamodb/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/protect-dynamodb/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/protect-dynamodb/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/protect-dynamodb/.env
- name: Create .env file in ./packages/drizzle/
run: |
touch ./packages/drizzle/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/drizzle/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/drizzle/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/drizzle/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/drizzle/.env
echo "DATABASE_URL=postgres://cipherstash:password@localhost:5432/cipherstash" >> ./packages/drizzle/.env
# Run TurboRepo tests
- name: Run tests
run: pnpm run test
# CLI E2E tests drive the built `dist/bin/stash.js` through a real
# pseudo-terminal via node-pty. Run via turbo so the `^build` + `build`
# deps declared on the `test:e2e` task are honored.
- name: Run CLI E2E tests
run: pnpm exec turbo run test:e2e --filter stash
e2e-tests:
name: Run E2E Tests
runs-on: blacksmith-4vcpu-ubuntu-2404
# Auth-dependent suites in `e2e/` skip themselves unless these env vars
# are set. We expose them at the job level so the wizard subprocess
# picks them up via `process.env`.
env:
CS_WORKSPACE_CRN: ${{ secrets.CS_WORKSPACE_CRN }}
CS_CLIENT_ID: ${{ secrets.CS_CLIENT_ID }}
CS_CLIENT_KEY: ${{ secrets.CS_CLIENT_KEY }}
CS_CLIENT_ACCESS_KEY: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
CS_ZEROKMS_HOST: https://ap-southeast-2.aws.zerokms.cipherstashmanaged.net
CS_CTS_HOST: https://ap-southeast-2.aws.cts.cipherstashmanaged.net
steps:
- name: Checkout Repo
uses: actions/checkout@v6
- uses: pnpm/action-setup@v6.0.8
name: Install pnpm
with:
run_install: false
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'
# node-pty's install hook falls back to `node-gyp rebuild` when no
# linux-x64 prebuild matches. pnpm/action-setup v6 no longer ships
# node-gyp on PATH, so install it explicitly.
- name: Install node-gyp
run: npm install -g node-gyp
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Auth-dependent `e2e/` suites skip themselves without these vars — a
# silent skip would hide regressions behind a green job. Fail loudly.
- name: Require CipherStash secrets
uses: ./.github/actions/require-cs-secrets
with:
workspace-crn: ${{ secrets.CS_WORKSPACE_CRN }}
client-id: ${{ secrets.CS_CLIENT_ID }}
client-key: ${{ secrets.CS_CLIENT_KEY }}
client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
# Run the standalone `e2e/` workspace via turbo so the `^build`
# dep on the `test:e2e` task builds cli + wizard first. CLI's own
# E2E (`packages/cli/tests/e2e/**`) is covered by the `run-tests`
# job above; we filter to the new workspace here to avoid duplication.
- name: Run E2E tests
run: pnpm exec turbo run test:e2e --filter @cipherstash/e2e
# Verifies @cipherstash/stack/wasm-inline works under Deno — i.e. the
# WASM build of protect-ffi 0.26+ and auth 0.40+ can round-trip an
# encryption against ZeroKMS / CTS in a runtime with no native
# bindings available. The deno.json deliberately omits --allow-ffi so
# a silent fallback to the NAPI module is impossible.
wasm-e2e-tests:
name: Run WASM E2E Tests (Deno)
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: read
# CS_WORKSPACE_CRN is the single source of truth for workspace
# identity and region — the stack /wasm-inline config requires it and
# derives the AccessKeyStrategy region from it.
env:
CS_WORKSPACE_CRN: ${{ secrets.CS_WORKSPACE_CRN }}
CS_CLIENT_ID: ${{ secrets.CS_CLIENT_ID }}
CS_CLIENT_KEY: ${{ secrets.CS_CLIENT_KEY }}
CS_CLIENT_ACCESS_KEY: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
steps:
- name: Checkout Repo
uses: actions/checkout@v6
with:
persist-credentials: false
- uses: pnpm/action-setup@v6.0.8
name: Install pnpm
with:
run_install: false
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'
# node-pty (a dev-dep of @cipherstash/cli used by its E2E PTY
# tests) falls back to `node-gyp rebuild` when no prebuild matches
# the runner, and pnpm/action-setup v6 no longer ships node-gyp on
# PATH. The WASM smoke test itself uses no native modules — this
# install only exists so the workspace-wide `pnpm install` step
# below doesn't fail.
- name: Install node-gyp
run: npm install -g node-gyp
- name: Install Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Install dependencies
run: pnpm install --frozen-lockfile
# The Deno smoke test imports the locally-built dist/wasm-inline.js
# via a file URL in e2e/wasm/deno.json — it needs a fresh build.
- name: Build stack
run: pnpm exec turbo run build --filter @cipherstash/stack
# roundtrip.test.ts skips itself (Deno.test.ignore) when any of the four
# CS_* env vars is missing — fine locally, but in CI a silent skip would
# let a rotated / cleared secret hide a real WASM regression behind a
# green job. Fail loudly instead.
- name: Require CipherStash secrets
uses: ./.github/actions/require-cs-secrets
with:
workspace-crn: ${{ secrets.CS_WORKSPACE_CRN }}
client-id: ${{ secrets.CS_CLIENT_ID }}
client-key: ${{ secrets.CS_CLIENT_KEY }}
client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
- name: Run Deno WASM smoke test
working-directory: e2e/wasm
run: deno task test
run-tests-bun:
name: Run Tests (Bun)
runs-on: blacksmith-4vcpu-ubuntu-2404
continue-on-error: true
services:
postgres:
image: ghcr.io/cipherstash/postgres-eql:17-2.3.1
env:
POSTGRES_USER: cipherstash
POSTGRES_PASSWORD: password
POSTGRES_DB: cipherstash
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U cipherstash -d cipherstash"
--health-interval 2s
--health-timeout 5s
--health-retries 20
steps:
- name: Checkout Repo
uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- uses: pnpm/action-setup@v6.0.8
name: Install pnpm
with:
run_install: false
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'
- name: Install node-gyp
run: npm install -g node-gyp
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Create .env file in ./packages/protect/
run: |
touch ./packages/protect/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/protect/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/protect/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/protect/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/protect/.env
echo "DATABASE_URL=postgres://cipherstash:password@localhost:5432/cipherstash" >> ./packages/protect/.env
- name: Create .env file in ./packages/stack/
run: |
touch ./packages/stack/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/stack/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/stack/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/stack/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/stack/.env
echo "DATABASE_URL=postgres://cipherstash:password@localhost:5432/cipherstash" >> ./packages/stack/.env
- name: Create .env file in ./packages/protect-dynamodb/
run: |
touch ./packages/protect-dynamodb/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/protect-dynamodb/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/protect-dynamodb/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/protect-dynamodb/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/protect-dynamodb/.env
- name: Create .env file in ./packages/drizzle/
run: |
touch ./packages/drizzle/.env
echo "CS_WORKSPACE_CRN=${{ secrets.CS_WORKSPACE_CRN }}" >> ./packages/drizzle/.env
echo "CS_CLIENT_ID=${{ secrets.CS_CLIENT_ID }}" >> ./packages/drizzle/.env
echo "CS_CLIENT_KEY=${{ secrets.CS_CLIENT_KEY }}" >> ./packages/drizzle/.env
echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./packages/drizzle/.env
echo "DATABASE_URL=postgres://cipherstash:password@localhost:5432/cipherstash" >> ./packages/drizzle/.env
# Build with Node (turbo/tsup need Node), then run tests with Bun
- name: Build packages
run: pnpm turbo build --filter './packages/*'
- name: Run tests with Bun
run: |
for dir in packages/schema packages/protect packages/stack packages/protect-dynamodb packages/drizzle packages/stack-forge; do
if [ -f "$dir/vitest.config.ts" ] || [ -f "$dir/package.json" ]; then
echo "--- Testing $dir ---"
(cd "$dir" && bunx --bun vitest run) || true
fi
done