Skip to content

Add bypass allowlist for branch protection#36514

Draft
bircni wants to merge 25 commits intogo-gitea:mainfrom
bircni:feature/bypass-branch-protection-allowlist
Draft

Add bypass allowlist for branch protection#36514
bircni wants to merge 25 commits intogo-gitea:mainfrom
bircni:feature/bypass-branch-protection-allowlist

Conversation

@bircni
Copy link
Copy Markdown
Member

@bircni bircni commented Feb 1, 2026

  • Introduce a “Bypass Protection Allowlist” on branch rules (users/teams) alongside admins, with BlockAdminMergeOverride
    still respected.
    • Surface the allowlist in API (create/edit options, structs) and settings UI; merge box now shows the red button +
      message for bypass-capable users.
    • Apply bypass logic to merge checks and pre-receive so allowlisted users can override unmet approvals/status checks/
      protected files when force-merging.
    • Add migration for new columns, locale strings, and unit tests (bypass helper; queue test tweak).
image

Fixes #36476

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 1, 2026
@github-actions github-actions bot added modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code modifies/templates This PR modifies the template files modifies/migrations labels Feb 1, 2026
@bircni bircni force-pushed the feature/bypass-branch-protection-allowlist branch from 03c404c to 36d1fbf Compare February 1, 2026 16:32
@silverwind silverwind requested a review from Copilot February 12, 2026 10:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces a "Bypass Protection Allowlist" feature for branch protection rules, allowing specific users and teams to bypass branch protection checks (required approvals, status checks, and protected files) without requiring full administrator privileges. This addresses the need for "Merge Masters" or "Technical Leads" who need bypass capabilities while following the Principle of Least Privilege.

Changes:

  • Added database columns EnableBypassAllowlist, BypassAllowlistUserIDs, and BypassAllowlistTeamIDs to the ProtectedBranch model with migration v326
  • Implemented CanBypassBranchProtection helper function that checks both admin privileges and allowlist membership
  • Extended API endpoints and Swagger documentation to support bypass allowlist configuration
  • Updated branch protection settings UI to allow configuration of bypass users and teams
  • Modified pull request merge box to display appropriate messages for bypass-capable users
  • Applied bypass logic in pre-receive hooks and merge checks to allow allowlisted users to override unmet requirements

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
models/migrations/v1_26/v326.go Migration adding three new columns to ProtectedBranch table for bypass allowlist feature
models/migrations/migrations.go Registers the new migration v326
models/git/protected_branch.go Adds bypass allowlist fields to ProtectedBranch model and implements CanBypassBranchProtection function
models/git/protected_branch_test.go Unit tests for CanBypassBranchProtection covering various scenarios
modules/structs/repo_branch.go Extends API structs (BranchProtection, CreateBranchProtectionOption, EditBranchProtectionOption) with bypass allowlist fields
routers/api/v1/repo/branch.go Updates API endpoints to handle bypass allowlist users and teams during branch protection creation and editing
routers/web/repo/setting/protected_branch.go Handles bypass allowlist data in web UI forms for branch protection settings
routers/web/repo/issue_view.go Sets template data for bypass permissions to control merge button visibility and messages
routers/private/hook_pre_receive.go Applies bypass logic in pre-receive hook to allow bypass users to push despite protection checks
services/pull/check.go Uses CanBypassBranchProtection in merge checks instead of admin-only check, updates comment
services/pull/check_test.go Removes redundant queue.Has() checks that could cause test flakiness
services/forms/repo_form.go Adds bypass allowlist fields to ProtectBranchForm
services/convert/convert.go Converts bypass allowlist IDs to usernames/team names for API responses
templates/repo/settings/protected_branch.tmpl UI form for configuring bypass allowlist users and teams
templates/repo/issue/view_content/pull_merge_box.tmpl Displays context-appropriate message when bypass user can force merge
templates/swagger/v1_json.tmpl Swagger documentation for bypass allowlist fields in API
options/locale/locale_en-US.json Locale strings for bypass allowlist UI elements and messages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bircni bircni force-pushed the feature/bypass-branch-protection-allowlist branch from 36d1fbf to da1f775 Compare February 12, 2026 20:45
@silverwind
Copy link
Copy Markdown
Member

Review

I reviewed the full diff. The overall structure follows existing patterns well (model fields, migration, API plumbing, settings UI, template). A few observations:

1. Breaking behavior change in pre-receive hook

The original hook_pre_receive.go (line 371) unconditionally allows admins through:

if ctx.userPerm.IsAdmin() {
    return
}

