Skip to content

ci: decide in selector jobs whether the remaining checks run - #1426

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

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

Conversation

@auxesis

@auxesis auxesis commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Summary

This converts the last four pull request workflows to the selector job design. Lint release tooling and musl build image used a workflow-level path filter. A workflow skipped that way leaves its required checks pending, and GitHub's documentation on required status checks says that blocks a merge. CodeQL and OSV-Scanner had no filter, and ran on every pull request to main.

After this change, each workflow starts with a selector job and ends with a summary job. CodeQL no longer runs for a pull request that changes only Rust, Go, SQL, or Markdown. OSV-Scanner no longer runs for a pull request that changes no lockfile or manifest.

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

Changes

  • Lint release tooling and musl build image: the selector filter keeps the paths of the old filter.
  • CodeQL: it analyses JavaScript and TypeScript only. Its trigger paths are the file types its JavaScript extractor reads: HTML and templates, JavaScript, JSON, TypeScript, and YAML. I took the list from FileType in the extractor's FileExtractor.java.
  • OSV-Scanner: it reads dependencies from lockfiles and manifests. Its trigger paths are those files, for each ecosystem it supports, and osv-scanner.toml. The weekday schedule still scans everything for new advisories.
  • Permissions: the selector job and the summary job in CodeQL and OSV-Scanner get contents: read. They do not get the security-events: write that the workflow grants.
  • Summary job: last in each workflow. It passes when each needed job passed or was skipped.
  • Shared test code: the first two commits are the same as in ci(crates): decide in selector jobs which crate checks run #1421.
  • New test: other-selectors.test.mjs pins what each selector decides.
  • Changed tests: lint-release-scope.test.mjs and musl-build-image.test.mjs read the selector filter. The parity test loses the lint-release.yml entry.

Verification

  • pnpm run test:scripts: 83 files, 1,506 tests passed, 3 skipped.
  • actionlint 1.7.12 with shellcheck 0.11.0 on the four workflows: no findings.
  • git ls-files lists these lockfiles and manifests in the repository today: pnpm-lock.yaml, nine Cargo.lock, deno.lock, eleven go.mod, and one requirements.txt. The OSV filter covers all of them.
  • Not yet verified: a run on GitHub. This pull request changes each workflow, so each one runs here.
  • Not verified: I did not check which of these types the CodeQL autobuild extracts by default. The filter lists every type the extractor supports, so it can only run CodeQL more often than needed.

Related

Review notes

  • Look first at the CodeQL and OSV filters. Those two workflows had no filter before, so this is a narrowing.
  • CodeQL and OSV-Scanner run only for pull requests to main. A stacked pull request does not start them, before or after this change.
  • impact.yml, claude-review.yml, and code-review.yml are not converted. They are advisory, not checks.
  • 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.
Lint release tooling and musl build image 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. CodeQL and OSV-Scanner had no path
filter and ran on every pull request to main.

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

- Lint release tooling and musl build image keep the paths of the
  filter they had.
- CodeQL analyses JavaScript and TypeScript only. Its trigger paths are
  the file types its JavaScript extractor reads: HTML and templates,
  JavaScript, JSON, TypeScript and YAML. A change to Rust, Go, SQL or
  Markdown alone no longer runs it on a pull request.
- OSV-Scanner reads dependencies from lockfiles and manifests. Its
  trigger paths are those files, for each ecosystem it supports, and its
  config. The weekday schedule still scans everything for new
  advisories.

In CodeQL and OSV-Scanner the selector and summary jobs get
`contents: read`, not the workflow's `security-events: write`.

The release lint scope test and the musl image test read the selector
filter. other-selectors.test.mjs pins what each selector decides.
@changeset-bot

changeset-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 64c4d83

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

@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.

@auxesis

auxesis commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

"Build the Alpine musl image" fails here because an apk pin no longer resolves. That is #1380: the scheduled run on main has failed the same way since 26 October. This pull request does not change the Dockerfile. The run does show the summary job failing when its job fails: musl build image summary read success failure and exited 1.

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