fix(stack): close v3 drizzle fail-open paths, fix false-negative tests #1599
Workflow file for this run
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: 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 | |
| - name: Lint — no hardcoded package-manager runners | |
| run: pnpm run lint:runners | |
| - name: Test — lint script self-tests | |
| run: pnpm run test:scripts | |
| - 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 |