The new code replaces this with CanBypassBranchProtection, which checks isRepoAdmin && !protectBranch.BlockAdminMergeOverride. This means admins who have BlockAdminMergeOverride enabled on a branch rule will now also be blocked in the git push (pre-receive) path, not just the web merge path. Previously those admins could always push past status checks, reviews, and protected files via direct push even with BlockAdminMergeOverride set.

This is arguably more correct behavior (closing an inconsistency), but it is a breaking change for existing setups and should be called out explicitly in the PR description and release notes.

2. Unrelated test change in check_test.go

The removal of prPatchCheckerQueue.Has(...) assertions and the reorder of go prPatchCheckerQueue.Run() is a test flakiness fix unrelated to the bypass allowlist feature. It should be in a separate commit (or separate PR) to keep the changeset focused.

3. Unused template variable IsBranchProtectionBypasser

In issue_view.go, IsBranchProtectionBypasser is computed and set in ctx.Data but is never referenced in any template. Either it should be used (perhaps to show a different UI indicator for bypass-list users vs admins), or it should be removed.

4. No integration test for the bypass merge path

The unit test for CanBypassBranchProtection is good, but there is no integration test covering the actual merge flow—e.g., a non-admin bypass-listed user force-merging a PR with failing status checks or missing approvals. Given this touches both the web merge check (CheckPullMergeable) and the pre-receive hook, an integration test would significantly increase confidence.

5. Minor: interaction between BlockAdminMergeOverride and bypass list

When BlockAdminMergeOverride is true, an admin who is also on the bypass allowlist can still bypass (because CanBypassBranchProtection falls through the admin check into the allowlist check). This is probably intentional, but it may surprise users who expect BlockAdminMergeOverride to block everyone. Worth a note in the UI help text or docs.


This comment was written by Claude (claude-opus-4-6) via Claude Code.

@silverwind
Copy link
Copy Markdown
Member

What do we do about point 1? Is it worth calling out a breaking change? I think not as it's probably too obscure of a feature.

@bircni
Copy link
Copy Markdown
Member Author

bircni commented Feb 26, 2026

I would not call it breaking but idk

@silverwind
Copy link
Copy Markdown
Member

Ok, please address points 3 and 4 if you can.

@bircni
Copy link
Copy Markdown
Member Author

bircni commented Feb 26, 2026

both are already done - I think

@silverwind silverwind requested a review from Copilot February 26, 2026 18:47
@silverwind
Copy link
Copy Markdown
Member

any screenshot of the added ui?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bircni
Copy link
Copy Markdown
Member Author

bircni commented Mar 3, 2026

fixed

@silverwind
Copy link
Copy Markdown
Member

Fix merge conflicts please and show a screenshot of the added UI.

@bircni bircni force-pushed the feature/bypass-branch-protection-allowlist branch from 03d5b44 to b108b00 Compare March 13, 2026 20:29
@bircni
Copy link
Copy Markdown
Member Author

bircni commented Mar 13, 2026

@silverwind Done - here a screenshot
image

@bircni
Copy link
Copy Markdown
Member Author

bircni commented Mar 16, 2026

Updated so no conflicts

@bircni
Copy link
Copy Markdown
Member Author

bircni commented Mar 16, 2026

Also added a test which I somehow forgot back then :-(

@bircni bircni requested review from lunny and removed request for lunny April 5, 2026 07:31
@bircni bircni force-pushed the feature/bypass-branch-protection-allowlist branch from 0831502 to 96f4123 Compare April 5, 2026 08:14
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Apr 5, 2026
@bircni bircni added the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Apr 5, 2026
@wxiaoguang wxiaoguang marked this pull request as draft April 6, 2026 03:12
Comment on lines +239 to +242
cacheKey := fmt.Sprintf("%d:%d:%v", user.ID, protectBranch.RepoID, protectBranch.BypassAllowlistTeamIDs)
in, err := cache.GetWithContextCache(ctx, cachegroup.BypassAllowlist, cacheKey, func(ctx context.Context, _ string) (bool, error) {
return organization.IsUserInTeams(ctx, user.ID, protectBranch.BypassAllowlistTeamIDs)
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this cache help anything? @lunny @bircni

Copy link
Copy Markdown
Contributor

@wxiaoguang wxiaoguang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You skipped too many useful messages?

Details image

@GiteaBot GiteaBot added lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged and removed lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. labels Apr 6, 2026
@wxiaoguang
Copy link
Copy Markdown
Contributor

It seems the messages conflicte with each other?

Fixed

The useful message should be kept.

image

@wxiaoguang wxiaoguang removed the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged modifies/api This PR adds API routes or modifies them modifies/frontend modifies/go Pull requests that update Go code modifies/migrations modifies/templates This PR modifies the template files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow specific users or teams to bypass branch protection rules (approval/status checks)

6 participants