tabu-pfade-guard: V16 — relative Pfade bei riskantem cwd blocken (Vorfall 16.07.)
Nacht-Worker t_7a05992a ersetzte 03:59 den Live-Checkout mit cwd=$HOME und
RELATIVEN Pfaden (rm -rf mission-control-v2 && git clone ...) — der Guard
prueft beim terminal-Tool nur den Kommandotext auf home-verankerte Formen
und liess das durch (.venv weg -> Gateway 203/EXEC-Crash-Loop).
Drei Stopfen:
(1) cwd IN einem Tabu-Pfad -> jede Schreib-Operation geblockt (Lesen frei).
(2) git clone/init mit Ziel direkt in $HOME geblockt (Worker klonen im
Task-Workspace); explizites Ziel ausserhalb $HOME bleibt erlaubt.
(3) cwd == Vorfahr eines Tabu-Pfads -> relative Nennung des Tabu-Ziels
zaehlt als Treffer; Lookarounds lassen den Workspace-Klon-Pfad
(.hermes/kanban/workspaces/<id>/mission-control-v2) weiter durch.
Nebenbefund zu: clone fehlte in der git-Schreibliste (a) — auch
git clone URL ~/mission-control-v2 war vorher ungeblockt.
Lokal bewiesen: 35/35 Payload-Faelle (Vorfalls-Kommando geblockt,
Workspace-Arbeit/Lesen frei, Alt-Verhalten regressionsfrei).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,9 +12,11 @@ Task-Scope waere hier sogar gefaehrlich: Worker tragen als task_id den Session-Z
|
|||||||
(z.B. 20260713_224206_267304), NICHT die Kanban-t_-ID — ein "nur t_"-Check liesse also alle
|
(z.B. 20260713_224206_267304), NICHT die Kanban-t_-ID — ein "nur t_"-Check liesse also alle
|
||||||
Worker-Schreibzugriffe durch (Bug 13.07., so entdeckt).
|
Worker-Schreibzugriffe durch (Bug 13.07., so entdeckt).
|
||||||
|
|
||||||
WICHTIG: Gesperrt wird NUR der home-verankerte Live-Checkout ($HOME/mission-control-v2), NIE
|
WICHTIG: Gesperrt wird der home-verankerte Live-Checkout ($HOME/mission-control-v2); der
|
||||||
der blosse Name "mission-control-v2" (der Workspace-Klon enthaelt ihn) — sonst waere die
|
blosse Name "mission-control-v2" zaehlt NUR, wenn er vom cwd aus in einen Tabu-Pfad aufloest
|
||||||
legitime Worker-Arbeit blockiert. Lesen ist erlaubt; geblockt werden nur Schreib-Operationen.
|
(V16 unten) — der Workspace-Klon (~/.hermes/kanban/workspaces/<id>/mission-control-v2) bleibt
|
||||||
|
frei, sonst waere die legitime Worker-Arbeit blockiert. Lesen ist erlaubt; geblockt werden
|
||||||
|
nur Schreib-Operationen.
|
||||||
|
|
||||||
Ausgabe {"action":"block","message":...} = Tool geblockt; {} = durchlassen.
|
Ausgabe {"action":"block","message":...} = Tool geblockt; {} = durchlassen.
|
||||||
"""
|
"""
|
||||||
@@ -78,6 +80,8 @@ if tool == "terminal":
|
|||||||
cmd = ti.get("command") or ""
|
cmd = ti.get("command") or ""
|
||||||
if not cmd:
|
if not cmd:
|
||||||
out({})
|
out({})
|
||||||
|
cwd_raw = payload.get("cwd") or ""
|
||||||
|
cwd = os.path.realpath(os.path.expanduser(cwd_raw)) if cwd_raw else ""
|
||||||
# R5 (Review 15.07.): `git init` im Kanban-Workspace hart blocken. Drei Naechte in
|
# R5 (Review 15.07.): `git init` im Kanban-Workspace hart blocken. Drei Naechte in
|
||||||
# Folge bauten Worker git-init-Orphans ohne gemeinsamen Ursprung mit main
|
# Folge bauten Worker git-init-Orphans ohne gemeinsamen Ursprung mit main
|
||||||
# (cleanse-skill-index 12.07., skill-kanten-generator 13.07., blogwatcher-logging
|
# (cleanse-skill-index 12.07., skill-kanten-generator 13.07., blogwatcher-logging
|
||||||
@@ -86,13 +90,50 @@ if tool == "terminal":
|
|||||||
# klonen (SOUL/GRENZEN). Scope: nur Kanban-Worker (Lucy/CLI duerfen z. B. fuer
|
# klonen (SOUL/GRENZEN). Scope: nur Kanban-Worker (Lucy/CLI duerfen z. B. fuer
|
||||||
# projekt-start neue Repos initialisieren).
|
# projekt-start neue Repos initialisieren).
|
||||||
ws_dir = os.path.join(home, ".hermes", "kanban", "workspaces")
|
ws_dir = os.path.join(home, ".hermes", "kanban", "workspaces")
|
||||||
if (payload.get("cwd") or "").startswith(ws_dir) and re.search(r"(?:^|[^\w])git\s+init\b", cmd):
|
if cwd_raw.startswith(ws_dir) and re.search(r"(?:^|[^\w])git\s+init\b", cmd):
|
||||||
out({"action": "block", "message": (
|
out({"action": "block", "message": (
|
||||||
"TABU (R5): `git init` ist im Worker-Workspace gesperrt — Orphan-Branches ohne "
|
"TABU (R5): `git init` ist im Worker-Workspace gesperrt — Orphan-Branches ohne "
|
||||||
"gemeinsamen Ursprung mit main sind bei der Annahme technisch tot (Vorfaelle "
|
"gemeinsamen Ursprung mit main sind bei der Annahme technisch tot (Vorfaelle "
|
||||||
"12.–14.07.). Richtiger Weg: VOLL klonen, z. B. git clone "
|
"12.–14.07.). Richtiger Weg: VOLL klonen, z. B. git clone "
|
||||||
"https://git.tobisniceshomelab.ddnsfree.com/Hitonabi/mission-control-v2 "
|
"https://git.tobisniceshomelab.ddnsfree.com/Hitonabi/mission-control-v2 "
|
||||||
"(Credentials liegen in ~/.git-credentials), dann Branch von origin/main abzweigen.")})
|
"(Credentials liegen in ~/.git-credentials), dann Branch von origin/main abzweigen.")})
|
||||||
|
# Schreib-Subkommandos von git (V16: + clone — `git clone URL ~/mission-control-v2`
|
||||||
|
# rutschte vorher an (a) UND (d) vorbei).
|
||||||
|
git_write = (
|
||||||
|
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|clone|remote|config)\b"
|
||||||
|
)
|
||||||
|
|
||||||
|
# V16 (Vorfall 16.07.2026): Werkstatt-Worker t_7a05992a ersetzte um 03:59 den Live-
|
||||||
|
# Checkout mit cwd=$HOME und RELATIVEN Pfaden (`rm -rf mission-control-v2 && git
|
||||||
|
# clone ...`) — keine home-verankerte Tabu-Form im Kommandotext, der Guard sah nur
|
||||||
|
# Strings und liess durch (.venv weg -> Gateway im 203/EXEC-Crash-Loop). Drei Stopfen:
|
||||||
|
# (1) cwd liegt IN einem Tabu-Pfad -> jede Schreib-Operation blocken (relative Ziele
|
||||||
|
# treffen zwangslaeufig den Tabu-Baum). Lesen bleibt erlaubt.
|
||||||
|
if cwd and under_tabu(cwd):
|
||||||
|
if (re.search(git_write, cmd) or re.search(r"(?:^|[^\w])sed\s+-i", cmd)
|
||||||
|
or re.search(r"(?:^|[^\w])(rm|rmdir|mv|cp|truncate|dd|chmod|chown|ln|install|mkdir|touch)\s", cmd)
|
||||||
|
or re.search(r">>?\s*(?![/&])", cmd)
|
||||||
|
or re.search(r"(?:^|[^\w])tee\s+(?:-a\s+)?(?!/)", cmd)):
|
||||||
|
block()
|
||||||
|
# (2) cwd == $HOME -> `git clone`/`git init`, deren Ziel direkt in $HOME landet,
|
||||||
|
# blocken (exakt der Vorfalls-Hergang). Worker klonen im Task-Workspace; ein
|
||||||
|
# explizites Ziel AUSSERHALB von $HOME (z.B. Unterordner) bleibt erlaubt.
|
||||||
|
m = re.search(r"(?:^|[^\w])git(?:\s+-C\s+\S+)?\s+(?:-[\w-]+\s+)*(?:clone|init)\b([^|&;]*)", cmd)
|
||||||
|
if cwd == home and m:
|
||||||
|
toks = m.group(1).split()
|
||||||
|
dest = toks[-1] if toks else ""
|
||||||
|
# kein brauchbares Ziel-Argument (leer, Option oder URL) -> implizit direkt in $HOME
|
||||||
|
implicit = (not dest or dest.startswith("-")
|
||||||
|
or re.search(r"://|^git@|^[\w.-]+@[\w.-]+:|\.git$", dest))
|
||||||
|
if (implicit or under_tabu(os.path.join(home, dest))
|
||||||
|
or os.path.dirname(os.path.realpath(os.path.join(home, dest))) == home):
|
||||||
|
out({"action": "block", "message": (
|
||||||
|
"TABU (V16): `git clone`/`git init` direkt in $HOME ist gesperrt — so wurde "
|
||||||
|
"am 16.07. der Live-Checkout ~/mission-control-v2 durch einen frischen Klon "
|
||||||
|
"ersetzt (.venv weg, Gateway tot). Klone/initialisiere in deinem Task-"
|
||||||
|
"Workspace (~/.hermes/kanban/workspaces/<task>/...) oder gib ein Ziel "
|
||||||
|
"ausserhalb von $HOME an.")})
|
||||||
# Home-verankerte Tabu-Formen. Der Workspace-Klon
|
# Home-verankerte Tabu-Formen. Der Workspace-Klon
|
||||||
# ($HOME/.hermes/kanban/.../mission-control-v2) enthaelt KEINE davon als Teilstring.
|
# ($HOME/.hermes/kanban/.../mission-control-v2) enthaelt KEINE davon als Teilstring.
|
||||||
tabu_forms = [
|
tabu_forms = [
|
||||||
@@ -100,16 +141,24 @@ if tool == "terminal":
|
|||||||
SRC, "~/.hermes/hermes-agent", "$HOME/.hermes/hermes-agent", "${HOME}/.hermes/hermes-agent",
|
SRC, "~/.hermes/hermes-agent", "$HOME/.hermes/hermes-agent", "${HOME}/.hermes/hermes-agent",
|
||||||
SYSD, "~/.config/systemd/user", "$HOME/.config/systemd/user", "${HOME}/.config/systemd/user",
|
SYSD, "~/.config/systemd/user", "$HOME/.config/systemd/user", "${HOME}/.config/systemd/user",
|
||||||
]
|
]
|
||||||
tabu_alt = "(?:" + "|".join(re.escape(t) for t in tabu_forms) + ")"
|
# (3) cwd == Vorfahr eines Tabu-Pfads (z.B. $HOME) -> auch die RELATIVE Nennung des
|
||||||
|
# Tabu-Ziels (mission-control-v2, .hermes/hermes-agent, .config/systemd/user)
|
||||||
|
# zaehlt als Treffer fuer die Schreib-Checks unten. Die Lookarounds stellen
|
||||||
|
# sicher, dass der Name ein eigenes Argument beginnt — als Teil eines laengeren
|
||||||
|
# Pfades (z.B. .hermes/kanban/workspaces/<id>/mission-control-v2) matcht er
|
||||||
|
# NICHT, die legitime Workspace-Arbeit bleibt frei.
|
||||||
|
rel_pats = []
|
||||||
|
if cwd:
|
||||||
|
for t in (LIVE, SRC, SYSD):
|
||||||
|
if t.startswith(cwd + os.sep):
|
||||||
|
rel = os.path.relpath(t, cwd).replace(os.sep, "/")
|
||||||
|
rel_pats.append(r"(?<![\w./@-])(?:\./)?" + re.escape(rel) + r"(?![\w.-])")
|
||||||
|
tabu_alt = "(?:" + "|".join([re.escape(t) for t in tabu_forms] + rel_pats) + ")"
|
||||||
if not re.search(tabu_alt, cmd):
|
if not re.search(tabu_alt, cmd):
|
||||||
out({}) # kein home-verankerter Tabu-Pfad referenziert -> Workspace-Arbeit, durchlassen
|
out({}) # kein Tabu-Pfad referenziert -> Workspace-Arbeit, durchlassen
|
||||||
|
|
||||||
# (a) git-Schreib-Subkommando (Repo-Kontext ist der referenzierte Tabu-Pfad).
|
# (a) git-Schreib-Subkommando (Repo-Kontext ist der referenzierte Tabu-Pfad).
|
||||||
if re.search(
|
if re.search(git_write, cmd):
|
||||||
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()
|
block()
|
||||||
# (b) sed -i, das einen Tabu-Pfad anfasst.
|
# (b) sed -i, das einen Tabu-Pfad anfasst.
|
||||||
if re.search(r"(?:^|[^\w])sed\s+-i\S*\s+[^|&;]*" + tabu_alt, cmd):
|
if re.search(r"(?:^|[^\w])sed\s+-i\S*\s+[^|&;]*" + tabu_alt, cmd):
|
||||||
|
|||||||
Reference in New Issue
Block a user