Die Oberflaeche legt einen Vorgang an und schickt nur dessen ID in die
Warteschlange; der Worker fuehrt ihn aus und haelt Status, Ergebnis
oder Fehler fest. So bleiben lange SSH-Vorgaenge aus dem Webprozess
heraus, und der Fortschritt ist ohne Job-Interna sichtbar.
Kein automatisches Wiederholen: ein halb ausgefuehrter Schreibvorgang
auf einem Host gehoert vor einen Menschen. Fehlertexte aus fremden
Bibliotheken erreichen die Oberflaeche nie.
Dockerfile und Compose fuer den Betrieb: Master-Key als Secret nur im
Worker, Datenbank in einem internen Netz.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/screenshots.ts nimmt Uebersicht und Schluesseldetail bei
1440x900 und 390x844 auf und meldet nebenbei horizontalen Ueberlauf,
damit es fuer die Anleitung (#029) und als schneller Layout-Test taugt.
Issue #002 ist damit erledigt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Klickbarer Prototyp mit Beispieldaten aus src/beispiel/, sichtbar als
Beispiel gekennzeichnet. Er zeigt das verbindliche Design an echten
Bildschirmen, bevor die Lesemodelle (#012, #021, #026) existieren; die
Seiten tauschen spaeter nur die Datenquelle. Die bisherige Startseite
entfaellt zugunsten der Route-Gruppe (app).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Huelle bekommt Benutzer und optional den aktiven Pfad als Props und
kennt weder Sitzung noch Datenbank; ohne Pfad ermittelt die Navigation
ihn per usePathname(), weil ein Layout den Pfad nicht kennt. Die
Benutzerermittlung steckt in huellenBenutzerErmitteln(), damit #004 nur
diese Funktion ersetzen muss.
Unter 1024 px klappt die Leiste ein; geschlossen ist sie invisible und
damit auch nicht per Tab erreichbar. Alle Navigationsziele haben eine
Platzhalterseite, damit nichts auf eine 404 fuehrt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bildmarke als Inline-SVG und Wortmarke, dazu Karte, Button, Badge,
Statuspunkt, Tabelle, Kennzahl, Diff-Box, Breadcrumb, Seitenkopf,
Leerzustand und MonoKopieren. Die Bausteine kapseln die Designregeln
(44 px Klickflaeche, Status nie nur ueber Farbe, Tabellen scrollen im
eigenen Container), damit spaetere Seiten sie nicht neu erfinden.
Nur MonoKopieren ist Client-Komponente, weil sie die Zwischenablage
braucht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Farben des Tresor-Designs stehen als CSS-Variablen in :root und
werden per @theme inline an Tailwind gereicht, damit Inline-SVGs und
Utility-Klassen dieselbe Quelle nutzen. Schriften kommen selbst gehostet
aus @fontsource, nur in den benutzten Gewichten und im Latin-Ausschnitt.
src/lib/format.ts rechnet fest in Europe/Berlin: der Server laeuft im
Container auf UTC, die Anzeige soll aber ueberall dieselbe Ortszeit
zeigen. relativ() nimmt den Bezugspunkt als Parameter, damit statische
Seiten und Tests deterministisch bleiben.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der framework-freie Kern ist fertig; Deployment-Key, Master-Key im Worker
und der Nachweis am Datenbank-Dump haengen an Datenbank und Worker und
kommen mit #007. Die Entscheidungen (16 bcrypt-Runden, Fehlercodes,
RSA-Mindestlaenge abschaltbar fuers Beobachten, Umschlag-Format,
Dateirechte des Master-Keys) stehen im Issue, damit die Anbindung nicht
raten muss.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sitzung, OIDC-Fluss und Rueckruf aus Laufzettel uebernommen und auf
sshkv angepasst. Abweichungen mit Absicht:
- Ohne passende sshkv-Gruppe gibt es keinen Zugang, auch keinen
Lesezugriff: schon die Hostliste verraet, wer wohin darf.
- Notfall-Admin nur mit TOTP (Freigabe Frage 5). Ein richtiges
Passwort fuehrt beim ersten Mal nur zur Einrichtung. Jeder Code gilt
einmal, fuenf Fehlversuche sperren 15 Minuten.
- Kritische Rechte verlangen eine Bestaetigung, die hoechstens fuenf
Minuten alt ist. Bei OIDC mit prompt=login, max_age=0 und Pruefung
von auth_time, sonst zaehlte eine laufende SSO-Sitzung als Beweis.
- Sitzungen laufen acht statt zwoelf Stunden.
Die Seiten folgen, sobald das Design-System (#002) steht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Private Keys, Passwoerter und Tokens duerfen nie in Log oder Protokoll
landen (CLAUDE.md). Ein Netz ueber Feldnamen allein reicht nicht: Ein Key
kann in einer Fehlermeldung oder einem Stacktrace stecken, ohne dass das
Feld danach heisst. Deshalb schwaerzt `schwaerzen` sowohl Felder mit
verdaechtigen Namen (irgendwo im Namen, nicht nur am Anfang) als auch
jeden PEM-Private-Key in beliebigen Zeichenketten, auch abgeschnittene.
Der Helfer ist framework-frei und wird mit dem Logger und dem Protokoll
eingebaut.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Private Keys liegen spaeter verschluesselt in PostgreSQL. Ein eigener DEK
je Geheimnis erlaubt eine Master-Key-Rotation, ohne die Chiffrate selbst
anzufassen; das AAD (Schluessel-ID und Fingerprint) bindet jedes Chiffrat
an seinen Datensatz, sodass vertauschte Zeilen beim Oeffnen auffallen
statt einen fremden Key zu liefern. Die Master-Key-Version steckt im AAD
des DEK.
masterKeyLaden akzeptiert roh, Base64 und Hex, weil `openssl rand` der
naheliegende Weg zum Anlegen ist, und bricht ab, wenn Gruppe oder Welt
die Datei lesen duerfen – ein lesbarer Master-Key oeffnet alle Private
Keys. SSHKV_MASTER_KEY_UNSICHER_ERLAUBT=1 erlaubt das bewusst.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Private Keys sollen nie als Datei auf dem sshkv-Server liegen, auch nicht
kurz. ssh-keygen braucht aber genau das. Deshalb erzeugt Node crypto die
Schluessel (ed25519, RSA-4096), und ein eigener Serializer schreibt das
Format openssh-key-v1 – unverschluesselt oder mit aes256-ctr und
bcrypt_pbkdf (16 Runden, 16 Byte Salt), Checkint und Padding wie OpenSSH.
Der Parser liest auch von ssh-keygen erzeugte Dateien, prueft, dass
Private und Public Key zusammengehoeren, und meldet fehlende oder falsche
Passphrasen ueber eigene Codes. Fehlermeldungen sind feste Saetze ohne
Eingabe darin, damit kein Schluesselmaterial in Logs geraet. RSA unter
2048 Bit wird beim Import abgelehnt; wer nur beobachtet, kann die Grenze
ausschalten.
Die Tests pruefen beide Richtungen gegen das echte ssh-keygen (-y, -lf).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Alle Modelle fuer die fuenf Phasen in einer Migration, damit spaetere
Phasen keine Umbauten an Kerntabellen brauchen. Was auch an der
Service-Schicht vorbei gelten muss, steht als CHECK, partieller Index
oder Trigger in der Datenbank: Personen-Keys ohne Private Key, genau
ein Instanz-Deployment-Key, ein vertrauter Host-Key je Algorithmus,
shell-sichere Zielbenutzer und Pfade.
Das Protokoll ist append-only und per Hash-Kette verbunden; den Hash
berechnet ein Trigger, damit keine Zeile ohne Verkettung entstehen
kann (#005 baut darauf auf).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Bildmarke liegt als SVG in drei Varianten (dunkel, hell, mono) vor.
Rasterdateien erzeugt scripts/icons.mjs mit sharp und sie werden
eingecheckt, damit Build und Laufzeitabbild kein sharp brauchen. Unter
32 px dient eine reduzierte Marke ohne Zahlenring und Bolzen, weil die
Details dort zu Rauschen verschwimmen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Konfiguration aus Laufzettel uebernommen, damit alle Projekte gleich
gebaut und geprueft werden. Entwicklungsdatenbank auf 5436, weil 5433
und 5434 von ProxLedger und Laufzettel belegt sind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan nach Freigabe vom 12.10.2026 mit den Antworten auf die sieben
Rueckfragen. Issues fuer alle fuenf Phasen als Dateien, bis der
Gitea-Zugang da ist (#030).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>