From f89b09bef6d8d4d9d27728265fea1166aecc0fbd Mon Sep 17 00:00:00 2001 From: Ian Roberts Date: Sun, 27 Oct 2024 16:27:31 +0000 Subject: [PATCH 01/10] fix: use CGO_ENABLED=0 for release builds (#705) Ensure that release builds are built with cgo disabled. This is usually the case for cross-compiled builds anyway, but adding this flag makes builds consistent regardless of what platform they are being built on. In particular, without CGO_ENABLED=0, if you make the release builds on a linux/amd64 system then the linux/amd64 binary is dynamically linked against the system libc, meaning a binary built on a glibc-based system like Ubuntu will not work on a musl libc system like Alpine. This is what appears to have happened for release 2.8.1. But the same source code built on a different system (e.g. darwin/arm64) would cross-compile the linux/amd64 binary with cgo disabled, making a static binary that works on both glibc and musl systems. This is what appears to have happened for release 2.8.2. Setting CGO_ENABLED=0 in the Makefile will make the behaviour consistent for future releases, producing static binaries for the linux builds in all cases, whatever the build platform. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1a06482..903b7a3 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ release: clean deps ## Generate releases for unix systems do \ echo "Building $$os-$$arch"; \ mkdir -p build/webhook-$$os-$$arch/; \ - GOOS=$$os GOARCH=$$arch go build -o build/webhook-$$os-$$arch/webhook; \ + CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -o build/webhook-$$os-$$arch/webhook; \ tar cz -C build -f build/webhook-$$os-$$arch.tar.gz webhook-$$os-$$arch; \ done \ done From ce08a68a13c9cd56a4a12cf00c72c1922c2d9e18 Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Tue, 12 Nov 2024 23:01:26 -0600 Subject: [PATCH 02/10] docs: remove reference to Hookecho (#711) --- docs/Hook-Examples.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Hook-Examples.md b/docs/Hook-Examples.md index 7d07932..1b01ea4 100644 --- a/docs/Hook-Examples.md +++ b/docs/Hook-Examples.md @@ -498,7 +498,8 @@ A reference to the second item in the array would look like this: [ { "id": "sendgrid", - "execute-command": "{{ .Hookecho }}", + "execute-command": "/root/my-server/deployment.sh", + "command-working-directory": "/root/my-server", "trigger-rule": { "match": { "type": "value", From 7bb680821daf096961632ecc34c1bcaa4bf5573c Mon Sep 17 00:00:00 2001 From: Phil Leggetter Date: Sat, 30 Nov 2024 21:41:50 +0000 Subject: [PATCH 03/10] update Hookdeck images (light and dark) and description (#713) --- README.md | 4 ++-- images/hookdeck-black.svg | 11 +++++++++++ images/hookdeck-white.svg | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 images/hookdeck-black.svg create mode 100644 images/hookdeck-white.svg diff --git a/README.md b/README.md index c9b43a5..279c494 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ If you use Mattermost or Slack, you can set up an "Outgoing webhook integration" Everything else is the responsibility of the command's author. ## Not what you're looking for? -| hookdoo | hookdeck | +| hookdoo | hookdeck | | :-: | :-: | -| Scriptable webhook gateway to safely run your custom builds, deploys, and proxy scripts on your servers. | Inspect, monitor and replay webhooks without the back and forth troubleshooting. | +| Scriptable webhook gateway to safely run your custom builds, deploys, and proxy scripts on your servers. | An event gateway to reliably ingest, verify, queue, transform, filter, inspect, monitor, and replay webhooks. | # Getting started diff --git a/images/hookdeck-black.svg b/images/hookdeck-black.svg new file mode 100644 index 0000000..962b07d --- /dev/null +++ b/images/hookdeck-black.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/hookdeck-white.svg b/images/hookdeck-white.svg new file mode 100644 index 0000000..19afbbf --- /dev/null +++ b/images/hookdeck-white.svg @@ -0,0 +1 @@ + \ No newline at end of file From eb7e8f5ba827ee4c2b6dc687a4d9685d5f207386 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Sun, 12 Jan 2025 00:42:22 +0100 Subject: [PATCH 04/10] feat: Add two template functions (#712) * chore: replace ioutil.ReadFile by os.ReadFile * feat: Add two template functions - cat: Allows reading a value from a file - credential: Allows reading a credential passed by systemd --- internal/hook/hook.go | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/internal/hook/hook.go b/internal/hook/hook.go index 6699eeb..1796e1c 100644 --- a/internal/hook/hook.go +++ b/internal/hook/hook.go @@ -13,12 +13,12 @@ import ( "errors" "fmt" "hash" - "io/ioutil" "log" "math" "net" "net/textproto" "os" + "path" "reflect" "regexp" "strconv" @@ -750,14 +750,18 @@ func (h *Hooks) LoadFromFile(path string, asTemplate bool) error { } // parse hook file for hooks - file, e := ioutil.ReadFile(path) + file, e := os.ReadFile(path) if e != nil { return e } if asTemplate { - funcMap := template.FuncMap{"getenv": getenv} + funcMap := template.FuncMap{ + "cat": cat, + "credential": credential, + "getenv": getenv, + } tmpl, err := template.New("hooks").Funcs(funcMap).Parse(string(file)) if err != nil { @@ -956,3 +960,27 @@ func compare(a, b string) bool { func getenv(s string) string { return os.Getenv(s) } + +// cat provides a template function to retrieve content of files +// Similarly to getenv, if no file is found, it returns the empty string +func cat(s string) string { + data, e := os.ReadFile(s) + + if e != nil { + return "" + } + + return string(data) +} + +// credential provides a template function to retreive secrets using systemd's LoadCredential mechanism +func credential(s string) string { + dir := getenv("CREDENTIALS_DIRECTORY") + + // If no credential directory is found, fallback to the env variable + if dir == "" { + return getenv(s) + } + + return cat(path.Join(dir, s)) +} From 1b1335519635bdd210a071404c8f05cb26026c3d Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Sun, 12 Jan 2025 12:27:16 +0100 Subject: [PATCH 05/10] fix: Trim the cat output (#720) `os.ReadFile` includes a trailing EOL, so we have to remove it to get the correct value --- internal/hook/hook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/hook/hook.go b/internal/hook/hook.go index 1796e1c..394dd79 100644 --- a/internal/hook/hook.go +++ b/internal/hook/hook.go @@ -970,7 +970,7 @@ func cat(s string) string { return "" } - return string(data) + return strings.TrimSuffix(string(data), "\n") } // credential provides a template function to retreive secrets using systemd's LoadCredential mechanism From 5981da27170faf39050b21a831c0b628c8663b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20Erdem=20Seyfi?= <43253140+kugurerdem@users.noreply.github.com> Date: Tue, 12 Aug 2025 00:00:21 +0300 Subject: [PATCH 06/10] docs: update README.md (#733) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 279c494..20dd6a8 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ Check out [Hook examples page](docs/Hook-Examples.md) for more complex examples - [Using Prometheus to Automatically Scale WebLogic Clusters on Kubernetes](https://blogs.oracle.com/weblogicserver/using-prometheus-to-automatically-scale-weblogic-clusters-on-kubernetes-v5) by [Marina Kogan](https://blogs.oracle.com/author/9a4fe754-1cc2-4c64-95fc-360642b62927) - [Github Pages and Jekyll - A New Platform for LACNIC Labs](https://labs.lacnic.net/a-new-platform-for-lacniclabs/) by [Carlos Martínez Cagnazzo](https://twitter.com/carlosm3011) - [How to Deploy React Apps Using Webhooks and Integrating Slack on Ubuntu](https://www.alibabacloud.com/blog/how-to-deploy-react-apps-using-webhooks-and-integrating-slack-on-ubuntu_594116) by Arslan Ud Din Shafiq - - [Private webhooks](https://ihateithe.re/2018/01/private-webhooks/) by [Thomas](https://ihateithe.re/colophon/) + - [Private webhooks](https://tmertz.com/2018/01/private-webhooks/) by [Thomas](https://tmertz.com) - [Adventures in webhooks](https://medium.com/@draketech/adventures-in-webhooks-2d6584501c62) by [Drake](https://medium.com/@draketech) - [GitHub pro tips](http://notes.spencerlyon.com/2016/01/04/github-pro-tips/) by [Spencer Lyon](http://notes.spencerlyon.com/) - [XiaoMi Vacuum + Amazon Button = Dash Cleaning](https://www.instructables.com/id/XiaoMi-Vacuum-Amazon-Button-Dash-Cleaning/) by [c0mmensal](https://www.instructables.com/member/c0mmensal/) From 2da9957e86f184783d6dbb92aba2185300377f97 Mon Sep 17 00:00:00 2001 From: Tom <22802157+tomdess@users.noreply.github.com> Date: Mon, 11 Aug 2025 23:01:42 +0200 Subject: [PATCH 07/10] docs: add ACR webhook to Hook-Examples.md (#731) * add ACR webhook to Hook-Examples.md Incoming Azure Container Registry (ACR) webhook syntax and format with link to a working docker container used to handle webhook and feed a local registry cache * Update Hook-Examples.md changed text according to suggestions of https://github.com/moorereason (see PR) --- docs/Hook-Examples.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/docs/Hook-Examples.md b/docs/Hook-Examples.md index 1b01ea4..08de456 100644 --- a/docs/Hook-Examples.md +++ b/docs/Hook-Examples.md @@ -22,6 +22,7 @@ although the examples on this page all use the JSON format. * [Multipart Form Data](#multipart-form-data) * [Pass string arguments to command](#pass-string-arguments-to-command) * [Receive Synology DSM notifications](#receive-synology-notifications) +* [Incoming Azure Container Registry (ACR) webhook](#incoming-acr-webhook) ## Incoming Github webhook @@ -673,3 +674,72 @@ Webhooks feature introduced in DSM 7.x seems to be incomplete & broken, but you } ] ``` +## Incoming Azure Container Registry (ACR) webhook + +ACR can send webhooks on image push events. The `hooks.json` below will handle those events and pass relevant properties as environment variables to a command. + +Here is an example of a working docker webhook container used to handle the webhooks and fill the cache of a local registry: [ACR Harbor local cache feeder](https://github.com/tomdess/registry-cache-feeder). + + +```json +[ + { + "id": "acr-push-event", + "execute-command": "/config/script-acr.sh", + "command-working-directory": "/config", + "pass-environment-to-command": + [ + { + "envname": "ACTION", + "source": "payload", + "name": "action" + }, + { + "envname": "REPO", + "source": "payload", + "name": "target.repository" + }, + { + "envname": "TAG", + "source": "payload", + "name": "target.tag" + }, + { + "envname": "DIGEST", + "source": "payload", + "name": "target.digest" + } + ], + "trigger-rule": + { + "and": + [ + { + "match": + { + "type": "value", + "value": "mysecretToken", + "parameter": + { + "source": "header", + "name": "X-Static-Token" + } + } + }, + { + "match": + { + "type": "value", + "value": "push", + "parameter": + { + "source": "payload", + "name": "action" + } + } + } + ] + } + } +] +``` From 7ea2a53bbb36038e3faa821a97ddf62397dc5e09 Mon Sep 17 00:00:00 2001 From: Jonathan Leroy <671734+jleroy@users.noreply.github.com> Date: Thu, 28 Aug 2025 23:17:53 +0200 Subject: [PATCH 08/10] Fix Gitea incoming webhook example and add a YAML version (#737) * Fix Gitea incoming webhook example and add a YAML version * Fix payload-hmac-sha256 secret attribute name --- docs/Hook-Examples.md | 45 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/docs/Hook-Examples.md b/docs/Hook-Examples.md index 08de456..854d010 100644 --- a/docs/Hook-Examples.md +++ b/docs/Hook-Examples.md @@ -214,7 +214,11 @@ Values in the request body can be accessed in the command or to the match rule b } ] ``` + ## Incoming Gitea webhook + +JSON version: + ```json [ { @@ -229,7 +233,7 @@ Values in the request body can be accessed in the command or to the match rule b }, { "source": "payload", - "name": "pusher.name" + "name": "pusher.full_name" }, { "source": "payload", @@ -243,12 +247,12 @@ Values in the request body can be accessed in the command or to the match rule b { "match": { - "type": "value", - "value": "mysecret", + "type": "payload-hmac-sha256", + "secret": "mysecret", "parameter": { - "source": "payload", - "name": "secret" + "source": "header", + "name": "X-Gitea-Signature" } } }, @@ -256,7 +260,7 @@ Values in the request body can be accessed in the command or to the match rule b "match": { "type": "value", - "value": "refs/heads/master", + "value": "refs/heads/main", "parameter": { "source": "payload", @@ -270,6 +274,35 @@ Values in the request body can be accessed in the command or to the match rule b ] ``` +YAML version: + +```yaml +- id: webhook + execute-command: /home/adnan/redeploy-go-webhook.sh + command-working-directory: /home/adnan/go + pass-arguments-to-command: + - source: payload + name: head_commit.id + - source: payload + name: pusher.full_name + - source: payload + name: pusher.email + trigger-rule: + and: + - match: + type: payload-hmac-sha256 + secret: mysecret + parameter: + source: header + name: X-Gitea-Signature + - match: + type: value + value: refs/heads/main + parameter: + source: payload + name: ref +``` + ## Slack slash command ```json [ From 34d4418840058592f5d5eff56651adb9940a0445 Mon Sep 17 00:00:00 2001 From: DIGVIJAY <144053736+digvijay-y@users.noreply.github.com> Date: Fri, 28 Nov 2025 02:39:50 +0530 Subject: [PATCH 09/10] docs: Documented cat and credential template functions (#739) --- docs/Templates.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/Templates.md b/docs/Templates.md index 35f10a0..3355112 100644 --- a/docs/Templates.md +++ b/docs/Templates.md @@ -73,5 +73,38 @@ Additionally, the result is piped through the built-in Go template function `js` ``` +## Template Functions + +In addition to the [built-in Go template functions and features][tt], `webhook` provides the following functions: + +### `getenv` + +The `getenv` template function can be used for inserting environment variables into a templated configuration file. + +Example: +``` +"Secret": "{{getenv TEST_secret | js}}" +``` + +### `cat` + +The `cat` template function can be used to read a file from the local filesystem. This is useful for reading secrets from files. If the file doesn't exist, it returns an empty string. + +Example: +``` +"secret": "{{ cat "/run/secrets/my-secret" | js }}" +``` + +### `credential` + +The `credential` template function provides a way to retrieve secrets using [systemd's LoadCredential mechanism](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Credentials). It reads the file specified by the given name from the directory specified in the `CREDENTIALS_DIRECTORY` environment variable. + +If `CREDENTIALS_DIRECTORY` is not set, it will fall back to using `getenv` to read the secret from an environment variable of the given name. + +Example: +``` +"secret": "{{ credential "my-secret" | js }}" +``` + [w]: https://github.com/adnanh/webhook [tt]: https://golang.org/pkg/text/template/ From 8a2d3f85cd3e0b285239ce1d3d8ec0eddaceb89a Mon Sep 17 00:00:00 2001 From: Julio Date: Fri, 9 Jan 2026 11:08:29 -0400 Subject: [PATCH 10/10] Added Printing the Raw Webhook Payload to Standard Output example (#746) --- docs/Hook-Examples.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/Hook-Examples.md b/docs/Hook-Examples.md index 854d010..66aa5a7 100644 --- a/docs/Hook-Examples.md +++ b/docs/Hook-Examples.md @@ -24,6 +24,24 @@ although the examples on this page all use the JSON format. * [Receive Synology DSM notifications](#receive-synology-notifications) * [Incoming Azure Container Registry (ACR) webhook](#incoming-acr-webhook) +## Printing the Raw Webhook Payload to Standard Output + +This hook configuration receives incoming webhook requests and prints the raw request body (payload) directly to the server's standard output (visible in the webhook process logs when running with -verbose). It is particularly useful for debugging and verifying webhook deliveries from external services. + +```json +[ + { + "id": "print-payload", + "execute-command": "/bin/echo", + "pass-arguments-to-command": [ + { + "source": "entire-payload", + } + ] + } +] +``` + ## Incoming Github webhook This example works on 2.8+ versions of Webhook - if you are on a previous series, change `payload-hmac-sha1` to `payload-hash-sha1`.