Skip to content

Merge pull request #941 from cipherstash/toby/cip-3742-eql-release-pi… #8

Merge pull request #941 from cipherstash/toby/cip-3742-eql-release-pi…

Merge pull request #941 from cipherstash/toby/cip-3742-eql-release-pi… #8

Workflow file for this run

name: "Bench EQL"
# Ported from cipherstash/encrypt-query-language with the subtree. See
# `.github/workflows/test-eql.yml` for the full account of what the move costs;
# this file needed the same four path rewrites plus two changes of its own,
# noted at the steps that carry them.
#
# Runs the slow benchmark / regression / scale SQLx tests gated behind the
# `bench` cargo feature. Not on pull requests — those use the fast `test-eql`
# workflow.
# Triggers:
# - push to main (catches regressions before release)
# - nightly schedule (additional smoke)
# - manual workflow_dispatch (PR triage)
on:
push:
branches:
- main
# Repo-root relative, so every entry gained the subtree prefix. Unprefixed,
# `src/**` and `tests/**` match nothing under this repository's root and the
# bench would simply stop running on pushes — silently, since a workflow
# that never triggers reports nothing at all.
#
# IDENTICAL to `test-eql.yml`'s list, modulo each file naming itself, and
# held that way by `scripts/__tests__/eql-workflow-filters.test.mjs`. The
# bench is a strict subset of that suite's inputs, so a bespoke narrower
# list here is possible and was what the port carried — and it had drifted
# three ways, each of them a change that alters what the bench measures
# while never starting it:
#
# * `src/**/*.sql` missed `src/v3/version.template`, which `tasks/build.sh`
# names in its own `#MISE sources` and `sed`s into `version.sql`.
# * `tests/sqlx/**/*` missed `tests/docker-compose.yml` — the file
# `postgres:up` actually runs, one level above the glob.
# * `mise.toml` was absent entirely, and it defines every `mise run` task
# below plus the toolchain that compiles them.
#
# Two lists that answer the same question are worth more kept equal than
# kept minimal: the cost of over-triggering is one nightly-budget bench run,
# and the cost of under-triggering is a regression that lands and is
# attributed to whatever merges next.
#
# The last four entries are the one place that reasoning is doing visible
# work. The bench runs `postgres:up` and `test:bench` and reads no
# documentation at all — they are inputs to `test-eql.yml`'s `docs-static`
# job, not to anything here, and the derivation in
# `scripts/__tests__/eql-workflow-filters.test.mjs` correctly derives none
# of them for this file. They are listed because the three copies are held
# equal, which is the whole point of the paragraph above: the cost is a
# bench run on a docs push, and the alternative is a bespoke narrower list
# of exactly the kind that had already drifted three ways.
paths:
- ".github/workflows/bench-eql.yml"
- ".github/actions/require-cs-secrets/**"
- "packages/eql/src/**"
- "packages/eql/tests/**"
- "packages/eql/tasks/**"
- "packages/eql/crates/**"
- "packages/eql/packages/**"
- "packages/eql/Cargo.toml"
- "packages/eql/Cargo.lock"
- "packages/eql/mise.toml"
- "packages/eql/docs/**"
- "packages/eql/docker/**"
- "packages/eql/README.md"
- "packages/eql/SUPABASE.md"
schedule:
# 02:00 UTC daily
- cron: "0 2 * * *"
workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
MISE_VERBOSE: "1"
permissions:
contents: read
defaults:
run:
shell: bash {0}
# Every `run:` here is written against the EQL root.
working-directory: packages/eql
jobs:
bench:
name: "Bench EQL (Postgres 17)"
runs-on: blacksmith-16vcpu-ubuntu-2204
timeout-minutes: 60
env:
POSTGRES_VERSION: "17"
steps:
# SHA-pinned, where upstream used floating major tags. The rest of the
# imported suite already pins by SHA; a mutable tag on a job that holds
# live CipherStash credentials means the code running there can change
# without a commit here. Same three pins as test-eql.yml — keep them in
# step. (checkout moves v4 -> v6 with this, matching that file.)
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
# Fast pre-flight: fail in seconds if a secret was rotated or cleared,
# before the rust-cache restore and a bench run budgeted at 60 minutes.
# This is a scheduled job, so nobody is watching it start — the difference
# between failing here and failing in `test:bench` is a legible nightly
# failure versus "Auth strategy error: Not authenticated" an hour in.
- 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 }}
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4
with:
version: 2026.4.0
install: true
cache: true
# mise reads config from cwd and its PARENTS, so an action running at
# the repo root never sees packages/eql/mise.toml.
working_directory: packages/eql
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: packages/eql
shared-key: sqlx-tests
# `build-archive` in test-eql.yml is the sole SAVER of this shared
# key — it compiles the full heavy dependency tree, so its `target/`
# is the one worth keeping. Every other consumer restores only, or a
# fast-finishing light job wins the save race and overwrites the entry
# with a deps-less `target/`. This job is the worst possible winner of
# that race: it is bench-gated and nightly, so a stale entry it saved
# would go unnoticed until someone wondered why the PR matrix got
# slow. Asserted by scripts/__tests__/eql-suite-ci.test.mjs.
save-if: false
- name: Setup database
run: |
mise run postgres:up "postgres-${POSTGRES_VERSION}" --extra-args "--detach --wait"
- name: Run bench tests
# CS_* scoped to THIS step only (least privilege): test:bench -> test:sqlx:prep
# -> fixture:generate:all encrypts via cipherstash-client and needs BOTH a
# ZeroKMS auth credential (CS_CLIENT_ACCESS_KEY + CS_WORKSPACE_CRN) AND a client
# key (CS_CLIENT_ID + CS_CLIENT_KEY); without them it fails "Auth strategy error:
# Not authenticated". Kept off job scope so checkout/mise/rust-cache actions
# never see them.
#
# CS_WORKSPACE_CRN and CS_CLIENT_ID read from `vars.`, not `secrets.` —
# this repo keeps the two non-sensitive ones there. Reading them from
# `secrets.` yields the empty string rather than an error.
env:
CS_CLIENT_ACCESS_KEY: ${{ secrets.CS_CLIENT_ACCESS_KEY }}
CS_WORKSPACE_CRN: ${{ vars.CS_WORKSPACE_CRN }}
CS_CLIENT_ID: ${{ vars.CS_CLIENT_ID }}
CS_CLIENT_KEY: ${{ secrets.CS_CLIENT_KEY }}
# `set -euo pipefail` because the workflow-wide `shell: bash {0}` drops
# GitHub's implicit `-eo pipefail`: without it a failing `rustup
# component add` is discarded and only `test:bench` decides the step,
# which then fails several minutes later for a reason that reads as a
# bench regression. Enforced by
# `scripts/__tests__/workflow-run-fail-fast.test.mjs`.
#
# Assignment on its own rather than `export x=$(…)`: errexit ignores
# the substitution's status when the line starts with a command word.
run: |
set -euo pipefail
active_rust_toolchain=$(rustup show active-toolchain | cut -d' ' -f1)
rustup component add --toolchain "${active_rust_toolchain}" rustfmt clippy
mise run --output prefix test:bench --postgres "${POSTGRES_VERSION}"