Dip

Dip is a configurable webhook server.

It will listen on endpoints, and every time that endpoint is hit, it will run through a set of commands defined through configuration files.

Deployment

Download Dip

The easiest way to get a copy of Dip is to download a binary from the releases page.

Alternatively, clone the repository and compile from source.

HTTP Server setup

Dip runs an HTTP server. By default it serves on port 5000 on all interfaces. Use --bind on the executable to change this.

It's recommended to vhost your Dip through a server such as Nginx. Here's a sample Nginx config:

location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host $host;
    proxy_pass http://localhost:5000;
}

Root configuration directory

Delegate a directory on your server to act as a root config directory.

Systemd

Systemd is useful for keeping Dip running as a daemon, and starting it automatically on startup. Here's a sample systemd config:

[Unit]
Description=Configurable Webhook Server

[Service]
User=dip
Environment="RUST_BACKTRACE=1"
ExecStart=/usr/bin/dip --root /etc/dip --bind "127.0.0.1:5000"

[Install]
WantedBy=default.target

Configuration

The configuration directory should contain two subdirectories: handlers and hooks. The hooks directory should contain configuration files for webhooks. These files are defined in TOML. For example, here is a config file for a website deployment using gutenberg:

[[handlers]]
type = "github"
secret = "**************"

[[handlers]]
type = "command"
command = "rm -rf /var/www/default/*"

[[handlers]]
type = "command"
command = "gutenberg build --output-dir /var/www/default"

If this config file existed at $DIP_ROOT/hooks/website, then it would be served from http://localhost:5000/webhook/website.

Config File Format

The hook config should contain an array called handlers, which is a sequence of handler tables.

The type key

Each handler must contain at least one key required by dip, type, which determines what kind of hook will be run.

Dip comes with two built-in handlers:

If you set type to one of these values, dip will automatically use the built-in. Otherwise, dip will look into the handlers subdirectory for an executable matching the type that you specified. For example, if you set type = "mkdir", then it will look for $DIP_ROOT/handlers/mkdir, which must be an executable file. It will not run the system mkdir. If you want to run the system mkdir, use type = "command", so it will run a bash command instead.

Handler Input and Output

Think of a handler as a function that takes two inputs: a configuration and per-instance data. The configuration is specified in the configuration file, while the per-instance data is specific to that run of the webhook.

For example, suppose we have the following setup:

[[handlers]]
type = "github"
secret = "hunter2"

If a new Github webhook is deployed, then the first config input will be:

{
    "secret": "hunter2"
}

This input will be provided to the executable using --config in JSON format. For example, if github was not a builtin, then a call to the github executable might look like:

/usr/bin/github --config '{"secret":"hunter2"}'

The second input that's provided to the handler is information specific to this run. For the first handler in the sequence, this will be data serialized from the HTTP request, and for subsequent handlers, it will be the output of the previous handler. This input is provided through standard input directly as is.

Think of it as a fold over the list of handlers:

foldl (\input next_handler -> next_handler input) http_data handlers

Environment Variables

Every process spawned by Dip as part of a webhook will have certain variables set to give it information about its environment:

  • DIP_ROOT: the root config directory for Dip.
  • DIP_WORKDIR: the temporary directory created for this specific hook invocation.

Built-in Handlers

Dip comes with two built-in handlers: Bash commands and Github webhooks.

Bash commands

Bash commands are invoked with type = "command". It will run whatever is specified in the command field using bash (assuming it exists on the system).

An full config using a command handler follows:

[[handlers]]
type = "command"

# the command to run using bash
command = "echo hi"

Github webhooks

For Github webhooks, dip will verify the webhook (by using the provided secret) and then clone the repository that the webhook was attached to into the temporary directory created for that specific invocation.

This handler isn't very useful by itself, so it's a good idea to follow up this handler with some commands or other handlers to use the newly cloned repository (for example, build or deploy).

An full config using a github handler follows:

[[handlers]]
type = "github"

# webhook secret
secret = "**************"

# turn off secret verification (false by default)
disable_hmac_verify = false

# path to clone to
path = "."