test: SSH-Testziele und Mock-OIDC fuer Integrationstests (#011)

Bootstrap, Host-Key-Pruefung und spaeteres Ausrollen brauchen echte
sshd-Gegenstellen. Zwei Debian-13-Container (ziel-a, ziel-b) in einem
gemeinsamen Netz bilden frische Hosts vor dem Bootstrap nach: root- und
Passwort-Login sind absichtlich offen, Host-Keys entstehen erst beim
Start, und `hostkeys-tauschen` erlaubt den Test "geaenderter Host-Key
wird abgelehnt" ohne Neuerstellen des Containers.

Die Testhilfen lesen dieselben Adress-Variablen wie die Compose-Datei
und lassen Tests mit Hinweis auf den Startbefehl fehlschlagen, statt
sie still zu ueberspringen - ein uebersprungener Integrationstest sieht
sonst wie ein bestandener aus.

Der Mock-OIDC-Anbieter ersetzt authentik in der Entwicklung (PLAN.md,
Entscheidung 7). Bei interaktivem Login uebernimmt er nur Claims aus dem
Formular, daher belegt eine eigene Login-Seite email, name und groups
vor und laesst die Gruppen frei waehlen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 09:13:56 +02:00
co-authored by Claude Opus 5.5
parent 224386106b
commit e89112a761
11 changed files with 614 additions and 6 deletions
+34 -6
View File
@@ -1,21 +1,49 @@
# #011 Test-SSH-Container und Integrationstests
**Status:** offen
**Status:** erledigt
**Meilenstein:** v0.1.0
**Labels:** test
**Geschätzt:** 2 h **Tatsächlich:** –
**Geschätzt:** 2 h **Tatsächlich:** 0,25 h
## Ziel
Debian-Container mit sshd für Integrationstests (Bootstrap, Host-Key, später Ausrollen).
## Aufgaben
- [ ] Dockerfile `tests/ssh-ziel/` (Debian 13, sshd, sudo, Passwort für root/test)
- [ ] Compose-Datei für Tests, zwei Ziele (für Host-zu-Host)
- [ ] Vitest-Projekt `integration`
- [x] Dockerfile `tests/ssh-ziel/` (Debian 13, sshd, sudo, Passwort für root/test)
- [x] Compose-Datei für Tests, zwei Ziele (für Host-zu-Host)
- [x] Vitest-Projekt `integration`
- [x] Mock-OIDC-Anbieter für die Entwicklung (`mock-oidc` in `docker-compose.test.yml`)
- [x] Hilfen `tests/integration/hilfen/ziele.ts` und Rauchtest `tests/integration/ziele.test.ts`
## Akzeptanzkriterien
- [ ] `pnpm test:integration` läuft lokal
- [x] `pnpm test:integration` läuft lokal
## Abhängigkeiten
#001
## Notizen / Entscheidungen
- **Start:** `pnpm test:ziele:up` (= `docker compose -f docker-compose.test.yml up -d --build --wait`),
Stopp: `pnpm test:ziele:down`. Projektname `sshkv-test`.
- **Ports** nur auf 127.0.0.1: `ziel-a` 2221, `ziel-b` 2222, `mock-oidc` 8090. Überschreibbar über
`SSHKV_TEST_ZIEL_A`/`SSHKV_TEST_ZIEL_B`/`SSHKV_TEST_OIDC` (Format `host:port`) – dieselben
Variablen lesen Compose (Port-Bindung) und die Testhilfen, damit beide nie auseinanderlaufen.
- **Testziel** (`debian:trixie-slim`): root und `test` (Gruppe `sudo`) mit Passwort
`sshkv-test` (ENV `SSHKV_TEST_ROOT_PASSWORT`/`SSHKV_TEST_TEST_PASSWORT`, wird beim Start per
`chpasswd` gesetzt). `PermitRootLogin yes` und `PasswordAuthentication yes` absichtlich –
das Ziel bildet einen Host vor dem Bootstrap nach.
- **Host-Keys** werden nicht ins Image gebacken, sondern beim Start mit `ssh-keygen -A` erzeugt:
jeder neu erstellte Container hat eigene Keys. `hostkeys-tauschen` im Container erzeugt neue
Keys, schickt sshd (PID 1) ein SIGHUP und wartet, bis `ssh-keyscan` den neuen Key sieht.
- **Fingerprint-Vergleich** handelt nur `ssh-ed25519` aus, sonst könnte der gezeigte Key-Typ
wechseln und der Vergleich flattern.
- **Nicht laufende Ziele** lassen die Tests mit Hinweis auf den Startbefehl fehlschlagen
(`zielBereit` wartet bis 15 s auf das SSH-Banner) – kein stilles Überspringen.
- Beide Ziele bauen ohne gemeinsames `image:`-Tag: Mit gemeinsamem Tag bricht der parallele
Build mit „already exists“ ab.
- **Mock-OIDC:** `ghcr.io/navikt/mock-oauth2-server:6.0.5` (exakt gepinnt).
Issuer `http://127.0.0.1:8090/sshkv` – der Mock leitet ihn aus dem Host-Header ab, mit
`localhost` entstünde ein anderer Issuer. Client-ID und -Secret werden nicht geprüft.
Bei `interactiveLogin` übernimmt der Mock **nur** die Claims aus dem Login-Formular
(`tokenCallbacks` greifen dann nicht). Deshalb liefert `tests/mock-oidc/login.html` eine
eigene Login-Seite (`loginPagePath`), die `email`, `email_verified`, `name`,
`preferred_username` und `groups: ["sshkv-admins"]` vorbelegt; Knöpfe für Admin/Operator/
Reader/ohne Gruppe, das JSON bleibt frei änderbar.