From cab748f32eb50da46b407d900cd4b8885ddf6a4d Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Fri, 17 Jul 2026 18:29:30 +0200 Subject: [PATCH] Lucy kann Projekt-Repos anlegen (gitea-repo-create.sh) - PRIVAT-only Lucke im "Projekte selbst starten"-Weg: Werkstatt konnte nur Branches in bestehende Repos proposen, kein neues Projekt-Repo anlegen. Neues Skript: POST /api/v1/user/repos, IMMER privat (Gitea ist oeffentlich erreichbar!), auto_init + default main, Token aus ~/.git-credentials (nie ausgegeben), Audit-Log + stiller Chronik-Spiegel je Anlage. Braucht Token-Scope write:user (aktuelles Box-Token hat nur write:repository); ohne das meldet das Skript GENAU, welches Token in Gitea zu generieren ist, statt kryptisch zu scheitern. Token-Upgrade = Commander-Handgriff (Credential). Co-Authored-By: Claude Fable 5 --- deploy/deploy.sh | 5 ++- deploy/gitea-repo-create.sh | 84 +++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 deploy/gitea-repo-create.sh diff --git a/deploy/deploy.sh b/deploy/deploy.sh index b1c0fc6..62d343c 100644 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -126,6 +126,9 @@ cp "$SRC/deploy/pruefstand/pruefstand.sh" "$HOME/.hermes/scripts/pruefstand.sh" # Python-Nebendienst-venvs (mem0, voice) — melden nur, ändern nichts. cp "$SRC/deploy/restore-probe.sh" "$HOME/.hermes/scripts/restore-probe.sh" cp "$SRC/deploy/venv-audit.sh" "$HOME/.hermes/scripts/venv-audit.sh" +# Gitea-Repo-Anlage (17.07.2026): schließt Lucys „Projekte selbst starten"-Lücke — +# legt PRIVATE Projekt-Repos an (Token aus ~/.git-credentials, braucht write:user-Scope). +cp "$SRC/deploy/gitea-repo-create.sh" "$HOME/.hermes/scripts/gitea-repo-create.sh" # Werkstatt-Kanban-Profil (Ideen-Queue, 10.07.2026): Leitplanken des Worker-Profils nachziehen # (Profil selbst wurde einmalig per `hermes profile create werkstatt --clone` angelegt). [ -d "$HOME/.hermes/profiles/werkstatt" ] && cp "$SRC/deploy/werkstatt-SOUL.md" "$HOME/.hermes/profiles/werkstatt/SOUL.md" @@ -133,7 +136,7 @@ cp "$SRC/deploy/venv-audit.sh" "$HOME/.hermes/scripts/venv-audit.sh" # statt Lucy-default. Profil selbst wird einmalig per `hermes profile create betrieb # --clone-from werkstatt` angelegt (model coder→hermes, Description fürs Specifier-Routing). [ -d "$HOME/.hermes/profiles/betrieb" ] && cp "$SRC/deploy/betrieb-SOUL.md" "$HOME/.hermes/profiles/betrieb/SOUL.md" -chmod +x "$HOME/.hermes/scripts/fremdblick.sh" "$HOME/.hermes/scripts/dreaming-feed.sh" "$HOME/.hermes/scripts/worker.sh" "$HOME/.hermes/scripts/chef-gutachter-feed.sh" "$HOME/.hermes/scripts/hermes-release-radar-feed.sh" "$HOME/.hermes/scripts/radar-selbstkritik-wrapper.sh" "$HOME/.hermes/scripts/idle-radar-feed.sh" "$HOME/.hermes/scripts/selbst-inventur.sh" "$HOME/.hermes/scripts/karten-gutachter.sh" "$HOME/.hermes/scripts/trend-radar-feed.sh" "$HOME/.hermes/scripts/pruefstand.sh" "$HOME/.hermes/scripts/restore-probe.sh" "$HOME/.hermes/scripts/venv-audit.sh" +chmod +x "$HOME/.hermes/scripts/fremdblick.sh" "$HOME/.hermes/scripts/dreaming-feed.sh" "$HOME/.hermes/scripts/worker.sh" "$HOME/.hermes/scripts/chef-gutachter-feed.sh" "$HOME/.hermes/scripts/hermes-release-radar-feed.sh" "$HOME/.hermes/scripts/radar-selbstkritik-wrapper.sh" "$HOME/.hermes/scripts/idle-radar-feed.sh" "$HOME/.hermes/scripts/selbst-inventur.sh" "$HOME/.hermes/scripts/karten-gutachter.sh" "$HOME/.hermes/scripts/trend-radar-feed.sh" "$HOME/.hermes/scripts/pruefstand.sh" "$HOME/.hermes/scripts/restore-probe.sh" "$HOME/.hermes/scripts/venv-audit.sh" "$HOME/.hermes/scripts/gitea-repo-create.sh" # Werkstatt-Skill (Autonomie E6): Selbstwartungs-Kreislauf für Hermes. mkdir -p "$HOME/.hermes/skills/wartung" cp "$SRC/deploy/skills/wartung/SKILL.md" "$HOME/.hermes/skills/wartung/SKILL.md" diff --git a/deploy/gitea-repo-create.sh b/deploy/gitea-repo-create.sh new file mode 100644 index 0000000..e47979a --- /dev/null +++ b/deploy/gitea-repo-create.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# Gitea-Repo-Anlage für Lucy (17.07.2026): schließt die Lücke im „Projekte selbst +# starten"-Weg — bislang konnte die Werkstatt nur Branches in BESTEHENDE Repos +# proposen, aber kein neues Projekt-Repo anlegen. +# +# Nutzung: gitea-repo-create.sh ["Beschreibung"] +# Ergebnis (stdout, letzte Zeile): CLONE → Aufrufer kann direkt klonen. +# +# HARTE Sicherheits-Leitplanken (Gitea ist öffentlich erreichbar!): +# • Repos werden IMMER PRIVAT angelegt (kein öffentliches Repo aus Versehen). +# • Token wird aus ~/.git-credentials gelesen, NIE ausgegeben/geloggt. +# • Jede Anlage wird protokolliert (Audit-Spur) + still an die Chronik gespiegelt. +# Braucht ein Token mit Scope `write:user` (zusätzlich zu `write:repository`); ohne das +# meldet Gitea 403 — das Skript sagt dann genau, was zu tun ist (Token in Gitea neu +# generieren), statt kryptisch zu scheitern. +set -uo pipefail + +NAME="${1:-}" +BESCHREIBUNG="${2:-Von Lucy angelegtes Projekt-Repo.}" +CRED="$HOME/.git-credentials" +LOG="$HOME/.hermes/state/gitea-repos-created.log" + +if [ -z "$NAME" ]; then + echo "Nutzung: gitea-repo-create.sh [\"Beschreibung\"]" >&2 + exit 2 +fi +# Repo-Name defensiv prüfen (Gitea erlaubt Buchstaben/Ziffern/-/_/.) +if ! printf '%s' "$NAME" | grep -qE '^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$'; then + echo "Ungültiger Repo-Name '$NAME' (erlaubt: Buchstaben/Ziffern/.-_, Beginn alphanumerisch)." >&2 + exit 2 +fi +if [ ! -r "$CRED" ]; then + echo "Keine ~/.git-credentials gefunden — ohne gespeicherte Gitea-Anmeldung geht das nicht." >&2 + exit 1 +fi + +# Zeile für den Gitea-Host herausgreifen (falls mehrere Hosts hinterlegt sind) +LINE="$(grep -m1 'git\.tobisniceshomelab\.ddnsfree\.com' "$CRED" || head -1 "$CRED")" +USER="$(printf '%s' "$LINE" | sed -E 's#https://([^:]+):.*#\1#')" +TOKEN="$(printf '%s' "$LINE" | sed -E 's#https://[^:]+:([^@]+)@.*#\1#')" +HOST="$(printf '%s' "$LINE" | sed -E 's#https://[^@]+@([^/]+).*#\1#')" +BASE="https://${HOST}" + +if [ -z "$USER" ] || [ -z "$TOKEN" ] || [ -z "$HOST" ]; then + echo "Konnte User/Token/Host nicht aus ~/.git-credentials lesen." >&2 + exit 1 +fi + +RESP="$(mktemp)"; trap 'rm -f "$RESP"' EXIT +CODE="$(curl -s -o "$RESP" -w '%{http_code}' -X POST "$BASE/api/v1/user/repos" \ + -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ + -d "$(python3 -c 'import json,sys; print(json.dumps({"name":sys.argv[1],"description":sys.argv[2],"private":True,"auto_init":True,"default_branch":"main"}))' "$NAME" "$BESCHREIBUNG")")" + +case "$CODE" in + 201) + CLONE="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("clone_url",""))' "$RESP" 2>/dev/null)" + FULL="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("full_name",""))' "$RESP" 2>/dev/null)" + mkdir -p "$(dirname "$LOG")" + echo "$(date '+%Y-%m-%d %H:%M') angelegt (privat): $FULL" >> "$LOG" + # Stiller Chronik-Spiegel (Audit-Spur, wie die Radar-Meldungen) + curl -sf -m 5 -X POST "${MC_ANNOUNCE_URL:-http://127.0.0.1:9001/api/voice/announce}" \ + -H 'Content-Type: application/json' \ + --data "$(python3 -c 'import json,sys; print(json.dumps({"text":"Neues PRIVATES Projekt-Repo angelegt: "+sys.argv[1],"subject":"Gitea","source":"gitea-repo-create","priority":"silent"}))' "$FULL")" \ + >/dev/null 2>&1 || true + echo "Repo '$FULL' angelegt (privat, main initialisiert)." + echo "CLONE ${CLONE}" + exit 0 ;; + 403) + if grep -q 'write:user' "$RESP"; then + echo "FEHLT: Das gespeicherte Gitea-Token darf keine Repos anlegen (Scope 'write:user' fehlt)." >&2 + echo "So wird es freigeschaltet (einmalig, durch den Commander):" >&2 + echo " Gitea → Einstellungen → Anwendungen → neues Token mit Scopes 'write:repository' UND 'write:user'," >&2 + echo " dann in ~/.git-credentials das alte Token ersetzen. Danach funktioniert dieses Skript." >&2 + else + echo "403 von Gitea:" >&2; head -c 300 "$RESP" >&2; echo >&2 + fi + exit 3 ;; + 409) + echo "Ein Repo namens '$NAME' existiert bereits." >&2 + exit 4 ;; + *) + echo "Gitea antwortete mit HTTP $CODE:" >&2; head -c 300 "$RESP" >&2; echo >&2 + exit 1 ;; +esac