aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/entrypoint.sh')
-rwxr-xr-xscripts/entrypoint.sh141+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
;;