Ampel / ampel (push) Failing after 41s
Teil A (ganze Dateien): windows_app, fenster, setup_fenster, einrichtung, standalone, daemon, drives/windows + win_ioctl, platform/verknuepfungen + win_registry, tools/einrichten, rip/audio_cd + musicbrainz_cd, queue/ (lokal + laeufer), packaging/windows/, test_keine_container_reste — samt Tests. Bilanz: +51 / -10.039 Zeilen in 48 Dateien. Bleibt TROTZ § 11.2-Listung (Importe gemessen, nicht geraten): winlauf (OHNE_FENSTER nutzt der Worker; Teil B laeuft nativ Windows), dateiangaben/katalog/beschaffen (ripping + api importieren sie), makemkv_aufruf KOMPLETT (ablauf.py ruft key_setzen_und_pruefen; Registry-Zweige braucht der Remote-Worker), bus/waechter (bedient Jobs/Logs/Laufwerke der API), die nativ-Pfadzweige (Teil B). Teil C: drives/treiber() liefert unter Windows den Klartext-Platzhalter kein_windows.py (Importe/Testsammlung auf Entwicklungs-PCs bleiben heil, BENUTZUNG wirft mit Verweis auf v5); ripping.rip_cd ohne Windows-Zweig; betrieb.windows_laufwerke + Aufrufer raus; /worker-setup/windows* bleibt (Teil B, Entscheid 8). Lokal: Ruff gruen, 658 Tests gruen (vorher 977 — die Differenz sind die Windows-Tests, deren Gegenstand mitgegangen ist). Das Wissen liegt vollstaendig in Rippy v5 (rippy-windows/), mit denselben Testfaellen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
80 lines
3.4 KiB
Python
80 lines
3.4 KiB
Python
"""Welche Pfade darf die API anfassen — und wo ist „oben"?
|
|
|
|
## Warum diese Grenze verschiebbar sein muss (Befund 28.08.2026)
|
|
|
|
`MEDIA_ROOT = "/app/media"` war zugleich Vorgabe UND Pfadgrenze. Im Container
|
|
ist beides richtig. Auf dem Windows-PC des Commanders war beides falsch, und
|
|
die Folge war eine Oberflaeche, die stillschweigend nichts konnte:
|
|
|
|
* `/storage-targets` lieferte `[]` (der Ordner existiert dort nicht),
|
|
* `/browse` antwortete auf JEDEN Pfad mit 422,
|
|
* im Auswahlfeld fuer das Arbeitsverzeichnis stand genau ein Eintrag.
|
|
|
|
Sein Befund dazu: „Wäre es möglich das Arbeitsverzeichnis zu ändern?
|
|
momentan geht das nicht."
|
|
|
|
Die Grenze faellt aber NICHT einfach weg. Im Container haengt die API im
|
|
Netz — eine Weboberflaeche, die jeden Pfad des Wirts ausliefern kann, ist ein
|
|
Loch. Sie gilt nur dort nicht, wo Rippy den Menschen bedient, der vor dem
|
|
Rechner sitzt. Diese Tests halten beide Haelften fest.
|
|
"""
|
|
|
|
import main
|
|
|
|
|
|
# ── Die Grenze gilt, wo zugehoert wird ──────────────────────────────────
|
|
def test_im_container_gilt_die_wurzel_weiter():
|
|
"""Der Docker-Weg darf sich durch die Reparatur NICHT lockern."""
|
|
assert main.pfad_erlaubt("/app/media/movies", "/app/media", frei=False)
|
|
assert not main.pfad_erlaubt("/etc/passwd", "/app/media", frei=False)
|
|
# Der Klassiker: beginnt mit der Wurzel, liegt aber ausserhalb.
|
|
assert not main.pfad_erlaubt("/app/media-boese/x", "/app/media", frei=False)
|
|
|
|
|
|
def test_nativ_ist_auch_eine_freigabe_erlaubt():
|
|
"""Sein Ziel ist `\\\\192.168.179.62\\rippy\\movies` — das liegt unter gar
|
|
keiner lokalen Wurzel. Mit der alten Regel war es unerreichbar."""
|
|
assert main.pfad_erlaubt(r"\\192.168.179.62\rippy\movies", "/app/media", frei=True)
|
|
assert main.pfad_erlaubt(r"D:\Rippy-Arbeit", "/app/media", frei=True)
|
|
|
|
|
|
def test_ein_leerer_pfad_ist_nie_erlaubt():
|
|
"""Sonst wuerde aus einem vergessenen Feld ein Zugriff auf `/`."""
|
|
assert not main.pfad_erlaubt("", "/app/media", frei=True)
|
|
assert not main.pfad_erlaubt("", "/app/media", frei=False)
|
|
|
|
|
|
# ── Wo ist oben ─────────────────────────────────────────────────────────
|
|
def test_an_der_wurzel_ist_schluss():
|
|
"""Im Container. `None` heisst: kein Knopf „nach oben"."""
|
|
assert main.eltern_von("/app/media", "/app/media", frei=False) is None
|
|
assert main.eltern_von("/app/media/movies", "/app/media", frei=False) == "/app/media"
|
|
|
|
|
|
def test_ueber_der_laufwerkswurzel_steht_die_laufwerksliste():
|
|
"""Zwei Fallen auf einmal.
|
|
|
|
`os.path.dirname("C:\\\\")` ist wieder `"C:\\\\"` — ein Knopf „nach oben",
|
|
der auf denselben Ordner zeigt, sieht aus wie ein Fehler. Und ueber der
|
|
Laufwerkswurzel steht nicht *nichts*, sondern die Liste der Laufwerke:
|
|
Sonst kaeme man von `D:\\` nie zu `C:\\`, und genau dort ist Platz fuer
|
|
100 GB Rohdaten.
|
|
"""
|
|
import ntpath
|
|
import os
|
|
|
|
echt = os.path.dirname
|
|
os.path.dirname = ntpath.dirname # Windows-Pfade auch auf Linux
|
|
try:
|
|
assert main.eltern_von("C:\\", "D:\\Rippy", frei=True) == ""
|
|
assert main.eltern_von("C:\\Users\\Tobi", "D:\\Rippy", frei=True) == "C:\\Users"
|
|
finally:
|
|
os.path.dirname = echt
|
|
|
|
|
|
def test_die_wurzel_kommt_aus_dem_betrieb_und_ist_nie_leer():
|
|
"""Eine leere Wurzel wuerde jede Pruefung durchwinken."""
|
|
assert main.medien_wurzel()
|
|
|
|
|