feat(ausrollen): Verbindungstest von Host A nach Host B (#020)

Auf A als Zielbenutzer ssh mit BatchMode und StrictHostKeyChecking:
keine Rueckfrage, keine stille Annahme eines Host-Keys. Der Test
beweist damit genau das, was ein Cronjob auf A spaeter braucht. Die
letzte Meldung von ssh landet in Vorgang und Protokoll; ein Erfolg
setzt die letzte Verwendung des Schluessels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 10:50:43 +02:00
co-authored by Claude Opus 5.5
parent edc38d0c27
commit 61a52d4538
4 changed files with 90 additions and 1 deletions
+13
View File
@@ -112,6 +112,19 @@ describe("Host-zu-Host", () => {
expect(test.stdout.trim()).toBe("root");
expect(await prisma.privateVerwendung.count({ where: { zustand: "AUSGEROLLT" } })).toBe(1);
// Verbindungstest als Vorgang (#020).
const verwendung = await prisma.privateVerwendung.findFirstOrThrow();
const test2 = await vorgangLaufen("VERBINDUNGSTEST", { eingabe: { privatVerwendungId: verwendung.id } });
expect(test2.fehler).toBeNull();
expect(
(await prisma.schluessel.findUniqueOrThrow({ where: { id: schluessel.id } })).zuletztVerwendetAm,
).not.toBeNull();
// Ohne Public Key auf B scheitert der Test verstaendlich.
await befehlAlsRoot(zielB, "rm -f /root/.ssh/authorized_keys");
const test3 = await vorgangLaufen("VERBINDUNGSTEST", { eingabe: { privatVerwendungId: verwendung.id } });
expect(test3.fehler).toMatch(/Permission denied/);
const protokoll = await prisma.protokoll.findFirst({ where: { aktion: "privatekey.ausgerollt" } });
expect(protokoll?.diff).toContain("anlegen /root/.ssh/id_ed25519_backup-a-b");
expect(JSON.stringify(protokoll?.details)).not.toContain("PRIVATE");