#!/usr/bin/env bash # Selbstreparatur-Modus (Autonomie 0g, Kür): Macht ein Hermes-Update den Gehirn-Check rot, # WEIL sich Config-Schlüssel geändert haben (v0.18-Klasse: „Unknown key … → stiller Default → # alle Tools hingen"), versucht die Box den Config-Bruch SELBST zu ziehen — bevor zurückgerollt # wird, um die neue Version zu behalten. NUR Config, NIE Code, NIE Security-Schlüssel. # # Sicher durch Kapselung — jeder Schritt ist reversibel und hart gegatet: # Backup → nur EINDEUTIGE (genau 1× vorkommende), nicht-sicherheitsrelevante Keys auskommentieren # → YAML muss gültig bleiben → Gehirn-Check (hermes-postcheck.sh) muss GRÜN werden → sonst zurück. # Schlimmster Fall bei Fehlgriff = exakt der heutige: Rollback. Der Aufrufer (autoupdate.sh) ruft # dies VOR seinem Rollback; bei Rückgabe 2 rollt er wie gehabt zurück + pinnt. # # Rückgabe: 0 = repariert (Gehirn-Check danach grün) · 2 = nichts sicher reparierbar. # Gibt bei Misserfolg eine Zeile „SELFREPAIR_SUGGESTION=" auf stdout aus. set -uo pipefail SRC_DIR="$(cd "$(dirname "$0")" && pwd)" HERMES="${HERMES_HOME:-$HOME/.hermes}" CFG="$HERMES/config.yaml" WARN_FILE="${HERMES_CONFIG_WARNINGS:-/tmp/hermes-config-warnings.txt}" LLAMA="${LLAMA_SWAP_URL:-http://127.0.0.1:8080}" VENV_PY="$HERMES/hermes-agent/venv/bin/python" export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" say(){ echo "[self-repair] $*"; } # ── 1) Evidenz: Postcheck-Warnungen + frisches Gateway-Journal ──────────────── EVID="$(cat "$WARN_FILE" 2>/dev/null)" JOURN="$(journalctl --user -u hermes-gateway --since '-6 minutes' --no-pager -o cat 2>/dev/null \ | grep -iE "Unknown [a-z._]+ '|deprecated .*(setting|option|config)|defaulting to|invalid config" \ | grep -v check_fn | head -10)" [ -z "$EVID" ] && EVID="$JOURN" if [ -z "$EVID" ]; then say "Keine Config-Bruch-Hinweise gefunden — hier ist (sicher) nichts zu reparieren." exit 2 fi say "Config-Hinweise:"; echo "$EVID" # LLM-Diagnose/Empfehlung (best-effort) — für die Meldung, egal ob wir reparieren. SUGG="$(curl -sf -m 60 "$LLAMA/v1/chat/completions" -H 'Content-Type: application/json' \ -d "$(python3 - "$EVID" <<'PY' import json, sys p = ("Ein Hermes-Agent-Update hat den Selbsttest rot gemacht. Log-Hinweise:\n" + sys.argv[1] + "\n\nNenne auf Deutsch in 1-2 kurzen Sätzen die wahrscheinliche Ursache und die konkrete " "Config-Korrektur in ~/.hermes/config.yaml (Schlüssel → neuer Wert). Keine Einleitung.") print(json.dumps({"model": "coder-lite", "max_tokens": 200, "temperature": 0.1, "messages": [{"role": "user", "content": p}]})) PY )" 2>/dev/null | python3 -c 'import sys,json; print((json.load(sys.stdin).get("choices") or [{}])[0].get("message",{}).get("content","").strip())' 2>/dev/null)" # ── 2) Offending Leaf-Keys ziehen ──────────────────────────────────────────── KEYS="$(echo "$EVID" | grep -oE "Unknown [a-zA-Z0-9_.]+|'[a-zA-Z0-9_.]+'" | sed -E "s/^Unknown //; s/'//g" | sort -u)" LEAVES="$(for k in $KEYS; do echo "${k##*.}"; done | sort -u | grep -vE '^(true|false|null|)$')" SEC_RX='token|secret|password|approval|api_server_key|ufw|sudo|allowlist|credential' BAK="$CFG.selfrepair-bak-$(date +%Y%m%d-%H%M%S)" cp -a "$CFG" "$BAK" CHANGED=""; SKIPPED="" for leaf in $LEAVES; do if echo "$leaf" | grep -qiE "$SEC_RX"; then SKIPPED="$SKIPPED $leaf(security-tabu)"; continue; fi # Nur EINDEUTIGE Schlüssel-Zeilen (genau 1×) anfassen — Mehrdeutige sind zu riskant. n="$(grep -cE "^[[:space:]]*${leaf}:" "$CFG" 2>/dev/null || echo 0)" if [ "$n" = "1" ]; then sed -i -E "s|^([[:space:]]*)(${leaf}:.*)$|\1# [selbstrepariert $(date +%F)] \2|" "$CFG" CHANGED="$CHANGED $leaf"; say "auskommentiert: $leaf (unbekannt/veraltet)" else SKIPPED="$SKIPPED $leaf(${n}x)" fi done [ -n "$SKIPPED" ] && say "nicht automatisch angefasst:$SKIPPED" if [ -z "$CHANGED" ]; then say "Nichts sicher automatisch reparierbar." cp -a "$BAK" "$CFG" echo "SELFREPAIR_SUGGESTION=$SUGG" exit 2 fi # ── 3) YAML noch gültig? ────────────────────────────────────────────────────── if [ -x "$VENV_PY" ] && ! "$VENV_PY" -c "import yaml; yaml.safe_load(open('$CFG'))" 2>/dev/null; then say "YAML nach Fix ungültig → zurück zum Backup." cp -a "$BAK" "$CFG"; echo "SELFREPAIR_SUGGESTION=$SUGG"; exit 2 fi # ── 4) Neustart + Gehirn-Check ──────────────────────────────────────────────── systemctl --user restart hermes-gateway; sleep 6 if bash "$SRC_DIR/hermes-postcheck.sh" >/dev/null 2>&1; then say "Gehirn-Check nach Selbstreparatur GRÜN." bash "$SRC_DIR/notify.sh" -s "[Box-Update]" \ "Commander, nach dem Hermes-Update hakte der Selbsttest wegen geänderter Einstellungen — ich habe das selbst gerichtet (angepasst:${CHANGED// /, }). Der Test ist wieder grün, die neue Version läuft. Ein Rollback war nicht nötig." || true exit 0 fi say "Auch nach Selbstreparatur rot → zurück zum Backup (der Aufrufer rollt zurück)." cp -a "$BAK" "$CFG" systemctl --user restart hermes-gateway; sleep 6 echo "SELFREPAIR_SUGGESTION=$SUGG" exit 2