feat: org branch protection per-user (username/email) allowlists + actions-bot toggle (#727) #750

Merged
jmiller merged 1 commits from feature/org-branch-protection-user-allowlists into dev 2026-07-05 22:54:51 +00:00
Owner

Adds individual-user allowlists (by username OR email) and an "allow actions bot" toggle to org-level branch protection — on top of the existing team-only allowlists. Requested as a pre-ship requirement for #733 ("email-based must work at the org level"). API-only (org branch protection has no web form); the API-bot toggle is deferred to #747.

Changes (9 files, +642/−11, on current dev)

  • models/git/org_protected_branch.go — adds WhitelistUserIDs / MergeWhitelistUserIDs / ForcePushAllowlistUserIDs / DeleteAllowlistUserIDs / ApprovalsWhitelistUserIDs ([]int64) and WhitelistActionsUser / Merge / ForcePush / Delete actions-user bools (approvals has no actions-user, matching repo-level). ToProtectedBranch() carries all 9 into enforcement.
  • Migration 367 (models/migrations/v1_27/v368.go) — additive x.Sync of the 9 columns; registered after 366.
  • modules/structs/org_branch.go*_whitelist_usernames + *_whitelist_actions_user on Create/Edit/response (same json names as repo-level repo_branch.go).
  • routers/api/v1/org/branch_protection.goresolveUserIDs (GetUserByName → GetUserByEmail fallback, dedupe, 422 on unknown); wired into Create/Edit gated on the same Enable* flags as the team lists; toAPIOrgBranchProtection renders user IDs → usernames + the toggles.
  • models/git/protected_branch_merge.go — new mergeAllowFlag (most-restrictive, enable-aware); the four actions-user flags now merge properly (supersedes the earlier #741 pass-through, which was a workaround for org being unable to express them). Deploy-keys stay pass-through (org still can't express them). User-ID lists already flow through mergeAllowlist (intersection). + unit test.
  • Swagger regenerated (purely additive: +306, −0).

Enforcement semantics

  • Only an org rule matches → ToProtectedBranch() carries the user IDs + toggles directly.
  • Both a repo and org rule match → mergeMostRestrictive intersects user/team allowlists and mergeAllowFlags the actions-user toggle (both-enabled → AND; one-enabled → that side; neither → repo value, so no spurious lockout).

Verification (local, Go 1.26.3, on dev base)

  • go build ./...exit 0 (independently confirmed, not masked); gofmt -l clean on all changed files.
  • go test ./models/git/... → ok (incl. the new mergeAllowFlag / merge test).
  • Swagger validates; regen additive-only.

Note: an earlier attempt built against stale main and was discarded; this branch is verified based on current dev (6c0c2c3f).

Related: #727, #733 (release — this is its last blocker), #747 (API-bot toggle, later).

https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT

Adds **individual-user allowlists (by username OR email) and an "allow actions bot" toggle** to org-level branch protection — on top of the existing team-only allowlists. Requested as a **pre-ship requirement for #733** ("email-based must work at the org level"). API-only (org branch protection has no web form); the API-bot toggle is deferred to #747. ## Changes (9 files, +642/−11, on current dev) - **`models/git/org_protected_branch.go`** — adds `WhitelistUserIDs` / `MergeWhitelistUserIDs` / `ForcePushAllowlistUserIDs` / `DeleteAllowlistUserIDs` / `ApprovalsWhitelistUserIDs` (`[]int64`) and `WhitelistActionsUser` / `Merge / ForcePush / Delete` actions-user bools (approvals has no actions-user, matching repo-level). `ToProtectedBranch()` carries all 9 into enforcement. - **Migration 367** (`models/migrations/v1_27/v368.go`) — additive `x.Sync` of the 9 columns; registered after 366. - **`modules/structs/org_branch.go`** — `*_whitelist_usernames` + `*_whitelist_actions_user` on Create/Edit/response (same json names as repo-level `repo_branch.go`). - **`routers/api/v1/org/branch_protection.go`** — `resolveUserIDs` (GetUserByName → GetUserByEmail fallback, dedupe, 422 on unknown); wired into Create/Edit gated on the same `Enable*` flags as the team lists; `toAPIOrgBranchProtection` renders user IDs → usernames + the toggles. - **`models/git/protected_branch_merge.go`** — new `mergeAllowFlag` (most-restrictive, enable-aware); the four actions-user flags now merge properly (supersedes the earlier #741 pass-through, which was a workaround for org being unable to express them). Deploy-keys **stay** pass-through (org still can't express them). User-ID lists already flow through `mergeAllowlist` (intersection). + unit test. - **Swagger** regenerated (purely additive: +306, −0). ## Enforcement semantics - Only an org rule matches → `ToProtectedBranch()` carries the user IDs + toggles directly. - Both a repo and org rule match → `mergeMostRestrictive` intersects user/team allowlists and `mergeAllowFlag`s the actions-user toggle (both-enabled → AND; one-enabled → that side; neither → repo value, so no spurious lockout). ## Verification (local, Go 1.26.3, on dev base) - `go build ./...` → **exit 0** (independently confirmed, not masked); `gofmt -l` clean on all changed files. - `go test ./models/git/...` → ok (incl. the new `mergeAllowFlag` / merge test). - Swagger validates; regen additive-only. Note: an earlier attempt built against stale `main` and was discarded; this branch is verified based on current `dev` (`6c0c2c3f`). Related: #727, #733 (release — this is its last blocker), #747 (API-bot toggle, later). https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
jmiller added 1 commit 2026-07-05 22:53:44 +00:00
feat: org branch protection per-user allowlists + Actions-bot toggle (#727)
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Successful in 14s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 1m3s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m42s
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
cac06c2ac7
Extend org-level branch protection to support per-user allowlists (resolved
from username OR email) and an "allow Actions bot" toggle, alongside the
existing team allowlists, for all five categories (push, merge, force-push,
delete, approvals).

- models/git/org_protected_branch.go: add WhitelistUserIDs, MergeWhitelistUserIDs,
  ForcePushAllowlistUserIDs, DeleteAllowlistUserIDs, ApprovalsWhitelistUserIDs
  ([]int64) plus WhitelistActionsUser, MergeWhitelistActionsUser,
  ForcePushAllowlistActionsUser, DeleteAllowlistActionsUser (bool); copy all 9
  into ProtectedBranch in ToProtectedBranch().
- models/migrations/v1_27/v368.go: migration 367 adds the 9 columns.
- modules/structs/org_branch.go: add *Usernames []string and *ActionsUser bool
  to Create/Edit options and the response, matching repo-level json names.
- routers/api/v1/org/branch_protection.go: resolveUserIDs (username then email,
  dedupe, 422 on unknown); wire into Create + Edit and toAPIOrgBranchProtection.
- models/git/protected_branch_merge.go: add mergeAllowFlag and merge the four
  Actions-user flags most-restrictively (org can now express them); deploy-key
  flags stay repo-only pass-through.
- models/git/protected_branch_merge_test.go: mergeAllowFlag truth table, user-ID
  intersection, deploy-key pass-through.
- regenerate swagger v1 + openapi3 specs.

Claude-Session: https://claude.ai/code/session_01Wsno14cxE49MstXFs9G5KT
jmiller merged commit b9301a8f31 into dev 2026-07-05 22:54:51 +00:00
jmiller deleted branch feature/org-branch-protection-user-allowlists 2026-07-05 22:54:54 +00:00
Sign in to join this conversation.