Skip to content

ci(crates): decide in selector jobs which crate checks run - #1421

Draft
auxesis wants to merge 3 commits into
ci/test-eql-selector-jobfrom
ci/crates-selector-jobs
Draft

auxesis wants to merge 3 commits into
ci/test-eql-selector-jobfrom
ci/crates-selector-jobs

Conversation

@auxesis

@auxesis auxesis commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Seven workflows check the Rust crates. Six of them used a workflow-level path filter, so they did not start at all on most pull requests. A workflow skipped that way leaves its required checks pending, and GitHub's documentation on required status checks says that blocks a merge. So none of them could become a required check.

After this change, each workflow starts on every pull request. A selector job decides which of its checks run, and a summary job reports the result. Each check's trigger paths now list what that check builds. So some checks run less often than before, and a few run for files they missed.

This pull request is stacked on #1417. Merge that one first.

Changes

  • Workflows: crap-crates.yml, fuzz.yml, miri.yml, udeps.yml, tests-crates.yml, tests-rust.yml, and tests-auth-refresh.yml.
  • Selector job: first in each workflow, on ubuntu-latest. It uses dorny/paths-filter with one filter per check. It fails when a filter gives no answer on a pull request.
  • Gated jobs: each has needs: [selector] and an if: that excludes pull requests, such as github.event_name != 'pull_request' || needs.selector.outputs.stack_auth == 'true'.
  • Summary job: last in each workflow. It passes when each needed job passed or was skipped.
  • CRAP: one filter per crate. The stack-auth gate also reads stack-profile. The stack-encrypt gate also reads stack-encrypt-derive, stack-kms, stack-auth, and stack-profile. Both read .config/nextest.toml, because the mise tasks use its ci profile.
  • Fuzz: adds stack-profile and stack-encrypt-derive. The fuzzed crates build them by path.
  • Tests (crates): two filters. The cargo job no longer runs for a change to pnpm-lock.yaml alone. The node bindings job no longer runs for stack-kms, stack-encrypt, or stack-guest-abi. Its filter now includes package.json and pnpm-workspace.yaml. Its pnpm install reads both.
  • Unused dependencies and Tests (Rust): add the root mise.toml. That file pins the rust they build with.
  • Auth refresh: the changes job becomes the selector job. The long soak adds stack-profile. The short soak still runs on every pull request.
  • Documentation: CRAP, Fuzz, Miri, and Unused dependencies still skip Markdown and .example files. They use dorny's every quantifier for that.
  • Push lists: tests-crates.yml and udeps.yml keep a push list. Each now matches the union of its selector's filters.
  • Shared test code: the first commit is the same as in ci(mutants): decide in a selector job whether the gate runs #1420. The second commit makes three guards read a job's selector filter as well as on.*.paths.
  • New test: crates-selectors.test.mjs pins what each selector decides.
  • Changed tests: the parity test loses the exemptions for crap-crates.yml, fuzz.yml, miri.yml, and tests-rust.yml. The soak test reads the selector job.

Verification

  • pnpm run test:scripts: 83 files, 1,565 tests passed, 3 skipped.
  • src/lintWiring.test.ts and src/integrationSuiteCi.test.ts in protect-ffi read tests-rust.yml. Both pass, after pnpm --filter @cipherstash/protect-ffi run build.
  • actionlint 1.7.12 with shellcheck 0.11.0 on the seven workflows: no findings.
  • I checked the path dependencies with the Cargo.toml of each crate. I read the crap:*, fuzz:*, miri:*, and test:integration:* mise tasks.
  • Not yet verified: a run on GitHub. This pull request changes each workflow, so each one runs its gated jobs here.

Related

Review notes

  • Look first at the filters in crap-crates.yml and tests-crates.yml. Those are the changes to when checks run.
  • fuzz-campaign never runs on a pull request. So the selector does not decide it.
  • In workflow-paths-filter-parity.test.mjs, this pull request and ci(mutants): decide in a selector job whether the gate runs #1420 edit neighbouring lines. The second to merge needs a rebase.
  • The new jobs have timeout-minutes: 10. The selector job in tests-auth-refresh.yml replaces a changes job that had 5.
  • Merge queue runs select every job. Comparing a queue commit with the entry ahead of it is a separate change.

Test EQL has a selector job, and the other pull request workflows are
getting one each. Each workflow's selector must follow the same rules:
no path filter on pull_request, one dorny/paths-filter step, an output
named after each filter, every job selected on other events, a failure
when a filter gives no answer, `if:` conditions that exclude
pull_request, and a summary job that needs every other job.

workflow-selectors.test.mjs checks those rules for every workflow that
has a selector job, found by scanning. It runs the selector's own
decision script and the summary job's own check.

lib/selector.mjs holds the shared code. It reads a selector job, runs
its script, and works out which jobs a pull request runs from the files
it changes. It reads dorny's `every` quantifier and brace patterns,
which a filter needs to exclude documentation.

The parity test now compares a selector workflow's push paths with the
union of its selector filters, by what each selects from the tracked
files. That replaces Test EQL's written exemption. The dispatch test
holds every selector output open, whatever its name.
Three guards check that a workflow's path filter covers what its jobs
read: the binding build inputs, the auth binding sources, and the
sources the integration suites import. They read `on.push.paths` and
`on.pull_request.paths`. Once a workflow has a selector job, its pull
request list moves into the selector filter of each job, and those
guards would stop checking it.

They now read, per job, the lists that decide whether that job runs:
the workflow's push and pull_request lists, and the selector filter the
job reads. For a workflow without a selector job this is the same two
lists as before. They also check only the jobs that build or load the
binding, not every job in the workflow.
Six of the Rust crate workflows used a workflow-level path filter on
pull_request. A workflow that a path filter skips leaves its required
checks pending, and GitHub's documentation on required status checks
says that blocks a merge. Tests (auth refresh cancellation) already
had a `changes` job, without the rest of the design.

Each workflow now runs on every pull request. A `selector` job on a
GitHub-hosted runner decides which jobs run, and fails when a filter
gives no answer. A summary job ends each workflow, and passes when
every needed job passed or was skipped.

The trigger paths are per check, and list what it builds:

- CRAP gets one filter per crate. stack-auth's gate also reads
  stack-profile, and stack-encrypt's reads stack-encrypt-derive,
  stack-kms, stack-auth and stack-profile. Both read
  .config/nextest.toml, because the mise tasks use its `ci` profile.
- Fuzz adds stack-profile and stack-encrypt-derive, which the fuzzed
  crates build by path.
- Tests (crates) splits in two. The cargo job no longer runs for a
  change to pnpm-lock.yaml alone. The node bindings job no longer runs
  for stack-kms, stack-encrypt or stack-guest-abi, and gains
  package.json and pnpm-workspace.yaml, which its pnpm install reads.
- Unused dependencies and Tests (Rust) add the root mise.toml, which
  pins the rust they build with.
- The long auth refresh soak adds stack-profile.

CRAP, Fuzz, Miri and Unused dependencies keep excluding Markdown and
`.example` files, through dorny's `every` quantifier. Push lists that
remain match the union of each selector's filters, which the parity
test now checks.
@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@changeset-bot

changeset-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: a951fff

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant