Required checks lint, build and test are satisfied by a skip when dependency-locks fails
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 31.6k
- Forks
- 5.7k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 96
Description
The required checks lint, build, test (HTTPX2), test (Python 3.10) and test (Python 3.14) all come from jobs that declare needs: dependency-locks, and dependency-locks is not itself a required check. Because GitHub treats a skipped required check as satisfied, a failure in dependency-locks skips all five and the branch rule is met with none of them having run.
From About protected branches:
Required status checks must have a
successful,skipped, orneutralstatus before collaborators can make changes to a protected branch.
The state in .github/workflows/ci.yml on main today:
| job | check name | required | needs |
|---|---|---|---|
dependency-locks |
dependency lock freshness | no | — |
lint |
lint | yes | dependency-locks |
build |
build | yes | dependency-locks |
test |
test (Python 3.10 / 3.14) | yes | dependency-locks |
test-httpx2 |
test (HTTPX2) | yes | dependency-locks |
None of the five carries an always() or !cancelled() guard, so the default skip-on-upstream-failure behaviour applies. dependency-locks failing is not hypothetical — it is the job that fails when pyproject.toml and uv.lock disagree, which is exactly the situation where you would most want lint and the test suite to run.
The narrowest fix is to make the dependency it gates on a gate itself, by adding dependency lock freshness to the required checks in the ruleset. Nothing in the workflow changes, and a lock failure then blocks on its own terms rather than by silently withdrawing four other checks.
The alternative, if you would rather not grow the required list, is the aggregate-gate shape you already have elsewhere in the ecosystem: one job with if: always() that inspects needs.*.result and exits non-zero, required in place of the individual checks.
Two caveats on scope. Those five jobs also carry if: github.event_name == 'push' || github.event_name == 'merge_group' || github.event.pull_request.head.repo.fork, so on a same-repo pull request they are skipped by design and the real run happens in the merge queue; the exposure I am describing is inside the queue, where a dependency-locks failure would skip the rest of the run and the queue would see satisfied checks. And I can only read your rulesets, not classic branch protection, so if additional enforcement exists that I cannot see, this may already be covered.
Found with greenwash, a tool I wrote for auditing this specific failure mode; greenwash audit --repo openai/openai-python reproduces it.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review .github/workflows/ci.yml and the repository rulesets to confirm the dependency-locks job and its dependent checks. Add dependency lock freshness to the required checks, then verify that a dependency-locks failure blocks the merge queue without treating the dependent checks as successful. Confirm whether any existing branch protection rules provide additional enforcement.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, python, yaml
- Domain
- ci-cd
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100