chore(deps-dev): bump the dev-dependencies group across 1 directory with 3 updates #96
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 EQL" | |
| # The EQL suite, ported from cipherstash/encrypt-query-language when the subtree | |
| # landed at `packages/eql`. It arrived under `packages/eql/.github/workflows/` — | |
| # a directory GitHub never reads — so between the import and this file it ran | |
| # NOWHERE. That is the same failure the protect-ffi absorption hit, and | |
| # `scripts/__tests__/eql-suite-ci.test.mjs` is what stops it recurring. | |
| # | |
| # Four things changed in the port, all of them because the tree moved one level | |
| # down. Each is silent when wrong: | |
| # | |
| # * `defaults.run.working-directory` — every `run:` here is written against | |
| # the EQL root (`mise run …`, `release/*.sql`, `tests/sqlx/snapshots`). | |
| # Without it they resolve against the monorepo root and fail with paths that | |
| # look like typos. | |
| # * `working_directory:` on each mise-action step — mise reads config from the | |
| # current directory and its PARENTS, so an action running at the repo root | |
| # never sees `packages/eql/mise.toml`. It would install nothing and leave the | |
| # config untrusted, and the first `mise run` fails with "Config files … are | |
| # not trusted", which reads as a toolchain problem rather than a path one. | |
| # `defaults.run` does not reach a `uses:` step, so this is separate. | |
| # * `workspaces:` on each rust-cache step — the Cargo workspace is nested now. | |
| # * artifact `path:`/`path:` on upload/download — those are workspace-root | |
| # relative and `defaults.run` does not touch them either. | |
| # | |
| # The credentials also changed shape. Upstream read all four from `secrets.`; | |
| # this repo keeps the two non-sensitive ones in `vars.` (see | |
| # `.github/actions/require-cs-secrets`), so `CS_WORKSPACE_CRN` and | |
| # `CS_CLIENT_ID` are `vars.` here. Reading them from `secrets.` would not error | |
| # — it yields the empty string, and the suite would fail at client construction | |
| # in every shard instead of saying what was missing. | |
| # | |
| # NB: NO path filter on `pull_request`. A workflow skipped by a path filter | |
| # leaves its required checks stuck Pending and blocks merge. Relevance is | |
| # computed by the `changes` job and applied per-job via `if:` instead. `push` | |
| # carries one because nothing waits on a push run, so a skipped one costs | |
| # nothing — and the two lists are kept identical by | |
| # `scripts/__tests__/eql-workflow-filters.test.mjs`. | |
| # | |
| # WHY `push` AND `schedule` EXIST. The port arrived with `merge_group` as the | |
| # ONLY route to the full PG 14-17 matrix, and with no `push:` at all, | |
| # justified by "under a required merge queue, push-to-main validation is | |
| # redundant". Every clause of that premise is false in this repository, checked | |
| # against the live API: there is no merge queue on `main` | |
| # (`mergeQueue(branch:"main")` -> null), `main` is not protected | |
| # (`branches/main/protection` -> 404), and the active ruleset carries no | |
| # `required_status_checks` rule, so `ci-required` is required by nothing. | |
| # `merge_group` is an event this repo never emits — so PG 14, 15 and 16 were | |
| # tested NEVER, and nothing EQL-related ran after a merge. Both failures are | |
| # invisible, because an event that is never delivered produces no runs to | |
| # notice the absence of. Pinned by | |
| # `scripts/__tests__/eql-matrix-triggers.test.mjs`, which refuses to count | |
| # `merge_group` or `workflow_dispatch` as reachable. | |
| # | |
| # WHY THIS SHAPE, and not "full matrix on every push". The expensive axis is | |
| # the fan-out, not the trigger: PG 14-17 x 2 shards is roughly double the | |
| # runner-minutes of the PR lane. So the cost is bounded by the FILTER rather | |
| # than by running a smaller matrix — a `push` run only starts when the merge | |
| # actually touched EQL, which is a small fraction of merges to `main`, and when | |
| # it does start the extra PG versions are the entire reason to run it at all. | |
| # Attributing a PG14 break to the merge that caused it is worth much more than | |
| # finding it detached at 04:00 the next morning. `schedule` then backstops the | |
| # case the filter cannot see (a dependency or toolchain moving underneath a | |
| # tree nobody touched), and both use the same full matrix. | |
| # | |
| # `pull_request` keeps the fast lane — PG17 x 4 shards, every PR, unfiltered, | |
| # with relevance applied per job — because latency is what matters there and | |
| # PG17 catches all but version-specific breakage. | |
| on: | |
| pull_request: {} | |
| push: | |
| branches: [main] | |
| # Identical to the `relevant:` filter in the `changes` job below. GitHub | |
| # Actions has no YAML anchors, so the list is written twice; the guard named | |
| # above fails a one-sided edit. | |
| # | |
| # The last four entries are the documentation surface, and they are here | |
| # because a job in THIS file reads them: `docs-static` runs | |
| # `mise run test:docs_v3_grep`, which scans `README.md`, `SUPABASE.md`, | |
| # `docker/README.md` and every tracked `docs/` markdown for the eql_v2 | |
| # surface removed in 3.0.0. All four were missing from all three copies of | |
| # this list, so a push to main touching only docs started no run of this | |
| # workflow at all — `pull_request` was unaffected, because it applies no | |
| # `paths:` filter and `docs-static` is deliberately not relevance-gated. | |
| # Derived rather than remembered now: the second half of | |
| # `scripts/__tests__/eql-workflow-filters.test.mjs` walks each `mise run` | |
| # out to the paths the task names and fails on any this list does not select. | |
| paths: | |
| - ".github/workflows/test-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: | |
| - cron: "0 4 * * *" # 04:00 UTC daily; full matrix, off the merge path | |
| merge_group: {} # inert today (no queue); kept so enabling one works | |
| workflow_dispatch: {} # manual runs use the PR shape (PG17 x 4 shards) | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| MISE_VERBOSE: "1" | |
| # CI compile-time tuning (CI-only; local dev keeps full debuginfo + incremental). | |
| # Clean CI builds never reuse incremental state, so it only bloats target/ and | |
| # the rust-cache up/download. line-tables-only keeps readable panic backtraces | |
| # for failing tests at a fraction of full-debuginfo compile cost. nextest's | |
| # `test` profile inherits these from `dev`. | |
| CARGO_INCREMENTAL: "0" | |
| CARGO_PROFILE_DEV_DEBUG: "line-tables-only" | |
| defaults: | |
| run: | |
| shell: bash {0} | |
| # Every `run:` in this workflow is written against the EQL root. This is the | |
| # one-line form of what would otherwise be ~30 per-step `working-directory:` | |
| # lines, each of which could be forgotten independently. | |
| working-directory: packages/eql | |
| permissions: | |
| contents: read | |
| # PRs cancel superseded runs; the merge queue must NOT cancel — a cancelled | |
| # merge_group run never reports a final status and ejects the PR from the queue. | |
| concurrency: | |
| group: test-eql-${{ github.event_name }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| # Runs on EVERY event and MUST always succeed (never skipped, never failed) — | |
| # downstream heavy jobs `needs: [changes]`, and a skipped/failed `changes` | |
| # would either skip the merge-queue matrix or deadlock `ci-required`. | |
| changes: | |
| name: "Detect relevant changes" | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| outputs: | |
| relevant: ${{ steps.r.outputs.relevant }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| # Diff ONLY on pull_request, where a base ref is well-defined. On | |
| # push/schedule/merge_group/workflow_dispatch there is no base ref to | |
| # diff against and the filter errors or empties — so those events take the | |
| # hardcoded default in the step below instead. `push` does not need it: | |
| # its `on:`-level `paths:` has already decided whether the run happens. | |
| - id: f | |
| if: github.event_name == 'pull_request' | |
| uses: dorny/paths-filter@0e4a8c6effa4802afeda77dc8d303f8176d7dfad # v3 | |
| with: | |
| # Every path except the workflow itself gained the `packages/eql/` | |
| # prefix with the subtree. dorny/paths-filter matches against | |
| # repo-root-relative paths, so the unprefixed globs would match | |
| # `packages/stack/src/**` and friends instead — firing the whole | |
| # matrix on changes that cannot affect EQL, and (worse) NOT firing on | |
| # EQL's own `src/`, since nothing at the repo root is called that. | |
| # | |
| # Identical to the `push` `paths:` list at the top of this file — the | |
| # same question asked of two mechanisms GitHub gives no way to share. | |
| # `scripts/__tests__/eql-workflow-filters.test.mjs` compares them, and | |
| # also fails any entry here that matches no tracked file (a dead | |
| # `packages/eql/sql/**` sat in this list from the port: there is no | |
| # such directory, so it narrowed the filter by exactly nothing while | |
| # reading as coverage). | |
| # | |
| # The four documentation entries are inputs to `docs-static` and | |
| # `doc-anchors`, neither of which is relevance-gated, so this copy | |
| # does not strictly need them. It carries them because the three | |
| # copies are held EQUAL — see the note above the `push` list, and the | |
| # reasoning on `bench-eql.yml`'s own filter for why equal beats | |
| # minimal. | |
| filters: | | |
| relevant: | |
| - ".github/workflows/test-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" | |
| # Explicit default (not `|| 'true'`, which trips GitHub's inconsistent | |
| # treatment of the string 'false'). push/schedule/merge_group/dispatch | |
| # never run the filter above — it needs a base ref that only a pull | |
| # request has — so they take the default, and `push` is already narrowed | |
| # by its own `on:`-level `paths:`. | |
| # | |
| # The event arrives through `env:`, not through a `${{ }}` interpolated | |
| # into the body. That is what lets | |
| # `scripts/__tests__/eql-matrix-triggers.test.mjs` EXECUTE this script | |
| # once per event and read back what it wrote, rather than reimplementing | |
| # the branch and agreeing with a rewritten one by luck. | |
| - id: r | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| FILTER_RELEVANT: ${{ steps.f.outputs.relevant }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$EVENT_NAME" = "pull_request" ]; then | |
| echo "relevant=$FILTER_RELEVANT" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "relevant=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| # Pure bash; no checkout/toolchain. Derives the PG-version + shard fan-out | |
| # from the event: PR and manual dispatch -> PG17 x 4 shards (latency lane); | |
| # everything else -> PG 14-17 x 2 shards (coverage lane). | |
| setup: | |
| name: "Compute matrix" | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| # Opts out of the workflow-level `working-directory: packages/eql`. This job | |
| # deliberately does not check out — it is pure bash deriving a matrix — so | |
| # `packages/eql` does not exist on the runner and every `run:` step fails | |
| # before its first line, with `chdir: No such file or directory`. Guarded by | |
| # `scripts/__tests__/workflow-working-directory.test.mjs`. | |
| defaults: | |
| run: | |
| working-directory: . | |
| outputs: | |
| pg-versions: ${{ steps.cfg.outputs.pg }} | |
| shard-total: ${{ steps.cfg.outputs.shard_total }} | |
| shards: ${{ steps.cfg.outputs.shards }} | |
| steps: | |
| # Written as an exclusion, and that direction is the point: the FULL | |
| # matrix is the default, so a trigger added later lands in the coverage | |
| # lane rather than in the fast one. The version of this that enumerated | |
| # `merge_group` as the only full-matrix event is why PG 14-16 went | |
| # untested for the life of the port — an allowlist fails shut on the case | |
| # nobody enumerated, and here "shut" meant three Postgres versions. | |
| # | |
| # The event arrives through `env:` rather than an interpolated `${{ }}` | |
| # so `scripts/__tests__/eql-matrix-triggers.test.mjs` can run this script | |
| # against each event and read the real fan-out back out of | |
| # `$GITHUB_OUTPUT`. | |
| - id: cfg | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| set -euo pipefail | |
| case "$EVENT_NAME" in | |
| pull_request|workflow_dispatch) | |
| # Latency lane: PG17 only, split four ways. | |
| echo 'pg=[17]' >> "$GITHUB_OUTPUT" | |
| echo 'shard_total=4' >> "$GITHUB_OUTPUT" | |
| echo 'shards=[1,2,3,4]' >> "$GITHUB_OUTPUT" | |
| ;; | |
| *) | |
| # Coverage lane: every version tests/docker-compose.yml ships a | |
| # container for. Kept in step by the guard named above. | |
| echo 'pg=[14,15,16,17]' >> "$GITHUB_OUTPUT" | |
| echo 'shard_total=2' >> "$GITHUB_OUTPUT" | |
| echo 'shards=[1,2]' >> "$GITHUB_OUTPUT" | |
| ;; | |
| esac | |
| # Compile the test binaries ONCE. Runs on every non-PR event, and on PRs only | |
| # when relevant files changed (docs-only PRs never pay the ~4-min compile). | |
| build-archive: | |
| name: "Build test archive" | |
| needs: [changes] | |
| # This repo is PUBLIC and accepts fork PRs (the approval policy only gates | |
| # first-time contributors). build-archive is the sole holder of the CS_* | |
| # credentials below, so it must never run on a fork PR. The trailing clause | |
| # is the only thing that skips it: a fork pull request. Every other event — | |
| # push, schedule, merge_group, dispatch, and a same-repo branch PR — runs; | |
| # the downstream test/validate shards `needs:` it, so they skip on fork PRs | |
| # too. | |
| # | |
| # Both clauses are written as exclusions rather than as a list of admitted | |
| # events. An allowlist fails SHUT on the event nobody enumerated, and the | |
| # `push`/`schedule` triggers added above would have skipped every job in | |
| # this file while the run still reported success. Pinned by | |
| # `scripts/__tests__/eql-matrix-triggers.test.mjs`; the fork clause itself | |
| # is compared verbatim across all eight copies in the repo by | |
| # `scripts/__tests__/workflow-dispatch-job-conditions.test.mjs`. | |
| if: >- | |
| (github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true') | |
| && (github.event_name != 'pull_request' | |
| || github.event.pull_request.head.repo.full_name == github.repository) | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| env: | |
| # test:sqlx:archive depends on test:sqlx:prep, which copies the built EQL | |
| # into migrations/, applies it to a live Postgres, and regenerates the | |
| # per-type fixtures — both are include_str!'d into the test binaries at | |
| # COMPILE time, so they must exist before `cargo nextest archive`. Fixture | |
| # generation needs a live PG with EQL installed (the postgres:up step | |
| # below) plus CS_* creds. The job-level `if:` above keeps those creds off | |
| # fork-PR runs. | |
| POSTGRES_VERSION: "17" | |
| 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 }} | |
| steps: | |
| - 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 the ~4-minute nextest archive build. | |
| # Ordering is asserted by scripts/__tests__/ffi-binding-step-order.test.mjs. | |
| - 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 | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| # The sole saver of the shared cache: this job compiles the full heavy | |
| # dep tree, so it must own the `sqlx-tests` key. All other jobs set | |
| # `save-if: false` so a fast-finishing light job can't win the save race | |
| # and overwrite the key with a deps-less target/. | |
| - name: Setup database (Postgres 17) | |
| run: | | |
| mise run postgres:up "postgres-${POSTGRES_VERSION}" --extra-args "--detach --wait" | |
| - name: Build EQL + archive test binaries | |
| run: | | |
| mise run test:sqlx:archive | |
| # Ship the built release artifacts: build_validation_tests read | |
| # cipherstash-encrypt{,-uninstall}.sql from ../../release at RUN time | |
| # (std::fs, not embedded), and release/ is gitignored so the shard checkout | |
| # has none of them. `mise run build` (via prep) produced them in build-archive. | |
| # | |
| # `path:` is workspace-root relative — `defaults.run.working-directory` | |
| # does not reach a `uses:` step — hence the prefix. upload-artifact v4 | |
| # roots the archive at the least common ancestor of everything it matched, | |
| # which for these two is `packages/eql`, so the artifact still contains | |
| # `nextest.tar.zst` and `release/*.sql` at its top level and the shard's | |
| # `download-artifact` puts them back where the archive expects them. | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: nextest-archive | |
| path: | | |
| packages/eql/nextest.tar.zst | |
| packages/eql/release/*.sql | |
| retention-days: 1 | |
| if-no-files-found: error | |
| # Sharded sqlx suite. No longer needs [schema, codegen] (gate removed) — | |
| # shards start right after build-archive. | |
| test: | |
| name: "Shard PG${{ matrix.postgres-version }} ${{ matrix.shard }}/${{ needs.setup.outputs.shard-total }}" | |
| needs: [changes, setup, build-archive] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| postgres-version: ${{ fromJSON(needs.setup.outputs.pg-versions) }} | |
| shard: ${{ fromJSON(needs.setup.outputs.shards) }} | |
| env: | |
| POSTGRES_VERSION: ${{ matrix.postgres-version }} | |
| SHARD: ${{ matrix.shard }} | |
| SHARD_TOTAL: ${{ needs.setup.outputs.shard-total }} | |
| # No CS_* here: the shard runs the prebuilt archive (fixtures + migration | |
| # embedded by build-archive), so it does not regenerate fixtures and needs | |
| # no credentials. It only needs the live Postgres (below) for sqlx::test's | |
| # per-test scratch databases and the release/*.sql from the artifact. | |
| steps: | |
| # Checkout path MUST be identical to build-archive so the archive's | |
| # workspace remap lines up (design: archive<->commit coupling). | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| # Extracts to the workspace root by default, which would drop | |
| # `nextest.tar.zst` and `release/` two levels above where the archive's | |
| # workspace remap and the build_validation_tests expect them. | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| name: nextest-archive | |
| path: packages/eql | |
| - name: Setup database (Postgres ${{ matrix.postgres-version }}) | |
| run: | | |
| mise run postgres:up "postgres-${POSTGRES_VERSION}" --extra-args "--detach --wait" | |
| - name: Run shard ${{ matrix.shard }}/${{ needs.setup.outputs.shard-total }} | |
| run: | | |
| mise run test:sqlx:partition | |
| # docs:validate + Clean-DB v3 install smoke. Both are version-relevant, so | |
| # they follow the event's PG set (PG17 on PR; 14-17 in the queue). Moved out | |
| # of the old per-version test job so they run ONCE per version, not per shard. | |
| validate: | |
| name: "Validate (Postgres ${{ matrix.postgres-version }})" | |
| needs: [changes, setup] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| postgres-version: ${{ fromJSON(needs.setup.outputs.pg-versions) }} | |
| env: | |
| POSTGRES_VERSION: ${{ matrix.postgres-version }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Setup database (Postgres ${{ matrix.postgres-version }}) | |
| run: | | |
| mise run postgres:up "postgres-${POSTGRES_VERSION}" --extra-args "--detach --wait" | |
| # Source-only doc checks (coverage + required-tags) moved to the dedicated | |
| # `docs-static` job so they run exactly once, not per-Postgres. This step | |
| # keeps only the DB-backed SQL-syntax validation, which genuinely needs the | |
| # per-version Postgres. | |
| - name: Validate documented SQL syntax (Postgres ${{ matrix.postgres-version }}) | |
| run: | | |
| mise run docs:validate:documented-sql | |
| - name: Clean-DB v3 install smoke (Postgres ${{ matrix.postgres-version }}) | |
| # `set -euo pipefail` for the reason spelled out on `matrix-coverage`'s | |
| # inventory step and enforced by | |
| # `scripts/__tests__/workflow-run-fail-fast.test.mjs`: the workflow-wide | |
| # `shell: bash {0}` drops GitHub's implicit `-eo pipefail`, so without | |
| # it a failing BUILD on the first line is discarded and the smoke test | |
| # on the second decides the step — i.e. the install smoke would pass by | |
| # installing the previous build. | |
| run: | | |
| set -euo pipefail | |
| mise run clean && mise run build | |
| mise run test:clean_install_v3 | |
| schema: | |
| name: "JSON Schema validation" | |
| needs: [changes] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Validate v2.2 / v2.3 payload schemas | |
| run: | | |
| mise run test:schema | |
| rust-crates: | |
| name: "Rust workspace crates" | |
| needs: [changes] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| # `mise run test:crates` runs `cargo fmt --check` at the workspace root, | |
| # which covers tests/sqlx (a workspace member). This subsumes the old | |
| # standalone `test:lint` step that the removed per-version test job ran. | |
| - name: Compile, lint and test the Rust workspace crates | |
| run: | | |
| set -euo pipefail | |
| # Assignment on its own, not `export x=$(…)`: errexit ignores the | |
| # substitution's status when the line starts with a command word, so | |
| # the `export` form would swallow a failing `rustup show` even under | |
| # `set -e`. | |
| active_rust_toolchain=$(rustup show active-toolchain | cut -d' ' -f1) | |
| rustup component add --toolchain "${active_rust_toolchain}" rustfmt clippy | |
| mise run test:crates | |
| # Freshness gate for the eql-types codegen output: regenerate the | |
| # TypeScript bindings and JSON Schemas and fail if the checked-in | |
| # copies differ. Reuses the toolchain from the step above. | |
| - name: Verify eql-types bindings and schemas are fresh | |
| run: | | |
| mise run types:check | |
| # Publish gate for eql-bindings (the one crate we ship to crates.io via | |
| # release-plz). `--dry-run` packages + compiles the crate exactly as | |
| # crates.io would, catching publish-blockers — missing `license`/metadata, | |
| # a real path dependency without a version — on the PR rather than at | |
| # release time. No token needed. `--allow-dirty` tolerates any files the | |
| # preceding regenerate-and-diff steps leave in the working tree. | |
| - name: Verify eql-bindings packages cleanly for crates.io | |
| run: | | |
| cargo publish -p eql-bindings --dry-run --allow-dirty | |
| codegen: | |
| name: "Encrypted-domain codegen" | |
| needs: [changes] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Verify generator parity (golden) | |
| run: | | |
| mise run codegen:parity | |
| - name: Verify schema split parity (SQL owned_schemas vs Rust consts) | |
| run: | | |
| mise run test:schemas:parity | |
| self-contained-v3: | |
| name: "eql_v3 self-containment" | |
| needs: [changes] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Build EQL | |
| run: mise run clean && mise run --force build | |
| - name: Assert eql_v3 is self-contained | |
| run: mise run test:self_contained_v3 | |
| - name: Assert the installer contains every ordered file | |
| run: mise run test:installer_complete | |
| - name: Symbol-order cross-check (v3) | |
| run: mise run test:symbol_order_v3 | |
| - name: Build-ordering helper unit tests | |
| run: mise run test:build_ordering_helpers | |
| matrix-coverage: | |
| name: "Matrix coverage inventory" | |
| needs: [changes] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Verify the matrix test-name inventory | |
| # The workflow-wide `shell: bash {0}` default drops GitHub's implicit | |
| # `-eo pipefail`, so without fail-fast this multi-command step only | |
| # reports the LAST command's exit code and a failing inventory task is | |
| # silently swallowed. Restore fail-fast for this step. | |
| run: | | |
| set -euo pipefail | |
| mise run test:matrix:inventory | |
| mise run test:matrix:inventory:jsonb_entry | |
| mise run test:matrix:inventory:ope | |
| mise run test:v3-jsonb:inventory | |
| git add -N tests/sqlx/snapshots | |
| git diff --exit-code -- tests/sqlx/snapshots \ | |
| || { echo "Coverage inventory stale — run the relevant inventory task and commit."; exit 1; } | |
| - name: Verify catalog-surface coverage | |
| run: mise run test:matrix:catalog-coverage | |
| splinter: | |
| name: "Supabase splinter" | |
| needs: [changes] | |
| # Exclusion, not an allowlist — see the note on `build-archive`. | |
| if: >- | |
| github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| env: | |
| POSTGRES_VERSION: "17" | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| # This job looks Rust-free and is not. `test:splinter` is a bash script | |
| # that pipes SQL through psql, but the build step below runs `mise run | |
| # build`, and `tasks/build.sh` shells out to `cargo run -q -p eql-codegen` | |
| # twice — so without this restore the job cold-compiles that crate and its | |
| # dependency tree on every run, beside nine sibling jobs that restore a | |
| # warm `target/` for the same workspace. The only symptom is a slower run. | |
| # | |
| # `save-if: false` for the reason `build-archive` records: it is the sole | |
| # designated saver of this shared key. Both halves are asserted by | |
| # scripts/__tests__/eql-suite-ci.test.mjs, which finds the cargo by | |
| # closing over the mise task graph rather than grepping this file — the | |
| # string `cargo` appears nowhere in it. | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Setup database | |
| run: | | |
| mise run postgres:up "postgres-${POSTGRES_VERSION}" --extra-args "--detach --wait" | |
| - name: Build and install EQL | |
| run: | | |
| set -euo pipefail | |
| mise run clean && mise run --output prefix --force build | |
| # Redirected, not piped. `psql -v ON_ERROR_STOP=1` exits at the first | |
| # SQL error, which under `pipefail` leaves a `cat` writing into a | |
| # closed pipe and reports the step as 141 — the SIGPIPE hazard | |
| # `scripts/__tests__/workflow-grep-q-pipelines.test.mjs` documents. | |
| # The redirect is the same bytes with no writer to signal, so the | |
| # step reports psql's own status and says which statement failed. | |
| docker exec -i "postgres-${POSTGRES_VERSION}" \ | |
| psql -v ON_ERROR_STOP=1 \ | |
| postgresql://cipherstash:password@localhost/cipherstash -f- \ | |
| < release/cipherstash-encrypt.sql | |
| - name: Run splinter | |
| run: | | |
| mise run --output prefix test:splinter --postgres "${POSTGRES_VERSION}" | |
| # Source-only SQL documentation validation (coverage + required Doxygen tags). | |
| # Deliberately NOT relevance-gated: it runs on EVERY pull_request — including | |
| # docs-only PRs that skip the heavy jobs — so documentation is always | |
| # validated. DB-free and creds-free (the psql-backed syntax check stays in the | |
| # per-version `validate` job). | |
| docs-static: | |
| name: "SQL doc validation" | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Validate SQL doc coverage + required tags | |
| run: | | |
| mise run docs:validate:source | |
| - name: Assert user-facing docs are free of the removed eql_v2 surface | |
| run: | | |
| mise run test:docs_v3_grep | |
| - name: Assert public files contain no private issue identifiers | |
| run: | | |
| mise run test:public_identifiers | |
| # Every `known_failure` marker must name a real, OPEN issue, and its constant | |
| # must actually be referenced by a test. The Rust half of the contract is | |
| # self-expiring (the marker FAILS once the wrapped assertion starts passing); | |
| # this is the half that stops a suppression outliving a closed issue. | |
| # | |
| # Credential-free and DB-free — it only reads the registry and asks GitHub for | |
| # issue state, so it runs on every PR rather than hiding behind the e2e job. | |
| known-failures: | |
| name: "known-failure markers" | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| permissions: | |
| contents: read | |
| issues: read | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| # The gate detects drift by cross-checking a loose declaration count against | |
| # a strict parse, so an over-accepting parser defeats it silently. Runs | |
| # first, and needs no token: a broken parser makes the gate below | |
| # meaningless, not merely wrong. | |
| - name: The gate's strict ISSUE_ parser is sound | |
| run: | | |
| mise run test:known-failures:parser | |
| - name: Every suppressed test names an open issue | |
| env: | |
| # `gh` needs a token to read issue state; the default job token is | |
| # sufficient (issues: read, same repo). | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| mise run test:known-failures | |
| # Markdown anchor links. DB-free, credential-free and fast, and deliberately | |
| # NOT relevance-gated: its inputs are the docs themselves, so gating it on the | |
| # `relevant` filter (src/**, crates/**) would skip it on exactly the docs-only | |
| # PRs it exists to check. | |
| doc-anchors: | |
| name: "doc anchor links" | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4 | |
| with: | |
| version: 2026.4.0 | |
| install: true | |
| cache: true | |
| working_directory: packages/eql | |
| - name: Every intra-document anchor link resolves | |
| run: | | |
| mise run test:doc-anchors | |
| # The e2e (fresh-encryption) property suite. Encrypts random values through | |
| # ZeroKMS at run time, so it needs CS_* creds and is PG-version-independent — | |
| # one PG17 run, never the matrix. Compiles the `proptest-e2e`-gated binaries | |
| # (which the default-feature sharded archive excludes) and runs only the | |
| # e2e oracle. Like build-archive, it holds CS_* and so carries the same | |
| # fork-PR guard to keep the secrets off fork runs. | |
| e2e: | |
| name: "e2e property suite (fresh encryption)" | |
| needs: [changes, setup] | |
| # Exclusion, not an allowlist — see the note on `build-archive`, which | |
| # carries the same two clauses for the same two reasons. | |
| if: >- | |
| (github.event_name != 'pull_request' | |
| || needs.changes.outputs.relevant == 'true') | |
| && (github.event_name != 'pull_request' | |
| || github.event.pull_request.head.repo.full_name == github.repository) | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| env: | |
| POSTGRES_VERSION: "17" | |
| 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 }} | |
| steps: | |
| - 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 the proptest-e2e compile. | |
| - 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 | |
| working_directory: packages/eql | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| workspaces: packages/eql | |
| shared-key: sqlx-tests | |
| save-if: false | |
| - name: Setup database (Postgres 17) | |
| run: | | |
| mise run postgres:up "postgres-${POSTGRES_VERSION}" --extra-args "--detach --wait" | |
| - name: Run e2e property suite | |
| run: | | |
| mise run test:sqlx:e2e | |
| # The ONE required status check. Stable name on every event, so branch | |
| # protection never references an event-dependent leaf name (which would | |
| # deadlock). Passes iff every needed job is success or skipped. Treating | |
| # skipped as pass is intentional: heavy jobs are legitimately skipped on | |
| # docs-only PRs, and a genuine failure is still caught because the FAILING | |
| # source job is itself in `needs` and reports failure. | |
| ci-required: | |
| name: "ci-required" | |
| needs: [changes, setup, build-archive, test, validate, schema, rust-crates, | |
| codegen, self-contained-v3, matrix-coverage, splinter, docs-static, | |
| known-failures, doc-anchors, e2e] | |
| if: always() | |
| runs-on: blacksmith-16vcpu-ubuntu-2204 | |
| # Same opt-out as `setup`, and this is the worse of the two to get wrong: | |
| # this job is the required check. It reads `needs.*.result` and checks out | |
| # nothing, so under the workflow-level `working-directory` it fails for a | |
| # reason unrelated to any job it is reporting on — a red required check that | |
| # says nothing about the suite. | |
| defaults: | |
| run: | |
| working-directory: . | |
| steps: | |
| - name: Assert all required jobs passed or were skipped | |
| run: | | |
| set -euo pipefail | |
| results='${{ join(needs.*.result, ' ') }}' | |
| echo "needed results: $results" | |
| for r in $results; do | |
| case "$r" in | |
| success|skipped) ;; | |
| *) echo "gate fail: a needed job reported '$r'"; exit 1 ;; | |
| esac | |
| done | |
| echo "ci-required: all needed jobs passed or were skipped" |