spawner/docs/RECENT_FIXES_2026_03.md

251 lines
7.1 KiB
Markdown

# Kritische Fixes - März 2026
Diese Datei dokumentiert wichtige Bugfixes und Verbesserungen, die seit März 2026 implementiert wurden.
## 1. Traefik Network Routing Fix ✅
**Problem:** User-Container wurden nicht im `web`-Netzwerk registriert, obwohl Labels vorhanden waren.
**Ursache:** Docker SDK Parameter `network=` funktioniert nicht korrekt bei `containers.run()`.
**Lösung:** Explizite Netzwerk-Verbindung nach Container-Start mit `network.connect()`.
```python
# Vorher (funktioniert nicht):
container = client.containers.run(..., network=Config.TRAEFIK_NETWORK)
# Nachher (funktioniert):
container = client.containers.run(...) # Ohne network-Parameter
network = client.networks.get(Config.TRAEFIK_NETWORK)
network.connect(container)
```
**Commits:**
- `65a2a6e`: Connect containers to Traefik network using network.connect()
**Betroffen:** `container_manager.py` - Beide `spawn_container()` und `spawn_multi_container()`
---
## 2. Traefik Router Service-Labels Fix ✅
**Problem:** Traefik erkannte neue Container-Routes nicht, obwohl Labels korrekt waren.
**Ursache:** Router-Labels fehlte die Referenz zum Service. Traefik wusste nicht, zu welchem Service die Route führen soll.
**Lösung:** Router-Labels mit `.service` Claim hinzufügen, die auf den Service zeigen.
```python
# Vorher (unvollständig):
'traefik.http.routers.user1-template-dict.rule': '...',
'traefik.http.services.user1-template-dict.loadbalancer.server.port': '8080'
# Nachher (komplett):
'traefik.http.routers.user1-template-dict.rule': '...',
'traefik.http.routers.user1-template-dict.service': 'user1-template-dict', # ← Wichtig!
'traefik.http.services.user1-template-dict.loadbalancer.server.port': '8080'
```
**Commits:**
- `45bd329`: Add missing router.service labels
**Betroffen:** `container_manager.py` - Labels-Konfiguration
---
## 3. Cookie-basierte JWT-Authentication ✅
**Problem:** User-Container waren öffentlich zugänglich - jeder konnte URL nutzen ohne Login.
**Lösung:** JWT-Token als HttpOnly Cookie, validiert in jedem Container.
**Implementierung:**
### Backend (api.py)
- JWT-Token wird als HttpOnly Cookie nach Login gespeichert
- Cookie wird automatisch bei jedem Request mitgesendet
- Logout löscht den Cookie
```python
def create_auth_response(access_token, user_data, expires_in):
response = make_response(jsonify(response_data))
response.set_cookie(
'spawner_token',
access_token,
max_age=expires_in,
httponly=True, # JavaScript-zugriff blockiert
secure=True, # Nur über HTTPS
samesite='Lax' # CSRF-Schutz
)
return response
```
### Container (z.B. Dictionary-Template)
- `before_request` Hook validiert JWT im Cookie
- Ohne gültigen Token: `403 Forbidden`
- JWT_SECRET wird vom Spawner als Environment-Variable übergeben
```python
@app.before_request
def validate_jwt_token():
# GET / und /health sind öffentlich
if request.path == '/' or request.path == '/health':
return
# Alle API-Calls brauchen gültigen Token
token = request.cookies.get('spawner_token')
if not token:
return jsonify({'error': 'Authentifizierung erforderlich'}), 401
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
g.user_id = payload.get('sub')
except jwt.InvalidTokenError:
return jsonify({'error': 'Token ungültig'}), 401
```
**Commits:**
- `436b1c0`: Add cookie-based JWT authentication for user containers
**Betroffen:**
- `api.py` - JWT-Cookie setzen/löschen
- `container_manager.py` - JWT_SECRET als Environment-Variable
- `user-template-dictionary/app.py` - JWT-Validierung
- `user-template-dictionary/requirements.txt` - PyJWT hinzugefügt
---
## 4. install.sh Improvements ✅
### 4a. Git-Pull Auto-Fix für Synology
**Problem:** Auf Synology schlugen `git pull` Befehle fehl wegen Dateiberechtigungen.
**Lösung:**
```bash
git config core.filemode false # Ignoriere Berechtigungsbits
git reset --hard origin/main # Force-Sync mit Remote
```
**Commits:**
- `7111d7a`: Auto-fix git pull with core.filemode
### 4b. Update-and-Re-Exec Mechanism
**Problem:** Wenn `install.sh` selbst aktualisiert wird, lädt bash die alte Version weiter.
**Lösung:** Nach `git pull` Checksumme vergleichen und Script neu starten mit `exec bash`.
```bash
BEFORE_HASH=$(md5sum install.sh)
# ... git pull ...
AFTER_HASH=$(md5sum install.sh)
if [ "$BEFORE_HASH" != "$AFTER_HASH" ]; then
export ALREADY_REEXECED="true"
exec bash install.sh
fi
```
**Commits:**
- `bb25750`: Add update-and-re-exec mechanism
### 4c. Alte Container Auto-Cleanup
**Problem:** Nach Code-Updates blieben alte Container und verursachten Traefik-Konflikte.
**Lösung:** `install.sh` löscht alle alten User-Container vor Restart.
```bash
# install.sh Sektion 8:
docker rm -f $(docker ps -a | grep "user-" | awk '{print $1}')
```
**Commits:**
- `7beb1d0`: Add detailed output for old container cleanup
**Betroffen:** `install.sh`
---
## 5. Dictionary Template Routing Fix ✅
**Problem:** `/api/words` Requests return 404 weil Traefik den Pfad-Prefix nicht entfernt.
**Lösung:** API-Base-Pfad aus `window.location.pathname` berechnen.
```javascript
// Vorher (falsch):
const response = await fetch('/api/words')
// Nachher (richtig):
const apiBase = window.location.pathname.replace(/\/$/, ''); // z.B. "/e220dd278a12-template-dictionary"
const response = await fetch(`${apiBase}/api/words`)
```
**Commits:**
- `20a4d60`: Fix API paths in Dictionary template for Traefik routing
**Betroffen:** `user-template-dictionary/templates/index.html`
---
## Zusammengefasst
| Fix | Status | Commits | Wichtigkeit |
|-----|--------|---------|-------------|
| Traefik Network (network.connect) | ✅ | 65a2a6e | 🔴 KRITISCH |
| Traefik Router Service-Labels | ✅ | 45bd329 | 🔴 KRITISCH |
| JWT-Cookie-Auth | ✅ | 436b1c0 | 🔴 KRITISCH (Security) |
| install.sh Git-Fix | ✅ | 7111d7a | 🟡 Wichtig |
| install.sh Re-Exec | ✅ | bb25750 | 🟡 Wichtig |
| install.sh Container-Cleanup | ✅ | 7beb1d0 | 🟡 Wichtig |
| Dictionary API-Paths | ✅ | 20a4d60 | 🟡 Wichtig |
---
## Deployment-Schritte
Nach diesen Fixes sollte auf der Synology folgende Procedure ausgeführt werden:
```bash
bash install.sh
```
Das führt automatisch aus:
1. `git pull` mit Auto-Fix für Berechtigungen
2. Falls install.sh sich geändert hat: Neu starten
3. Alte User-Container löschen (Traefik-Konflikt-Prävention)
4. Alle Templates aus .env bauen
5. Docker-Compose mit neuen Containern starten
---
## Testen nach Deployment
1. **User-Authentication testen:**
```bash
# Mit Browser: https://spawner.wieland.org/
# Login mit Magic Link
```
2. **Container-Routing testen:**
```bash
# Container sollte im web-Netzwerk sein
docker network inspect web | grep user-
```
3. **JWT-Protection testen:**
```bash
# Versuche direkten Container-Zugriff OHNE Login
curl https://spawner.wieland.org/e220dd278a12-template-dictionary/api/words
# → Sollte 401 Unauthorized zurückgeben
```
4. **JWT-Cookie testen:**
```bash
# Nach erfolgreichem Login:
# Browser-DevTools → Application → Cookies
# → spawner_token sollte vorhanden und HttpOnly markiert sein
```