build: lint the repo python with ruff #246
Inga granskare
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra!246
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "build/add-ruff"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Adds
ruffconfig and fixes everything it found (#61). The repo has 2,077 lines of Python —including
controller.pyat 1,192 lines, which provisions and deletes ephemeral CI VMs — andnone of it was linted by anything.
Rule selection is the whole design decision here
Run with the rule set the review proposed (
E W F I UP B S SIM PTH RUF), ruff reports 378findings. 361 of those are
E501line-too-long — 95% cosmetic wrapping in otherwise-finecode. That is precisely the "hundreds of findings nobody triages" outcome that makes a check worse
than no check, because it trains you to ignore the output.
Three deliberate narrowings, each for a reason rather than to get to green:
line-length = 120. Measured, not guessed: the median line here is 37 characters and p99is 106, with one outlier at 157. Ruff's default of 88 would flag 361 lines. 120 flags only the
genuine outlier. (100 would flag 57; 160 would flag none and be meaningless.)
PTHdropped. It wanted 5open()→Path.open()rewrites in working scripts — amodernisation preference, not correctness, and pure churn in code that manages infrastructure.
S603ignored. It fired 7 times, and every site uses the safe list form(
subprocess.run(["openstack", ...])— no shell, no interpolation). The rule cannot distinguishsafe from unsafe, so it has no signal here; the injection risk it nominally guards is already
excluded by never passing
shell=True.That leaves 6 real findings, all fixed:
F401×2 —jsonandreimported but unused incontroller.pyjson.orre.in the file.E501— one 157-char Prometheus# HELPlineSIM105—try/except TimeoutExpired/passcontextlib.suppress, with the comment kept: a timeout there is the success path.S310×2 —urlopenscheme auditbaseis the operator-supplied Forgejo URL from the environment, the path is a literal API route, so no attacker-controlled scheme can reach it.RUF100 immediately earned its place
My first attempt at the
S310rationale began the comment with# noqa S310 on both lines below,which ruff correctly parsed as a blanket noqa directive and then flagged as unused via
RUF100.Reworded. A dead-suppression rule catching a dead suppression on its first run is a decent argument
for keeping it.
CI wiring is deliberately NOT in this PR
ruffis added toscripts/bake-runner-image.sh(alongsideansible/ansible-lint, samepip --break-system-packagesline) and to the bake's sanity check, so the next image bake includesit. The CI step itself has to wait until the image is re-baked — adding it now would fail every
PR until then, which is exactly the lockout that
bitborg-reconcile-triggerjust went through.Sequence: merge this → re-bake the runner image (
scripts/bake-runner-image.sh) → follow-up PR addsthe gating
ruff checkstep.Verified locally:
ruff checkreportsAll checks passed!, all six Python files compile, therunner-controller test still passes
9/9, andformat:check/mdlint/shellcheck/ansible-lintare green.Refs #61