diff --git a/.drone.sec b/.drone.sec index 3e37d3c..0fdefce 100644 --- a/.drone.sec +++ b/.drone.sec @@ -1 +1 @@ -eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Hsd15sfwSET0yXg92mosT1cs-1kiyW7VZlSZiWKkIu4EKDWnslBPZzbTKVi9OY4lXKJmXuAo38E3wtj5EvD7GA5azd090-Rnv-VOrQfXNmjZd9jxc7861IWQOFZb9XEDQZF6X2JM8fK_psSs6mrew9BjuOx6ws68h-zTl8ttcjHZC3Y7SZ5AjYj5i4T-Z0hJpLk2kwjCYF3SH599R3L3kZxDi6IcO9qW_Lj6zcBT5SttLgikUpvHwY409pbFBohl-AVhCZuDuyJPDns4n7jjWj4sELH4w-8dbc5oijzxI1FoxnUhXTRsrwNgfgCBAFM_umXGXLHAQlb2QzH2JHtB6g.rednhhAPc9V-KExp.qf0pSc_4pCgKIgK5T03yEmWz1yF5u2S0lSDBAvu7yOeCl469QBRIOxCv_RHImCG4tjOwYZjNaS8gaKVIoNNtxhKxC04Y2G7pxYDgNh2pU-sJOi05A1BaIbdIC209uK0r-mKkX_hfMDtNNWuOCyHXju4ugbNHwH64KvLzy4_RfFa0n9AOhpS1xNT3aa_eJvj0RQCfFs10BckWJoGlIfbS6VMyeeHeQEX6QWFSauxUwUPOAvrRlNjtNSxxVvNr1CbJso_8Cl0frD8DELaWxu3uKvLkSm2_GVMjPbvmZIqvcVxpxYnFMjwngQOAqnmiI-n_3LlO-dZb-Gf5AwN2F61PQDKXkdOcNiM4bNU_V11VKHP_BCJpVcaL6detQLNzHIuyU93zbw.fkefbX3B_-97eQdiQcyCYQ \ No newline at end of file +eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Hsd15sfwSET0yXg92mosT1cs-1kiyW7VZlSZiWKkIu4EKDWnslBPZzbTKVi9OY4lXKJmXuAo38E3wtj5EvD7GA5azd090-Rnv-VOrQfXNmjZd9jxc7861IWQOFZb9XEDQZF6X2JM8fK_psSs6mrew9BjuOx6ws68h-zTl8ttcjHZC3Y7SZ5AjYj5i4T-Z0hJpLk2kwjCYF3SH599R3L3kZxDi6IcO9qW_Lj6zcBT5SttLgikUpvHwY409pbFBohl-AVhCZuDuyJPDns4n7jjWj4sELH4w-8dbc5oijzxI1FoxnUhXTRsrwNgfgCBAFM_umXGXLHAQlb2QzH2JHtB6g.rednhhAPc9V-KExp.qf0pSc_4pCgKIgK5T03yEmWz1yF5u2S0lSDBAvu7yOeCl469QBRIOxCv_RHImCG4tjOwYZjNaS8gaKVIoNNtxhKxC04Y2G7pxYDgNh2pU-sJOi05A1BaIbdIC209uK0r-mKkX_hfMDtNNWuOCyHXju4ugbNHwH64KvLzy4_RfFa0n9AOhpS1xNT3aa_eJvj0RQCfFs10BckWJoGlIfbS6VMyeeHeQEX6QWFSauxUwUPOAvrRlNjtNSxxVvNr1CbJso_8Cl0frD8DELaWxu3uKvLkSm2_GVMjPbvmZIqvcVxpxYnFMjwngQOAqnmiI-n_3LlO-dZb-Gf5AwN2F61PQDKXkdOcNiM4bNU_V11VKHP_BCJpVcaL6detQLNzHIuyU93zbw.fkefbX3B_-97eQdiQcyCYQ diff --git a/DOCS.md b/DOCS.md index 637bb2e..091990a 100644 --- a/DOCS.md +++ b/DOCS.md @@ -83,4 +83,77 @@ notify: repo: {{.Repo.FullName}} build: {{.Build.Number}} commit: {{.Build.Commit}} -``` \ No newline at end of file +``` + +## Basic Authentication + +>It is important to note that with HTTP Basic Authentication the provided username and password are not encrypted. + +In some cases your webhook may need to authenticate with another service. You can set the basic `Authentication` header with a username and password. For these use cases we expose the following additional parameters: + +* `auth` - Sets the request's `Authorization` header to use HTTP Basic Authentication with the provided username and password below. + * `username` - The username as a string. + * `password` - The password as a string. + +Example configuration to include HTTP Basic Authentication: + +```yaml +notify: + webhook: + method: POST + auth: + username: $$USERNAME + password: $$PASSWORD + urls: + - https://tower.example.com/... + content_type: application/yaml + template: > + repo: {{.Repo.FullName}} + build: {{.Build.Number}} + commit: {{.Build.Commit}} +``` + +## Debugging Webhooks + +>If you have private variables that are encrypted and hidden in `.drone.sec`, remember that the `debug` flag may print out those sensitive values. Please use `dubug: true` wisely. + +In some cases complicated webhooks may need debugging to ensure `urls`, `template`, `auth` and more a properly configured. For these use cases we expose the following `debug` parameter: + +* `debug` - If `debug: true` it will print out each URL request and response information. + +Example configuration to include the `debug` parameter: + +```yaml +notify: + webhook: + debug: true + method: POST + auth: + username: $$TOWER_USER + password: $$TOWER_PASS + urls: + - http://tower.example.com/api/v1/job_templates/44/launch/ + - http://tower.example.com/api/v1/job_templates/45/launch/ + content_type: application/json + template: '{"name": "project.deploy","extra_vars": "{\"env\": \"dev\",\"git_branch\": \"{{ .Build.Branch }}\",\"hipchat_token\": \"$$HIPCHAT_TOKEN\"}"}' +``` + +Example of a debug print result: + +```yaml +[debug] Webhook 1 + URL: http://tower.example.com/api/v1/job_templates/44/launch/ + METHOD: POST + HEADERS: map[Content-Type:[application/json] Authorization:[Basic EMfNB3fakB8EMfNB3fakB8==]] + REQUEST BODY: {"name": "project.deploy","extra_vars": "{\"env\": \"dev\",\"git_branch\": \"develop\",\"hipchat_token\": \"h1pchatT0k3n\"}"} + RESPONSE STATUS: 202 ACCEPTED + RESPONSE BODY: {"job": 236} + +[debug] Webhook 2 + URL: http://tower.example.com/api/v1/job_templates/45/launch/ + METHOD: POST + HEADERS: map[Content-Type:[application/json] Authorization:[Basic EMfNB3fakB8EMfNB3fakB8==]] + REQUEST BODY: {"name": "project.deploy","extra_vars": "{\"env\": \"dev\",\"git_branch\": \"develop\",\"hipchat_token\": \"h1pchatT0k3n\"}"} + RESPONSE STATUS: 202 ACCEPTED + RESPONSE BODY: {"job": 406} +``` diff --git a/Dockerfile b/Dockerfile index 5ce7091..e1fb93b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # CGO_ENABLED=0 go build -a -tags netgo # docker build --rm=true -t plugins/drone-webhook . -FROM gliderlabs/alpine:3.1 +FROM gliderlabs/alpine:3.2 RUN apk-install ca-certificates ADD drone-webhook /bin/ ENTRYPOINT ["/bin/drone-webhook"] diff --git a/README.md b/README.md index 494fafc..afdd537 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # drone-webhook -Drone plugin for sending Webhook notifications by [@chromakode](https://github.com/chromakode). +Drone plugin for sending Webhook notifications. ## Overview @@ -25,7 +25,18 @@ This plugin is responsible for sending build notifications via Webhooks: "author_email": "john.smith@gmail.com" }, "vargs": { - "urls": [ "https://your.webhook/..." ] + "urls": ["https://your.webhook/..."], + "debug": true, + "auth": { + "username": "johnsmith", + "password": "secretPass" + }, + "headers": { + "SomeHeader": "SomeHeaderValue" + }, + "method": "POST", + "template": "{\"git_branch\": \"{{ .Build.Branch }}\"}", + "content_type": "application/json" } } EOF @@ -63,7 +74,18 @@ docker run -i plugins/drone-webhook < 0 { + if len(vargs.Auth.Password) > 0 { + req.SetBasicAuth(vargs.Auth.Username, vargs.Auth.Password) + } else { + req.SetBasicAuth(vargs.Auth.Username, "") + } + } + resp, err := http.DefaultClient.Do(req) if err != nil { fmt.Printf("Error executing http request. %s\n", err) os.Exit(1) } - resp.Body.Close() + defer resp.Body.Close() + + // if debug is on or response status code is bad + if vargs.Debug || resp.StatusCode >= http.StatusBadRequest { + + // read the response body + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + // I do not think we need to os.Exit(1) if we are + // unable to read a http response body. + fmt.Printf("Error reading http response body. %s\n", err) + } + + // debug/info print + if vargs.Debug { + fmt.Printf("[debug] Webhook %d\n URL: %s\n METHOD: %s\n HEADERS: %s\n REQUEST BODY: %s\n RESPONSE STATUS: %s\n RESPONSE BODY: %s\n", i+1, req.URL, req.Method, req.Header, string(b), resp.Status, string(body)) + } else { + fmt.Printf("[info] Webhook %d\n URL: %s\n RESPONSE STATUS: %s\n RESPONSE BODY: %s\n", i+1, req.URL, resp.Status, string(body)) + } + } } } diff --git a/webhook.go b/webhook.go new file mode 100644 index 0000000..80ffb2c --- /dev/null +++ b/webhook.go @@ -0,0 +1,16 @@ +package main + +type Webhook struct { + Urls []string `json:"urls"` + Debug bool `json:"debug"` + Auth BasicAuth `json:"auth"` + Headers map[string]string `json:"header"` + Method string `json:"method"` + Template string `json:"template"` + ContentType string `json:"content_type"` +} + +type BasicAuth struct { + Username string `json:"username"` + Password string `json:"password"` +}