diff options
Diffstat (limited to 'scripts/entrypoint.sh')
| -rwxr-xr-x | scripts/entrypoint.sh | 141 | +73 −68 |
1 files changed, 73 insertions, 68 deletions
diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 6da7570..b32a3bc 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -4,79 +4,83 @@ # shellcheck shell=dash set -eu -umask 077 state=/var/lib/gilti run_dir=/run/gilti -ssh_run_dir=$run_dir/ssh +cache_dir=/var/cache/cgit git_home=$state/git -repositories=$git_home/repositories host_key_dir=$state/ssh -authorized_keys_source=${GILTI_AUTHORIZED_KEYS_FILE:-/etc/gilti/authorized_keys} -authorized_keys=$ssh_run_dir/authorized_keys + +admin_key=${GILTI_ADMIN_KEY_FILE:-/run/gilti-bootstrap/admin.pub} log() { printf 'gilti: %s\n' "$*" >&2 } +run_as_git() { + su-exec git:git env HOME="$git_home" USER=git LOGNAME=git "$@" +} + prepare_runtime() { [ "$(id -u)" -eq 0 ] || { log "the supervisor must start as root"; exit 1; } - for path in "$git_home" "$repositories"; do - [ ! -L "$path" ] || { log "refusing symlinked state path $path"; exit 1; } - done install -d -m 0755 -o root -g root "$state" - install -d -m 0750 -o git -g git "$git_home" "$repositories" + install -d -m 0750 -o git -g git "$git_home" "$cache_dir" install -d -m 0700 -o root -g root "$host_key_dir" - install -d -m 0755 -o root -g root "$run_dir" - install -d -m 0750 -o root -g git "$ssh_run_dir" - rm -f "$ssh_run_dir/sshd.pid" "$authorized_keys" "$authorized_keys".* + install -d -m 0755 "$run_dir" + chown git:git "$cache_dir" + rm -f "$run_dir/fcgiwrap.sock" "$run_dir/nginx.pid" "$run_dir/sshd.pid" } -prepare_authorized_keys() { - [ -f "$authorized_keys_source" ] && [ -r "$authorized_keys_source" ] || { - log "SSH public keys are required at $authorized_keys_source" - exit 1 - } +state_status() { + complete=true + for path in .gitolite.rc .gitolite repositories .ssh/authorized_keys; do + [ -e "$git_home/$path" ] || complete=false + done + if [ "$complete" = true ]; then + printf '%s\n' complete + return + fi - output=$authorized_keys.tmp.$$ - candidate=$authorized_keys.key.$$ - : >"$output" - count=0 - while IFS= read -r key || [ -n "$key" ]; do - case $key in - ''|'#'*) continue ;; - esac - case $key in - ssh-*|ecdsa-*|sk-*) ;; - *) - rm -f "$output" "$candidate" - log "$authorized_keys_source contains an invalid SSH public key" - exit 1 - ;; - esac - printf '%s\n' "$key" >"$candidate" - if ! ssh-keygen -l -f "$candidate" >/dev/null 2>&1; then - rm -f "$output" "$candidate" - log "$authorized_keys_source contains an invalid SSH public key" - exit 1 - fi - printf 'restrict %s\n' "$key" >>"$output" - count=$((count + 1)) - done <"$authorized_keys_source" - rm -f "$candidate" - - if [ "$count" -eq 0 ]; then - rm -f "$output" - log "$authorized_keys_source contains no SSH public keys" - exit 1 + partial=false + for path in .gitolite.rc .gitolite repositories .ssh/authorized_keys projects.list; do + [ ! -e "$git_home/$path" ] || partial=true + done + if [ "$partial" = true ]; then + printf '%s\n' partial + else + printf '%s\n' fresh fi - chown root:git "$output" - chmod 0640 "$output" - mv -f "$output" "$authorized_keys" } -prepare_host_key() { +initialize() { + prepare_runtime + + case $(state_status) in + complete) + ;; + partial) + log "refusing to overwrite partial Gitolite state in $git_home" + exit 1 + ;; + fresh) + [ -r "$admin_key" ] || { + log "fresh state requires an admin public key at $admin_key" + exit 1 + } + ssh-keygen -l -f "$admin_key" >/dev/null 2>&1 || { + log "the bootstrap admin key is not a valid SSH public key" + exit 1 + } + log "initializing Gitolite" + run_as_git gitolite setup -pk "$admin_key" + ;; + esac + + if [ ! -e "$git_home/projects.list" ]; then + install -m 0640 -o git -g git /dev/null "$git_home/projects.list" + fi + host_key=$host_key_dir/ssh_host_ed25519_key if [ -L "$host_key" ]; then log "refusing symlinked SSH host key" @@ -98,53 +102,51 @@ prepare_host_key() { ssh-keygen -y -f "$host_key" >"$host_key.pub.tmp" chmod 0644 "$host_key.pub.tmp" mv -f "$host_key.pub.tmp" "$host_key.pub" -} -prepare() { - prepare_runtime - prepare_authorized_keys - prepare_host_key - /usr/local/bin/gilti --check - /usr/local/bin/gilti-ssh --check + nginx -t -e /dev/stderr -c /etc/nginx/nginx.conf /usr/sbin/sshd -t -f /etc/ssh/sshd_config } stop_services() { trap - TERM INT HUP - for pid in ${httpd_pid:-} ${sshd_pid:-}; do + for pid in ${fcgi_pid:-} ${sshd_pid:-} ${nginx_pid:-}; do kill -TERM "$pid" 2>/dev/null || true done attempts=0 while [ "$attempts" -lt 50 ]; do running=false - for pid in ${httpd_pid:-} ${sshd_pid:-}; do + for pid in ${fcgi_pid:-} ${sshd_pid:-} ${nginx_pid:-}; do kill -0 "$pid" 2>/dev/null && running=true done [ "$running" = true ] || break attempts=$((attempts + 1)) sleep 0.1 done - for pid in ${httpd_pid:-} ${sshd_pid:-}; do + for pid in ${fcgi_pid:-} ${sshd_pid:-} ${nginx_pid:-}; do kill -KILL "$pid" 2>/dev/null || true wait "$pid" 2>/dev/null || true done } supervise() { - prepare + initialize trap stop_services TERM INT HUP + HOME="$git_home" spawn-fcgi -n \ + -s "$run_dir/fcgiwrap.sock" -M 0660 -U git -G git \ + -u git -g git -- /usr/bin/fcgiwrap -f & + fcgi_pid=$! + /usr/sbin/sshd -D -e -f /etc/ssh/sshd_config & sshd_pid=$! - su-exec git:git env HOME="$git_home" USER=git LOGNAME=git \ - /usr/local/bin/gilti & - httpd_pid=$! + nginx -e /dev/stderr -c /etc/nginx/nginx.conf -g 'daemon off;' & + nginx_pid=$! while :; do - for pid in "$sshd_pid" "$httpd_pid"; do + for pid in "$fcgi_pid" "$sshd_pid" "$nginx_pid"; do if ! kill -0 "$pid" 2>/dev/null; then - if wait "$pid"; then status=1; else status=$?; fi + if wait "$pid"; then status=0; else status=$?; fi log "a service exited; stopping the pod" stop_services exit "$status" @@ -155,6 +157,9 @@ supervise() { } case ${1:-serve} in + init) + initialize + ;; serve) supervise ;; |
