Plugin-Update/Deinstall: rmtree-Fehler lässt Plugin halb entfernt statt sauberem Fehler #93

Closed
opened 2026-10-22 19:44:15 +00:00 by alf · 1 comment
Owner

Beobachtet (2026-10-22, Dev-Host alf@iris-server):

iris-plugin-dev 0.1.15 in die Drop-Zone gelegt → der Wächter ruft install_plugin_from_archive, deren shutil.rmtree(plugin_dir) auf ein root-owned __pycache__ im Skill-Ordner trifft (entstanden durch ein docker exec ohne -u im Server-Container — dieselbe Fehlerklasse wie der dokumentierte root-owned-.venv-Fall, drittes Vorkommnis). Die App läuft als iris (non-root) → PermissionError.

Folgen:

  1. rmtree bricht mitten in der Entfernung ab (zuerst entfernte Dateien bleiben weg) → das Plugin-Verzeichnis ist halb entfernt (kein plugin.json, kein web/), der Index trägt weiterhin die alte Version, das Panel ist tot.
  2. Die Exception läuft ungefangen durch den Wächter → Traceback je 60-s-Poll-Zyklus statt einer lesbaren Fehlermeldung.
  3. uninstall_plugin hat dasselbe Muster in schlechterer Reihenfolge: Skills und Systemprompt werden vor dem rmtree entfernt — schlägt der rmtree fehl, ist der Index-Eintrag da, aber Skills und Prompt fort: ein in sich inkonsistenter Zustand.

Fix:

  • Install-Pfad: rmtree-OSError fangen → sauberes Fehler-Dict (Paket bleibt in der Drop-Zone, Wächter setzt nach Berechtigungs-Bereinigung erneut an; Hinweis: Rechte/Owner prüfen oder Container neu starten — der Entrypoint chownt die data-Pfade).
  • Uninstall-Pfad: rmtree vor der Skill-/Prompt-Entfernung, OSError → False (nichts berührt, Plugin bleibt vollständig, Retry möglich).

Recovery auf dem Host (erledigt): kaputtes Verzeichnis per docker exec -u root rm -rf entfernt, Wächter hat 0.1.15 neu installiert; docker exec in diesen Containern immer mit -u iris (steht in der CLAUDE.md).

**Beobachtet (2026-10-22, Dev-Host `alf@iris-server`):** `iris-plugin-dev` 0.1.15 in die Drop-Zone gelegt → der Wächter ruft `install_plugin_from_archive`, deren `shutil.rmtree(plugin_dir)` auf ein **root-owned** `__pycache__` im Skill-Ordner trifft (entstanden durch ein `docker exec` ohne `-u` im Server-Container — dieselbe Fehlerklasse wie der dokumentierte root-owned-`.venv`-Fall, drittes Vorkommnis). Die App läuft als `iris` (non-root) → `PermissionError`. **Folgen:** 1. `rmtree` bricht **mitten in der Entfernung** ab (zuerst entfernte Dateien bleiben weg) → das Plugin-Verzeichnis ist halb entfernt (kein `plugin.json`, kein `web/`), der Index trägt weiterhin die alte Version, das Panel ist tot. 2. Die Exception läuft ungefangen durch den Wächter → Traceback je 60-s-Poll-Zyklus statt einer lesbaren Fehlermeldung. 3. `uninstall_plugin` hat dasselbe Muster in schlechterer Reihenfolge: Skills und Systemprompt werden **vor** dem `rmtree` entfernt — schlägt der `rmtree` fehl, ist der Index-Eintrag da, aber Skills und Prompt fort: ein in sich inkonsistenter Zustand. **Fix:** - Install-Pfad: `rmtree`-`OSError` fangen → sauberes Fehler-Dict (Paket bleibt in der Drop-Zone, Wächter setzt nach Berechtigungs-Bereinigung erneut an; Hinweis: Rechte/Owner prüfen oder Container neu starten — der Entrypoint chownt die data-Pfade). - Uninstall-Pfad: `rmtree` **vor** der Skill-/Prompt-Entfernung, `OSError` → `False` (nichts berührt, Plugin bleibt vollständig, Retry möglich). **Recovery auf dem Host (erledigt):** kaputtes Verzeichnis per `docker exec -u root rm -rf` entfernt, Wächter hat 0.1.15 neu installiert; `docker exec` in diesen Containern immer mit `-u iris` (steht in der CLAUDE.md).
Author
Owner

