Skip to content

nixpkgs branch protection rules: require status checks to pass #130

@wolfgangwalther

Description

@wolfgangwalther

NixOS/nixpkgs#417957 has the base to allow enabling required status checks efficiently, thus I propose to do that.

Requiring status checks would help prevent accidental merges. To be clear, they are not about lack of trust. Instead, they are about protecting committers. Nobody wants to break CI for others by accidentally merging something that actually fails CI. Also, those checks are a prerequisite for merge queues.

A little breakdown of how they work:

  • The branch protection rule specifies the name of a status check. This will appear as "pending" in all PRs immediately after the rule is activated. It looks like this:

    Image

  • Once a job with this name runs, it will replace that pending status check with either "success/skipped" or "failure". Skipped counts as success. When it's successful, a merge is allowed. When it's failed, the merge is blocked. In the UI, the merge button is disabled (similar to when a PR is merge conflicted). When merging from the command line, it shows like this:

     remote: error: GH013: Repository rule violations found for refs/heads/master.
     remote: Review all repository rules at https://github.com/wolfgangwalther/nixpkgs/rules?ref=refs%2Fheads%2Fmaster
     remote:
     remote: - Required status check "required to merge" is expected.
     remote:
     To github.com:wolfgangwalther/nixpkgs.git
      ! [remote rejected]           HEAD -> master (push declined due to repository rule violations)
     error: failed to push some refs to 'github.com:wolfgangwalther/nixpkgs.git'
    
  • The branch protection rule can have a number of bypassers set up. The teams/roles with this privilege can merge a PR despite some required checks failing. In the web UI, it looks like this:

    Image

  • When merging from the command line with bypass privileges, the push will always succeed. If a branch protection rule failed, it looks like this:

    remote: Bypassed rule violations for refs/heads/master:
    remote:
    remote: - Required status check "required to merge" is expected.
    remote:
    To github.com:wolfgangwalther/nixpkgs.git
       f68c81b1b9b4..a6086158c33b  HEAD -> master
    

Now, the question becomes: Which bypassers do we want to allow?

  1. One approach could be to allow all committers to bypass, for example proposed by @Mic92 in teams/ci: init nixpkgs#416459 (comment).
    It's unfortunate that checks will always be bypassed from the command line - because merging from the command line is also in principle most likely to miss a failing check, since it's easier to see the list of checks right next to the merge button in the UI. Thus, to really protect committers from accidental merging, we should not allow all committers to bypass.

  2. The opposite approach would be to only allow a minimum number of specific teams to bypass. To do this, we'd need to identify cases in which bypassing is actually required. I can see the following cases from most likely to least:

    1. When making CI changes, sometimes jobs fail before they are merged and only start passing once on master. There is no sensible way to avoid that in all cases, it depends on the kind of changes. This is on purpose.
    2. When making CI changes, sometimes jobs pass in the PR, but start failing on master. In this case, a follow up PR to fix them, might still have failing jobs. This is by accident.
    3. A job could be flawed and fail for a regular change, which is supposed to be fine.
    4. Jobs could start to fail randomly, for example because GitHub Actions is having issues.

Are there any other, possibly even regular, cases where PRs must be merged with failing checks?

For 2i and 2ii, the new NixOS/Nixpkgs-CI team needs the ability to bypass.

I'd argue that for 2iii, the job is not ready to be "required", yet/anymore. In this case, any regular committer can open a PR towards the CI workflows to propose removing the job from the list of required jobs.

When everything breaks down in 2iv: Do we actually want to keep merging stuff if we're not sure about the validity of the changes? I'd say no, if we care about CI results, then bigger scale GitHub issues just need to decrease velocity.

In NixOS/nixpkgs#416459 (comment), @MattSturgeon mentioned to assume that "other teams would also get bypass permission, e.g. the security team and org owners". Of course, org owners can always change the branch protection rules and disable them. According to the list above, so far, the security team would not need to be able to bypass.

Thus, assuming that only the CI team can bypass, we'll need to answer the following questions / concerns:

  • In teams/ci: init nixpkgs#416459 (comment), @Mic92 mentioned that maybe the team could too small and thus the branch protection rules could lead to blocking others / we create an arbitrary bottleneck.
  • In a hypothetical scenario, where a non-CI-team-member merges some CI-breaking changes, they can't go back and revert that.
  • Others?

Regarding team size: Even though we only have 5 members, we also org owners on top, who can always disable the rules. I think that should give us enough people to have somebody available to react in the worst-case. Implementing a "only those who regularly need to merge non-passing PRs are bypassers" should be possible. This would only be the CI team right now.

Regarding the second case above: Maybe we could implement an exception for revert PRs. Those could bypass the required check. This would allow anyone to always recover from such an accident.


With all these things in mind, I propose the following steps:

  1. Implement "reverts are always allowed".

  2. At first, add all committers as bypassers for some time. Collect data, see how often the status checks are actually bypassed intentionally.

  3. Later switch to only the CI team as bypasser. Adjust accordingly, if new requirements come up in step 2.

If we're confident enough, step 2 could also be optional.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions