lint gate: server-side ruff autofix for same-repo PRs#264
Draft
cailmdaley wants to merge 1 commit into
Draft
Conversation
On a PR whose head branch lives in this repo, the lint gate now applies ruff's own fixes (`ruff format` + `check --fix-only`), commits them as the github-actions bot, and pushes them back to the PR branch, then re-lints the fixed tree in the same run and gates on the residual. Fully clean -> green with an "autofix pushed" comment; unsafe/judgement lint that survives -> red, comment lists only the residual. Fork PRs and develop pushes keep their existing report-only behaviour. Safe under pull_request_target: only ruff (static, never executes PR code) runs over the untrusted tree, and only ruff's own diff is pushed. Push uses the workflow token explicitly (checkout keeps persist-credentials: false); adds contents: write. A GITHUB_TOKEN push doesn't retrigger the workflow, so the pass/fail is decided in this run rather than by a rerun that never comes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AAwoWLvWvNdt18RZJR2mek
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Extends the
developlint gate so that, on a PR whose head branch lives in this repo, it doesn't just report ruff violations — it fixes the mechanical ones for you.When the first ruff pass on such a PR isn't clean, the gate:
ruff check --fix-only .+ruff format .over the PR head checkout,github-actions[bot]and pushes it back to the PR branch (message:ruff autofix (format + safe lint fixes)),🤖 autofix pushed <sha>, ruff is clean;F821undefined name, unused vars) → job red, PR comment lists only the residual, noting the formatting/safe fixes were already pushed.Fork PRs and direct
developpushes are unchanged (report-only: PR comment / lint-debt issue).The model
github.event.pull_request.head.repo.full_name == github.repository— same-repo branches only, because only there can CI push back with the workflow token. Forks get the existing read-only behaviour.contents: writeto permissions (scoped comment in the workflow). Checkout keepspersist-credentials: false; the push authenticates explicitly viax-access-token:${{ github.token }}in the remote URL.Security (pull_request_target)
Running tooling over an untrusted PR tree is safe here because we run only ruff — a static analyzer that parses files but never imports/executes them — and we push back only the diff ruff itself produced. No PR-authored code runs with the write token.
uvx --no-configstill neutralizes anyuv.toml/[tool.uv]in the PR tree.Two subtleties worth flagging for review
GITHUB_TOKENpush does not trigger a new workflow run — so there's no recursion, but also no fresh CI on the bot commit. That's exactly why the gate re-lints and decides pass/fail within the same run on the fixed tree, rather than waiting for a rerun that never comes.Verification
The gate runs the base branch's copy of the workflow, so this PR won't exercise its own changes. Verified instead by:
ruff@0.15.18,--no-config) against dirty fixtures, covering all three paths:residual_passed=true(green);F821undefined name) → autofix pushes formatting/safe fixes,F821survives →residual_passed=false, residual report lists only theF821(red);F821alone, clean formatting) → ruff produces no diff →pushed=false, gate falls back to the first-pass result with the original report (red).Also updates the "Code style and the lint gate" section of
CONTRIBUTING.mdand the workflow's header comment block to describe the new model.🤖 Generated with Claude Code