M7: REST-Transport erstmals live verifiziert, vier Bugs gefunden+gefixt
Erstmaliger REST-Schreibtest gegen echte Hardware (www-ssl vorher auf jedem Testgerät aus, Pfad lief nur gegen Mocks). Vier Bugs gefunden: - baseURL fehlte trailing slash, relative URL-Auflösung warf "/rest" aus jedem Pfad (404, fiel still auf SSH zurück statt Zertifikat- Dialog zu zeigen) - .add nutzte POST statt PUT (RouterOS' REST-API erwartet PUT für neue Einträge) - RouterOS sendet Cache-Control: max-age=31536000 auf jede REST- Antwort, URLSession cachte dadurch die erste (leere) GET-Antwort für den Rest der App-Laufzeit - Löschen aktualisierte die Experte-Tab-Liste nicht in-place (SwiftUI- Render-Problem, kein Datenfehler) — Anlegen/Bearbeiten laufen über ein Sheet, dessen Schließen automatisch neu rendert, Löschen über ein confirmationDialog ohne Remount Anlegen/Bearbeiten (inkl. Feld-Leeren)/Löschen live bestätigt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+80
-9
@@ -629,13 +629,79 @@ wiederholen.
|
||||
nur zum Löschen dieser einen Datei erschien nicht aufwandsgerecht.
|
||||
Harmlos (überschreibt sich beim nächsten Restore selbst), aber bewusst
|
||||
in Kauf genommen, nicht vergessen.
|
||||
- **REST-Pfad ungetestet für Schreibvorgänge** — auf beiden bisherigen
|
||||
Testgeräten war `www-ssl` (Port 443) aus, jeder Schreibtest lief über
|
||||
SSH. Der REST-`apply()`-Pfad (`POST`/`PATCH`, `findItemID` für `.set`)
|
||||
ist nur gegen Mocks getestet. Der REST-Zweig von `fetchFieldValues`
|
||||
(M12/Bug 14) ist zusätzlich auf einer nirgends offiziell dokumentierten
|
||||
Annahme aufgebaut (Query-String-Filter `?feld=wert` auf einem GET) —
|
||||
komplett unverifiziert.
|
||||
- ~~REST-Pfad ungetestet für Schreibvorgänge~~ — am 2026-09-16 erstmals
|
||||
live getestet: `www-ssl` auf dem hEX-Testrouter aktiviert (eigene CA
|
||||
`local-ca` + davon signiertes `rest-cert` angelegt, da direktes
|
||||
Selbstsignieren ohne separate CA mit "failure: CA not found"
|
||||
scheiterte — RouterOS braucht dafür `key-usage=key-cert-sign,crl-sign`
|
||||
auf einem eigenen CA-Zertifikat, das per `ca=<name>` referenziert
|
||||
wird). Dabei **drei echte, vorher unentdeckte Bugs gefunden und
|
||||
gefixt**, alle drei ausschließlich möglich, weil kein Testgerät vorher
|
||||
je `www-ssl` an hatte:
|
||||
- **Bug 30:** `RestTransport.baseURL` fehlte der abschließende `/`
|
||||
(`".../rest"` statt `".../rest/"`). `URL(string:relativeTo:)`
|
||||
ersetzt bei relativer Auflösung das *letzte Pfadsegment* der Basis
|
||||
(RFC 3986 §5.3) — ohne trailing slash ist "rest" selbst das letzte
|
||||
Segment, ein Pfad wie "system/resource" ersetzt es also statt
|
||||
danach angehängt zu werden (`.../rest` + "system/resource" →
|
||||
`.../system/resource`, 404). Jede REST-Verbindung scheiterte dadurch
|
||||
mit stillschweigend verschlucktem "HTTP 404" (der generische
|
||||
`catch`-Zweig in `ConnectionService.connect` loggte den Fehler
|
||||
nirgends), fiel auf SSH zurück, ohne je den Zertifikats-Dialog zu
|
||||
zeigen — sah aus wie "kein Zertifikat-Prompt trotz neuem
|
||||
Zertifikat", war tatsächlich ein komplett anderer, tieferliegender
|
||||
Bug. Gefunden über einen temporären Debug-`print` im Fallback-Pfad.
|
||||
- **Bug 31:** `RestTransport.apply()`s `.add`-Fall nutzte `POST`,
|
||||
RouterOS' REST-API erwartet dafür aber `PUT` — `POST` auf
|
||||
`/rest/ip/firewall/address-list` lieferte `{"detail":"no such
|
||||
command","error":400,"message":"Bad Request"}`, `PUT` mit
|
||||
identischem Body `201` mit vollem Echo des neuen Items. Nebenbei
|
||||
`send()`s Fehlerbehandlung verbessert: zeigte bisher nur den nackten
|
||||
Statuscode ("HTTP 400"), jetzt wird RouterOS' eigener JSON-Fehler-
|
||||
Body (`detail`-Feld) mit ausgegeben, falls vorhanden — genau dieser
|
||||
Body war es, der den Bug überhaupt auffindbar machte (per direktem
|
||||
`curl`-Replay derselben Anfrage).
|
||||
- **Bug 32, am folgenreichsten:** RouterOS sendet auf *jede*
|
||||
`/rest/...`-Antwort `Cache-Control: max-age=31536000` (ein Jahr) +
|
||||
passenden `Expires`-Header — vermutlich ein Blanket-Default für
|
||||
statische Web-UI-Assets, der auch auf die REST-API durchschlägt.
|
||||
`URLSession(configuration: .ephemeral)` bedeutet nur "nichts auf
|
||||
Platte persistieren", hält aber weiterhin einen Im-Speicher-
|
||||
`URLCache` und hält sich an diese Header — die *erste* GET-Antwort
|
||||
auf einen Pfad (z.B. eine leere Artikelliste, abgerufen durch
|
||||
`loadCrossReferenceOptions` oder ein früheres Öffnen desselben
|
||||
Menüs) wurde für den Rest der App-Laufzeit unverändert zurückgegeben,
|
||||
komplett unabhängig von späteren `.add`/`.set`/`.remove`-Änderungen.
|
||||
Live-Symptom: ein frisch angelegter Adress-Listen-Eintrag (per
|
||||
`curl` als real bestätigt) erschien nie in der Experte-Tab-Liste,
|
||||
auch nach Weg-und-zurück-Navigation nicht. Fix: `urlCache = nil` +
|
||||
`.reloadIgnoringLocalCacheData` auf Session- *und* Request-Ebene
|
||||
(RouterOS' Schreib-Endpunkte sind nicht idempotent genug, um sich
|
||||
nur auf eine der beiden Ebenen zu verlassen).
|
||||
Nach allen drei Fixes live durchgespielt: Anlegen (`PUT`), Bearbeiten
|
||||
inkl. Feld-Leeren (`PATCH`, Kommentar gesetzt dann wieder gelöscht —
|
||||
REST-seitig direkt per `curl` verifiziert, dass ein leerer String das
|
||||
Feld tatsächlich löscht, genau wie bei SSH/Bug 25), Löschen (`DELETE`)
|
||||
— alle drei vom Nutzer bestätigt ("funktioniert"). Damit ist der
|
||||
REST-Transport erstmals end-to-end gegen echte Hardware verifiziert,
|
||||
nicht mehr nur gegen Mocks. Der REST-Zweig von `fetchFieldValues`
|
||||
(M12/Bug 14, Query-String-Filter `?feld=wert` auf einem GET) bleibt
|
||||
weiterhin unverifiziert — dabei nicht auf den Weg gekreuzt.
|
||||
- **Bug 33, direkt danach gefunden:** Löschen eines Eintrags im
|
||||
Experte-Tab aktualisierte die sichtbare Liste nicht, bis der Nutzer
|
||||
in einen anderen Tab und zurück wechselte — sah zunächst wieder wie
|
||||
ein Cache-/Refresh-Problem aus, war es aber nicht: ein temporärer
|
||||
Debug-`print` in `confirmRemoval` bestätigte `items.count` geht
|
||||
korrekt von 1 auf 0 nach `reloadItems()`, das `@Published`-Modell
|
||||
war also die ganze Zeit richtig. Reines SwiftUI-Render-Problem:
|
||||
Anlegen/Bearbeiten laufen über `ExpertItemEditView` als `.sheet(item:)`,
|
||||
dessen Schließen `ExpertMenuDetailView` automatisch neu mountet —
|
||||
genau das erzwingt implizit den Refresh, den Löschen (über ein
|
||||
direkt an `ExpertMenuDetailView` gehängtes `.confirmationDialog`,
|
||||
kein Sheet, kein Remount) nie bekam. Fix: `.id(viewModel.items.count)`
|
||||
auf der Einträge-`Section`, zwingt SwiftUI bei jeder Mengenänderung
|
||||
zu einer frischen View-Identität statt sich auf In-Place-Diffing zu
|
||||
verlassen. Live bestätigt ("funktioniert").
|
||||
- **`fetchMenuItems`s `.id`-Positions-Überlagerung: Verlässlichkeit für
|
||||
andere Menüs ungeprüft** (siehe Bug 15) — bei `/ip dhcp-server lease`
|
||||
live als falsch bestätigt (`.id` landete auf der falschen Zeile), für
|
||||
@@ -1331,8 +1397,13 @@ passenden Namen lesbar. Live bestätigt ("sieht gut aus").
|
||||
alles erledigt, live bestätigt ("funktioniert"). Damit sind alle
|
||||
fünf Tabs vollständig zweisprachig (DE/EN).
|
||||
2. WLAN (M5) an einem Gerät mit echtem WLAN-Chip nachholen.
|
||||
2. Rest von M7: Fehlerzustände/Politur, REST-Schreibtest an einem Gerät
|
||||
mit aktivem `www-ssl`.
|
||||
2. ~~Rest von M7: REST-Schreibtest an einem Gerät mit aktivem
|
||||
`www-ssl`~~ — erledigt (2026-09-16), siehe "Bekannte Einschränkungen"
|
||||
oben (Bug 30–32). `www-ssl` bleibt auf dem hEX-Testrouter aktiv
|
||||
(eigene CA `local-ca` + `rest-cert`), damit die App weiterhin
|
||||
REST-zuerst verbindet statt SSH-Fallback. Fehlerzustände/Politur im
|
||||
REST-Pfad noch nicht gezielt geprüft (z.B. Verbindungsabbruch
|
||||
mitten im Apply) — optional für später.
|
||||
3. M9 UI (Einfach/Experte-Modusumschalter im Einrichten-Tab selbst) noch
|
||||
manuell durchklicken — M10s Experte-Tab wurde bereits vom Nutzer
|
||||
bestätigt (siehe oben), der Moduswechsel im Wizard noch nicht.
|
||||
|
||||
Reference in New Issue
Block a user