pyronear / pyronear/pyro-engine

Harden branch protection: required status checks are empty on develop and main

Open
#401 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

topic: ci type: enhancement
Dominant language
Python
Stars
19
Forks
8
PR merge metrics
No merged PRs in 30d

Description

Context

On 2026-08-14 a history-rewriting force-push (git push --force --all) rewrote every branch in this repository. develop was rejected by its protection rule and survived, which is the only reason the canonical history still exists. Everything else was rewritten: 20 branches lost their common ancestor with develop, 286 GPG signatures were stripped, and the 4 open PRs whose head branch lived in this repo were auto-closed by GitHub (a PR with no merge base has no computable diff).

Recovery was only possible because one contributor's local clone still held the pre-rewrite objects. There is no server-side reflog to fall back on.

The incident has been cleaned up. This issue is about the gaps it exposed, not the cleanup. To be studied after the summer, none of this is urgent.

Current state

develop    force=false  del=false  reviews=1     required_checks=[]   <- empty
main       force=false  del=false  reviews=1     required_checks=[]   <- empty
gh-pages   force=true   del=false  reviews=none  required_checks=none

main and gh-pages were unprotected until 2026-08-17 and are now covered.

Proposals, ranked by value

1. Fill in the required status checks

This is the only real gap, and it is unrelated to force-pushes. requiresStatusChecks is true on both develop and main but requiredStatusCheckContexts is empty, so the gate is decorative: a PR can be merged with the whole CI red. Seven workflows run on every PR and not one of them blocks a merge.

Suggested contexts (verified to run on pull requests):

  • ruff
  • mypy
  • pytest (ubuntu-latest, 3.11)
  • headers (ubuntu-latest)

Deliberately excluded: Build and Push pyronear/* only run on push, never on PRs, so requiring them would block every merge permanently. codecov-upload and see-page-build-payload are flaky.

Open question: whether to also require build (ubuntu-latest, 3.11) and the docker job. They are slower and would add several minutes per merge.

2. Replace the two duplicated rules with a single ruleset

develop and main are currently two separate legacy branch-protection rules with identical settings, which will drift the first time someone edits one and forgets the other. A single repository ruleset targeting both is the modern mechanism and keeps them in sync by construction.

3. Document the two things that turned this into a repo-wide incident

Worth a short section in CONTRIBUTING.md:

  • Never git push --force --all. This flag is what escalated a local mistake into everyone's problem: it pushes every branch at once, without showing which ones. Push one named branch at a time and read the output.
  • History rewriting is for secrets, oversized blobs, legal removals and repo splits. It is never worth it for cosmetics. To fix commit attribution for an email address, add the address to your GitHub account instead: it corrects retroactively across the whole history without touching a single commit.
  • The correct recovery after a rewrite is to re-clone, not git pull and not git rebase. Rebasing a branch that has lost its common ancestor replays the entire history.
4. Same audit on pyro-api

pyronear/pyro-api has the mirror-image version of gap 1: it does require 5 checks (pytest, pytest-client, client (ubuntu-latest, 3.11), docker, end-to-end), but ruff, ty, headers and precommit-hooks run without being required, so a PR can merge with lint, types and license headers red. It also has a Code Quality Copilot review ruleset sitting at enforcement: disabled, which should be either enabled or deleted.

Explicitly not proposed

  • Do not block force-pushes on gh-pages. docs.yml deploys via JamesIves/github-pages-deploy-action with CLEAN: true and an SSH deploy key. That push has to rewrite the branch and cannot satisfy a review requirement. Blocking it breaks every docs deploy, silently. Deletion protection is enough there.
  • Do not block force-pushes repository-wide. Contributors need to force-push their own PR branches to rebase.
  • Do not require commit signatures. Real cost for volunteer contributors, no benefit against the failure mode seen here.
  • isAdminEnforced is currently false, so admins bypass all of the above. That is a deliberate trade-off for a small team that occasionally needs to hotfix during fire season. Worth a conscious decision rather than a silent default, but changing it is not recommended.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the branch-protection settings for develop and main and the pull-request workflows that provide ruff, mypy, pytest, headers, build, and docker checks. The scope still needs a decision among required checks, a combined ruleset, CONTRIBUTING.md documentation, and the pyro-api audit; done should be defined after selecting one of these proposals.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, github-actions
Domain
ci-cd, devops, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.