Skip to content

feat(eql): absorb the EQL subsystem, and kill the version skew #7

feat(eql): absorb the EQL subsystem, and kill the version skew

feat(eql): absorb the EQL subsystem, and kill the version skew #7

Workflow file for this run

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 at on: level. A workflow skipped by a path/branch filter
# leaves its required checks stuck Pending and blocks merge. Relevance is
# computed by the `changes` job and applied per-job via `if:` instead.
#
# NB: NO `push:` trigger, and that is not the same as "runs rarely". This runs
# on `pull_request` — every PR, unfiltered, with relevance applied per job — and
# on `merge_group`. Under a required merge queue, push-to-main validation is
# redundant: the queue already validated the exact merge commit, and branch
# protection blocks direct pushes. (Resolves the design's ambiguous "light jobs
# only on push:main" sanity net by dropping the trigger entirely.)
on:
pull_request: {}
merge_group: {} # required pre-merge gate; runs the full matrix
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
# merge_group/workflow_dispatch the base ref is absent and the filter errors/empties.
- id: f
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # 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.
filters: |
relevant:
- ".github/workflows/test-eql.yml"
- "packages/eql/src/**"
- "packages/eql/sql/**"
- "packages/eql/tests/**"
- "packages/eql/tasks/**"
- "packages/eql/crates/**"
- "packages/eql/Cargo.toml"
- "packages/eql/Cargo.lock"
- "packages/eql/mise.toml"
# Explicit default (not `|| 'true'`, which trips GitHub's inconsistent
# treatment of the string 'false'). merge_group/workflow_dispatch never
# read this value — their downstream `if:` branch ignores `relevant` — but
# default true is the safe value regardless.
- id: r
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "relevant=${{ steps.f.outputs.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 -> PG17 x 4 shards; merge queue -> PG 14-17 x 2 shards.
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:
- id: cfg
run: |
if [ "${{ github.event_name }}" = "merge_group" ]; then
echo 'pg=[14,15,16,17]' >> "$GITHUB_OUTPUT"
echo 'shard_total=2' >> "$GITHUB_OUTPUT"
echo 'shards=[1,2]' >> "$GITHUB_OUTPUT"
else
echo 'pg=[17]' >> "$GITHUB_OUTPUT"
echo 'shard_total=4' >> "$GITHUB_OUTPUT"
echo 'shards=[1,2,3,4]' >> "$GITHUB_OUTPUT"
fi
# Compile the test binaries ONCE. Runs in the queue and on workflow_dispatch
# always, 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
# restricts it to push / workflow_dispatch / same-repo branch PRs; the
# downstream test/validate shards `needs:` it, so they skip on fork PRs too.
if: >-
(github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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 }})
run: |
mise run clean && mise run build
mise run test:clean_install_v3
schema:
name: "JSON Schema validation"
needs: [changes]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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: |
export 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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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]
if: >-
github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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
- name: Setup database
run: |
mise run postgres:up postgres-${POSTGRES_VERSION} --extra-args "--detach --wait"
- name: Build and install EQL
run: |
mise run clean && mise run --output prefix --force build
cat release/cipherstash-encrypt.sql \
| docker exec -i postgres-${POSTGRES_VERSION} \
psql -v ON_ERROR_STOP=1 \
postgresql://cipherstash:password@localhost/cipherstash -f-
- 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]
if: >-
(github.event_name == 'merge_group'
|| github.event_name == 'workflow_dispatch'
|| (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: |
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"