mirror of
https://github.com/adnanh/webhook.git
synced 2026-07-23 02:08:39 +00:00
Merge remote-tracking branch 'o'
# Conflicts: # README.md # docs/Webhook-Parameters.md # go.mod # webhook_test.go
This commit is contained in:
commit
0645b1404f
604 changed files with 102778 additions and 130025 deletions
|
|
@ -22,6 +22,25 @@ 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)
|
||||
|
||||
## 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
|
||||
|
||||
|
|
@ -213,7 +232,11 @@ Values in the request body can be accessed in the command or to the match rule b
|
|||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Incoming Gitea webhook
|
||||
|
||||
JSON version:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
|
|
@ -228,7 +251,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",
|
||||
|
|
@ -242,12 +265,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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -255,7 +278,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",
|
||||
|
|
@ -269,6 +292,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
|
||||
[
|
||||
|
|
@ -331,7 +383,7 @@ __Not recommended in production due to low security__
|
|||
|
||||
### Webhook configuration
|
||||
|
||||
<pre>
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "test-file-webhook",
|
||||
|
|
@ -350,29 +402,29 @@ __Not recommended in production due to low security__
|
|||
"include-command-output-in-response": true
|
||||
}
|
||||
]
|
||||
</pre>
|
||||
```
|
||||
|
||||
### Sample client usage
|
||||
|
||||
Store the following file as `testRequest.json`.
|
||||
|
||||
<pre>
|
||||
```json
|
||||
{"binary":"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2lpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wUmlnaHRzPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvcmlnaHRzLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcFJpZ2h0czpNYXJrZWQ9IkZhbHNlIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjEzMTA4RDI0QzMxQjExRTBCMzYzRjY1QUQ1Njc4QzFBIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjEzMTA4RDIzQzMxQjExRTBCMzYzRjY1QUQ1Njc4QzFBIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzMgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ1dWlkOkFDMUYyRTgzMzI0QURGMTFBQUI4QzUzOTBEODVCNUIzIiBzdFJlZjpkb2N1bWVudElEPSJ1dWlkOkM5RDM0OTY2NEEzQ0REMTFCMDhBQkJCQ0ZGMTcyMTU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+IBFgEwAAAmJJREFUeNqkk89rE1EQx2d/NNq0xcYYayPYJDWC9ODBsKIgAREjBmvEg2cvHnr05KHQ9iB49SL+/BMEfxBQKHgwCEbTNNIYaqgaoanFJi+rcXezye4689jYkIMIDnx47837zrx583YFx3Hgf0xA6/dJyAkkgUy4vgryAnmNWH9L4EVmotFoKplMHgoGg6PkrFarjXQ6/bFcLj/G5W1E+3NaX4KZeDx+dX5+7kg4HBlmrC6JoiDFYrGhROLM/mp1Y6JSqdCd3/SW0GUqEAjkl5ZyHTSHKBQKnO6a9khD2m5cr91IJBJ1VVWdiM/n6LruNJtNDs3JR3ukIW03SHTHi8iVsbG9I51OG1bW16HVasHQZopDc/JZVgdIQ1o3BmTkEnJXURS/KIpgGAYPkCQJPi0u8uzDKQN0XQPbtgE1MmrHs9nsfSqAEjxCNtHxZHLy4G4smUQgyzL4LzOegDGGp1ucVqsNqKVrpJCM7F4hg6iaZvhqtZrg8XjA4xnAU3XeKLqWaRImoIZeQXVjQO5pYp4xNVirsR1erxer2O4yfa227WCwhtWoJmn7m0h270NxmemFW4706zMm8GCgxBGEASCfhnukIW03iFdQnOPz0LNKp3362JqQzSw4u2LXBe+Bs3xD+/oc1NxN55RiC9fOme0LEQiRf2rBzaKEeJJ37ZWTVunBeGN2WmQjg/DeLTVP89nzAive2dMwlo9bpFVC2xWMZr+A720FVn88fAUb3wDMOjyN7YNc6TvUSHQ4AH6TOUdLL7em68UtWPsJqxgTpgeiLu1EBt1R+Me/mF7CQPTfAgwAGxY2vOTrR3oAAAAASUVORK5CYII="}
|
||||
</pre>
|
||||
```
|
||||
|
||||
use then the curl tool to execute a request to the webhook.
|
||||
|
||||
<pre>
|
||||
```sh
|
||||
#!/bin/bash
|
||||
curl -H "Content-Type:application/json" -X POST -d @testRequest.json \
|
||||
http://localhost:9000/hooks/test-file-webhook
|
||||
</pre>
|
||||
```
|
||||
|
||||
or in a single line, using https://github.com/jpmens/jo to generate the JSON code
|
||||
<pre>
|
||||
```console
|
||||
jo binary=%filename.zip | curl -H "Content-Type:application/json" -X POST -d @- \
|
||||
http://localhost:9000/hooks/test-file-webhook
|
||||
</pre>
|
||||
```
|
||||
|
||||
|
||||
## Incoming Scalr Webhook
|
||||
|
|
@ -380,7 +432,7 @@ http://localhost:9000/hooks/test-file-webhook
|
|||
Scalr makes webhook calls based on an event to a configured webhook endpoint (for example Host Down, Host Up). Webhook endpoints are URLs where Scalr will deliver Webhook notifications.
|
||||
Scalr assigns a unique signing key for every configured webhook endpoint.
|
||||
Refer to this URL for information on how to setup the webhook call on the Scalr side: [Scalr Wiki Webhooks](https://scalr-wiki.atlassian.net/wiki/spaces/docs/pages/6193173/Webhooks)
|
||||
In order to leverage the Signing Key for addtional authentication/security you must configure the trigger rule with a match type of "scalr-signature".
|
||||
In order to leverage the Signing Key for additional authentication/security you must configure the trigger rule with a match type of "scalr-signature".
|
||||
|
||||
```json
|
||||
[
|
||||
|
|
@ -498,7 +550,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",
|
||||
|
|
@ -594,7 +647,6 @@ We only care about the payload part.
|
|||
}
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
Each part of a multipart form data body will have a `Content-Disposition` header.
|
||||
|
|
@ -675,3 +727,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -269,10 +269,12 @@ The IP can be IPv4- or IPv6-formatted, using [CIDR notation](https://en.wikipedi
|
|||
}
|
||||
```
|
||||
|
||||
Note this does not work if webhook is running behind a reverse proxy, as the "client IP" will either not be available at all (if webhook is using a Unix socket or named pipe) or it will be the address of the _proxy_, not of the real client. You will probably need to enforce client IP restrictions in the reverse proxy itself, before forwarding the requests to webhook.
|
||||
|
||||
### Match scalr-signature
|
||||
|
||||
The trigger rule checks the scalr signature and also checks that the request was signed less than 5 minutes before it was received.
|
||||
A unqiue signing key is generated for each webhook endpoint URL you register in Scalr.
|
||||
A unique signing key is generated for each webhook endpoint URL you register in Scalr.
|
||||
Given the time check make sure that NTP is enabled on both your Scalr and webhook server to prevent any issues
|
||||
|
||||
```json
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@ There are four types of request values:
|
|||
```
|
||||
|
||||
3. HTTP Request parameters
|
||||
#### Valid `name` Parameters:
|
||||
- `"name": "method"`
|
||||
- `"name": "remote-addr"`
|
||||
|
||||
*Note* Anything other than above mentioned `name` parameters would be invalid!
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
|||
61
docs/Systemd-Activation.md
Normal file
61
docs/Systemd-Activation.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Using systemd socket activation
|
||||
|
||||
_New in v2.8.2_
|
||||
|
||||
On platforms that use [systemd](https://systemd.io), [webhook][w]
|
||||
supports the _socket activation_ mechanism. In this mode, systemd itself is responsible for managing the listening socket, and it launches [webhook][w] the first time it receives a request on the socket. This has a number of advantages over the standard mode:
|
||||
|
||||
- [webhook][w] can run as a normal user while still being able to use a port number like 80 or 443 that would normally require root privilege
|
||||
- if the [webhook][w] process dies and is restarted, pending connections are not dropped - they just keep waiting until the restarted [webhook][w] is ready
|
||||
|
||||
No special configuration is necessary to tell [webhook][w] that socket activation is being used - socket activation sets specific environment variables when launching the activated service, if [webhook][w] detects these variables it will ignore the `-port` and `-socket` options and simply use the systemd-provided socket instead of opening its own.
|
||||
|
||||
## Configuration
|
||||
To run [webhook][w] with socket activation you need to create _two_ separate unit files in your systemd configuration directory (typically `/etc/systemd/system`), one for the socket and one for the service. They must have matching names; in this example we use `webhook.socket` and `webhook.service`. At their simplest, these files should look like:
|
||||
|
||||
**webhook.socket**
|
||||
```
|
||||
[Unit]
|
||||
Description=Webhook server socket
|
||||
|
||||
[Socket]
|
||||
# Listen on all network interfaces, port 9000
|
||||
ListenStream=9000
|
||||
|
||||
# Alternatives:
|
||||
|
||||
## Listen on one specific interface only
|
||||
# ListenStream=10.0.0.1:9000
|
||||
# FreeBind=true
|
||||
|
||||
## Listen on a Unix domain socket
|
||||
# ListenStream=/tmp/webhook.sock
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
**webhook.service**
|
||||
```
|
||||
[Unit]
|
||||
Description=Webhook server
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
ExecStart=webhook -nopanic -hooks /etc/webhook/hooks.yml
|
||||
|
||||
# Which user should the webhooks run as?
|
||||
User=nobody
|
||||
Group=nogroup
|
||||
```
|
||||
|
||||
You should enable and start the _socket_, but it is not necessary to enable the _service_ - this will be started automatically when the socket receives its first request.
|
||||
|
||||
```sh
|
||||
sudo systemctl enable webhook.socket
|
||||
sudo systemctl start webhook.socket
|
||||
```
|
||||
|
||||
Systemd unit files support many other options, see the [systemd.socket](https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html) and [systemd.service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) manual pages for full details.
|
||||
|
||||
[w]: https://github.com/adnanh/webhook
|
||||
|
|
@ -10,6 +10,7 @@ In the example JSON template file below (YAML is also supported), the `payload-h
|
|||
Additionally, the result is piped through the built-in Go template function `js` to ensure that the result is a well-formed Javascript/JSON string.
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": "webhook",
|
||||
"execute-command": "/home/adnan/redeploy-go-webhook.sh",
|
||||
|
|
@ -72,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/
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Usage of webhook:
|
|||
-hotreload
|
||||
watch hooks file for changes and reload them automatically
|
||||
-http-methods string
|
||||
globally restrict allowed HTTP methods; separate methods with comma
|
||||
set default allowed HTTP methods (ie. "POST"); separate methods with comma
|
||||
-ip string
|
||||
ip the webhook should serve hooks on (default "0.0.0.0")
|
||||
-key string
|
||||
|
|
@ -27,6 +27,8 @@ Usage of webhook:
|
|||
send log output to a file; implicitly enables verbose logging
|
||||
-max-concurrency int
|
||||
default maximum number of concurrent executions per hook; 0 disables the limit
|
||||
-max-multipart-mem int
|
||||
maximum memory in bytes for parsing multipart form data before disk caching (default 1048576)
|
||||
-nopanic
|
||||
do not panic if hooks cannot be loaded when webhook is not running in verbose mode
|
||||
-pidfile string
|
||||
|
|
@ -39,6 +41,8 @@ Usage of webhook:
|
|||
set group ID after opening listening port; must be used with setuid
|
||||
-setuid int
|
||||
set user ID after opening listening port; must be used with setgid
|
||||
-socket string
|
||||
path to a Unix socket (e.g. /tmp/webhook.sock) or Windows named pipe (e.g. \\.\pipe\webhook) to use instead of listening on an ip and port; if specified, the ip and port options are ignored
|
||||
-template
|
||||
parse hooks file as a Go template
|
||||
-tls-min-version string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue