fix(webhook): prevent tag events from bypassing branch filters targets (#35567) (#35577)

Backport #35567 by Exgene

Co-authored-by: Kausthubh J Rao <105716675+Exgene@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
Giteabot
2025-10-04 01:49:16 +08:00
committed by GitHub
parent 6c8879b832
commit d94faf6d7e
7 changed files with 83 additions and 34 deletions

View File

@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
@@ -46,21 +45,25 @@ func IsValidHookTaskType(name string) bool {
// hookQueue is a global queue of web hooks
var hookQueue *queue.WorkerPoolQueue[int64]
// getPayloadBranch returns branch for hook event, if applicable.
func getPayloadBranch(p api.Payloader) string {
// getPayloadRef returns the full ref name for hook event, if applicable.
func getPayloadRef(p api.Payloader) git.RefName {
switch pp := p.(type) {
case *api.CreatePayload:
if pp.RefType == "branch" {
return pp.Ref
switch pp.RefType {
case "branch":
return git.RefNameFromBranch(pp.Ref)
case "tag":
return git.RefNameFromTag(pp.Ref)
}
case *api.DeletePayload:
if pp.RefType == "branch" {
return pp.Ref
switch pp.RefType {
case "branch":
return git.RefNameFromBranch(pp.Ref)
case "tag":
return git.RefNameFromTag(pp.Ref)
}
case *api.PushPayload:
if strings.HasPrefix(pp.Ref, git.BranchPrefix) {
return pp.Ref[len(git.BranchPrefix):]
}
return git.RefName(pp.Ref)
}
return ""
}
@@ -108,19 +111,22 @@ func enqueueHookTask(taskID int64) error {
return nil
}
func checkBranch(w *webhook_model.Webhook, branch string) bool {
if w.BranchFilter == "" || w.BranchFilter == "*" {
func checkBranchFilter(branchFilter string, ref git.RefName) bool {
if branchFilter == "" || branchFilter == "*" || branchFilter == "**" {
return true
}
g, err := glob.Compile(w.BranchFilter)
g, err := glob.Compile(branchFilter)
if err != nil {
// should not really happen as BranchFilter is validated
log.Error("CheckBranch failed: %s", err)
log.Debug("checkBranchFilter failed to compile filer %q, err: %s", branchFilter, err)
return false
}
return g.Match(branch)
if ref.IsBranch() && g.Match(ref.BranchName()) {
return true
}
return g.Match(ref.String())
}
// PrepareWebhook creates a hook task and enqueues it for processing.
@@ -144,11 +150,10 @@ func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook
return nil
}
// If payload has no associated branch (e.g. it's a new tag, issue, etc.),
// branch filter has no effect.
if branch := getPayloadBranch(p); branch != "" {
if !checkBranch(w, branch) {
log.Info("Branch %q doesn't match branch filter %q, skipping", branch, w.BranchFilter)
// If payload has no associated branch (e.g. it's a new tag, issue, etc.), branch filter has no effect.
if ref := getPayloadRef(p); ref != "" {
// Check the payload's git ref against the webhook's branch filter.
if !checkBranchFilter(w.BranchFilter, ref) {
return nil
}
}