diff --git a/README.md b/README.md index 6bdc7a09..85239005 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ $ go get github.com/adnanh/webhook to get the latest version of the [webhook](https://github.com/adnanh/webhook/). ### Using package manager -#### Debian "sid" -If you are using unstable version of Debian linux ("sid"), you can install webhook using `apt-get install webhook` which will install community packaged version (thanks [@freeekanayaka](https://github.com/freeekanayaka)) from https://packages.debian.org/sid/webhook +#### Debian +If you are using Debian linux ("stretch" or later), you can install webhook using `apt-get install webhook` which will install community packaged version (thanks [@freeekanayaka](https://github.com/freeekanayaka)) from https://packages.debian.org/sid/webhook ### Download prebuilt binaries Prebuilt binaries for different architectures are available at [GitHub Releases](https://github.com/adnanh/webhook/releases). diff --git a/webhook.go b/webhook.go index 1034290c..12731c8a 100644 --- a/webhook.go +++ b/webhook.go @@ -155,11 +155,11 @@ func main() { l.SetFormat("{{.Status}} | {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n") - standardLogger := log.New(os.Stdout, "[webhook] ", log.Ldate|log.Ltime) + standardLogger := log.New(os.Stdout, "[webhook] ", log.Ldate|log.Ltime) - if !*verbose { - standardLogger.SetOutput(ioutil.Discard) - } + if !*verbose { + standardLogger.SetOutput(ioutil.Discard) + } l.ALogger = standardLogger @@ -312,7 +312,21 @@ func hookHandler(w http.ResponseWriter, r *http.Request) { func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, body *[]byte) (string, error) { var errors []error - cmd := exec.Command(h.ExecuteCommand) + // check the command exists + cmdPath, err := exec.LookPath(h.ExecuteCommand) + if err != nil { + log.Printf("unable to locate command: '%s'", h.ExecuteCommand) + + // check if parameters specified in execute-command by mistake + if strings.IndexByte(h.ExecuteCommand, ' ') != -1 { + s := strings.Fields(h.ExecuteCommand)[0] + log.Printf("use 'pass-arguments-to-command' to specify args for '%s'", s) + } + + return "", err + } + + cmd := exec.Command(cmdPath) cmd.Dir = h.CommandWorkingDirectory cmd.Args, errors = h.ExtractCommandArguments(headers, query, payload) diff --git a/webhook_test.go b/webhook_test.go index 5b3c760e..f7419707 100644 --- a/webhook_test.go +++ b/webhook_test.go @@ -1,13 +1,16 @@ package main import ( + "bytes" "fmt" "io/ioutil" + "log" "net" "net/http" "os" "os/exec" "path/filepath" + "regexp" "runtime" "strings" "testing" @@ -17,6 +20,91 @@ import ( "github.com/adnanh/webhook/hook" ) +func TestStaticParams(t *testing.T) { + + spHeaders := make(map[string]interface{}) + spHeaders["User-Agent"] = "curl/7.54.0" + spHeaders["Accept"] = "*/*" + + // case 1: correct entry + spHook := &hook.Hook{ + ID: "static-params-ok", + ExecuteCommand: "/bin/echo", + CommandWorkingDirectory: "/tmp", + ResponseMessage: "success", + CaptureCommandOutput: true, + PassArgumentsToCommand: []hook.Argument{ + hook.Argument{Source: "string", Name: "passed"}, + }, + } + + b := &bytes.Buffer{} + log.SetOutput(b) + + s, err := handleHook(spHook, &spHeaders, &map[string]interface{}{}, &map[string]interface{}{}, &[]byte{}) + if err != nil { + t.Fatalf("Unexpected error: %v\n", err) + } + matched, _ := regexp.MatchString("(?s).*command output: passed.*static-params-ok", b.String()) + if !matched { + t.Fatalf("Unexpected log output:\n%s", b) + } + + // case 2: binary with spaces in its name + err = os.Symlink("/usr/bin/true", "/tmp/with space") + if err != nil { + t.Fatalf("%v", err) + } + defer os.Remove("/tmp/with space") + + spHook = &hook.Hook{ + ID: "static-params-name-space", + ExecuteCommand: "/tmp/with space", + CommandWorkingDirectory: "/tmp", + ResponseMessage: "success", + CaptureCommandOutput: true, + PassArgumentsToCommand: []hook.Argument{ + hook.Argument{Source: "string", Name: "passed"}, + }, + } + + b = &bytes.Buffer{} + log.SetOutput(b) + + s, err = handleHook(spHook, &spHeaders, &map[string]interface{}{}, &map[string]interface{}{}, &[]byte{}) + if err != nil { + t.Fatalf("Unexpected error: %v\n", err) + } + matched, _ = regexp.MatchString("(?s)command output: .*static-params-name-space", b.String()) + if !matched { + t.Fatalf("Unexpected log output:\n%sn", b) + } + + // case 3: parameters specified in execute-command + spHook = &hook.Hook{ + ID: "static-params-bad", + ExecuteCommand: "/bin/echo success", + CommandWorkingDirectory: "/tmp", + ResponseMessage: "success", + CaptureCommandOutput: true, + PassArgumentsToCommand: []hook.Argument{ + hook.Argument{Source: "string", Name: "failed"}, + }, + } + + b = &bytes.Buffer{} + log.SetOutput(b) + + s, err = handleHook(spHook, &spHeaders, &map[string]interface{}{}, &map[string]interface{}{}, &[]byte{}) + if err == nil { + t.Fatalf("Error expected, but none returned: %s\n", s) + } + matched, _ = regexp.MatchString("(?s)unable to locate command: ..bin.echo success.*use 'pass-arguments-to-command'", b.String()) + if !matched { + t.Fatalf("Unexpected log output:\n%s\n", b) + } +} + func TestWebhook(t *testing.T) { hookecho, cleanupHookecho := buildHookecho(t) defer cleanupHookecho()