feat: Add bypass allowlist for branch protection (#36514)
- 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). <img width="1069" height="218" alt="image" src="https://github.com/user-attachments/assets/0b61bc2a-a27f-47f3-a923-613688008e65" /> Fixes #36476 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Giteabot <teabot@gitea.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Codex GPT-5.3 <codex@openai.com> Co-authored-by: GPT-5.2 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
@@ -305,6 +305,49 @@
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.protect_bypass_allowlist"}}</h5>
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="enable_bypass_allowlist" type="checkbox" class="toggle-target-enabled" data-target="#bypass_allowlist_box" {{if .Rule.EnableBypassAllowlist}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_enable_bypass_allowlist"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_enable_bypass_allowlist_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bypass_allowlist_box" class="grouped fields {{if not .Rule.EnableBypassAllowlist}}disabled{{end}}">
|
||||
<div class="checkbox-sub-item field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_bypass_allowlist_users"}}</label>
|
||||
<div class="ui multiple search selection dropdown">
|
||||
<input type="hidden" name="bypass_allowlist_users" value="{{.bypass_allowlist_users}}">
|
||||
<div class="default text">{{ctx.Locale.Tr "search.user_kind"}}</div>
|
||||
<div class="menu">
|
||||
{{range .Users}}
|
||||
<div class="item" data-value="{{.ID}}">
|
||||
{{ctx.AvatarUtils.Avatar . 28 "mini"}}{{template "repo/search_name" .}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{if .Owner.IsOrganization}}
|
||||
<div class="checkbox-sub-item field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_bypass_allowlist_teams"}}</label>
|
||||
<div class="ui multiple search selection dropdown">
|
||||
<input type="hidden" name="bypass_allowlist_teams" value="{{.bypass_allowlist_teams}}">
|
||||
<div class="default text">{{ctx.Locale.Tr "search.team_kind"}}</div>
|
||||
<div class="menu">
|
||||
{{range .Teams}}
|
||||
<div class="item" data-value="{{.ID}}">
|
||||
{{svg "octicon-people"}}
|
||||
{{.Name}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="block_on_rejected_reviews" type="checkbox" {{if .Rule.BlockOnRejectedReviews}}checked{{end}}>
|
||||
|
||||
54
templates/swagger/v1_json.tmpl
generated
54
templates/swagger/v1_json.tmpl
generated
@@ -22666,6 +22666,20 @@
|
||||
"type": "string",
|
||||
"x-go-name": "BranchName"
|
||||
},
|
||||
"bypass_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "BypassAllowlistTeams"
|
||||
},
|
||||
"bypass_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "BypassAllowlistUsernames"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
@@ -22679,6 +22693,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableApprovalsWhitelist"
|
||||
},
|
||||
"enable_bypass_allowlist": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableBypassAllowlist"
|
||||
},
|
||||
"enable_force_push": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableForcePush"
|
||||
@@ -23522,6 +23540,20 @@
|
||||
"type": "string",
|
||||
"x-go-name": "BranchName"
|
||||
},
|
||||
"bypass_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "BypassAllowlistTeams"
|
||||
},
|
||||
"bypass_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "BypassAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -23530,6 +23562,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableApprovalsWhitelist"
|
||||
},
|
||||
"enable_bypass_allowlist": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableBypassAllowlist"
|
||||
},
|
||||
"enable_force_push": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableForcePush"
|
||||
@@ -24929,6 +24965,20 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockOnRejectedReviews"
|
||||
},
|
||||
"bypass_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "BypassAllowlistTeams"
|
||||
},
|
||||
"bypass_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "BypassAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -24937,6 +24987,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableApprovalsWhitelist"
|
||||
},
|
||||
"enable_bypass_allowlist": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableBypassAllowlist"
|
||||
},
|
||||
"enable_force_push": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableForcePush"
|
||||
|
||||
@@ -2850,6 +2850,20 @@
|
||||
"type": "string",
|
||||
"x-go-name": "BranchName"
|
||||
},
|
||||
"bypass_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "BypassAllowlistTeams"
|
||||
},
|
||||
"bypass_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "BypassAllowlistUsernames"
|
||||
},
|
||||
"created_at": {
|
||||
"format": "date-time",
|
||||
"type": "string",
|
||||
@@ -2863,6 +2877,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableApprovalsWhitelist"
|
||||
},
|
||||
"enable_bypass_allowlist": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableBypassAllowlist"
|
||||
},
|
||||
"enable_force_push": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableForcePush"
|
||||
@@ -3724,6 +3742,20 @@
|
||||
"type": "string",
|
||||
"x-go-name": "BranchName"
|
||||
},
|
||||
"bypass_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "BypassAllowlistTeams"
|
||||
},
|
||||
"bypass_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "BypassAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -3732,6 +3764,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableApprovalsWhitelist"
|
||||
},
|
||||
"enable_bypass_allowlist": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableBypassAllowlist"
|
||||
},
|
||||
"enable_force_push": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableForcePush"
|
||||
@@ -5100,6 +5136,20 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockOnRejectedReviews"
|
||||
},
|
||||
"bypass_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "BypassAllowlistTeams"
|
||||
},
|
||||
"bypass_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "BypassAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -5108,6 +5158,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableApprovalsWhitelist"
|
||||
},
|
||||
"enable_bypass_allowlist": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableBypassAllowlist"
|
||||
},
|
||||
"enable_force_push": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableForcePush"
|
||||
|
||||
Reference in New Issue
Block a user