forked from heavy-duty/rig
A bare 'read -rsp' with no tty exits non-zero and set -e ends the script with no output at all: the release drill watched 'rig runner remove' exit 1 in complete silence, and a guest bootstrap stop mid-log the same way. Every prompt now checks for a tty first and dies naming the variable that unblocks an unattended run; every read is || die-guarded so EOF at a real prompt also gets a last word. The no-bare-read test swept up runner repoint's two prompts, which the issue had not counted. Fixes #42 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
112 lines
4.5 KiB
Bash
Executable file
112 lines
4.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# rig runner remove — take the service down and deregister the runner.
|
|
# Convergent: a box with nothing installed exits 0.
|
|
set -euo pipefail
|
|
|
|
log() { printf 'rig-runner: %s\n' "$*"; }
|
|
warn() { printf 'rig-runner: WARNING: %s\n' "$*" >&2; }
|
|
die() { printf 'rig-runner: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
usage: rig runner remove [options]
|
|
|
|
--local wipe this box's registration without contacting GitHub
|
|
(no token needed)
|
|
--user <name> unprivileged service user (default: github-runner)
|
|
|
|
Stops and uninstalls the systemd service, then deregisters the runner from
|
|
GitHub. The runner binary and its user stay on the box, so a later
|
|
`rig runner install` re-registers without downloading anything.
|
|
|
|
Provide the short-lived REMOVAL token — not a registration token, they are
|
|
different endpoints — via the RUNNER_REMOVE_TOKEN env var or the interactive
|
|
prompt:
|
|
gh api -X POST repos/<owner/repo>/actions/runners/remove-token
|
|
It is consumed at deregistration and never written to disk by rig.
|
|
|
|
--local is the escape hatch for when the registration is already gone
|
|
server-side, or you cannot mint a token: the box is cleaned, but a stale
|
|
offline runner is left listed in the repo — delete it by hand from
|
|
Settings > Actions > Runners.
|
|
|
|
Convergent: safe to re-run; a box with no runner installed exits 0.
|
|
EOF
|
|
}
|
|
|
|
# --- args (validated before the root check, so errors are testable) ---------
|
|
LOCAL=0
|
|
RUNNER_USER="github-runner"
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--local) LOCAL=1; shift ;;
|
|
--user)
|
|
[ $# -ge 2 ] || die "--user needs a value" 2
|
|
RUNNER_USER="$2"; shift 2 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) die "unknown flag: $1" 2 ;;
|
|
esac
|
|
done
|
|
|
|
# --- validation ------------------------------------------------------------
|
|
[ "$RUNNER_USER" != "root" ] || die "runner user must not be root" 2
|
|
|
|
# --- guards ----------------------------------------------------------------
|
|
[ "$(id -u)" -eq 0 ] || die "must run as root"
|
|
|
|
# --- nothing to remove? -----------------------------------------------------
|
|
if ! id -u "$RUNNER_USER" >/dev/null 2>&1; then
|
|
log "no ${RUNNER_USER} user on this box; nothing to remove"
|
|
exit 0
|
|
fi
|
|
USER_HOME="$(getent passwd "$RUNNER_USER" | cut -d: -f6)"
|
|
RUNNER_DIR="$USER_HOME/actions-runner"
|
|
if [ ! -e "$RUNNER_DIR/.runner" ] && [ ! -e "$RUNNER_DIR/.service" ]; then
|
|
log "no runner registered in ${RUNNER_DIR}; nothing to remove"
|
|
exit 0
|
|
fi
|
|
|
|
# --- removal token — only when a server-side deregistration is pending -------
|
|
REMOVE_TOKEN=""
|
|
if [ -e "$RUNNER_DIR/.runner" ] && [ "$LOCAL" -eq 0 ]; then
|
|
REMOVE_TOKEN="${RUNNER_REMOVE_TOKEN:-}"
|
|
# Prompt only on a tty: headless, a bare `read` dies under set -e with no
|
|
# message at all — the drill hit exactly this (wrong env var, exit 1, zero
|
|
# output). Refuse loudly, naming both the variable and the tokenless out.
|
|
if [ -z "$REMOVE_TOKEN" ]; then
|
|
[ -t 0 ] || die "RUNNER_REMOVE_TOKEN is unset and stdin is not a tty — set RUNNER_REMOVE_TOKEN to run unattended, or use --local"
|
|
read -rsp "runner removal token (short-lived): " REMOVE_TOKEN || { echo; die "no removal token read (EOF) — set RUNNER_REMOVE_TOKEN to run unattended, or use --local"; }
|
|
echo
|
|
fi
|
|
[ -n "$REMOVE_TOKEN" ] || die "empty removal token"
|
|
fi
|
|
|
|
# --- service ---------------------------------------------------------------
|
|
# This must come first in BOTH paths. config.sh's removal throws "Uninstall
|
|
# service first" while the service is configured; and `remove --local` skips
|
|
# that check entirely, which would otherwise strand a running service pointed
|
|
# at config that no longer exists.
|
|
if [ -e "$RUNNER_DIR/.service" ]; then
|
|
log "stopping and uninstalling the service"
|
|
(cd "$RUNNER_DIR" && ./svc.sh stop)
|
|
(cd "$RUNNER_DIR" && ./svc.sh uninstall)
|
|
else
|
|
log "no service installed; skipping"
|
|
fi
|
|
|
|
# --- deregister -------------------------------------------------------------
|
|
if [ -e "$RUNNER_DIR/.runner" ]; then
|
|
if [ "$LOCAL" -eq 1 ]; then
|
|
log "wiping the local registration only (--local)"
|
|
(cd "$RUNNER_DIR" && runuser -u "$RUNNER_USER" -- env HOME="$USER_HOME" \
|
|
./config.sh remove --local)
|
|
warn "a stale offline runner is still listed in the repo — delete it from Settings > Actions > Runners"
|
|
else
|
|
log "deregistering from GitHub"
|
|
(cd "$RUNNER_DIR" && runuser -u "$RUNNER_USER" -- env HOME="$USER_HOME" \
|
|
./config.sh remove --token "$REMOVE_TOKEN")
|
|
fi
|
|
rm -f "$RUNNER_DIR/.rig-labels"
|
|
fi
|
|
|
|
log "runner removed; the binary stays at ${RUNNER_DIR} for a future rig runner install"
|