NAME
snare.conf
—
snare configuration file
DESCRIPTION
snare.conf
is the configuration file for
snare(1). It consists of one
or more top-level options and one GitHub block.
The top-level options are:
- listen = "address";
- is a mandatory address and port number to listen on. The format of
address is either:
- x.x.x.x:port
- an IPv4 address and port. For example,
‘
0.0.0.0:8765
’ will listen on port 8765 on for all IPv4 addresses. - [x:x:x]:port
- an IPv6 address and port. For example,
‘
[::]:8765
’ will listen on port 8765 for all IPv4 and IPv6 addresses.
- maxjobs = int;
- is an optional non-zero positive integer specifying the maximum number of jobs to run in parallel. Defaults to the number of CPUs in the machine.
- user = "user-name";
- is an optional username that
snare.conf
will try and change into after it has bound to a network port. Note thatsnare.conf
will refuse to run as root unless user is specified. As part of changing user,snare.conf
:- changes its uid, euid, suid to the UID of user-name.
- changes its gid, egid, sgid to the primary GID of user-name.
- sets the $HOME environment variable to the home directory of user-name.
- sets the $USER environment variable to user-name.
All other environment variables are passed through to commands unchanged.
- github { ... }
- specifies GitHub specific options.
A ‘github’ block supports the following options:
- match "regex" { match-options }
- where regex is a regular expression in Rust regex format that must match against a "owner/repo" full repository name. If it matches, then match-options are applied. "regex" must match against the full repository name: in other words, it is equivalent to ^regex$. Thus the regex "a/b" does not match against the full repository name "a/bc", but the regex "a/b.*" does match against "a/bc".
A ‘match’ block supports the following options:
- cmd = "shell-cmd";
- optionally specifies a command to be run. shell-cmd will
be executed via ‘
$SHELL -c
’. The following escape sequences are recognised and replaced before execution:- %e
- the GitHub event type (e.g.
‘
pull_request
’). - %j
- the path to the GitHub JSON.
- %o
- the repository owner.
- %r
- the repository.
- %%
- a literal ‘
%
’.
Note that ‘
%
’ may not be followed by any character other than those above.The escape sequences are guaranteed to satisfy the regular expression "[a-zA-Z0-9._-]+" and not to be the strings "." or "..". This means that they are safe to pass as shell arguments and/or to be included in file system paths.
- errorcmd = "shell-cmd";
- optionally specifies a command to be run when a job exits unsuccessfully.
shell-cmd will be executed via
‘
$SHELL -c
’. The following escape sequences are recognised and replaced before execution:- %e
- the GitHub event type (e.g.
‘
pull_request
’). - %j
- the path to the GitHub JSON.
- %o
- the repository owner.
- %r
- the repository.
- %s
- the path to the file containing the job's combined stderr / stdout.
- %x
- the exit type: "status" (i.e. normal exit); "signal"; or "unknown".
- %?
- the exit status / signal number (either an integer or the literal string "unknown") that cmd failed with.
- %%
- a literal ‘
%
’.
Note that ‘
%
’ may not be followed by any character other than those above.The escape sequences are guaranteed to satisfy the regular expression "[a-zA-Z0-9._-]+" and not to be the strings "." or "..". This means that they are safe to pass as shell arguments and/or to be included in file system paths.
- queue = (evict | parallel | sequential);
- specifies what to do when multiple requests for the same repository are
queued at once:
- evict
- only run one job for this repository at a time. Additional jobs will stay on the queue: if a new job comes in for that repository, it evicts any previously queued jobs for that repository. In other words, for this repository there can be at most one running job and one queued job at any point.
- parallel
- run as many jobs for this repository in parallel as possible.
- sequential
- only run one job for this repository at a time. Additional jobs will stay on the queue and be executed in FIFO order.
The default match block sets this to sequential, which is always safe, though at the possible expense of lower job throughput for any given repository.
- secret = "secret";
- is the optional GitHub secret used to sign the webhook request. This
allows
snare.conf
to tell the difference between genuine webhook requests and those from malfeasants. Although this is optional, we highly recommend setting it in all cases. Note also that if a GitHub request is signed, but you have not specified a secret, then snare will return the request as “unauthorised” to remind you to use the secret at both ends. - timeout = period;
- specifies the elapsed time, as a positive integer, in seconds that a process can run before being sent SIGTERM. The default match block sets this to one hour (3600 seconds).
match blocks are evaluated in order from top to bottom with each successful match overriding previous settings. A default match block is inserted before any user match blocks:
match ".*" { queue = sequential; timeout = 3600; }
EXAMPLES
The minimal recommended snare.conf
file is
as follows:
listen = "<address>:<port>"; github { match ".*" { cmd = "/path/to/prps/%o/%r %e %j"; errorcmd = "cat %s | mailx -s \"snare error: github.com/%o/%r\" someone@example.com"; secret = "<secret>"; } }
where "/path/to/prps" is a path to a directory where per-repo programs are stored. Each repository then has a unique program "%o/%r" which will be executed with two arguments: the GitHub event; and the path to the GitHub JSON. If a job exits unsuccessfully then an email will be sent to someone@example.com containing the job's comined stderr and stdout output (assuming that a suitable sendmail clone has been installed and activated).
The top-to-bottom evaluation of match blocks allow users to specify defaults which are only overridden for specific repositories. For example, for the following configuration file:
listen = "<address>:<port>"; github { match ".*" { cmd = "/path/to/prps/%o/%r %e %j"; errorcmd = "cat %s | mailx -s \"snare error: github.com/%o/%r\" abc@def.com"; secret = "sec"; } match "a/b" { errorcmd = "lpr %s"; } }
the following repositories will have these settings:
a/b: queue = sequential timeout = 3600 cmd = "/path/to/prps/%o/%r %e %j"; errorcmd = "lpr %s"; secret = "sec" c/d: queue = sequential timeout = 3600 cmd = "/path/to/prps/%o/%r %e %j"; errorcmd = "cat %s | mailx -s \"snare error: github.com/%o/%r\" abc@def.com"; secret = "sec"
The following program expects to be called with an event and a JSON path (i.e. "%e %j") and uses shell script to send a list of commits and diffs to the address specified in $EMAIL on each “push” to master. It works for any public GitHub repository:
#! /bin/sh set -euf # A list of email addresses separated by spaces. EMAILS="someone@example.com someone.else@example.com" # A GitHub URL either https or git. REPO_URL="git@github.com:owner/repo.git" if [ "$1" != "push" ]; then exit 0 fi ref=`jq .ref "$2" | tr -d ' if [ "$ref" != "refs/heads/master" ]; then exit 0 fi repo_fullname=`jq .repository.full_name "$2" | tr -d ' repo_url=`jq .repository.html_url "$2" | tr -d ' before_hash=`jq .before "$2" | tr -d ' after_hash=`jq .after "$2" | tr -d ' echo "$before_hash" | grep -E "^[a-fA-F0-9]+$" 2>&1 > /dev/null echo "$after_hash" | grep -E "^[a-fA-F0-9]+$" 2>&1 > /dev/null git clone "$REPO_URL" repo cd repo for email in `echo "$EMAILS"`; do git log --reverse -p "$before_hash..$after_hash" \ | mail -s "Push to $repo_fullname" "$email" done
where jq is a command-line JSON processor. Depending on your needs, you can make this type of script arbitrarily more complex and powerful (for example, not cloning afresh on each pull).
Note that this program is deliberately untrusting of external input: it is careful to quote all arguments obtained from JSON; and it uses a fixed directory name (“repo”) rather than a file name from JSON that might include characters (such as “../..”) that would cause the script to leak data about other parts of the file system.
SEE ALSO
AUTHORS
snare(1) was written by Laurence Tratt https://tratt.net/laurie/