PR #96 gemergt: fix(plugins): Update/Deinstall bei nicht entfernbarem Plugin-Verzeichnis sauber statt halb entfernt (#93)
#96

Commits:

  • fix(plugins): Update/Deinstall bei nicht entfernbarem Plugin-Verzeichnis sauber statt halb entfernt (#93)

Stand (#93)

Befund (live, 2026-10-22 auf alf@iris-server): Beim Drop-Zone-Update von iris-plugin-dev (0.1.14 → 0.1.15) brach shutil.rmtree(plugin_dir) in install_plugin_from_archive mit PermissionError ab: das Skill-Verzeichnis enthielt ein root-owned __pycache__ (entstanden durch ein docker exec ohne -u während der 0.1.14-Verifikation — dieselbe Klasse wie der dokumentierte root-owned-.venv-Fall). Die App läuft als iris (non-root) und konnte das Verzeichnis nicht vollständig entfernen.

Folgen:

  1. rmtree brach mitten in der Entfernung ab → Plugin-Verzeichnis halb entfernt (kein plugin.json, kein web/), Index mit alter Version, Panel tot.
  2. Ungefangene Exception im Wächter → Traceback je 60-s-Poll-Zyklus.
  3. uninstall_plugin hatte das Muster in schlechterer Reihenfolge: Skills + Systemprompt wurden vor dem rmtree entfernt → bei einem Abbruch ein in sich inkonsistenter Zustand.

Geändert:

  • app/plugin_installer.py (Install-Pfad): rmtree-OSError gefangen → sauberes Fehler-Dict; Paket bleibt in der Drop-Zone, Wächter setzt nach Berechtigungs-Bereinigung oder Container-Neustart (Entrypoint chownt die data-Pfade) erneut an.
  • app/plugin_installer.py (uninstall_plugin): rmtree vor der Skill-/Prompt-Entfernung; OSError → False, nichts anderes berührt (Index, Skills, Prompt bleiben; Retry möglich).
  • CLAUDE.md: Die -u iris-Regel für docker exec gilt jetzt auch für iris-server (bisher nur iris-hermes/iris-hermes-scheduled).
  • STAND-PROTOKOLL.md: Bugfix-Eintrag.

Geprüft:

  • tests/test_plugin_installer_rmtree.py (neu, 2 Tests): Update mit abbrechendem rmtree → sauberes Fehler-Dict, Index und Paket intakt; Deinstallation bei PermissionError → False, Verzeichnis und Index unangetastet.
  • Bestands-Tests test_plugin_installer_driver_group.py + test_plugins_dropzone_watcher.py grün (16 Tests zusammen, lokal).
  • Recovery auf dem Host: kaputtes Verzeichnis entfernt, Wächter hat 0.1.15 neu installiert; Live-Panel dort verifiziert (Picker, eigener-einrichten, repo-anlegen mit Wegwerf-Repo, Konfiguration wiederhergestellt).

Nicht geprüft:

  • Die volle pytest-Suite (läuft gegen den echten Server, ~2 Min) und das rsync-Deploy mit Container-Neubau auf alf@iris-server — beides folgt auf dem Fuß; das aktuelle Deployment auf dem Host läuft noch mit dem alten Stand (der Wächter-Fehler wäre dort bis zum Neuaufbau gleich, tritt aber ohne root-owned Artefakt nicht wieder auf, solange docker exec mit -u iris bleibt).
  • Das Label typ/bug für #93 fehlt: Die Forgejo-Instanz legt Labels per API stillschweigend ab (an 3 Issues verifiziert, u. a. labels_index); #93 und die Wegwerf-Proben #94/#95 wurden über die API ohne Label angelegt, 94/95 gelöscht. Im Web-UI mit einem Klick nachtragbar.
PR #96 gemergt: fix(plugins): Update/Deinstall bei nicht entfernbarem Plugin-Verzeichnis sauber statt halb entfernt (#93) https://forgejo.lewerken.duckdns.org/iris/iris-linux-server/pulls/96 Commits: - fix(plugins): Update/Deinstall bei nicht entfernbarem Plugin-Verzeichnis sauber statt halb entfernt (#93) --- ## Stand (#93) **Befund (live, 2026-10-22 auf `alf@iris-server`):** Beim Drop-Zone-Update von `iris-plugin-dev` (0.1.14 → 0.1.15) brach `shutil.rmtree(plugin_dir)` in `install_plugin_from_archive` mit `PermissionError` ab: das Skill-Verzeichnis enthielt ein root-owned `__pycache__` (entstanden durch ein `docker exec` **ohne** `-u` während der 0.1.14-Verifikation — dieselbe Klasse wie der dokumentierte root-owned-`.venv`-Fall). Die App läuft als `iris` (non-root) und konnte das Verzeichnis nicht vollständig entfernen. **Folgen:** 1. `rmtree` brach mitten in der Entfernung ab → Plugin-Verzeichnis halb entfernt (kein `plugin.json`, kein `web/`), Index mit alter Version, Panel tot. 2. Ungefangene Exception im Wächter → Traceback je 60-s-Poll-Zyklus. 3. `uninstall_plugin` hatte das Muster in schlechterer Reihenfolge: Skills + Systemprompt wurden **vor** dem `rmtree` entfernt → bei einem Abbruch ein in sich inkonsistenter Zustand. **Geändert:** - `app/plugin_installer.py` (Install-Pfad): `rmtree`-`OSError` gefangen → sauberes Fehler-Dict; Paket bleibt in der Drop-Zone, Wächter setzt nach Berechtigungs-Bereinigung oder Container-Neustart (Entrypoint chownt die data-Pfade) erneut an. - `app/plugin_installer.py` (`uninstall_plugin`): `rmtree` **vor** der Skill-/Prompt-Entfernung; `OSError` → `False`, nichts anderes berührt (Index, Skills, Prompt bleiben; Retry möglich). - `CLAUDE.md`: Die `-u iris`-Regel für `docker exec` gilt jetzt auch für `iris-server` (bisher nur `iris-hermes`/`iris-hermes-scheduled`). - `STAND-PROTOKOLL.md`: Bugfix-Eintrag. **Geprüft:** - `tests/test_plugin_installer_rmtree.py` (neu, 2 Tests): Update mit abbrechendem `rmtree` → sauberes Fehler-Dict, Index und Paket intakt; Deinstallation bei `PermissionError` → `False`, Verzeichnis und Index unangetastet. - Bestands-Tests `test_plugin_installer_driver_group.py` + `test_plugins_dropzone_watcher.py` grün (16 Tests zusammen, lokal). - Recovery auf dem Host: kaputtes Verzeichnis entfernt, Wächter hat 0.1.15 neu installiert; Live-Panel dort verifiziert (Picker, `eigener-einrichten`, `repo-anlegen` mit Wegwerf-Repo, Konfiguration wiederhergestellt). **Nicht geprüft:** - Die volle pytest-Suite (läuft gegen den echten Server, ~2 Min) und das rsync-Deploy mit Container-Neubau auf `alf@iris-server` — beides folgt auf dem Fuß; das aktuelle Deployment auf dem Host läuft noch mit dem alten Stand (der Wächter-Fehler wäre dort bis zum Neuaufbau gleich, tritt aber ohne root-owned Artefakt nicht wieder auf, solange `docker exec` mit `-u iris` bleibt). - Das Label `typ/bug` für #93 fehlt: Die Forgejo-Instanz legt Labels per API stillschweigend ab (an 3 Issues verifiziert, u. a. `labels_index`); #93 und die Wegwerf-Proben #94/#95 wurden über die API ohne Label angelegt, 94/95 gelöscht. Im Web-UI mit einem Klick nachtragbar.
alf closed this issue 2026-10-27 10:40:54 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
iris/iris-linux-server#93
No description provided.