feat(org): show inherited org branch-protection rules in repo settings (#727)
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Successful in 13s
Generic: Project CI / Lint & Validate (pull_request) Successful in 42s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 1m18s
PR RC Release / Build RC Release (pull_request) Successful in 1m17s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Has been skipped
Universal: PR Check / Secret Scan (pull_request) Successful in 1m32s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled

The org "floor" is enforced implicitly at the choke point, so a repo admin
couldn't see which org-level rules apply to their repo. Surface them in the
repo's Branch Protection settings page (read-only), the way GitHub shows
organization rulesets in a repository.

- ProtectedBranchRules handler: when the owner is an org, load
  FindOrgProtectedBranchRules and expose them as OrgProtectedBranches.
- branches.tmpl: new read-only "Organization Branch Protection" section listing
  each org rule with an "Organization" badge, a lock/read-only marker, and
  compact indicators (required approvals, signed commits, status checks). No
  edit/delete controls — these are managed at the org level.
- en-US locale strings.

Note: no Go toolchain available locally, so not compiled/gofmt'd/tested here.

Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
This commit is contained in:
2026-07-04 20:25:24 -05:00
parent 24b3516c1d
commit 86bd8a2cad
3 changed files with 46 additions and 0 deletions
+7
View File
@@ -2411,6 +2411,13 @@
"repo.settings.protected_branch": "Branch Protection",
"repo.settings.protected_branch.save_rule": "Save Rule",
"repo.settings.protected_branch.delete_rule": "Delete Rule",
"repo.settings.org_protected_branch": "Organization Branch Protection",
"repo.settings.org_protected_branch_desc": "These rules are defined by the organization and are enforced on top of this repository's own rules — the stricter of the two applies. They cannot be edited here.",
"repo.settings.org_protected_branch.inherited": "Organization",
"repo.settings.org_protected_branch.read_only": "Read-only",
"repo.settings.org_protected_branch.approvals": "%d approvals required",
"repo.settings.org_protected_branch.signed": "Signed commits",
"repo.settings.org_protected_branch.status_check": "Status checks",
"repo.settings.protected_branch_can_push": "Allow push?",
"repo.settings.protected_branch_can_push_yes": "You can push",
"repo.settings.protected_branch_can_push_no": "You cannot push",
@@ -46,6 +46,18 @@ func ProtectedBranchRules(ctx *context.Context) {
}
ctx.Data["ProtectedBranches"] = rules
// Surface the organization-level rules that also apply to this repo (read-only),
// so admins can see the org "floor" that is layered on top of the repo's own
// rules at enforcement time. See issue #727.
if ctx.Repo.Owner.IsOrganization() {
orgRules, err := git_model.FindOrgProtectedBranchRules(ctx, ctx.Repo.Owner.ID)
if err != nil {
ctx.ServerError("FindOrgProtectedBranchRules", err)
return
}
ctx.Data["OrgProtectedBranches"] = orgRules
}
repo.PrepareBranchList(ctx)
if ctx.Written() {
return
+27
View File
@@ -62,6 +62,33 @@
{{end}}
</div>
</div>
{{if .OrgProtectedBranches}}
<h4 class="ui top attached header">
{{ctx.Locale.Tr "repo.settings.org_protected_branch"}}
</h4>
<div class="ui attached segment">
<p class="tw-mb-3">{{ctx.Locale.Tr "repo.settings.org_protected_branch_desc"}}</p>
<div class="flex-divided-list items-with-main">
{{range .OrgProtectedBranches}}
<div class="item tw-items-center">
<div class="item-main">
<div class="item-title tw-flex tw-items-center tw-gap-2 tw-flex-wrap">
<div class="ui basic label">{{.RuleName}}</div>
<span class="ui tiny label">{{svg "octicon-organization" 12}} {{ctx.Locale.Tr "repo.settings.org_protected_branch.inherited"}}</span>
{{if gt .RequiredApprovals 0}}<span class="ui tiny basic label">{{ctx.Locale.Tr "repo.settings.org_protected_branch.approvals" .RequiredApprovals}}</span>{{end}}
{{if .RequireSignedCommits}}<span class="ui tiny basic label">{{ctx.Locale.Tr "repo.settings.org_protected_branch.signed"}}</span>{{end}}
{{if .EnableStatusCheck}}<span class="ui tiny basic label">{{ctx.Locale.Tr "repo.settings.org_protected_branch.status_check"}}</span>{{end}}
</div>
</div>
<div class="item-trailing">
<span class="text grey tw-text-sm">{{svg "octicon-lock" 14}} {{ctx.Locale.Tr "repo.settings.org_protected_branch.read_only"}}</span>
</div>
</div>
{{end}}
</div>
</div>
{{end}}
{{end}}
</div>