From 79b70893601c33a33d8d44eb0421797dfd846a47 Mon Sep 17 00:00:00 2001 From: Gusted Date: Thu, 28 Mar 2024 21:41:52 +0100 Subject: [FEAT] Configure if protected branch rule should apply to admins - Currently protected branch rules do not apply to admins, however in some cases (like in the case of Forgejo project) you might also want to apply these rules to admins to avoid accidental merges. - Add new option to configure this on a per-rule basis. - Adds integration tests. - Resolves #65 --- routers/api/v1/repo/branch.go | 5 +++++ routers/private/hook_pre_receive.go | 16 ++++++++-------- routers/web/repo/setting/protected_branch.go | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'routers') diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 5e6b6a8658..c33beee0ae 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -621,6 +621,7 @@ func CreateBranchProtection(ctx *context.APIContext) { ProtectedFilePatterns: form.ProtectedFilePatterns, UnprotectedFilePatterns: form.UnprotectedFilePatterns, BlockOnOutdatedBranch: form.BlockOnOutdatedBranch, + ApplyToAdmins: form.ApplyToAdmins, } err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{ @@ -808,6 +809,10 @@ func EditBranchProtection(ctx *context.APIContext) { protectBranch.BlockOnOutdatedBranch = *form.BlockOnOutdatedBranch } + if form.ApplyToAdmins != nil { + protectBranch.ApplyToAdmins = *form.ApplyToAdmins + } + var whitelistUsers []int64 if form.PushWhitelistUsernames != nil { whitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.PushWhitelistUsernames, false) diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index f45e57b9e3..0613492845 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -337,13 +337,9 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r return } - // If we're an admin for the repository we can ignore status checks, reviews and override protected files - if ctx.userPerm.IsAdmin() { - return - } - - // Now if we're not an admin - we can't overwrite protected files so fail now - if changedProtectedfiles { + // It's not allowed t overwrite protected files. Unless if the user is an + // admin and the protected branch rule doesn't apply to admins. + if changedProtectedfiles && (!ctx.user.IsAdmin || protectBranch.ApplyToAdmins) { log.Warn("Forbidden: Branch: %s in %-v is protected from changing file %s", branchName, repo, protectedFilePath) ctx.JSON(http.StatusForbidden, private.Response{ UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath), @@ -352,8 +348,12 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r } // Check all status checks and reviews are ok - if err := pull_service.CheckPullBranchProtections(ctx, pr, true); err != nil { + if pb, err := pull_service.CheckPullBranchProtections(ctx, pr, true); err != nil { if models.IsErrDisallowedToMerge(err) { + // Allow this if the rule doesn't apply to admins and the user is an admin. + if ctx.user.IsAdmin && !pb.ApplyToAdmins { + return + } log.Warn("Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s", ctx.opts.UserID, branchName, repo, pr.Index, err.Error()) ctx.JSON(http.StatusForbidden, private.Response{ UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()), diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index 7ee67e5925..25146779de 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -237,6 +237,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) { protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns protectBranch.UnprotectedFilePatterns = f.UnprotectedFilePatterns protectBranch.BlockOnOutdatedBranch = f.BlockOnOutdatedBranch + protectBranch.ApplyToAdmins = f.ApplyToAdmins err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{ UserIDs: whitelistUsers, -- cgit v1.2.3