Remote View: Menüpunkt „Hermes Dashboard“ für den verbundenen Server #74

Closed
opened 2026-10-17 14:51:39 +00:00 by alf · 4 comments
Owner

Zweck

Im Einstellungen-Menu des Remote-View-Fensters (Zahnrad) fehlt der Zugang zum Hermes-Dashboard des
verbundenen Servers. Es soll ein Menüpunkt „Hermes Dashboard“ geben, der das Dashboard des Servers
öffnet, auf dem Iris gerade verbunden ist.

Spezifikation

Position: im Einstellungen-Menu nach „Flow-Debugger“ (bei den Fenster-Öffnen-Punkten, vor dem
Divider zu Onboard-Assistent / Iris-Server aktualisieren / iOS-Pairing).

Öffnen: in einem Iris-eigenen Fenster (WKWebView), wie das Hermes-Web-GUI-Fenster aus iris/Iris#70.
Bei erneutem Klick wird dasselbe Fenster fokussiert, nicht ein zweites geöffnet.

Sichtbarkeit: nur wenn Hermes auf dem Server verfügbar ist (available_agents.hermes aus /health,
RemoteServerClient.swift:846). Menüpunkt deaktiviert, wenn nicht verbunden — wie die Nachbarn.

Login: das Fenster zeigt die Hermes-Login-Seite des Servers; die gespeicherten Credentials
(hermesRemoteServeUsername/hermesRemoteServePassword) werden vorausgefüllt, wenn sie zur
Verbindung passen.

