Massenwiderruf: Der neue E2E-Test (widerruf.spec.ts) fand einen echten Fehler: Die Seite /schluessel/widerruf filterte ?id= mit /^[a-z0-9]{1,64}$/. Vom Worker erzeugte Schlüssel tragen
eine UUID mit Bindestrichen – jeder erzeugte Schlüssel fiel still heraus („Keine Schlüssel gewählt“).
Jetzt idsAusSuchparameter in src/lib/schluessel.ts (mit Test). Außerdem nannte der Hinweis nach
verweigerter Bestätigung den falschen Knopf („Widerruf vorbereiten“ statt „2 Schlüssel widerrufen“). datenbank() und oidcBestaetigen() liegen jetzt in tests/e2e/hilfen.ts.
Rotation abbrechen: kein neues Feld. Abbrechen = Widerruf des Nachfolgers über den Ablauf aus #024
(Dry-Run, er kann schon ausgerollt sein); ein Nachfolger im Widerruf bzw. widerrufen ist die
abgebrochene Rotation (rotationAbgebrochen). vorgaengerId bleibt für die Historie, der Abbruch
steht als schluessel.rotation.abgebrochen im Protokoll – in derselben Transaktion wie das Vormerken
(widerrufEinleiten nimmt dafür optional zusaetzlich an). Der alte Schlüssel bleibt unverändert; bei
gleichem Alias zeigt die config nach dem Anwenden wieder auf die alte Datei (nur verbleibende
Zuweisungen landen im Block).
Abbrechen geht nur, solange der alte Schlüssel noch nicht entfernt wird (Schritt 5) – sonst wären am
Ende beide halb entfernt. Auf dem Nachfolger ersetzt „Rotation abbrechen“ den normalen
„Widerrufen“-Knopf, damit der Abbruch immer im Protokoll steht.
widerrufAbschliessen setzt ROTIERT nur noch bei einem aktiven Nachfolger, der nicht selbst im
Widerruf ist; die Seite schreibt „Ersetzt durch …“ nur bei ROTIERT.
Kein zweiter Nachfolger:vorgaengerId ist eindeutig (1:1-Relation). Nach einem Abbruch lässt sich
derselbe Schlüssel deshalb nicht erneut über sshkv rotieren; Seite und Fehlermeldung sagen das
(neuen Schlüssel anlegen, zuweisen, alten widerrufen). Eine erneute Rotation bräuchte eine
1:n-Relation mit eindeutigem Teilindex „ein nicht widerrufener Nachfolger je Vorgänger“.
→ Behoben in #033 (partieller Index statt 1:1).
Protokoll-IDs: Migration 20261012173000_protokoll_id_lueckenlos setzt den Spalten-Default auf den
Platzhalter 0 (Prisma: @default(0), create ohne ID geht weiter); die ID zieht nur noch der
Trigger unter der Advisory-Sperre aus der weiterhin zugeordneten Sequenz. Bestehende Zeilen bleiben
unverändert (die ID steckt in der Hash-Eingabe), alte Lücken bleiben also stehen. Eine mitgegebene ID
überschreibt der Trigger weiterhin.
Anker: Die Dry-Run-Karte trägt id="dry-run" (Karte nimmt eine optionale id) und scroll-mt-20 wegen der festen Kopfleiste der schmalen Ansicht; „Zum Dry-Run“ zeigt auf /schluessel/<id>#dry-run.
Quelle: docs/issues/032-nacharbeiten.md – dort wird dieses Issue gepflegt.
## Ziel
Kleinere offene Punkte aus den Berichten der Phasen 4 und 5 erledigen.
## Aufgaben
- [x] Massenwiderruf im Browser testen (E2E mit frischer Bestätigung über den Mock-OIDC)
- [x] Laufende Rotation abbrechen können (Nachfolger widerrufen, Vorgänger wieder aktiv)
- [x] Protokoll-IDs ohne Zweierschritte (Spalten-Default und Trigger ziehen beide `nextval`)
- [x] „Zum Dry-Run“ aus der Zuweisungsmatrix direkt zur Dry-Run-Karte springen (Anker)
## Akzeptanzkriterien
- [x] Alle Suiten grün
## Abhängigkeiten
#023, #024, #025, #027
## Notizen / Entscheidungen
- **Massenwiderruf:** Der neue E2E-Test (`widerruf.spec.ts`) fand einen echten Fehler: Die Seite
`/schluessel/widerruf` filterte `?id=` mit `/^[a-z0-9]{1,64}$/`. Vom Worker erzeugte Schlüssel tragen
eine UUID mit Bindestrichen – jeder erzeugte Schlüssel fiel still heraus („Keine Schlüssel gewählt“).
Jetzt `idsAusSuchparameter` in `src/lib/schluessel.ts` (mit Test). Außerdem nannte der Hinweis nach
verweigerter Bestätigung den falschen Knopf („Widerruf vorbereiten“ statt „2 Schlüssel widerrufen“).
`datenbank()` und `oidcBestaetigen()` liegen jetzt in `tests/e2e/hilfen.ts`.
- **Rotation abbrechen:** kein neues Feld. Abbrechen = Widerruf des Nachfolgers über den Ablauf aus #024
(Dry-Run, er kann schon ausgerollt sein); ein Nachfolger im Widerruf bzw. widerrufen *ist* die
abgebrochene Rotation (`rotationAbgebrochen`). `vorgaengerId` bleibt für die Historie, der Abbruch
steht als `schluessel.rotation.abgebrochen` im Protokoll – in derselben Transaktion wie das Vormerken
(`widerrufEinleiten` nimmt dafür optional `zusaetzlich` an). Der alte Schlüssel bleibt unverändert; bei
gleichem Alias zeigt die config nach dem Anwenden wieder auf die alte Datei (nur verbleibende
Zuweisungen landen im Block).
- Abbrechen geht nur, solange der alte Schlüssel noch nicht entfernt wird (Schritt 5) – sonst wären am
Ende beide halb entfernt. Auf dem Nachfolger ersetzt „Rotation abbrechen“ den normalen
„Widerrufen“-Knopf, damit der Abbruch immer im Protokoll steht.
- `widerrufAbschliessen` setzt `ROTIERT` nur noch bei einem aktiven Nachfolger, der nicht selbst im
Widerruf ist; die Seite schreibt „Ersetzt durch …“ nur bei `ROTIERT`.
- **Kein zweiter Nachfolger:** `vorgaengerId` ist eindeutig (1:1-Relation). Nach einem Abbruch lässt sich
derselbe Schlüssel deshalb nicht erneut über sshkv rotieren; Seite und Fehlermeldung sagen das
(neuen Schlüssel anlegen, zuweisen, alten widerrufen). Eine erneute Rotation bräuchte eine
1:n-Relation mit eindeutigem Teilindex „ein nicht widerrufener Nachfolger je Vorgänger“.
→ Behoben in #033 (partieller Index statt 1:1).
- **Protokoll-IDs:** Migration `20261012173000_protokoll_id_lueckenlos` setzt den Spalten-Default auf den
Platzhalter `0` (Prisma: `@default(0)`, `create` ohne ID geht weiter); die ID zieht nur noch der
Trigger unter der Advisory-Sperre aus der weiterhin zugeordneten Sequenz. Bestehende Zeilen bleiben
unverändert (die ID steckt in der Hash-Eingabe), alte Lücken bleiben also stehen. Eine mitgegebene ID
überschreibt der Trigger weiterhin.
- **Anker:** Die Dry-Run-Karte trägt `id="dry-run"` (`Karte` nimmt eine optionale `id`) und
`scroll-mt-20` wegen der festen Kopfleiste der schmalen Ansicht; „Zum Dry-Run“ zeigt auf
`/schluessel/<id>#dry-run`.
---
Quelle: `docs/issues/032-nacharbeiten.md` – dort wird dieses Issue gepflegt.
florian.wilde
added this to the v1.0.0 milestone 2026-10-12 15:13:29 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ziel
Kleinere offene Punkte aus den Berichten der Phasen 4 und 5 erledigen.
Aufgaben
nextval)Akzeptanzkriterien
Abhängigkeiten
#023, #024, #025, #027
Notizen / Entscheidungen
widerruf.spec.ts) fand einen echten Fehler: Die Seite/schluessel/widerruffilterte?id=mit/^[a-z0-9]{1,64}$/. Vom Worker erzeugte Schlüssel trageneine UUID mit Bindestrichen – jeder erzeugte Schlüssel fiel still heraus („Keine Schlüssel gewählt“).
Jetzt
idsAusSuchparameterinsrc/lib/schluessel.ts(mit Test). Außerdem nannte der Hinweis nachverweigerter Bestätigung den falschen Knopf („Widerruf vorbereiten“ statt „2 Schlüssel widerrufen“).
datenbank()undoidcBestaetigen()liegen jetzt intests/e2e/hilfen.ts.(Dry-Run, er kann schon ausgerollt sein); ein Nachfolger im Widerruf bzw. widerrufen ist die
abgebrochene Rotation (
rotationAbgebrochen).vorgaengerIdbleibt für die Historie, der Abbruchsteht als
schluessel.rotation.abgebrochenim Protokoll – in derselben Transaktion wie das Vormerken(
widerrufEinleitennimmt dafür optionalzusaetzlichan). Der alte Schlüssel bleibt unverändert; beigleichem Alias zeigt die config nach dem Anwenden wieder auf die alte Datei (nur verbleibende
Zuweisungen landen im Block).
Ende beide halb entfernt. Auf dem Nachfolger ersetzt „Rotation abbrechen“ den normalen
„Widerrufen“-Knopf, damit der Abbruch immer im Protokoll steht.
widerrufAbschliessensetztROTIERTnur noch bei einem aktiven Nachfolger, der nicht selbst imWiderruf ist; die Seite schreibt „Ersetzt durch …“ nur bei
ROTIERT.vorgaengerIdist eindeutig (1:1-Relation). Nach einem Abbruch lässt sichderselbe Schlüssel deshalb nicht erneut über sshkv rotieren; Seite und Fehlermeldung sagen das
(neuen Schlüssel anlegen, zuweisen, alten widerrufen). Eine erneute Rotation bräuchte eine
1:n-Relation mit eindeutigem Teilindex „ein nicht widerrufener Nachfolger je Vorgänger“.
→ Behoben in #033 (partieller Index statt 1:1).
20261012173000_protokoll_id_lueckenlossetzt den Spalten-Default auf denPlatzhalter
0(Prisma:@default(0),createohne ID geht weiter); die ID zieht nur noch derTrigger unter der Advisory-Sperre aus der weiterhin zugeordneten Sequenz. Bestehende Zeilen bleiben
unverändert (die ID steckt in der Hash-Eingabe), alte Lücken bleiben also stehen. Eine mitgegebene ID
überschreibt der Trigger weiterhin.
id="dry-run"(Kartenimmt eine optionaleid) undscroll-mt-20wegen der festen Kopfleiste der schmalen Ansicht; „Zum Dry-Run“ zeigt auf/schluessel/<id>#dry-run.Quelle:
docs/issues/032-nacharbeiten.md– dort wird dieses Issue gepflegt.