feat(rotation): gefuehrte Rotation mit Test vor dem Widerruf (#023)
Einen Schlüssel zu tauschen soll keinen Ausfall riskieren: Der Nachfolger übernimmt alle aktiven Zuweisungen, wird ausgerollt und per Verbindungstest geprüft – erst wenn alle Tests seit dem letzten Ausrollen grün sind, entfernt der Widerruf aus #024 den alten Schlüssel, der dann als ROTIERT endet. Private Keys bekommen einen neuen Pfad (-rJJJJMMTT) bei gleichem Alias. Damit ssh den neuen nimmt, schreibt privat.ts je Alias nur noch einen config-Eintrag; die jüngste Zuweisung gewinnt. Der Worker setzt vorgaengerId schon beim Erzeugen, so ist die Kette auch nach einem Abbruch vollständig und die Schrittfolge wiederaufnehmbar. Personen-Keys ohne Private Key in sshkv bekommen nur einen Hinweis: dafür braucht es einen neuen Public Key von der Person. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -191,3 +191,44 @@ export async function vorlagenAuswahl() {
|
||||
select: { id: true, name: true, standardLaufzeitTage: true },
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Rotationskette (#023)
|
||||
|
||||
export type KettenGlied = { readonly id: string; readonly name: string; readonly status: SchluesselStatus };
|
||||
|
||||
/**
|
||||
* Die ganze Rotationskette eines Schluessels, aeltester zuerst. Begrenzt, damit eine (durch
|
||||
* Fehler entstandene) Schleife die Seite nicht aufhaengt.
|
||||
*/
|
||||
export async function rotationsKette(id: string, maximal = 25): Promise<KettenGlied[]> {
|
||||
const glied = (schluesselId: string) =>
|
||||
prisma.schluessel.findUnique({
|
||||
where: { id: schluesselId },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
status: true,
|
||||
vorgaengerId: true,
|
||||
nachfolger: { select: { id: true } },
|
||||
},
|
||||
});
|
||||
const start = await glied(id);
|
||||
if (!start) return [];
|
||||
const kette: KettenGlied[] = [{ id: start.id, name: start.name, status: start.status }];
|
||||
const gesehen = new Set([start.id]);
|
||||
for (let davor = start.vorgaengerId; davor && kette.length < maximal && !gesehen.has(davor);) {
|
||||
const g = await glied(davor);
|
||||
if (!g) break;
|
||||
gesehen.add(g.id);
|
||||
kette.unshift({ id: g.id, name: g.name, status: g.status });
|
||||
davor = g.vorgaengerId;
|
||||
}
|
||||
for (let danach = start.nachfolger?.id; danach && kette.length < maximal && !gesehen.has(danach);) {
|
||||
const g = await glied(danach);
|
||||
if (!g) break;
|
||||
gesehen.add(g.id);
|
||||
kette.push({ id: g.id, name: g.name, status: g.status });
|
||||
danach = g.nachfolger?.id;
|
||||
}
|
||||
return kette;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user