diff options
author | jemstep-edward <42668885+jemstep-edward@users.noreply.github.com> | 2020-03-04 10:47:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-04 10:47:17 +0200 |
commit | 9f792b1b2154dc4f0a2e54cabf7c75d7e700ce81 (patch) | |
tree | 67dae2673528cca86a831a555efff5ec65ce2583 | |
parent | d5c752e36d88d048be20e6e525d0146b0d2f0a81 (diff) | |
parent | 126f5dc06e6ebe8f5eb267cc67f6916c610ab554 (diff) |
Merge pull request #48 from jemstep/github-prereceive-environment
GitHub prereceive sandbox environment
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | github/Dockerfile | 3 | ||||
-rwxr-xr-x | github/create-github-pre-receive-environment.sh | 18 | ||||
-rw-r--r-- | github/readme.org | 31 | ||||
-rw-r--r-- | readme.org | 34 | ||||
-rw-r--r-- | src/gpg.rs | 9 |
6 files changed, 93 insertions, 5 deletions
@@ -4,3 +4,6 @@ # These are backup files generated by rustfmt **/*.rs.bk + +# Pre-receive sandbox environment generated from script +capn-pre-receive.tar.gz diff --git a/github/Dockerfile b/github/Dockerfile new file mode 100644 index 0000000..f8a1e8d --- /dev/null +++ b/github/Dockerfile @@ -0,0 +1,3 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y git gnupg1 && ln -s /usr/bin/gpg1 /usr/bin/gpg + diff --git a/github/create-github-pre-receive-environment.sh b/github/create-github-pre-receive-environment.sh new file mode 100755 index 0000000..976262b --- /dev/null +++ b/github/create-github-pre-receive-environment.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR=$(dirname "$0") + +if ! command -v docker >/dev/null 2>&1; then + echo "Docker does not appear to be installed." + echo "Please install Docker and ensure that it is on the path." + exit 1 +fi + +docker rm capn-pre-receive || true +docker build -f $SCRIPT_DIR/Dockerfile -t capn-pre-receive $SCRIPT_DIR +docker create --name capn-pre-receive capn-pre-receive /bin/true +docker export capn-pre-receive | gzip > capn-pre-receive.tar.gz + +echo "Successfully created capn-pre-receive.tar.gz" diff --git a/github/readme.org b/github/readme.org new file mode 100644 index 0000000..4f7375c --- /dev/null +++ b/github/readme.org @@ -0,0 +1,31 @@ +* GitHub Enterprise Pre-receive Hook Sandbox Environment + +GitHub Enterprise imposes certain additional requirements on running +server-side pre-receive hooks. + +1. The hook has a strict 5 second time limit in which to run. +2. The hook must run within a sandboxed environment, which only lives + for the duration of the hook running. The default does not work for + Captain Git Hook because it does not include dirmngr. +3. GitHub runs the hook in Firejail, which may impose additional + limitations. The one that I ran into is that gpg could not + communicate with dirmngr over a socket. + +A suitable sandbox is specified in [[./Dockerfile]]. You can build this +Dockerfile into an appropriate tarball for upload to GitHub using the +script [[./create-github-pre-receive-environment.sh]]. + +#+BEGIN_SRC sh + # we're running the script in the same directory as this readme, but you can run it from anywhere + cd github + + # this produces capn-pre-receive.tar.gz + ./create-github-pre-receive-environment.sh + + # you can now upload the tarball to GitHub +#+END_SRC + +The following two documents show how to set up this sandbox +environment on GitHub: +- [[https://help.github.com/en/enterprise/2.20/admin/developer-workflow/creating-a-pre-receive-hook-environment]] +- [[https://help.github.com/en/enterprise/2.20/admin/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-server-appliance]] @@ -56,6 +56,15 @@ This will add an executable to your path called ~capn~. #+END_SRC ** Usage +*** Runtime Dependencies +Captain Git Hook requires certain command line applications to be +installed and on the path. +- git - This is used as a binary on the CLI only for cases unsupported + by libgit2, such as verifying signatures. +- gpg - This is used for verifying signatures. +- dirmngr - This is a gpg component that gpg uses as part of fetching + gpg keys from a keyserver. On some distros, this is bundled together + with gpg. *** Git Hooks Captain Git Hook works by installing hooks in your Git repository. Git @@ -76,6 +85,11 @@ How to install this will depend on how you administrate your Git server. For example, these are the instructions for GitHub Enterprise: [[https://help.github.com/en/enterprise/2.19/admin/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-server-appliance][Managing pre-receive hooks on the GitHub Enterprise Server appliance]]. +Some Git servers, like GitHub Enterprise, require specifying a sandbox +environment for the pre-receive hook to run in. For convenience, we +include a Dockerfile and script for setting up a GitHub Enterprise +sandbox. [[./github/readme.org]] + *** Policy Configuration The policies that Captain Git Hook will apply for a repo are @@ -154,6 +168,26 @@ git tag --sign <tag-name> git push <remote> <tag-name> #+END_SRC +*** Monitoring +By default, logging output is produced to the terminal, following the +convention of output to stdout, diagnostics to stderr. + +Additional diagnostics can be produced to stderr by specifying =-v= or +=--verbose= on the command line. For example, =capn -v pre-receive= +will produce debug level logging, which =capn pre-receive= will only +produce info level logging. + +Diagnostic logging over TCP is also supported with the =--log-url= +command line parameter. Network logs are sent in JSON format. + +In the case of network logging, it's usually useful to provide some +data to contextualise the log. A server side hook using all of the +context parameters would look like this: + +#+BEGIN_SRC rust + capn-qa -vv --log-url 10.0.0.123:123 --repo "$GITHUB_REPO_NAME" --user "$GITHUB_USER_LOGIN" --ip "$GITHUB_USER_IP" pre-receive +#+END_SRC + * Development ** High level architecture @@ -92,16 +92,15 @@ impl LiveGpg { .args(&["--keyserver", &self.keyserver]) .arg("--recv-keys") .arg(fingerprint) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status()?; + .output()?; - if result.success() { + if result.status.success() { Ok(()) } else { + debug!("GPG Stderr: {:?}", String::from_utf8(result.stderr)); Err(Box::new(CapnError::new(format!( "Call to GPG keyserver failed with code {:?}", - result.code() + result.status.code() )))) } } |