Rahmen, der die Bauform bestimmt (live geprüft)

  1. Kein Server-Hermes liefert heute ein Dashboard-UI. Beide Server starten Hermes headless:
    • Mac: Onboarding-LaunchAgent hermes serve --host 0.0.0.0 — app.state.serves_spa = not headless
      (hermes_cli/web_server.py:1326), live: GET http://127.0.0.1:9119/ → 302 /login, danach nur
      JSON-API, kein SPA.
    • Linux: Container iris-hermes startet hermes gateway restart (Compose-CMD) — das ist nur das
      Gateway auf 8642, bewusst nicht auf den Host gemappt, nur intern im Docker-Netzwerk
      (http://hermes:8642). Dort gibt es überhaupt keinen Webserver.
      Ein hermes dashboard verweigert sich gegen einen headless Backend (exit 78) — das Dashboard braucht
      einen eigenen SPA-liefernden Prozess auf dem Server.
  2. Nicht-Loopback-Bind ist login-pflichtig. Das Auth-Gate greift bei jeder non-loopback Bind
    (should_require_auth, hermes_cli/web_server.py:481). Der Client sitzt nicht auf der Loopback des
    Servers, also ist das Server-Dashboard immer gated — anders als Iris' lokales Fenster aus #70,
    das login-frei ist.
  3. TLS-Pinning-Muster für WKWebView existiert: PinnedWebView in HTMLPreviewWindowController.swift:135
    prüft die ServerTrust gegen den gepinnten Fingerabdruck. HermesWebGUIWindowController (#70) lädt
    bisher nur http://127.0.0.1:<port> ohne Pinning — das muss auf eine https-URL des Servers
    verallgemeinert werden.

Beteiligte Dateien

  • Iris/RemoteClientView.swift — Einstellungen-Menu
  • Iris/HermesWebGUIWindowController.swift — showOrFocus(port:) auf URL verallgemeinern,
    Pinning-Delegate für https
  • Iris/HermesWebGUIManager.swift — lokaler Fall existiert aus #70; für Gegenstellen braucht der
    Server einen Start-Mechanismus
  • Server-Seite: Route, die das Dashboard-Backend startet und die URL meldet (Mac IrisRemoteServer.swift
    • Linux app/ — Wire-Protokoll, beide Server im selben Zug)
  • Iris/Localizable.xcstrings — neuer Schlüssel mit englischer Übersetzung

Entscheidung, die den Umfang bestimmt

Wie das Server-Dashboard erreichbar wird:

  • A (empfohlen): Iris startet das Dashboard bei Bedarf auf dem Server — Mac lokal
    hermes dashboard --no-open --port 0 (genau das Muster aus #70), Linux per Exec im iris-hermes-
    Container — und der Client öffnet die gemeldete URL im Fenster. Der LaunchAgent und das Gateway
    bleiben unberührt. Braucht eine neue Server-Route (beide Server) und Login im Fenster.
  • B: Die Server liefern das Dashboard dauerhaft (LaunchAgent auf hermes dashboard umstellen,
    Compose-Dienst mit Port). Das ändert den etablierten headless-Betrieb und ist mehr Dauerbetrieb.

Nicht enthalten

  • Kein System-Browser
  • Kein Auto-Login ohne Credentials
  • Keine Änderung am LaunchAgent oder am Gateway-Betrieb
## Zweck Im Einstellungen-Menu des Remote-View-Fensters (Zahnrad) fehlt der Zugang zum Hermes-Dashboard des verbundenen Servers. Es soll ein Menüpunkt „Hermes Dashboard“ geben, der das Dashboard des Servers öffnet, auf dem Iris gerade verbunden ist. ## Spezifikation **Position:** im Einstellungen-Menu nach „Flow-Debugger“ (bei den Fenster-Öffnen-Punkten, vor dem Divider zu Onboard-Assistent / Iris-Server aktualisieren / iOS-Pairing). **Öffnen:** in einem Iris-eigenen Fenster (WKWebView), wie das Hermes-Web-GUI-Fenster aus iris/Iris#70. Bei erneutem Klick wird dasselbe Fenster fokussiert, nicht ein zweites geöffnet. **Sichtbarkeit:** nur wenn Hermes auf dem Server verfügbar ist (`available_agents.hermes` aus `/health`, `RemoteServerClient.swift:846`). Menüpunkt deaktiviert, wenn nicht verbunden — wie die Nachbarn. **Login:** das Fenster zeigt die Hermes-Login-Seite des Servers; die gespeicherten Credentials (`hermesRemoteServeUsername`/`hermesRemoteServePassword`) werden vorausgefüllt, wenn sie zur Verbindung passen. ## Rahmen, der die Bauform bestimmt (live geprüft) 1. **Kein Server-Hermes liefert heute ein Dashboard-UI.** Beide Server starten Hermes headless: - Mac: Onboarding-LaunchAgent `hermes serve --host 0.0.0.0` — `app.state.serves_spa = not headless` (`hermes_cli/web_server.py:1326`), live: `GET http://127.0.0.1:9119/` → `302 /login`, danach nur JSON-API, kein SPA. - Linux: Container `iris-hermes` startet `hermes gateway restart` (Compose-CMD) — das ist nur das Gateway auf 8642, bewusst nicht auf den Host gemappt, nur intern im Docker-Netzwerk (`http://hermes:8642`). Dort gibt es überhaupt keinen Webserver. Ein `hermes dashboard` verweigert sich gegen einen headless Backend (exit 78) — das Dashboard braucht einen eigenen SPA-liefernden Prozess auf dem Server. 2. **Nicht-Loopback-Bind ist login-pflichtig.** Das Auth-Gate greift bei jeder non-loopback Bind (`should_require_auth`, `hermes_cli/web_server.py:481`). Der Client sitzt nicht auf der Loopback des Servers, also ist das Server-Dashboard immer gated — anders als Iris' lokales Fenster aus #70, das login-frei ist. 3. **TLS-Pinning-Muster für WKWebView existiert:** `PinnedWebView` in `HTMLPreviewWindowController.swift:135` prüft die ServerTrust gegen den gepinnten Fingerabdruck. `HermesWebGUIWindowController` (#70) lädt bisher nur `http://127.0.0.1:<port>` ohne Pinning — das muss auf eine https-URL des Servers verallgemeinert werden. ## Beteiligte Dateien - `Iris/RemoteClientView.swift` — Einstellungen-Menu - `Iris/HermesWebGUIWindowController.swift` — `showOrFocus(port:)` auf URL verallgemeinern, Pinning-Delegate für https - `Iris/HermesWebGUIManager.swift` — lokaler Fall existiert aus #70; für Gegenstellen braucht der Server einen Start-Mechanismus - Server-Seite: Route, die das Dashboard-Backend startet und die URL meldet (Mac `IrisRemoteServer.swift` + Linux `app/` — Wire-Protokoll, beide Server im selben Zug) - `Iris/Localizable.xcstrings` — neuer Schlüssel mit englischer Übersetzung ## Entscheidung, die den Umfang bestimmt Wie das Server-Dashboard erreichbar wird: - **A (empfohlen):** Iris startet das Dashboard bei Bedarf auf dem Server — Mac lokal `hermes dashboard --no-open --port 0` (genau das Muster aus #70), Linux per Exec im `iris-hermes`- Container — und der Client öffnet die gemeldete URL im Fenster. Der LaunchAgent und das Gateway bleiben unberührt. Braucht eine neue Server-Route (beide Server) und Login im Fenster. - **B:** Die Server liefern das Dashboard dauerhaft (LaunchAgent auf `hermes dashboard` umstellen, Compose-Dienst mit Port). Das ändert den etablierten headless-Betrieb und ist mehr Dauerbetrieb. ## Nicht enthalten - Kein System-Browser - Kein Auto-Login ohne Credentials - Keine Änderung am LaunchAgent oder am Gateway-Betrieb
Author
Owner

PR #36 gemergt: feat(hermes): Hermes-Dashboard-Proxy — Start-Route und Reverse-Proxy (iris/Iris#74)
iris/iris-linux-server#36

Commits:

  • feat(hermes): Hermes-Dashboard-Proxy — Start-Route und Reverse-Proxy (iris/Iris#74)
PR #36 gemergt: feat(hermes): Hermes-Dashboard-Proxy — Start-Route und Reverse-Proxy (iris/Iris#74) https://forgejo.lewerken.duckdns.org/iris/iris-linux-server/pulls/36 Commits: - feat(hermes): Hermes-Dashboard-Proxy — Start-Route und Reverse-Proxy (iris/Iris#74)
Author
Owner

PR #75 gemergt: feat(remote): Menüpunkt Hermes Dashboard — Client-Fenster und Server-Proxy (iris/Iris#74)
#75

Commits:

  • feat(remote): Menüpunkt Hermes Dashboard — Client-Fenster und Server-Proxy (iris/Iris#74)
PR #75 gemergt: feat(remote): Menüpunkt Hermes Dashboard — Client-Fenster und Server-Proxy (iris/Iris#74) https://forgejo.lewerken.duckdns.org/iris/Iris/pulls/75 Commits: - feat(remote): Menüpunkt Hermes Dashboard — Client-Fenster und Server-Proxy (iris/Iris#74)
Author
Owner

PR #37 gemergt: docs(plan): Lessons Learned zum SPA-Präfix-Proxy (iris/Iris#74)
iris/iris-linux-server#37

Commits:

  • docs(plan): Lessons Learned zum SPA-Präfix-Proxy (iris/Iris#74)
PR #37 gemergt: docs(plan): Lessons Learned zum SPA-Präfix-Proxy (iris/Iris#74) https://forgejo.lewerken.duckdns.org/iris/iris-linux-server/pulls/37 Commits: - docs(plan): Lessons Learned zum SPA-Präfix-Proxy (iris/Iris#74)
Author
Owner

Stand (2026-10-17)

Gebaut: Client-Menüpunkt im Remote-View-Einstellungen-Menu (RemoteClientView.swift),
RemoteServerClient.startHermesDashboard() (POST /hermes/dashboard/start), Fenster
HermesDashboardWindowController.swift (Singleton-NSWindow mit PinnedWebView, Pinning gegen das
selbst-signierte Server-Zertifikat — anders als das loopback-Fenster aus iris/Iris#70). Mac-Server:
handleHermesDashboardStart + handleHermesDashboardProxy, Zustand hermesDashboardProxies nur auf
serverQueue (weil HermesWebGUIManager @MainActor ist); HermesWebGUIManager setzt das
Session-Token jetzt selbst und gibt Port + Token über dashboardEndpoint(hermesPath:) zurück.
Linux-Server: app/hermes_dashboard_routes.py, eigener hermes dashboard --isolated-Prozess im
Hermes-Container auf Port 9119 (nur Docker-Netzwerk), Basic-Provider-Passwort persistent per
secrets_store, einmalig gemintete Session, Cookie bei jeder weitergeleiteten Anfrage.

Gemessen / geprüft:

  • Linux: 7 Tests grün gegen die laufende Instanz auf alf@iris-server (tests/test_hermes_dashboard.py)
    — Start-Pfad-Form, unbekanntes Token 404, injizierter Vollpräfix, API-Call durch den Präfix,
    Schreibmethode POST, Content-Type-Durchreichung, CSS-Asset-URLs umgeschrieben. Deployt per rsync +
    --force-recreate, Sandbox-Container entfernt, /health antwortet.
  • Die übrige Suite -m "not slow": 400 grün, 18 Fehler — alle Lese-/Schreib-Timeouts gegen den
    laufenden Server (Backup, Vault-Maintenance, freecad-Plugin), inhaltlich unverändert. Zwei Tests
    (test_gpu_targets.py, test_plugin_ssh_target.py) lassen sich lokal nicht sammeln, weil
    app/email_config_store.py erst beim Docker-Build aus vendored/ nach app/ kopiert wird.
  • Iris- und IrisClient-Target bauen beide (Xcode, per AppleScript).

Grenzen:

  • Der Klick im laufenden Iris ist noch nicht geprüft — die laufende App ist der Build vor der Änderung.
  • /api/ws wird bewusst nicht durchgeleitet, der Chat-Tab im Dashboard funktioniert nicht.
  • WKWebView sendet kein X-Device-ID; die Dashboard-Requests zählen unter dem IP-Geräte-Eintrag in
    „Verbundene Geräte“ (dieselbe Folge wie beim htmlserver-Proxy).
  • iOS hat denselben Menüpunkt nicht.
  • Der Content-Type-Fall ist durch einen Test abgedeckt; die ursprüngliche Beobachtung (422 bei einem
    Login-POST über den Proxy) kam aus einem Live-Test im selben Zug und steht als Kommentar im Code.

Offen: Klick, Fensterfokus und Laden im laufenden Iris; iOS-Parität, falls gewünscht.

## Stand (2026-10-17) **Gebaut:** Client-Menüpunkt im Remote-View-Einstellungen-Menu (`RemoteClientView.swift`), `RemoteServerClient.startHermesDashboard()` (`POST /hermes/dashboard/start`), Fenster `HermesDashboardWindowController.swift` (Singleton-NSWindow mit `PinnedWebView`, Pinning gegen das selbst-signierte Server-Zertifikat — anders als das loopback-Fenster aus iris/Iris#70). Mac-Server: `handleHermesDashboardStart` + `handleHermesDashboardProxy`, Zustand `hermesDashboardProxies` nur auf `serverQueue` (weil `HermesWebGUIManager` `@MainActor` ist); `HermesWebGUIManager` setzt das Session-Token jetzt selbst und gibt Port + Token über `dashboardEndpoint(hermesPath:)` zurück. Linux-Server: `app/hermes_dashboard_routes.py`, eigener `hermes dashboard --isolated`-Prozess im Hermes-Container auf Port 9119 (nur Docker-Netzwerk), Basic-Provider-Passwort persistent per `secrets_store`, einmalig gemintete Session, Cookie bei jeder weitergeleiteten Anfrage. **Gemessen / geprüft:** - Linux: 7 Tests grün gegen die laufende Instanz auf `alf@iris-server` (`tests/test_hermes_dashboard.py`) — Start-Pfad-Form, unbekanntes Token 404, injizierter Vollpräfix, API-Call durch den Präfix, Schreibmethode POST, Content-Type-Durchreichung, CSS-Asset-URLs umgeschrieben. Deployt per rsync + `--force-recreate`, Sandbox-Container entfernt, `/health` antwortet. - Die übrige Suite `-m "not slow"`: 400 grün, 18 Fehler — alle Lese-/Schreib-Timeouts gegen den laufenden Server (Backup, Vault-Maintenance, freecad-Plugin), inhaltlich unverändert. Zwei Tests (`test_gpu_targets.py`, `test_plugin_ssh_target.py`) lassen sich lokal nicht sammeln, weil `app/email_config_store.py` erst beim Docker-Build aus `vendored/` nach `app/` kopiert wird. - Iris- und IrisClient-Target bauen beide (Xcode, per AppleScript). **Grenzen:** - Der Klick im laufenden Iris ist noch nicht geprüft — die laufende App ist der Build vor der Änderung. - `/api/ws` wird bewusst nicht durchgeleitet, der Chat-Tab im Dashboard funktioniert nicht. - WKWebView sendet kein `X-Device-ID`; die Dashboard-Requests zählen unter dem IP-Geräte-Eintrag in „Verbundene Geräte“ (dieselbe Folge wie beim htmlserver-Proxy). - iOS hat denselben Menüpunkt nicht. - Der Content-Type-Fall ist durch einen Test abgedeckt; die ursprüngliche Beobachtung (422 bei einem Login-POST über den Proxy) kam aus einem Live-Test im selben Zug und steht als Kommentar im Code. **Offen:** Klick, Fensterfokus und Laden im laufenden Iris; iOS-Parität, falls gewünscht.
alf closed this issue 2026-10-21 23:26:05 +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#74
No description provided.