From 34c4b1c16686ec07beef6671684cc7f012a835a1 Mon Sep 17 00:00:00 2001 From: Marco Descher Date: Fri, 25 Aug 2017 15:01:57 +0200 Subject: [PATCH 1/6] Provide means to transfer files #162 --- hook/hook.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++--- webhook.go | 27 ++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/hook/hook.go b/hook/hook.go index 6fcda3e..0727911 100644 --- a/hook/hook.go +++ b/hook/hook.go @@ -4,11 +4,13 @@ import ( "crypto/hmac" "crypto/sha1" "crypto/sha256" + "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" "io/ioutil" + "log" "net" "net/textproto" "reflect" @@ -263,9 +265,11 @@ func ExtractParameterAsString(s string, params interface{}) (string, bool) { // Argument type specifies the parameter key name and the source it should // be extracted from type Argument struct { - Source string `json:"source,omitempty"` - Name string `json:"name,omitempty"` - EnvName string `json:"envname,omitempty"` + Source string `json:"source,omitempty"` + Name string `json:"name,omitempty"` + EnvName string `json:"envname,omitempty"` + FileName string `json:"filename,omitempty"` + Base64Decode bool `json:"base64decode,omitempty"` } // Get Argument method returns the value for the Argument's key name @@ -380,6 +384,7 @@ type Hook struct { CaptureCommandOutput bool `json:"include-command-output-in-response,omitempty"` PassEnvironmentToCommand []Argument `json:"pass-environment-to-command,omitempty"` PassArgumentsToCommand []Argument `json:"pass-arguments-to-command,omitempty"` + PassFileToCommand []Argument `json:"pass-file-to-command,omitempty"` JSONStringParameters []Argument `json:"parse-parameters-as-json,omitempty"` TriggerRule *Rules `json:"trigger-rule,omitempty"` TriggerRuleMismatchHttpResponseCode int `json:"trigger-rule-mismatch-http-response-code,omitempty"` @@ -489,6 +494,52 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string return args, nil } +// FileParameter describes a pass-file-to-command instance to be stored as file +type FileParameter struct { + Filename string + Data []byte +} + +// ExtractCommandArgumentsForFile creates a list of arguments in key=value +// format, based on the PassFileToCommand property that is ready to be used +// with exec.Command(). +func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[string]interface{}) ([]FileParameter, []error) { + var args = make([]FileParameter, 0) + var errors = make([]error, 0) + for i := range h.PassFileToCommand { + if arg, ok := h.PassFileToCommand[i].Get(headers, query, payload); ok { + + if h.PassFileToCommand[i].FileName == "" { + // if no filename is set, fall-back on the name + log.Printf("no filename specified, falling back to [%s]", EnvNamespace+h.PassFileToCommand[i].Name) + h.PassFileToCommand[i].FileName = EnvNamespace + h.PassFileToCommand[i].Name + } + + var fileContent []byte + if h.PassFileToCommand[i].Base64Decode { + dec, err := base64.StdEncoding.DecodeString(arg) + if err != nil { + log.Printf("error decoding string [%s]", err) + } + fileContent = []byte(dec) + } else { + fileContent = []byte(arg) + } + + args = append(args, FileParameter{Filename: h.PassFileToCommand[i].FileName, Data: fileContent}) + + } else { + errors = append(errors, &ArgumentError{h.PassFileToCommand[i]}) + } + } + + if len(errors) > 0 { + return args, errors + } + + return args, nil +} + // Hooks is an array of Hook objects type Hooks []Hook diff --git a/webhook.go b/webhook.go index 1034290..671794a 100644 --- a/webhook.go +++ b/webhook.go @@ -12,7 +12,7 @@ import ( "os/exec" "strings" - "github.com/adnanh/webhook/hook" + "./hook" "github.com/codegangsta/negroni" "github.com/gorilla/mux" @@ -333,6 +333,31 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b cmd.Env = append(os.Environ(), envs...) + var files []hook.FileParameter + files, errors = h.ExtractCommandArgumentsForFile(headers, query, payload) + + if errors != nil { + for _, err := range errors { + log.Printf("error extracting command arguments for file: %s\n", err) + } + } + + for i := range files { + var filename string + if h.CommandWorkingDirectory != "" { + filename = h.CommandWorkingDirectory + "/" + files[i].Filename + } else { + filename = files[i].Filename + } + + log.Printf("writing file %s", filename) + + err := ioutil.WriteFile(filename, files[i].Data, 0644) + if err != nil { + log.Printf("error writing file %s [%s]", filename, err) + } + } + log.Printf("executing %s (%s) with arguments %q and environment %s using %s as cwd\n", h.ExecuteCommand, cmd.Path, cmd.Args, envs, cmd.Dir) out, err := cmd.CombinedOutput() From 395fb41d23d25881203ad16d740cf9c9b6160f15 Mon Sep 17 00:00:00 2001 From: Marco Descher Date: Tue, 29 Aug 2017 14:42:14 +0200 Subject: [PATCH 2/6] Provide means to transfer files #162 add deleteOnExit --- hook/hook.go | 8 +++++--- webhook.go | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/hook/hook.go b/hook/hook.go index 0727911..0f42478 100644 --- a/hook/hook.go +++ b/hook/hook.go @@ -270,6 +270,7 @@ type Argument struct { EnvName string `json:"envname,omitempty"` FileName string `json:"filename,omitempty"` Base64Decode bool `json:"base64decode,omitempty"` + DeleteOnExit bool `json:"deleteOnExit,omitempty"` } // Get Argument method returns the value for the Argument's key name @@ -496,8 +497,9 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string // FileParameter describes a pass-file-to-command instance to be stored as file type FileParameter struct { - Filename string - Data []byte + Filename string + Data []byte + DeleteOnExit bool } // ExtractCommandArgumentsForFile creates a list of arguments in key=value @@ -526,7 +528,7 @@ func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[strin fileContent = []byte(arg) } - args = append(args, FileParameter{Filename: h.PassFileToCommand[i].FileName, Data: fileContent}) + args = append(args, FileParameter{Filename: h.PassFileToCommand[i].FileName, Data: fileContent, DeleteOnExit: h.PassFileToCommand[i].DeleteOnExit}) } else { errors = append(errors, &ArgumentError{h.PassFileToCommand[i]}) diff --git a/webhook.go b/webhook.go index 671794a..939b430 100644 --- a/webhook.go +++ b/webhook.go @@ -343,18 +343,14 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b } for i := range files { - var filename string if h.CommandWorkingDirectory != "" { - filename = h.CommandWorkingDirectory + "/" + files[i].Filename - } else { - filename = files[i].Filename + files[i].Filename = h.CommandWorkingDirectory + "/" + files[i].Filename } - log.Printf("writing file %s", filename) - - err := ioutil.WriteFile(filename, files[i].Data, 0644) + log.Printf("writing file %s", files[i].Filename) + err := ioutil.WriteFile(files[i].Filename, files[i].Data, 0644) if err != nil { - log.Printf("error writing file %s [%s]", filename, err) + log.Printf("error writing file %s [%s]", files[i].Filename, err) } } @@ -368,6 +364,16 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b log.Printf("error occurred: %+v\n", err) } + for i := range files { + if files[i].DeleteOnExit { + log.Printf("removing file: %s\n", files[i].Filename) + err := os.Remove(files[i].Filename) + if err != nil { + log.Printf("error removing file %s [%s]", files[i].Filename, err) + } + } + } + log.Printf("finished handling %s\n", h.ID) return string(out), err From 78aa85e0c185941863dbe1c1f318d84ef433174c Mon Sep 17 00:00:00 2001 From: Marco Descher Date: Wed, 30 Aug 2017 14:23:29 +0200 Subject: [PATCH 3/6] Revert to original hook import --- webhook.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/webhook.go b/webhook.go index 939b430..492c2ac 100644 --- a/webhook.go +++ b/webhook.go @@ -12,7 +12,7 @@ import ( "os/exec" "strings" - "./hook" + "github.com/adnanh/webhook/hook" "github.com/codegangsta/negroni" "github.com/gorilla/mux" @@ -333,8 +333,7 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b cmd.Env = append(os.Environ(), envs...) - var files []hook.FileParameter - files, errors = h.ExtractCommandArgumentsForFile(headers, query, payload) + files, errors := h.ExtractCommandArgumentsForFile(headers, query, payload) if errors != nil { for _, err := range errors { From 213e4529e8e51359c122ff7794930f5e1b74e072 Mon Sep 17 00:00:00 2001 From: Marco Descher Date: Fri, 15 Sep 2017 13:30:44 +0200 Subject: [PATCH 4/6] #162 do use temporary files, provide env variable --- hook/hook.go | 15 ++++++++------- webhook.go | 29 +++++++++++++++++------------ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/hook/hook.go b/hook/hook.go index 0f42478..d60ae26 100644 --- a/hook/hook.go +++ b/hook/hook.go @@ -13,6 +13,7 @@ import ( "log" "net" "net/textproto" + "os" "reflect" "regexp" "strconv" @@ -268,7 +269,6 @@ type Argument struct { Source string `json:"source,omitempty"` Name string `json:"name,omitempty"` EnvName string `json:"envname,omitempty"` - FileName string `json:"filename,omitempty"` Base64Decode bool `json:"base64decode,omitempty"` DeleteOnExit bool `json:"deleteOnExit,omitempty"` } @@ -497,7 +497,8 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string // FileParameter describes a pass-file-to-command instance to be stored as file type FileParameter struct { - Filename string + File *os.File + EnvName string Data []byte DeleteOnExit bool } @@ -511,10 +512,10 @@ func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[strin for i := range h.PassFileToCommand { if arg, ok := h.PassFileToCommand[i].Get(headers, query, payload); ok { - if h.PassFileToCommand[i].FileName == "" { - // if no filename is set, fall-back on the name - log.Printf("no filename specified, falling back to [%s]", EnvNamespace+h.PassFileToCommand[i].Name) - h.PassFileToCommand[i].FileName = EnvNamespace + h.PassFileToCommand[i].Name + if h.PassFileToCommand[i].EnvName == "" { + // if no environment-variable name is set, fall-back on the name + log.Printf("no ENVVAR name specified, falling back to [%s]", EnvNamespace+strings.ToUpper(h.PassFileToCommand[i].Name)) + h.PassFileToCommand[i].EnvName = EnvNamespace + strings.ToUpper(h.PassFileToCommand[i].Name) } var fileContent []byte @@ -528,7 +529,7 @@ func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[strin fileContent = []byte(arg) } - args = append(args, FileParameter{Filename: h.PassFileToCommand[i].FileName, Data: fileContent, DeleteOnExit: h.PassFileToCommand[i].DeleteOnExit}) + args = append(args, FileParameter{EnvName: h.PassFileToCommand[i].EnvName, Data: fileContent, DeleteOnExit: h.PassFileToCommand[i].DeleteOnExit}) } else { errors = append(errors, &ArgumentError{h.PassFileToCommand[i]}) diff --git a/webhook.go b/webhook.go index 492c2ac..fc943e5 100644 --- a/webhook.go +++ b/webhook.go @@ -331,8 +331,6 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b } } - cmd.Env = append(os.Environ(), envs...) - files, errors := h.ExtractCommandArgumentsForFile(headers, query, payload) if errors != nil { @@ -342,17 +340,24 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b } for i := range files { - if h.CommandWorkingDirectory != "" { - files[i].Filename = h.CommandWorkingDirectory + "/" + files[i].Filename + tmpfile, err := ioutil.TempFile(h.CommandWorkingDirectory, files[i].EnvName) + if err != nil { + log.Printf("error creating temp file [%s]", err) + } + log.Printf("writing env %s file %s", files[i].EnvName, tmpfile.Name()) + if _, err := tmpfile.Write(files[i].Data); err != nil { + log.Printf("error writing file %s [%s]", tmpfile.Name(), err) + } + if err := tmpfile.Close(); err != nil { + log.Printf("error closing file %s [%s]", tmpfile.Name(), err) } - log.Printf("writing file %s", files[i].Filename) - err := ioutil.WriteFile(files[i].Filename, files[i].Data, 0644) - if err != nil { - log.Printf("error writing file %s [%s]", files[i].Filename, err) - } + files[i].File = tmpfile + envs = append(envs, files[i].EnvName+"="+tmpfile.Name()) } + cmd.Env = append(os.Environ(), envs...) + log.Printf("executing %s (%s) with arguments %q and environment %s using %s as cwd\n", h.ExecuteCommand, cmd.Path, cmd.Args, envs, cmd.Dir) out, err := cmd.CombinedOutput() @@ -365,10 +370,10 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b for i := range files { if files[i].DeleteOnExit { - log.Printf("removing file: %s\n", files[i].Filename) - err := os.Remove(files[i].Filename) + log.Printf("removing file %s\n", files[i].File.Name()) + err := os.Remove(files[i].File.Name()) if err != nil { - log.Printf("error removing file %s [%s]", files[i].Filename, err) + log.Printf("error removing file %s [%s]", files[i].File.Name(), err) } } } From 614563467068ba1f7356e45dbf5dabd610d0188e Mon Sep 17 00:00:00 2001 From: Marco Descher Date: Tue, 7 Nov 2017 16:19:22 +0100 Subject: [PATCH 5/6] Adapt to #173 --- webhook.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/webhook.go b/webhook.go index 32331ce..58c28d2 100644 --- a/webhook.go +++ b/webhook.go @@ -355,21 +355,21 @@ func handleHook(h *hook.Hook, rid string, headers, query, payload *map[string]in if errors != nil { for _, err := range errors { - log.Printf("error extracting command arguments for file: %s\n", err) + log.Printf("[%s] error extracting command arguments for file: %s\n", rid, err) } } for i := range files { tmpfile, err := ioutil.TempFile(h.CommandWorkingDirectory, files[i].EnvName) if err != nil { - log.Printf("error creating temp file [%s]", err) + log.Printf("[%s] error creating temp file [%s]", rid, err) } - log.Printf("writing env %s file %s", files[i].EnvName, tmpfile.Name()) + log.Printf("[%s] writing env %s file %s", rid, files[i].EnvName, tmpfile.Name()) if _, err := tmpfile.Write(files[i].Data); err != nil { - log.Printf("error writing file %s [%s]", tmpfile.Name(), err) + log.Printf("[%s] error writing file %s [%s]", rid, tmpfile.Name(), err) } if err := tmpfile.Close(); err != nil { - log.Printf("error closing file %s [%s]", tmpfile.Name(), err) + log.Printf("[%s] error closing file %s [%s]", rid, tmpfile.Name(), err) } files[i].File = tmpfile From c9abc252e8e43e98eb97ca37fd92d162a3e59e7a Mon Sep 17 00:00:00 2001 From: Marco Descher Date: Tue, 7 Nov 2017 16:38:12 +0100 Subject: [PATCH 6/6] Delete hook files by default --- hook/hook.go | 10 +++--- hook/hook_test.go | 88 +++++++++++++++++++++++------------------------ webhook.go | 10 +++--- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/hook/hook.go b/hook/hook.go index d60ae26..47ae7dd 100644 --- a/hook/hook.go +++ b/hook/hook.go @@ -270,7 +270,6 @@ type Argument struct { Name string `json:"name,omitempty"` EnvName string `json:"envname,omitempty"` Base64Decode bool `json:"base64decode,omitempty"` - DeleteOnExit bool `json:"deleteOnExit,omitempty"` } // Get Argument method returns the value for the Argument's key name @@ -497,10 +496,9 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string // FileParameter describes a pass-file-to-command instance to be stored as file type FileParameter struct { - File *os.File - EnvName string - Data []byte - DeleteOnExit bool + File *os.File + EnvName string + Data []byte } // ExtractCommandArgumentsForFile creates a list of arguments in key=value @@ -529,7 +527,7 @@ func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[strin fileContent = []byte(arg) } - args = append(args, FileParameter{EnvName: h.PassFileToCommand[i].EnvName, Data: fileContent, DeleteOnExit: h.PassFileToCommand[i].DeleteOnExit}) + args = append(args, FileParameter{EnvName: h.PassFileToCommand[i].EnvName, Data: fileContent}) } else { errors = append(errors, &ArgumentError{h.PassFileToCommand[i]}) diff --git a/hook/hook_test.go b/hook/hook_test.go index dc83cf5..98be216 100644 --- a/hook/hook_test.go +++ b/hook/hook_test.go @@ -111,7 +111,7 @@ var argumentGetTests = []struct { func TestArgumentGet(t *testing.T) { for _, tt := range argumentGetTests { - a := Argument{tt.source, tt.name, ""} + a := Argument{tt.source, tt.name, "", false} value, ok := a.Get(tt.headers, tt.query, tt.payload) if ok != tt.ok || value != tt.value { t.Errorf("failed to get {%q, %q}:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, ok:%#v}", tt.source, tt.name, tt.value, tt.ok, value, ok) @@ -125,14 +125,14 @@ var hookParseJSONParametersTests = []struct { rheaders, rquery, rpayload *map[string]interface{} ok bool }{ - {[]Argument{Argument{"header", "a", ""}}, &map[string]interface{}{"A": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"A": map[string]interface{}{"b": "y"}}, nil, nil, true}, - {[]Argument{Argument{"url", "a", ""}}, nil, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}, nil, true}, - {[]Argument{Argument{"payload", "a", ""}}, nil, nil, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}, true}, - {[]Argument{Argument{"header", "z", ""}}, &map[string]interface{}{"Z": `{}`}, nil, nil, &map[string]interface{}{"Z": map[string]interface{}{}}, nil, nil, true}, + {[]Argument{Argument{"header", "a", "", false}}, &map[string]interface{}{"A": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"A": map[string]interface{}{"b": "y"}}, nil, nil, true}, + {[]Argument{Argument{"url", "a", "", false}}, nil, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}, nil, true}, + {[]Argument{Argument{"payload", "a", "", false}}, nil, nil, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}, true}, + {[]Argument{Argument{"header", "z", "", false}}, &map[string]interface{}{"Z": `{}`}, nil, nil, &map[string]interface{}{"Z": map[string]interface{}{}}, nil, nil, true}, // failures - {[]Argument{Argument{"header", "z", ""}}, &map[string]interface{}{"Z": ``}, nil, nil, &map[string]interface{}{"Z": ``}, nil, nil, false}, // empty string - {[]Argument{Argument{"header", "y", ""}}, &map[string]interface{}{"X": `{}`}, nil, nil, &map[string]interface{}{"X": `{}`}, nil, nil, false}, // missing parameter - {[]Argument{Argument{"string", "z", ""}}, &map[string]interface{}{"Z": ``}, nil, nil, &map[string]interface{}{"Z": ``}, nil, nil, false}, // invalid argument source + {[]Argument{Argument{"header", "z", "", false}}, &map[string]interface{}{"Z": ``}, nil, nil, &map[string]interface{}{"Z": ``}, nil, nil, false}, // empty string + {[]Argument{Argument{"header", "y", "", false}}, &map[string]interface{}{"X": `{}`}, nil, nil, &map[string]interface{}{"X": `{}`}, nil, nil, false}, // missing parameter + {[]Argument{Argument{"string", "z", "", false}}, &map[string]interface{}{"Z": ``}, nil, nil, &map[string]interface{}{"Z": ``}, nil, nil, false}, // invalid argument source } func TestHookParseJSONParameters(t *testing.T) { @@ -152,9 +152,9 @@ var hookExtractCommandArgumentsTests = []struct { value []string ok bool }{ - {"test", []Argument{Argument{"header", "a", ""}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{"test", "z"}, true}, + {"test", []Argument{Argument{"header", "a", "", false}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{"test", "z"}, true}, // failures - {"fail", []Argument{Argument{"payload", "a", ""}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{"fail", ""}, false}, + {"fail", []Argument{Argument{"payload", "a", "", false}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{"fail", ""}, false}, } func TestHookExtractCommandArguments(t *testing.T) { @@ -196,14 +196,14 @@ var hookExtractCommandArgumentsForEnvTests = []struct { // successes { "test", - []Argument{Argument{"header", "a", ""}}, + []Argument{Argument{"header", "a", "", false}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{"HOOK_a=z"}, true, }, { "test", - []Argument{Argument{"header", "a", "MYKEY"}}, + []Argument{Argument{"header", "a", "MYKEY", false}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{"MYKEY=z"}, true, @@ -211,7 +211,7 @@ var hookExtractCommandArgumentsForEnvTests = []struct { // failures { "fail", - []Argument{Argument{"payload", "a", ""}}, + []Argument{Argument{"payload", "a", "", false}}, &map[string]interface{}{"A": "z"}, nil, nil, []string{}, false, @@ -233,7 +233,7 @@ var hooksLoadFromFileTests = []struct { ok bool }{ {"../hooks.json.example", true}, - {"../hooks.yaml.example", true}, + {"../hooks.yaml.example", true}, {"", true}, // failures {"missing.json", false}, @@ -276,18 +276,18 @@ var matchRuleTests = []struct { ok bool err bool }{ - {"value", "", "", "z", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", true, false}, - {"regex", "^z", "", "z", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", true, false}, - {"payload-hash-sha1", "", "secret", "", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "b17e04cbb22afa8ffbff8796fc1894ed27badd9e"}, nil, nil, []byte(`{"a": "z"}`), "", true, false}, - {"payload-hash-sha256", "", "secret", "", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89"}, nil, nil, []byte(`{"a": "z"}`), "", true, false}, + {"value", "", "", "z", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", true, false}, + {"regex", "^z", "", "z", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", true, false}, + {"payload-hash-sha1", "", "secret", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "b17e04cbb22afa8ffbff8796fc1894ed27badd9e"}, nil, nil, []byte(`{"a": "z"}`), "", true, false}, + {"payload-hash-sha256", "", "secret", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89"}, nil, nil, []byte(`{"a": "z"}`), "", true, false}, // failures - {"value", "", "", "X", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, false}, - {"regex", "^X", "", "", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, false}, - {"value", "", "2", "X", "", Argument{"header", "a", ""}, &map[string]interface{}{"Y": "z"}, nil, nil, []byte{}, "", false, false}, // reference invalid header + {"value", "", "", "X", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, false}, + {"regex", "^X", "", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, false}, + {"value", "", "2", "X", "", Argument{"header", "a", "", false}, &map[string]interface{}{"Y": "z"}, nil, nil, []byte{}, "", false, false}, // reference invalid header // errors - {"regex", "*", "", "", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, true}, // invalid regex - {"payload-hash-sha1", "", "secret", "", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": ""}, nil, nil, []byte{}, "", false, true}, // invalid hmac - {"payload-hash-sha256", "", "secret", "", "", Argument{"header", "a", ""}, &map[string]interface{}{"A": ""}, nil, nil, []byte{}, "", false, true}, // invalid hmac + {"regex", "*", "", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, true}, // invalid regex + {"payload-hash-sha1", "", "secret", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": ""}, nil, nil, []byte{}, "", false, true}, // invalid hmac + {"payload-hash-sha256", "", "secret", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": ""}, nil, nil, []byte{}, "", false, true}, // invalid hmac // IP whitelisting, valid cases {"ip-whitelist", "", "", "", "192.168.0.1/24", Argument{}, nil, nil, nil, []byte{}, "192.168.0.2:9000", true, false}, // valid IPv4, with range {"ip-whitelist", "", "", "", "192.168.0.1/24", Argument{}, nil, nil, nil, []byte{}, "192.168.0.2:9000", true, false}, // valid IPv4, with range @@ -324,8 +324,8 @@ var andRuleTests = []struct { { "(a=z, b=y): a=z && b=y", AndRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", "", false}, ""}}, }, &map[string]interface{}{"A": "z", "B": "y"}, nil, nil, []byte{}, true, false, @@ -333,8 +333,8 @@ var andRuleTests = []struct { { "(a=z, b=Y): a=z && b=y", AndRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", "", false}, ""}}, }, &map[string]interface{}{"A": "z", "B": "Y"}, nil, nil, []byte{}, false, false, @@ -343,22 +343,22 @@ var andRuleTests = []struct { { "(a=z, b=y, c=x, d=w=, e=X, f=X): a=z && (b=y && c=x) && (d=w || e=v) && !f=u", AndRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, { And: &AndRule{ - {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "x", Argument{"header", "c", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "x", Argument{"header", "c", "", false}, ""}}, }, }, { Or: &OrRule{ - {Match: &MatchRule{"value", "", "", "w", Argument{"header", "d", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "v", Argument{"header", "e", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "w", Argument{"header", "d", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "v", Argument{"header", "e", "", false}, ""}}, }, }, { Not: &NotRule{ - Match: &MatchRule{"value", "", "", "u", Argument{"header", "f", ""}, ""}, + Match: &MatchRule{"value", "", "", "u", Argument{"header", "f", "", false}, ""}, }, }, }, @@ -369,7 +369,7 @@ var andRuleTests = []struct { // failures { "invalid rule", - AndRule{{Match: &MatchRule{"value", "", "", "X", Argument{"header", "a", ""}, ""}}}, + AndRule{{Match: &MatchRule{"value", "", "", "X", Argument{"header", "a", "", false}, ""}}}, &map[string]interface{}{"Y": "z"}, nil, nil, nil, false, false, }, @@ -395,8 +395,8 @@ var orRuleTests = []struct { { "(a=z, b=X): a=z || b=y", OrRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", "", false}, ""}}, }, &map[string]interface{}{"A": "z", "B": "X"}, nil, nil, []byte{}, true, false, @@ -404,8 +404,8 @@ var orRuleTests = []struct { { "(a=X, b=y): a=z || b=y", OrRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", "", false}, ""}}, }, &map[string]interface{}{"A": "X", "B": "y"}, nil, nil, []byte{}, true, false, @@ -413,8 +413,8 @@ var orRuleTests = []struct { { "(a=Z, b=Y): a=z || b=y", OrRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, - {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, + {Match: &MatchRule{"value", "", "", "y", Argument{"header", "b", "", false}, ""}}, }, &map[string]interface{}{"A": "Z", "B": "Y"}, nil, nil, []byte{}, false, false, @@ -423,7 +423,7 @@ var orRuleTests = []struct { { "invalid rule", OrRule{ - {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, + {Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, }, &map[string]interface{}{"Y": "Z"}, nil, nil, []byte{}, false, false, @@ -447,8 +447,8 @@ var notRuleTests = []struct { ok bool err bool }{ - {"(a=z): !a=X", NotRule{Match: &MatchRule{"value", "", "", "X", Argument{"header", "a", ""}, ""}}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, true, false}, - {"(a=z): !a=z", NotRule{Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", ""}, ""}}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, false, false}, + {"(a=z): !a=X", NotRule{Match: &MatchRule{"value", "", "", "X", Argument{"header", "a", "", false}, ""}}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, true, false}, + {"(a=z): !a=z", NotRule{Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, false, false}, } func TestNotRule(t *testing.T) { diff --git a/webhook.go b/webhook.go index 58c28d2..41b02b1 100644 --- a/webhook.go +++ b/webhook.go @@ -389,12 +389,10 @@ func handleHook(h *hook.Hook, rid string, headers, query, payload *map[string]in } for i := range files { - if files[i].DeleteOnExit { - log.Printf("[%s] removing file %s\n", rid, files[i].File.Name()) - err := os.Remove(files[i].File.Name()) - if err != nil { - log.Printf("[%s] error removing file %s [%s]", rid, files[i].File.Name(), err) - } + log.Printf("[%s] removing file %s\n", rid, files[i].File.Name()) + err := os.Remove(files[i].File.Name()) + if err != nil { + log.Printf("[%s] error removing file %s [%s]", rid, files[i].File.Name(), err) } }