# `system-hook` [![Crates.io](https://img.shields.io/crates/v/system-hook.svg)](https://crates.io/crates/system-hook) [![Docs.rs](https://docs.rs/system-hook/badge.svg)](https://docs.rs/system-hook) `shook` at its core is a web server that listens for webhooks from Github and then will automatically pull new changes to your repository and restart your production servers with the new code. Shook assumes your server is running through `systemd` and will automatically pull new changes and restart the service. ## Installation note: `shook` is designed to run on linux systems that use `systemd`. ### cargo-binstall `shook` can be installed using [`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall): ```shell cargo binstall system-hook ``` ### Github Releases `shook` can be downloaded from [Github Releases](https://github.com/beaconbrigade/system-hook/releases/latest) ### Build from Source `shook` can be built from source using cargo: ```shell cargo install system-hook ``` Or, locally: ```shell git clone https://github.com/beaconbrigade/system-hook.git cd system-hook cargo build --release ``` ## Usage `shook` has three main commands: `init`, `serve` and `daemon`. To prepare `shook` navigate to the repository you want to watch, and run `sudo shook init`. Sidenote: `shook` usually needs to run as root because it interacts with `systemctl` or needs to write files in the `/etc/systemd/system/` directory. `shook` will guide you through creating a config and it will generate the `shook.toml` in your repository's directory and `/etc/systemd/system/shook.service`. The `shook.toml` file tells `shook` how to run. After generating a `shook.toml`, `shook` can be run using `shook serve` which starts the server in your terminal, or by running `sudo shook daemon start` which starts the `shook` systemd service. For testing out `shook` it is good to play with `shook serve`, you can use command line arguments to augment values in the `shook.toml` file. When running in production it would probably be more helpful to run `sudo shook daemon enable` so `shook` is started when your computer starts. note: `shook daemon` just runs `systemctl` `start`, `stop` and `enable` under the hood, so you can bypass `shook` and run those directly if you want. ### Sample behind `nginx` If your main server is running behind `nginx`, your webhook proxy might look like this: ```nginx http { server { # example route to serve static files location / { root /www-data; } # proxy `shook` behind nginx location /webhook { # remove the '/webhook' part of the url so requests to https://yourserver.com/webhook # are POSTed to '/' on `shook` (as it expects). rewrite /webhook(.*) /$1 break; # pass requests onto `shook` proxy_pass http://unix://var/run/shook.sock; } } } ``` ### Testing As a side note, it can be really handy to test if your webhook server is working. You can use the [Github CLI](https://cli.github.com/) to help with this. Refer to [here](https://docs.github.com/en/webhooks-and-events/webhooks/receiving-webhooks-with-the-github-cli) to set up webhook testing. To test `shook` I created an test repository on Github with a script `update.sh` that appends data to the README.md file, then commits and pushes. Then, running `shook serve --log-level=trace` in one terminal, `gh webhook ...` in another and `./update.sh` in a third you can test your deployment. ## Details `shook` creates its own `systemd` service to start listening for events. The `shook` service simply runs `shook serve` from the right directory and sets a default logging level and log file to `/var/log/shook.log`. The `github-webhook-extract` crate provides route extractors for a Github webhook event (note: `github-webhook-extract` supports _very_ few events at the moment). The `text-completions` crate provides environment variable and path tab completions for the `shook init` command. ### `shook init` The `init` command will generate both the `systemd` service file for `shook` and the `shook.toml` for your repository. The values for each config value can be optionally passed by command line, and if they aren't present, they will be read from stdin using [`dialoguer`](https://github.com/console-rs/dialoguer). The `init` command will store each config value in `shook.toml` stored in your given repositories directory. The `shook.service` file generated by `shook` will invoke `shook serve` setting the log file to `/var/log/shook.log` and will also put the working directory to your repositories path. ### `shook serve` The `serve` command will read the `shook.toml` file to configure itself. When the server receives a POST message it will extract a Github payload from it, and then check if the event matches the allowed events in your config. If there's a match, it will then use `git` to pull the most recent changes then `systemctl restart` your service. Each config field influences the server, here's an example: ```toml username = "rcullen" repo_path = "/home/rcullen/rust/test-webhoks" remote = "origin" branch = "master" system_name = "test-restart" update_events = ["push"] socket_group = "www-data" socket_user = "www-data" [addr] type = "Unix" value = "/var/run/shook.sock" ``` * username: `shook` will `su` to this user to run `git pull` so that the proper `https` or `ssh` verification is applied. * repo_path: `shook` will use this directory as its working directory, pull changes here, and find the `shook.toml` here. * remote: This is the remote `shook will pull from with git` it is the `origin` in `git pull origin main` * branch: The branch `shook` will try to pull from * system_name: This is the system that `shook` will restart when it receives a webhook payload * update_events: A list Github webhook events that `shook` will pull code after receiving * socket_group: If `shook` is configured to listen on a unix socket, it will `chgrp` the socket to this group * socket_user: If `shook` is configured to listen on a unix socket, it will `chown` the socket to this user * addr: The address shook will listen on: either a Unix socket (file path) or TCP socket (socket address) Final note: if `shook` serves through a unix socket, it will `chmod` the socket with `0o666`. ### `shook daemon` The `daemon` command is a simple proxy over `systemctl`. It can be easily bypassed without causing any harm.