connectiopn fix round 2 2

This commit is contained in:
2026-08-21 15:23:46 +02:00
parent 6b2c5ac8a2
commit 8c9af78672
4 changed files with 297 additions and 19 deletions

View File

@ -636,3 +636,56 @@ ist die massgebliche, aktuelle Fassung dieser Liste. Kurzfassung:
sollten das Problem loesen, sollten aber nach dem Deployment einmal
manuell im Browser bestaetigt werden.
</content>
## Phase 14: `get_server_host_key()` kennt kein `connect_timeout`
**Meldung:** `Host-Key konnte nicht ermittelt werden -- Ziel nicht erreichbar:
get_server_host_key() got an unexpected keyword argument 'connect_timeout'`,
und zwar in **unter einer Sekunde** nach dem Klick auf "Host-Key ermitteln".
**Ursache:** `asyncssh.get_server_host_key()` nimmt -- anders als
`asyncssh.connect()` -- **kein `**kwargs`** entgegen. Seine Parameterliste ist
in asyncssh 2.18.0 abschliessend (`host, port, tunnel, proxy_command, family,
flags, local_addr, sock, client_version, kex_algs, server_host_key_algs,
config, options`); `connect_timeout` gehoert **nicht** dazu. Nur
`asyncssh.connect()` reicht unbekannte Argumente ueber `**kwargs` an
`SSHClientConnectionOptions` weiter -- deshalb war `connect_timeout=10` dort
korrekt und hier ein sofortiger `TypeError`, noch bevor ein Socket geoeffnet
wurde. Daher die Reaktionszeit von unter einer Sekunde: es gab nie einen
Verbindungsversuch.
Der Fehler stammt aus Phase 12 und betraf **beide** Aufrufstellen in
`app/ssh_proxy/proxy.py`: `discover_and_store_host_key()` (Knopf "Host-Key
ermitteln") und `_verified_host_key()` -- letzteres liegt im regulaeren
Verbindungspfad, es war also **jede** SSH-Sitzung betroffen, nicht nur die
Ermittlung.
**Warum es dreimal falsch diagnostiziert wurde:** anfangs lief der `TypeError`
unbehandelt bis FastAPI -> nackter HTTP 500 ohne Wortlaut. Der Nachtrag zu
Phase 12 deutete diesen 500er als zu enges `except (asyncssh.Error, OSError)`
und verbreiterte auf `except Exception`. Damit wurde der `TypeError` zwar
gefangen -- aber als `HostKeyDiscoveryError` und damit als "Ziel nicht
erreichbar" **verkleidet**. Die Tests aus Phase 12 konnten es nicht sehen,
weil ihre asyncssh-Attrappen als `(host, port=22, **kw)` definiert waren und
jedes beliebige Argument klaglos schluckten.
**Loesung**
* Neuer Helfer `_fetch_server_host_key(address, port)` in `proxy.py`: ruft
`asyncssh.get_server_host_key(address, port=port)` auf und setzt das
Zeitlimit von aussen ueber `asyncio.wait_for()`
(`HOST_KEY_CONNECT_TIMEOUT = 10`). Damit ist der Aufruf unabhaengig davon,
wie einzelne asyncssh-Versionen ihre Optionen benennen.
* Beide Aufrufstellen benutzen den Helfer. Ein `asyncio.TimeoutError` wird als
`HostKeyDiscoveryError` mit Klartext "Zeitlimit von 10s ueberschritten"
gemeldet.
* **Ein `TypeError` wird ausdruecklich NICHT mehr maskiert**, sondern
durchgereicht (und mit vollem Traceback geloggt): ein Aufruffehler im
eigenen Code darf nicht als Netzwerkproblem erscheinen. Genau diese
Maskierung hat die Fehlersuche zweimal in die falsche Richtung geschickt.
Alle uebrigen Fehler dieses einen externen Aufrufs bleiben wie bisher breit
gefangen.
* `tests/test_phase12.py`: die Attrappen haben jetzt **kein** `**kw` mehr.
* `tests/test_phase14.py` (8 Faelle), u.a. ein Test, der per
`inspect.signature(asyncssh.get_server_host_key).bind(...)` gegen das
**tatsaechlich installierte** asyncssh prueft -- der haette den Bug im
Produktivsystem gefunden.