Faden 8: Tabu-Pfade hart sperren (pre_tool_call-Guard)
Fallstrick #2: Worker koennen in die falsche Ebene wandern - Patches im Live-Checkout ~/mission-control-v2 ablegen oder die Hermes-Quelle ~/.hermes/hermes-agent anfassen. Hermes' native is_write_denied deckt diese Pfade NICHT ab (nur Credentials/System, live geprueft). deploy/agent-hooks/tabu-pfade-guard.py (neu): pre_tool_call-Hook, blockt Schreib-Operationen (write_file/patch + terminal git-write/sed-i/redirect/rm) auf den home-verankerten Live-Checkout und die Hermes-Quelle - NUR fuer echte Kanban-Worker (task_id t_<hex>); Lucy/CLI (UUID) = No-op (~15 ms). Der Workspace-KLON (<workspace>/mission-control-v2) bleibt beschreibbar (nur der home-verankerte Pfad ist tabu) -> legitime Worker-Arbeit ungestoert. Lesen erlaubt. 25 Faelle gruen (Block + Allow, inkl. git log 2>/dev/null, Redirect nach /tmp, Workspace-Commit). deploy.sh synct den Hook (cmp-Guard). Registrierung in ~/.hermes/config.yaml (pre_tool_call) einmalig von Hand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
"""pre_tool_call-Guard (Faden 8, 13.07.2026): sperrt Schreibzugriffe von Kanban-Workern
|
||||
auf den LIVE-Checkout ~/mission-control-v2 und die Hermes-QUELLE ~/.hermes/hermes-agent
|
||||
HART - egal welches Profil. Nur fuer echte Worker (task_id = t_<hex>); Lucy/Wartung/
|
||||
interaktiv/CLI (UUID-task_id) = sofortiger No-op. Loest Fallstrick #2 (Worker wandert in
|
||||
die falsche Ebene / lag Patches im Live-Checkout ab). Die native is_write_denied deckt
|
||||
diese Pfade NICHT ab (nur Credentials/System) -> dieser Guard schliesst die Luecke.
|
||||
|
||||
WICHTIG: Der Worker KLONT MC2 in seinen Workspace (<workspace>/mission-control-v2) und
|
||||
arbeitet DORT legitim. Gesperrt wird deshalb NUR der home-verankerte Live-Checkout
|
||||
($HOME/mission-control-v2), NIE der blosse Name "mission-control-v2". Lesen ist erlaubt -
|
||||
geblockt werden nur Schreib-Operationen.
|
||||
|
||||
Ausgabe {"action":"block","message":...} = Tool geblockt; {} = durchlassen.
|
||||
"""
|
||||
import sys, json, os, re
|
||||
|
||||
|
||||
def out(obj):
|
||||
sys.stdout.write(json.dumps(obj))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
try:
|
||||
payload = json.loads(sys.stdin.read() or "{}")
|
||||
except Exception:
|
||||
out({})
|
||||
|
||||
extra = payload.get("extra") or {}
|
||||
task_id = str(extra.get("task_id") or payload.get("task_id") or "")
|
||||
# Scope: NUR echte Kanban-Worker. Hermes setzt fuer Lucy/CLI eine UUID-task_id
|
||||
# (agent/turn_context.py) -> nur das t_<hex>-Muster ist ein Worker.
|
||||
if not re.match(r"^t_[0-9a-f]{4,}$", task_id):
|
||||
out({})
|
||||
|
||||
tool = payload.get("tool_name") or ""
|
||||
ti = payload.get("tool_input") or {}
|
||||
home = os.path.realpath(os.path.expanduser("~"))
|
||||
LIVE = os.path.join(home, "mission-control-v2")
|
||||
SRC = os.path.join(home, ".hermes", "hermes-agent")
|
||||
|
||||
MSG = (
|
||||
"TABU (Faden 8): Schreiben an dieser Stelle ist fuer Worker gesperrt. Der Live-Checkout "
|
||||
"~/mission-control-v2 und die Hermes-Quelle ~/.hermes/hermes-agent duerfen NIE veraendert "
|
||||
"werden. Arbeite im FRISCHEN Klon deines Task-Workspaces; MC2-Aenderungen kommen als "
|
||||
"Vorschlags-Branch (nie am Live-Checkout), Hermes-Verhalten nur ueber Config/SOUL/Skill/"
|
||||
"Hook/MCP. Siehe docs/wissen/GRENZEN.md."
|
||||
)
|
||||
|
||||
|
||||
def block():
|
||||
out({"action": "block", "message": MSG})
|
||||
|
||||
|
||||
def under_tabu(path):
|
||||
rp = os.path.realpath(path)
|
||||
return rp == LIVE or rp == SRC or rp.startswith(LIVE + os.sep) or rp.startswith(SRC + os.sep)
|
||||
|
||||
|
||||
# --- Datei-Tools: Zielpfad kanonisch pruefen (zuverlaessig) -------------------------
|
||||
if tool in ("write_file", "patch"):
|
||||
fp = ti.get("path") or ti.get("file_path") or ti.get("filepath") or ""
|
||||
if not fp:
|
||||
out({})
|
||||
fp = os.path.expanduser(fp)
|
||||
cwd = payload.get("cwd") or ""
|
||||
if not os.path.isabs(fp) and cwd:
|
||||
fp = os.path.join(cwd, fp)
|
||||
if under_tabu(fp):
|
||||
block()
|
||||
out({})
|
||||
|
||||
# --- Terminal: nur bei Schreib-Operation, die auf einen Tabu-Pfad zielt -------------
|
||||
if tool == "terminal":
|
||||
cmd = ti.get("command") or ""
|
||||
if not cmd:
|
||||
out({})
|
||||
# Home-verankerte Tabu-Formen. Der Workspace-Klon
|
||||
# ($HOME/.hermes/kanban/.../mission-control-v2) enthaelt KEINE davon als Teilstring.
|
||||
tabu_forms = [
|
||||
LIVE, "~/mission-control-v2", "$HOME/mission-control-v2", "${HOME}/mission-control-v2",
|
||||
SRC, "~/.hermes/hermes-agent", "$HOME/.hermes/hermes-agent", "${HOME}/.hermes/hermes-agent",
|
||||
]
|
||||
tabu_alt = "(?:" + "|".join(re.escape(t) for t in tabu_forms) + ")"
|
||||
if not re.search(tabu_alt, cmd):
|
||||
out({}) # kein home-verankerter Tabu-Pfad referenziert -> Workspace-Arbeit, durchlassen
|
||||
|
||||
# (a) git-Schreib-Subkommando (Repo-Kontext ist der referenzierte Tabu-Pfad).
|
||||
if re.search(
|
||||
r"(?:^|[^\w])git(?:\s+-C\s+\S+)?\s+(?:-[\w-]+\s+)*"
|
||||
r"(commit|push|reset|checkout|switch|merge|add|rm|mv|clean|stash|rebase|apply|restore|init|remote|config)\b",
|
||||
cmd,
|
||||
):
|
||||
block()
|
||||
# (b) sed -i, das einen Tabu-Pfad anfasst.
|
||||
if re.search(r"(?:^|[^\w])sed\s+-i\S*\s+[^|&;]*" + tabu_alt, cmd):
|
||||
block()
|
||||
# (c) Umleitung > / >> / tee, die auf einen Tabu-Pfad ZIELT (nicht 2>/dev/null o.ae.).
|
||||
if re.search(r"(?:>>?|(?:^|[^\w])tee\s+(?:-a\s+)?)\s*" + tabu_alt, cmd):
|
||||
block()
|
||||
# (d) destruktiv/kopierend mit Tabu-Pfad im selben Kommando-Segment.
|
||||
if re.search(
|
||||
r"(?:^|[^\w])(rm|rmdir|mv|cp|truncate|dd|chmod|chown|ln|install|mkdir|touch)\s+[^|&;]*" + tabu_alt,
|
||||
cmd,
|
||||
):
|
||||
block()
|
||||
out({})
|
||||
|
||||
out({})
|
||||
+1
-1
@@ -132,7 +132,7 @@ mkdir -p "$HOME/.hermes/agent-hooks"
|
||||
# Nur kopieren, wenn der Inhalt sich WIRKLICH geaendert hat — ein blindes cp aendert die
|
||||
# mtime auch bei identischem Inhalt und loest sonst bei JEDEM Deploy die harmlose
|
||||
# "script modified since approval"-Warnung von `hermes hooks doctor` aus.
|
||||
for _h in box-steckbrief-inject.sh pre-verify-gates.sh; do
|
||||
for _h in box-steckbrief-inject.sh pre-verify-gates.sh tabu-pfade-guard.py; do
|
||||
_src="$SRC/deploy/agent-hooks/$_h"; _dst="$HOME/.hermes/agent-hooks/$_h"
|
||||
cmp -s "$_src" "$_dst" 2>/dev/null || { cp "$_src" "$_dst"; chmod +x "$_dst"; }
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user