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>
54 lines
1.9 KiB
TypeScript
54 lines
1.9 KiB
TypeScript
import { PrismaPg } from "@prisma/adapter-pg";
|
||
import "dotenv/config";
|
||
import { PrismaClient } from "../src/generated/prisma/client";
|
||
import { PASSWORT_MINDESTLAENGE, passwortHashen } from "../src/lib/passwort-hash";
|
||
import { EINGEBAUTE_VORLAGEN } from "./vorlagen";
|
||
|
||
/**
|
||
* Grundausstattung (#003): Notfall-Admin und eingebaute Vorlagen.
|
||
*
|
||
* Laeuft bei jedem Start des migrate-Dienstes und ist deshalb idempotent. Ein bestehender
|
||
* Notfall-Admin wird nie angefasst – sonst setzte jeder Neustart ein in der Oberflaeche
|
||
* geaendertes Passwort zurueck.
|
||
*/
|
||
const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env["DATABASE_URL"] }) });
|
||
|
||
async function notfallAdmin(): Promise<void> {
|
||
const anmeldename = process.env["SSHKV_BREAKGLASS_USER"]?.trim() || "notfall";
|
||
const passwort = process.env["SSHKV_BREAKGLASS_PASSWORD"] ?? "";
|
||
if (await prisma.benutzer.findFirst({ where: { istNotfall: true } })) {
|
||
console.log("Notfall-Admin vorhanden – unverändert.");
|
||
return;
|
||
}
|
||
if (passwort.length < PASSWORT_MINDESTLAENGE) {
|
||
console.warn(
|
||
`Kein Notfall-Admin angelegt: SSHKV_BREAKGLASS_PASSWORD fehlt oder ist kürzer als ${PASSWORT_MINDESTLAENGE} Zeichen.`,
|
||
);
|
||
return;
|
||
}
|
||
await prisma.benutzer.create({
|
||
data: {
|
||
anmeldename,
|
||
name: "Notfall-Admin",
|
||
rolle: "ADMIN",
|
||
istNotfall: true,
|
||
passwortHash: await passwortHashen(passwort),
|
||
},
|
||
});
|
||
console.log(`Notfall-Admin „${anmeldename}“ angelegt. TOTP wird bei der ersten Anmeldung eingerichtet.`);
|
||
}
|
||
|
||
async function vorlagen(): Promise<void> {
|
||
for (const vorlage of EINGEBAUTE_VORLAGEN) {
|
||
await prisma.vorlage.upsert({ where: { name: vorlage.name }, create: vorlage, update: {} });
|
||
}
|
||
console.log(`${EINGEBAUTE_VORLAGEN.length} eingebaute Vorlagen geprüft.`);
|
||
}
|
||
|
||
try {
|
||
await notfallAdmin();
|
||
await vorlagen();
|
||
} finally {
|
||
await prisma.$disconnect();
|
||
}
|