- add scripts/gitea/register-runner.sh (idempotent register, host/docker modes, capacity arg, admin-API registration token, --force re-register) - GITEA_VM_SETUP.md Step 11: runner install/register, host-vs-docker tradeoffs, token externalization (env_file), concurrency (capacity), token rotation, end-to-end CI verification - document runner registration + secrets in persist/ephemeral table Live runner hardened separately: capacity 1->2, GITEA_NPM_TOKEN moved from inline config.yaml to chmod-600 runner.env via env_file.
107 lines
4.7 KiB
Bash
Executable File
107 lines
4.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# register-runner.sh — Reproducibly register (or re-register) a Gitea Actions
|
|
# runner against the local/VM Gitea instance.
|
|
#
|
|
# Why this exists: the runner was originally registered by hand, which is not
|
|
# reproducible for the next operator. This script captures the canonical flow:
|
|
# fetch a registration token from Gitea, register act_runner with the agreed
|
|
# labels + capacity, and externalise the npm token into a gitignored env_file
|
|
# (never inline in config.yaml).
|
|
#
|
|
# Usage:
|
|
# GITEA_ADMIN_USER=gitea-admin GITEA_ADMIN_PASS=... bash register-runner.sh
|
|
# bash register-runner.sh --instance http://localhost:3300 --name bytelyst-mac
|
|
# bash register-runner.sh --mode docker # containerized labels
|
|
# bash register-runner.sh --capacity 2 # parallel jobs
|
|
#
|
|
# Idempotent: if a runner is already registered (.runner exists), it prints the
|
|
# current registration and exits unless --force is passed.
|
|
set -euo pipefail
|
|
|
|
# ── defaults ───────────────────────────────────────────────────────────────
|
|
INSTANCE="${GITEA_INSTANCE:-http://localhost:3300}"
|
|
RUNNER_NAME="${RUNNER_NAME:-$(hostname -s)}"
|
|
CAPACITY="${RUNNER_CAPACITY:-2}"
|
|
MODE="host" # host | docker
|
|
FORCE=0
|
|
CONFIG_DIR="${ACT_RUNNER_CONFIG_DIR:-/opt/homebrew/etc/act_runner}"
|
|
RUNNER_FILE="${ACT_RUNNER_FILE:-/opt/homebrew/var/lib/act_runner/.runner}"
|
|
ENV_FILE="${ACT_RUNNER_ENV_FILE:-$CONFIG_DIR/runner.env}"
|
|
|
|
# Docker image used when MODE=docker (mirrors GitHub's ubuntu-latest closely).
|
|
DOCKER_IMAGE="${RUNNER_DOCKER_IMAGE:-catthehacker/ubuntu:act-latest}"
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--instance) INSTANCE="$2"; shift 2 ;;
|
|
--name) RUNNER_NAME="$2"; shift 2 ;;
|
|
--capacity) CAPACITY="$2"; shift 2 ;;
|
|
--mode) MODE="$2"; shift 2 ;;
|
|
--force) FORCE=1; shift ;;
|
|
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
*) echo "unknown arg: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
command -v act_runner >/dev/null 2>&1 || {
|
|
echo "✗ act_runner not on PATH. Install: brew install act_runner" >&2
|
|
exit 1
|
|
}
|
|
|
|
# ── labels per mode ──────────────────────────────────────────────────────────
|
|
if [ "$MODE" = "docker" ]; then
|
|
LABELS="ubuntu-latest:docker://$DOCKER_IMAGE,ubuntu-22.04:docker://$DOCKER_IMAGE,self-hosted:host"
|
|
else
|
|
LABELS="ubuntu-latest:host,macos-latest:host,macos-15:host,self-hosted:host"
|
|
fi
|
|
|
|
echo "── Gitea runner registration ──"
|
|
echo " instance : $INSTANCE"
|
|
echo " name : $RUNNER_NAME"
|
|
echo " mode : $MODE"
|
|
echo " capacity : $CAPACITY"
|
|
echo " labels : $LABELS"
|
|
|
|
# ── already registered? ──────────────────────────────────────────────────────
|
|
if [ -f "$RUNNER_FILE" ] && [ "$FORCE" -ne 1 ]; then
|
|
echo ""
|
|
echo "✓ runner already registered ($RUNNER_FILE). Current identity:"
|
|
python3 - "$RUNNER_FILE" <<'PY' 2>/dev/null || cat "$RUNNER_FILE"
|
|
import json, sys
|
|
d = json.load(open(sys.argv[1]))
|
|
for k in ("id", "uuid", "name", "address", "labels", "ephemeral"):
|
|
print(f" {k}: {d.get(k)}")
|
|
PY
|
|
echo ""
|
|
echo " Pass --force to re-register (this invalidates the old runner)."
|
|
exit 0
|
|
fi
|
|
|
|
# ── fetch a registration token ───────────────────────────────────────────────
|
|
# Admin-scoped: GET /admin/runners/registration-token (Gitea >= 1.20).
|
|
: "${GITEA_ADMIN_USER:?set GITEA_ADMIN_USER}"
|
|
: "${GITEA_ADMIN_PASS:?set GITEA_ADMIN_PASS}"
|
|
|
|
REG_TOKEN=$(curl -fsS -u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASS" \
|
|
"$INSTANCE/api/v1/admin/runners/registration-token" \
|
|
| python3 -c "import json,sys; print(json.load(sys.stdin)['token'])")
|
|
[ -n "$REG_TOKEN" ] || { echo "✗ could not fetch registration token" >&2; exit 1; }
|
|
echo "✓ registration token obtained"
|
|
|
|
# ── register ────────────────────────────────────────────────────────────────
|
|
[ "$FORCE" -eq 1 ] && rm -f "$RUNNER_FILE"
|
|
act_runner register \
|
|
--no-interactive \
|
|
--instance "$INSTANCE" \
|
|
--token "$REG_TOKEN" \
|
|
--name "$RUNNER_NAME" \
|
|
--labels "$LABELS" \
|
|
--config "$CONFIG_DIR/config.yaml"
|
|
echo "✓ runner registered"
|
|
|
|
echo ""
|
|
echo "Next: externalise secrets into $ENV_FILE (see GITEA_VM_SETUP.md §11),"
|
|
echo "set runner.capacity: $CAPACITY in config.yaml, then:"
|
|
echo " brew services restart act_runner"
|