feat: add delete allowlist for branch protection rules (#696) #706

Merged
jmiller merged 3 commits from feature/delete-whitelist into dev 2026-06-28 00:36:29 +00:00
Owner

Summary

  • Add configurable per-user/team/deploy-key allowlist for deleting protected branches (#696)
  • Previously protected branches could never be deleted via git push — now admins can configure deletion permissions with the same granularity as force-push allowlists
  • 13 files changed across model, migration, API, web handler, template, and locale layers

Changes

  • Model (models/git/protected_branch.go): 6 new fields (CanDelete, EnableDeleteAllowlist, DeleteAllowlistUserIDs/TeamIDs, DeleteAllowlistDeployKeys, DeleteAllowlistActionsUser), CanUserDelete() method, updated WhitelistOptions/removeIDs
  • Migration (models/migrations/v1_27/v361.go): v361 adds delete allowlist columns to protected_branch table
  • API structs (modules/structs/repo_branch.go): Delete allowlist fields in BranchProtection, Create, and Edit option structs
  • Pre-receive hook (routers/private/hook_pre_receive.go): Replaced unconditional deletion block with CanUserDelete check (handles both deploy key and user scenarios)
  • Branch service (services/repository/branch.go): CanDeleteBranch now uses GetFirstMatchProtectedBranchRule + CanUserDelete instead of IsBranchProtected
  • API handlers (routers/api/v1/repo/branch.go): Create and Edit branch protection endpoints support delete allowlist user/team resolution
  • Web handler (routers/web/repo/setting/protected_branch.go): Form processing for delete allowlist radio buttons and user/team dropdowns
  • Template (templates/repo/settings/protected_branch.tmpl): Delete allowlist UI section (none/all/whitelist radio pattern matching force-push)
  • Locale (options/locale/locale_en-US.json): 12 new locale strings
  • Convert (services/convert/convert.go): Model-to-API mapping for delete allowlist fields

Design decisions

  • Default permission when no allowlist is enabled: admin access (higher than force-push which defaults to write access) — deleting a protected branch is more destructive
  • CanUserDelete is independent of push permission (unlike CanUserForcePush which requires CanUserPush)
  • Pre-receive hook resolves user early for delete check since user resolution normally happens later in the push flow

Test plan

  • Create a branch protection rule with delete disabled (default) — verify branch cannot be deleted
  • Enable delete for "all" — verify admins can delete the branch
  • Enable delete with allowlist — verify only allowlisted users/teams can delete
  • Test via API: create/edit branch protection with delete allowlist fields
  • Test via web UI: settings page shows delete allowlist section with correct radio/dropdown behavior
  • Verify non-allowlisted users get 403 when trying to delete via git push

https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd

## Summary - Add configurable per-user/team/deploy-key allowlist for deleting protected branches (#696) - Previously protected branches could never be deleted via git push — now admins can configure deletion permissions with the same granularity as force-push allowlists - 13 files changed across model, migration, API, web handler, template, and locale layers ## Changes - **Model** (`models/git/protected_branch.go`): 6 new fields (CanDelete, EnableDeleteAllowlist, DeleteAllowlistUserIDs/TeamIDs, DeleteAllowlistDeployKeys, DeleteAllowlistActionsUser), `CanUserDelete()` method, updated WhitelistOptions/removeIDs - **Migration** (`models/migrations/v1_27/v361.go`): v361 adds delete allowlist columns to protected_branch table - **API structs** (`modules/structs/repo_branch.go`): Delete allowlist fields in BranchProtection, Create, and Edit option structs - **Pre-receive hook** (`routers/private/hook_pre_receive.go`): Replaced unconditional deletion block with CanUserDelete check (handles both deploy key and user scenarios) - **Branch service** (`services/repository/branch.go`): CanDeleteBranch now uses GetFirstMatchProtectedBranchRule + CanUserDelete instead of IsBranchProtected - **API handlers** (`routers/api/v1/repo/branch.go`): Create and Edit branch protection endpoints support delete allowlist user/team resolution - **Web handler** (`routers/web/repo/setting/protected_branch.go`): Form processing for delete allowlist radio buttons and user/team dropdowns - **Template** (`templates/repo/settings/protected_branch.tmpl`): Delete allowlist UI section (none/all/whitelist radio pattern matching force-push) - **Locale** (`options/locale/locale_en-US.json`): 12 new locale strings - **Convert** (`services/convert/convert.go`): Model-to-API mapping for delete allowlist fields ## Design decisions - Default permission when no allowlist is enabled: **admin access** (higher than force-push which defaults to write access) — deleting a protected branch is more destructive - `CanUserDelete` is independent of push permission (unlike `CanUserForcePush` which requires `CanUserPush`) - Pre-receive hook resolves user early for delete check since user resolution normally happens later in the push flow ## Test plan - [ ] Create a branch protection rule with delete disabled (default) — verify branch cannot be deleted - [ ] Enable delete for "all" — verify admins can delete the branch - [ ] Enable delete with allowlist — verify only allowlisted users/teams can delete - [ ] Test via API: create/edit branch protection with delete allowlist fields - [ ] Test via web UI: settings page shows delete allowlist section with correct radio/dropdown behavior - [ ] Verify non-allowlisted users get 403 when trying to delete via git push https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd
jmiller added 1 commit 2026-06-27 20:36:11 +00:00
feat: add delete allowlist for branch protection rules (#696)
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
PR RC Release / Build RC Release (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 13s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m33s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
4178e7f23e
Add configurable per-user/team/deploy-key allowlist for deleting
protected branches. Previously, protected branches could never be
deleted via git push. Now admins can configure deletion permissions
with the same granularity as force-push allowlists.

- 6 new model fields: CanDelete, EnableDeleteAllowlist, DeleteAllowlistUserIDs/TeamIDs, DeleteAllowlistDeployKeys, DeleteAllowlistActionsUser
- CanUserDelete() method with admin-level default (higher than push)
- Migration v361 adds columns to protected_branch table
- Pre-receive hook checks delete allowlist instead of unconditional block
- CanDeleteBranch service uses CanUserDelete instead of IsBranchProtected
- API create/edit endpoints support delete allowlist fields
- Web UI settings page with radio buttons and user/team dropdowns
- 12 new locale strings for the delete allowlist UI

Claude-Session: https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd
jmiller added 1 commit 2026-06-27 20:40:33 +00:00
fix: restore original whitespace alignment in convert.go
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m7s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
c47013edb0
Claude-Session: https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd
jmiller added 1 commit 2026-06-28 00:33:02 +00:00
fix: set protectBranch.Repo before CanUserDelete to avoid extra DB load
PR RC Release / Build RC Release (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m8s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
81d20e25bf
Claude-Session: https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd
jmiller merged commit 92cf6a8521 into dev 2026-06-28 00:36:29 +00:00
jmiller deleted branch feature/delete-whitelist 2026-06-28 00:36:29 +00:00
Sign in to join this conversation.