This commit is contained in:
team3
2026-07-12 16:13:50 +02:00
parent a284e03225
commit 31a42bbf1d
48 changed files with 3625 additions and 253 deletions

View File

@@ -18,7 +18,7 @@ import db
import guide
import ledger
import pipeline
from config import FRONTEND_DIST, PROJECT_ROOT
from config import FRONTEND_DIST, PROJECT_ROOT, topic_name_ok
from ws import hub
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(name)s %(levelname)s %(message)s")
@@ -93,6 +93,10 @@ def topics_liste():
def topic_anlegen(auftrag: TopicNeu):
if not auftrag.name.strip():
raise HTTPException(400, "Name fehlt")
# streng validieren: der Name wird Pfadkomponente (rmtree, Snapshots) und
# Shell-Argument (Transfer) — „..", „/" oder „;curl…" wären sonst gefährlich
if not topic_name_ok(auftrag.name):
raise HTTPException(400, "Name: nur Buchstaben/Ziffern/-/_ (Anfang alphanumerisch)")
if db.one("SELECT name FROM topics WHERE name=?", (auftrag.name,)):
raise HTTPException(409, "Topic existiert")
if auftrag.art not in ("thema", "uni"):
@@ -149,9 +153,14 @@ def state(topic: str):
"bausteine": db.query(
"SELECT b.*, s.stage FROM bausteine b LEFT JOIN sections s ON s.baustein_id=b.id"
" WHERE b.topic=? ORDER BY b.ord", (topic,)),
"diagramme": db.query(
"SELECT d.id, d.baustein_id, d.typ, d.quelle, d.status, b.titel, b.ord"
" FROM diagramme d JOIN bausteine b ON b.id=d.baustein_id"
" WHERE d.topic=? AND d.status!='kein' ORDER BY b.ord, d.id", (topic,)),
# topic-scoped: offene Befunde früherer Läufe bleiben nach Resume sichtbar
"befunde": db.query(
"SELECT * FROM befunde WHERE run_id=? AND status='offen' ORDER BY id",
(run["id"],)) if run else [],
"SELECT b.* FROM befunde b JOIN runs r ON r.id=b.run_id"
" WHERE r.topic=? AND b.status='offen' ORDER BY b.id", (topic,)),
"agenten": agents.aktive_agenten(),
}
@@ -177,6 +186,10 @@ async def transfer_ausfuehren(topic: str, richtung: str):
raise HTTPException(403, "Transfer nur lokal verfügbar")
if richtung not in ("push", "pull"):
raise HTTPException(404, "unbekannte Richtung")
# Name gegen die Whitelist prüfen UND Existenz sichern — der Name fließt in
# ein make-Shell-Rezept; ohne diese Schranke wäre er ein Injektionsvektor.
if not topic_name_ok(topic) or not db.one("SELECT name FROM topics WHERE name=?", (topic,)):
raise HTTPException(404, "unbekanntes Topic")
res = await asyncio.to_thread(
subprocess.run, ["make", f"server-{richtung}", f"TOPIC={topic}"],
cwd=PROJECT_ROOT, capture_output=True, text=True, timeout=600)