security: add permission check to 'delete branch after merge'

- Add a permission check that the doer has write permissions to the head
repository if the the 'delete branch after merge' is enabled when
merging a pull request.
- Unify the checks in the web and API router to `DeleteBranchAfterMerge`.
- Added integration tests.
This commit is contained in:
Gusted 2024-10-23 00:48:46 +02:00 committed by Earl Warren
parent 00379db370
commit 266e0b2ce9
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
7 changed files with 139 additions and 37 deletions

View file

@ -1389,21 +1389,11 @@ func MergePullRequest(ctx *context.Context) {
log.Trace("Pull request merged: %d", pr.ID)
if form.DeleteBranchAfterMerge {
// Don't cleanup when other pr use this branch as head branch
exist, err := issues_model.HasUnmergedPullRequestsByHeadInfo(ctx, pr.HeadRepoID, pr.HeadBranch)
if err != nil {
ctx.ServerError("HasUnmergedPullRequestsByHeadInfo", err)
return
}
if exist {
ctx.JSONRedirect(issue.Link())
return
}
var headRepo *git.Repository
if ctx.Repo != nil && ctx.Repo.Repository != nil && pr.HeadRepoID == ctx.Repo.Repository.ID && ctx.Repo.GitRepo != nil {
headRepo = ctx.Repo.GitRepo
} else {
var err error
headRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo)
if err != nil {
ctx.ServerError(fmt.Sprintf("OpenRepository[%s]", pr.HeadRepo.FullName()), err)
@ -1411,7 +1401,22 @@ func MergePullRequest(ctx *context.Context) {
}
defer headRepo.Close()
}
deleteBranch(ctx, pr, headRepo)
if err := repo_service.DeleteBranchAfterMerge(ctx, ctx.Doer, pr, headRepo); err != nil {
switch {
case errors.Is(err, repo_service.ErrBranchIsDefault):
ctx.Flash.Error(ctx.Tr("repo.pulls.delete_after_merge.head_branch.is_default"))
case errors.Is(err, git_model.ErrBranchIsProtected):
ctx.Flash.Error(ctx.Tr("repo.pulls.delete_after_merge.head_branch.is_protected"))
case errors.Is(err, util.ErrPermissionDenied):
ctx.Flash.Error(ctx.Tr("repo.pulls.delete_after_merge.head_branch.insufficient_branch"))
default:
ctx.ServerError("DeleteBranchAfterMerge", err)
}
ctx.JSONRedirect(issue.Link())
return
}
}
ctx.JSONRedirect(issue.Link())