diff options
author | WGH <wgh@torlan.ru> | 2019-09-09 08:48:21 +0300 |
---|---|---|
committer | Lauris BH <lauris.buksis@zzdats.lv> | 2019-09-09 08:48:21 +0300 |
commit | 6ddd3b0b470d16dfe62caf5fff21011cfff44a76 (patch) | |
tree | 05d4c7fedf8af21b489003890be000f839f69a51 /modules | |
parent | 0118b6aaf8ada3edd67cb975c776f6f124178ad2 (diff) | |
download | gitea-6ddd3b0b470d16dfe62caf5fff21011cfff44a76.tar.gz gitea-6ddd3b0b470d16dfe62caf5fff21011cfff44a76.zip |
Implement webhook branch filter (#7791)
* Fix validate() function to handle errors in embedded anon structs
* Implement webhook branch filter
See #2025, #3998.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/auth/auth.go | 17 | ||||
-rw-r--r-- | modules/auth/repo_form.go | 1 | ||||
-rw-r--r-- | modules/structs/hook.go | 12 | ||||
-rw-r--r-- | modules/validation/binding.go | 25 | ||||
-rw-r--r-- | modules/validation/binding_test.go | 5 | ||||
-rw-r--r-- | modules/validation/glob_pattern_test.go | 62 |
6 files changed, 106 insertions, 16 deletions
diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 68553941ec..624bb15cbf 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -310,6 +310,10 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro } data["HasError"] = true + // If the field with name errs[0].FieldNames[0] is not found in form + // somehow, some code later on will panic on Data["ErrorMsg"].(string). + // So initialize it to some default. + data["ErrorMsg"] = l.Tr("form.unknown_error") AssignForm(f, data) typ := reflect.TypeOf(f) @@ -320,16 +324,9 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro val = val.Elem() } - for i := 0; i < typ.NumField(); i++ { - field := typ.Field(i) - + if field, ok := typ.FieldByName(errs[0].FieldNames[0]); ok { fieldName := field.Tag.Get("form") - // Allow ignored fields in the struct - if fieldName == "-" { - continue - } - - if errs[0].FieldNames[0] == field.Name { + if fieldName != "-" { data["Err_"+field.Name] = true trName := field.Tag.Get("locale") @@ -360,6 +357,8 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro data["ErrorMsg"] = trName + l.Tr("form.url_error") case binding.ERR_INCLUDE: data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field)) + case validation.ErrGlobPattern: + data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message) default: data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification } diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 418f6d3874..56ae77a7f7 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -185,6 +185,7 @@ type WebhookForm struct { PullRequest bool Repository bool Active bool + BranchFilter string `binding:"GlobPattern"` } // PushOnly if the hook will be triggered when push diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 8dae578ec6..9a25219e36 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -40,17 +40,19 @@ type CreateHookOption struct { // enum: gitea,gogs,slack,discord Type string `json:"type" binding:"Required"` // required: true - Config map[string]string `json:"config" binding:"Required"` - Events []string `json:"events"` + Config map[string]string `json:"config" binding:"Required"` + Events []string `json:"events"` + BranchFilter string `json:"branch_filter" binding:"GlobPattern"` // default: false Active bool `json:"active"` } // EditHookOption options when modify one hook type EditHookOption struct { - Config map[string]string `json:"config"` - Events []string `json:"events"` - Active *bool `json:"active"` + Config map[string]string `json:"config"` + Events []string `json:"events"` + BranchFilter string `json:"branch_filter" binding:"GlobPattern"` + Active *bool `json:"active"` } // Payloader payload is some part of one hook diff --git a/modules/validation/binding.go b/modules/validation/binding.go index fc420e62fb..6ed75b50fb 100644 --- a/modules/validation/binding.go +++ b/modules/validation/binding.go @@ -10,11 +10,15 @@ import ( "strings" "gitea.com/macaron/binding" + "github.com/gobwas/glob" ) const ( // ErrGitRefName is git reference name error ErrGitRefName = "GitRefNameError" + + // ErrGlobPattern is returned when glob pattern is invalid + ErrGlobPattern = "GlobPattern" ) var ( @@ -28,6 +32,7 @@ var ( func AddBindingRules() { addGitRefNameBindingRule() addValidURLBindingRule() + addGlobPatternRule() } func addGitRefNameBindingRule() { @@ -82,6 +87,26 @@ func addValidURLBindingRule() { }) } +func addGlobPatternRule() { + binding.AddRule(&binding.Rule{ + IsMatch: func(rule string) bool { + return rule == "GlobPattern" + }, + IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) { + str := fmt.Sprintf("%v", val) + + if len(str) != 0 { + if _, err := glob.Compile(str); err != nil { + errs.Add([]string{name}, ErrGlobPattern, err.Error()) + return false, errs + } + } + + return true, errs + }, + }) +} + func portOnly(hostport string) string { colon := strings.IndexByte(hostport, ':') if colon == -1 { diff --git a/modules/validation/binding_test.go b/modules/validation/binding_test.go index 5ac88c9317..9fc9a6db08 100644 --- a/modules/validation/binding_test.go +++ b/modules/validation/binding_test.go @@ -26,8 +26,9 @@ type ( } TestForm struct { - BranchName string `form:"BranchName" binding:"GitRefName"` - URL string `form:"ValidUrl" binding:"ValidUrl"` + BranchName string `form:"BranchName" binding:"GitRefName"` + URL string `form:"ValidUrl" binding:"ValidUrl"` + GlobPattern string `form:"GlobPattern" binding:"GlobPattern"` } ) diff --git a/modules/validation/glob_pattern_test.go b/modules/validation/glob_pattern_test.go new file mode 100644 index 0000000000..26775167b4 --- /dev/null +++ b/modules/validation/glob_pattern_test.go @@ -0,0 +1,62 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package validation + +import ( + "testing" + + "gitea.com/macaron/binding" + "github.com/gobwas/glob" +) + +func getGlobPatternErrorString(pattern string) string { + // It would be unwise to rely on that glob + // compilation errors don't ever change. + if _, err := glob.Compile(pattern); err != nil { + return err.Error() + } + return "" +} + +var globValidationTestCases = []validationTestCase{ + { + description: "Empty glob pattern", + data: TestForm{ + GlobPattern: "", + }, + expectedErrors: binding.Errors{}, + }, + { + description: "Valid glob", + data: TestForm{ + GlobPattern: "{master,release*}", + }, + expectedErrors: binding.Errors{}, + }, + + { + description: "Invalid glob", + data: TestForm{ + GlobPattern: "[a-", + }, + expectedErrors: binding.Errors{ + binding.Error{ + FieldNames: []string{"GlobPattern"}, + Classification: ErrGlobPattern, + Message: getGlobPatternErrorString("[a-"), + }, + }, + }, +} + +func Test_GlobPatternValidation(t *testing.T) { + AddBindingRules() + + for _, testCase := range globValidationTestCases { + t.Run(testCase.description, func(t *testing.T) { + performValidationTest(t, testCase) + }) + } +} |