Files
proxmox-scripts/ct/runner.sh
T

156 lines
6.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Allgemeiner Gitea-Actions-Runner — instanzweit, OHNE Deploy-Rechte
#
# Motivation (nexus K-114-Blocker): Der nexus-Runner läuft auf dem
# Produktions-LXC und besitzt sudoers-Deploy-Rechte — er darf deshalb NICHT
# instanzweit registriert werden (jedes Repo könnte sonst Workflows auf der
# Produktionsmaschine ausführen). Dieser LXC ist die saubere Trennung:
# - instanzweite Registrierung (Site Administration → Actions → Runners)
# - Label "homelab:host" (Deploy-Jobs bleiben auf "nexus")
# - KEINE sudoers-Regeln, kein Zugriff auf Produktions-Verzeichnisse
# - Docker via Nesting für Wegwerf-Test-Container (z. B. pgvector in CI)
#
# Sicherheitsmodell: siehe Kopfkommentar in install/runner-install.sh —
# instanzweit + docker-Gruppe heißt: jedes Repo der Instanz kann diesen LXC
# kontrollieren. Akzeptiert, WEIL er nichts besitzt. Nicht auf privilegierte
# LXCs übertragen.
#
# Run on a Proxmox VE host:
# bash -c "$(curl -fsSL https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/ct/runner.sh)"
set -euo pipefail
APP="runner"
APP_DESCRIPTION="Allgemeiner Gitea-Actions-Runner (instanzweit, Label homelab, Docker, ohne Deploy-Rechte)"
LIB_URL="${LIB_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/lib}"
INSTALL_SCRIPT_URL="${INSTALL_SCRIPT_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/install/runner-install.sh}"
source <(curl -fsSL "$LIB_URL/build.func")
DEFAULT_HOSTNAME="runner"
DEFAULT_DISK="30"
DEFAULT_CORES="4"
DEFAULT_RAM="6144"
# ── Validierung (Review-Finding 80): Werte wandern in die Deploy-Env und in
# systemd/argv — strikte Zeichenklassen, Re-Prompt statt Abbruch.
# Bewusst LOKALE Validatoren: die Libs werden zur Laufzeit von main geladen,
# dieses Script muss aber unabhängig vom Merge-Stand der K-114-Helfer
# (prompt_validated/require_valid) funktionieren. Semantik ist identisch;
# Konsolidierung auf die build.func-Helfer ist als Follow-up notiert. ──────
_valid_url() { [[ "$1" =~ ^https?://[A-Za-z0-9.-]+(:[0-9]{1,5})?$ ]]; }
_valid_token() { [[ "$1" =~ ^[A-Za-z0-9_-]{16,128}$ ]]; }
_valid_word() { [[ "$1" =~ ^[A-Za-z0-9._:,-]+$ ]]; }
_prompt_until_valid() { # var prompt default validator secret(0|1)
local __var="$1" __prompt="$2" __default="$3" __validator="$4" __secret="${5:-0}" __val
while true; do
if [[ "$__secret" == "1" ]]; then
read -rsp "$__prompt" __val || { echo; msg_err "Eingabe abgebrochen (EOF)"; exit 1; }
echo
else
read -rp "$__prompt" __val || { echo; msg_err "Eingabe abgebrochen (EOF)"; exit 1; }
fi
__val="${__val:-$__default}"
if [[ -n "$__val" ]] && "$__validator" "$__val"; then
printf -v "$__var" '%s' "$__val"
return 0
fi
msg_warn "Ungültige Eingabe — bitte erneut (kein Paste mit Sonderzeichen)."
done
}
prompt_app_config() {
echo
echo "── Runner configuration ─────────────────────────────────────"
# env-präsetzte Werte werden validiert (Abbruch bei ungültig — K-114-Konvention),
# interaktive Eingaben re-prompten bis gültig.
if [[ -n "${GITEA_INSTANCE_URL:-}" ]]; then
_valid_url "$GITEA_INSTANCE_URL" || { msg_err "GITEA_INSTANCE_URL (env) ungültig"; exit 1; }
else
_prompt_until_valid GITEA_INSTANCE_URL \
"Gitea instance URL [https://gitea.luki-net.org]: " \
"https://gitea.luki-net.org" _valid_url 0
fi
# WICHTIG: den INSTANZWEITEN Token verwenden
# (Site Administration → Actions → Runners → Create new runner),
# NICHT den Repo-Token — sonst wiederholt sich der K-114-Scope-Blocker.
if [[ -n "${RUNNER_TOKEN:-}" ]]; then
_valid_token "$RUNNER_TOKEN" || { msg_err "RUNNER_TOKEN (env) ungültig (16128 Zeichen [A-Za-z0-9_-])"; exit 1; }
else
_prompt_until_valid RUNNER_TOKEN \
"INSTANZWEITER Runner-Registration-Token: " \
"" _valid_token 1
fi
RUNNER_NAME="${RUNNER_NAME:-$CT_HOSTNAME}"
RUNNER_LABELS="${RUNNER_LABELS:-homelab:host}"
RUNNER_VERSION="${RUNNER_VERSION:-0.2.13}"
NODE_MAJOR="${NODE_MAJOR:-22}"
_valid_word "$RUNNER_NAME" || { msg_err "RUNNER_NAME ungültig"; exit 1; }
_valid_word "$RUNNER_LABELS" || { msg_err "RUNNER_LABELS ungültig"; exit 1; }
[[ "$RUNNER_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { msg_err "RUNNER_VERSION ungültig"; exit 1; }
[[ "$NODE_MAJOR" =~ ^[0-9]+$ ]] || { msg_err "NODE_MAJOR ungültig"; exit 1; }
echo " → instance: $GITEA_INSTANCE_URL"
echo " → runner: $RUNNER_NAME labels: $RUNNER_LABELS (act_runner $RUNNER_VERSION, host mode, scope: INSTANZ)"
}
push_app_config() {
msg_info "Pushing runner config into container..."
local tmpf; tmpf=$(mktemp)
# Werte sind oben strikt validiert (keine Quotes/Whitespace möglich) —
# damit ist die env-Datei frei von Quoting-/Injection-Fallen (vgl. Finding 76).
cat >"$tmpf" <<EOF
GITEA_INSTANCE_URL=$GITEA_INSTANCE_URL
RUNNER_TOKEN=$RUNNER_TOKEN
RUNNER_NAME=$RUNNER_NAME
RUNNER_LABELS=$RUNNER_LABELS
RUNNER_VERSION=$RUNNER_VERSION
NODE_MAJOR=$NODE_MAJOR
EOF
pct push "$CTID" "$tmpf" /root/runner.deploy.env --perms 600
rm -f "$tmpf"
}
# Docker im unprivilegierten LXC braucht nesting+keyctl (Test-Container in CI).
enable_nesting() {
msg_info "Enabling nesting+keyctl features (Docker für CI-Test-Container)..."
pct set "$CTID" --features nesting=1,keyctl=1
pct reboot "$CTID"
for _ in $(seq 1 30); do
pct exec "$CTID" -- true >/dev/null 2>&1 && break
sleep 2
done
msg_ok "Container restarted with nesting enabled"
}
print_app_summary() {
local runner_state
runner_state=$(pct exec "$CTID" -- systemctl is-active act-runner.service 2>/dev/null | tr -d '\r\n')
cat <<EOF
Gitea-Actions-Runner: $RUNNER_NAME [$RUNNER_LABELS] — $runner_state
Scope: INSTANZWEIT — bedient alle Repos der Instanz
Mode: host (Docker verfügbar für Test-Container)
Sicherheit: kein sudoers, keine Deploy-Rechte, keine Produktions-Mounts
(Modell: siehe install/runner-install.sh Kopfkommentar)
Verify: $GITEA_INSTANCE_URL → Site Administration → Actions → Runners
Workflows anderer Repos nutzen: runs-on: ${RUNNER_LABELS%%:*}
(Deploy-Jobs von nexus bleiben auf dem nexus-LXC-Runner, Label "nexus".)
Logs: pct exec $CTID -- journalctl -u act-runner -f
EOF
}
trap _on_error ERR
preflight_pve
show_header "$APP" "$APP_DESCRIPTION"
prompt_lxc_config
prompt_app_config
resolve_debian_template
create_lxc
enable_nesting
push_app_config
bootstrap_install_script "$INSTALL_SCRIPT_URL"
print_summary