Merge branch 'phase/release-0.2.0'

This commit is contained in:
2026-10-12 11:05:59 +02:00
5 changed files with 76 additions and 15 deletions
+20
View File
@@ -15,6 +15,26 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
### Sicherheit ### Sicherheit
## [0.2.0] – 2026-10-12
Phase 2: Schlüssel, Personen und Ausrollen von Public Keys – dazu vorgezogen aus Phase 3 das Ausrollen von Private Keys.
### Hinzugefügt
- Schlüssel erzeugen (ed25519, RSA-4096, optional mit Passphrase), Paar oder Public Key importieren, Public Key exportieren; Liste mit Filter, Detailseite mit Verwendungen (#012)
- Personen verwalten; Self-Service „Meine Schlüssel“: jeder Benutzer hinterlegt eigene Public Keys, wirksam erst nach Zuweisung (#013)
- Private Key anzeigen und herunterladen – nur Admin, nur nach erneuter Bestätigung, genau einmal abholbar; Private Key aus SSHKeyVault löschen (#014)
- authorized_keys-Parser und verwalteter Block: fremde Zeilen bleiben bytegenau, beschädigte Blöcke werden nie überschrieben, Deployment-Key ist vor dem Entfernen geschützt (#015)
- Public Keys Hosts oder Hostgruppen zuweisen, Dry-Run mit Diff, Ausrollen mit Backup und optimistischer Sperre; Ansicht je Schlüssel und je Host (#016)
- Private Key auf einen Quell-Host ausrollen, mit verwaltetem Block in `~/.ssh/config` und `known_hosts` (#017)
- Verbindungstest von Host A nach Host B (#020, Teil)
- Zielbenutzer anlegen und sudoers pflegen – Grundlage, Oberfläche folgt (#018, Teil)
- Vorlagen: Platzhalter und Prüfung – Grundlage, Oberfläche folgt (#019, Teil)
### Sicherheit
- Importierte Private Keys reisen nur verschlüsselt im Job; Vorgang, Protokoll und Browser sehen sie nie (Tests)
- Private-Key-Ziele nimmt der Dry-Run nur für Admins auf
- Dateien in fremden Home-Verzeichnissen werden als deren Benutzer gelesen und geschrieben (Symlink-Schutz)
## [0.1.0] – 2026-10-12 ## [0.1.0] – 2026-10-12
Phase 1: Grundgerüst, Anmeldung, Hosts und Bootstrap. Phase 1: Grundgerüst, Anmeldung, Hosts und Bootstrap.
+31 -2
View File
@@ -2,8 +2,8 @@
## Zeitübersicht ## Zeitübersicht
**Gesamt (Wandzeit):** 1 h 25 min **Gesamt (Wandzeit):** 2 h 25 min
**Summe der Issue-Zeiten:** 4 h 23 min – Sub-Agenten arbeiteten parallel an #002, #006, #008 und #011. **Summe der Issue-Zeiten:** 7 h 08 min – Sub-Agenten arbeiteten parallel an #002, #006, #008, #011 und #012–#014.
| Issue | Zeit | | Issue | Zeit |
|---|---| |---|---|
@@ -19,10 +19,20 @@
| #009 Host-Key-Prüfung | 0 h 25 min | | #009 Host-Key-Prüfung | 0 h 25 min |
| #010 Bootstrap | 0 h 35 min | | #010 Bootstrap | 0 h 35 min |
| #011 Test-SSH-Container | 0 h 15 min | | #011 Test-SSH-Container | 0 h 15 min |
| #012 Schlüssel erzeugen, importieren, exportieren | 0 h 25 min |
| #013 Personen und Self-Service | 0 h 10 min |
| #014 Private Key anzeigen | 0 h 10 min |
| #015 authorized_keys-Parser | 0 h 15 min |
| #016 Public Key ausrollen | 0 h 40 min |
| #017 Private Key ausrollen | 0 h 45 min |
| #018 Zielbenutzer und sudoers (Teil) | 0 h 10 min |
| #019 Vorlagen (Teil) | 0 h 10 min |
| #020 Verbindungstest (Teil) | 0 h 05 min |
| Meilenstein | Zeit | | Meilenstein | Zeit |
|---|---| |---|---|
| v0.1.0 | 1 h 25 min (Wandzeit) | **abgeschlossen** | v0.1.0 | 1 h 25 min (Wandzeit) | **abgeschlossen**
| v0.2.0 | 1 h 00 min (Wandzeit) | **abgeschlossen**
--- ---
@@ -55,3 +65,22 @@
- **Eigene Testdatenbank je parallelem Lauf:** Sub-Agent und Hauptsitzung leerten sich gegenseitig die Tabellen (in `CLAUDE.md` festgehalten). - **Eigene Testdatenbank je parallelem Lauf:** Sub-Agent und Hauptsitzung leerten sich gegenseitig die Tabellen (in `CLAUDE.md` festgehalten).
- **Prisma-Client in den Worker gebündelt:** Im Standalone-Abbild fand die ESM-Auflösung `@prisma/client` sonst nicht (erst im echten Docker-Stapel aufgefallen). - **Prisma-Client in den Worker gebündelt:** Im Standalone-Abbild fand die ESM-Auflösung `@prisma/client` sonst nicht (erst im echten Docker-Stapel aufgefallen).
- **Worker-Benutzer in Compose wählbar** (`SSHKV_WORKER_USER`), weil Docker-Secrets ohne Swarm die Rechte der Host-Datei tragen. - **Worker-Benutzer in Compose wählbar** (`SSHKV_WORKER_USER`), weil Docker-Secrets ohne Swarm die Rechte der Host-Datei tragen.
## 2026-10-12 · Sitzung 2 · 10:07–11:07
**Issue:** #012–#020
**Version:** 0.2.0
### Erledigt
- #012–#014 (Schlüssel, Personen/Self-Service, Private Key anzeigen) von einem Sub-Agenten in eigenem Worktree, danach gemergt; Konflikte in `useVorgang` und der Handler-Tabelle zusammengeführt
- #015 authorized_keys-Parser und Merge mit 26 Randfall-Tests
- #016 Public Keys ausrollen: Soll, Trockenlauf, Ausrollen, Hostseite, Schlüsselseite – Integrationstests und E2E
- #017 Private Key mit `~/.ssh/config` und `known_hosts` – Integrationstest „A meldet sich bei B an“, E2E für den ganzen Kern-Anwendungsfall
- Vorgezogen: #018 Zielkonto-Skripte (Integrationstests), #019 Vorlagen-Logik, #020 Verbindungstest
- Stand: 410 Unit-/DB-Tests, 30 Integrationstests, 12 E2E-Abläufe grün
### Entscheidungen
- **Phase 3 teilweise vorgezogen,** weil Florian „weiter“ sagte, während der Agent noch an Phase 2 arbeitete – nur Teile ohne Schemaänderung, damit die Migrationen des Agenten nicht kollidieren.
- **Trockenlauf und Ausrollen als zwei Vorgänge mit Hash-Sperre:** Es wird nie etwas anderes geschrieben, als jemand gesehen hat.
- **Private-Key-Ziele im Dry-Run nur für Admins:** Sonst hätte ein Operator einen vorbereiteten Private Key ausrollen lassen können (Freigabe Frage 3).
- **Keine Sicherungskopie alter Private Keys** auf dem Host; config-Block am Dateianfang, weil ssh den ersten Treffer nimmt.
- **Ein Hook `useVorgang` für alle:** zwei parallel entstandene Fassungen zusammengeführt, beide Schnittstellen bleiben.
+12 -6
View File
@@ -1,21 +1,27 @@
# #016 Public Key ausrollen mit Dry-Run und Backup # #016 Public Key ausrollen mit Dry-Run und Backup
**Status:** offen **Status:** erledigt
**Meilenstein:** v0.2.0 **Meilenstein:** v0.2.0
**Labels:** backend, ui **Labels:** backend, ui
**Geschätzt:** 4 h **Tatsächlich:** – **Geschätzt:** 4 h **Tatsächlich:** 0 h 40 min
## Ziel ## Ziel
Zuweisungen Schlüssel × Host/Gruppe × Benutzer; Dry-Run-Diff, Backup, atomares Schreiben, Rechte. Zuweisungen Schlüssel × Host/Gruppe × Benutzer; Dry-Run-Diff, Backup, atomares Schreiben, Rechte.
## Aufgaben ## Aufgaben
- [ ] Remote-Skript - [x] Remote-Skript
- [ ] Optimistische Sperre über Datei-Hash - [x] Optimistische Sperre über Datei-Hash
- [ ] Diff-Box im Schlüsseldetail - [x] Diff-Box im Schlüsseldetail
## Akzeptanzkriterien ## Akzeptanzkriterien
- [ ] Integrationstest Ausrollen/Entfernen - [x] Integrationstest Ausrollen/Entfernen
## Abhängigkeiten ## Abhängigkeiten
#015, #010 #015, #010
## Notizen / Entscheidungen ## Notizen / Entscheidungen
- **Zwei Schritte:** TROCKENLAUF hält je Ziel Diff, Hinweise und die Hashes vorher/nachher fest; AUSROLLEN führt genau diesen Plan aus und bricht je Ziel ab, wenn sich Datei **oder** Soll geändert hat. Ein Trockenlauf gilt 15 Minuten und nur einmal.
- **Auf dem Host** alles als Zielbenutzer (`runuser`), Hash dort erneut geprüft, Sicherung (letzte 5 bleiben), Temp-Datei + `mv`, 0700/0600.
- **Nur gültiges UTF-8** wird bearbeitet, sonst ginge „bytegenau“ verloren.
- **Soll** = direkte und Gruppen-Zuweisungen; der Deployment-Key gehört immer zum Soll des Anmeldebenutzers (Aussperrschutz aus #015).
- Gruppen-Verwendungen: Zustand je Verwendung, Fehlschlag auf einem Host gewinnt. Zustand je Host folgt mit dem Abgleich (#021).
- Oberfläche: Zuweisen auf der Schlüsselseite, Dry-Run je Schlüssel und je Host.
+12 -6
View File
@@ -1,21 +1,27 @@
# #017 Private Key ausrollen und ~/.ssh/config # #017 Private Key ausrollen und ~/.ssh/config
**Status:** offen **Status:** erledigt
**Meilenstein:** v0.3.0 **Meilenstein:** v0.3.0
**Labels:** backend, ui **Labels:** backend, ui
**Geschätzt:** 4 h **Tatsächlich:** – **Geschätzt:** 4 h **Tatsächlich:** 0 h 45 min
## Ziel ## Ziel
Private Key auf Zielhost/-benutzer/-pfad, verwalteter Block in `~/.ssh/config`, `known_hosts`. Private Key auf Zielhost/-benutzer/-pfad, verwalteter Block in `~/.ssh/config`, `known_hosts`.
## Aufgaben ## Aufgaben
- [ ] Übertragung nur über stdin - [x] Übertragung nur über stdin
- [ ] Warnung bei Passphrase - [x] Warnung bei Passphrase
- [ ] nur Admin - [x] nur Admin
## Akzeptanzkriterien ## Akzeptanzkriterien
- [ ] Integrationstest - [x] Integrationstest
## Abhängigkeiten ## Abhängigkeiten
#016 #016
## Notizen / Entscheidungen ## Notizen / Entscheidungen
- **Dateien je Ziel:** Private Key (0600, keine Sicherungskopie), `.pub` (0644), verwalteter Block **am Anfang** von `~/.ssh/config` (ssh nimmt den ersten Treffer), verwalteter Block in `known_hosts` mit den vertrauten Host-Keys des Ziels unter dem HostName/Port aus der config.
- **Nie fremde Dateien überschreiben:** Liegt am Zielpfad schon etwas anderes, scheitert das Ziel im Trockenlauf.
- **Plan ohne Inhalt:** Der Trockenlauf zeigt beim Private Key nur die Aktion; weder Vorgang noch Protokoll noch Browser sehen den Schlüssel.
- **Nur Admins:** Zuweisen verlangt `privateKeyAusrollen`; der Trockenlauf nimmt Private-Key-Ziele nur für Admins auf.
- **Widerruf:** löschen oder umbenennen (`…sshkv-widerrufen.<Zeit>`), config- und known_hosts-Einträge verschwinden mit.
- Integrationstest: A meldet sich per Alias bei B an (StrictHostKeyChecking=yes). E2E im Browser für den ganzen Kern-Anwendungsfall.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "sshkv", "name": "sshkv",
"version": "0.1.0", "version": "0.2.0",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "SSHKeyVault – zentrale Verwaltung von SSH-Schluesseln mit Weboberflaeche", "description": "SSHKeyVault – zentrale Verwaltung von SSH-Schluesseln mit Weboberflaeche",