Commit Graph
4 Commits
Author SHA1 Message Date
msolarczekandClaude Opus 4.8 db36c795bd Fundament Benutzer-/Rollenverwaltung: Schema, Passwort-Policy, Force-Change
Vorbereitung für die Benutzer- & Rollenverwaltung (Pakete A–C) ohne E-Mail-Flow.

- Schema: User.mustChangePassword (erzwungener Wechsel), User.mfaEnrolledAt +
  recoveryCodes (optionale Nutzer-MFA, Paket C); neues Singleton PlatformSetting
  mit mfaRequired (Default aus → MFA optional). Migration additiv + Grant/Seed.
- RBAC: neue Permission role:manage (Rollenverwaltung), dem Mandanten-Admin
  zugewiesen; für den bestehenden Demo-Mandanten nachgezogen (neue Tenants via
  provision/seed automatisch).
- Passwort-Policy: lib/password-policy.ts (client-safe Validierung/Beschreibung,
  Defaults + Ableitung aus TenantSettings.securityPolicy) und server/password.ts
  (Argon2id-Hash + policy-konformer Einmal-Passwort-Generator).
- Force-Change-Flow: /change-password (außerhalb der (app)-Shell) + Self-Service-
  Action changeOwnPassword (policy-geprüft, Audit). (app)-Layout erzwingt den
  Wechsel autoritativ aus der DB und sperrt deaktivierte Konten (Abmelden-Screen).

tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:18:05 +02:00
msolarczekandClaude Opus 4.8 e07dcd9f2a Nicht-destruktiver Richtlinien-Re-Import (Phase-1-Härtung Paket 3)
Der Re-Import löschte bisher alle Policy-Zeilen und legte sie neu an — das setzte
per-Dokument-Status, TISAX-Override, Freigabe/Version und nutzergepflegte
Variablenwerte zurück. Jetzt Diff/Upsert über stabile Schlüssel, verlustfrei.

- Schema: PolicyDocument.archivedAt + PolicyRequirement.archivedAt (Lifecycle,
  orthogonal zum Freigabe-status). Migration additiv/nullable.
- import-policies.ts komplett auf Reconcile umgebaut:
  - Dokumente (code): neu→anlegen; vorhanden→nur Inhaltsfelder aktualisieren,
    Status/Version/Owner/Freigabe/Override bleiben; fehlend→archivedAt setzen
    (deaktivieren, nicht löschen); Wiederauftauchen→reaktivieren.
  - Anforderungen (reqId): analog inkl. Deaktivierung entfernter Anforderungen.
  - Variablen (key): Metadaten aktualisieren, aber value NIE überschreiben
    (Kundenpflege); fehlende bleiben bestehen (als obsolet ausgewiesen).
  - Baseline (blId) und Nachweise (nr): Upsert; fehlende bleiben erhalten.
  - Deaktivierung greift nur im Paket-Namensraum (L00/R*/VA-*/BASELINE/NACHWEIS)
    — verwaltete Register aus import-managed (CRYPTO/RISKMATRIX/CLASSIFICATION/
    HANDBUCH) werden nicht angetastet.
- Änderungsreport (added/updated/archived/reactivated/unchanged/obsolete) wird
  zurückgegeben und ins Audit-Log geschrieben (Entity policy_package). Option
  { dryRun: true } liefert die Vorschau ohne Schreibzugriff. Idempotent.
- Aktive Ansichten (Bibliothek/Coverage, Dokument-Detail) filtern archivedAt: null;
  Historie bleibt per Direktlink erreichbar.

Akzeptanztest scripts/test-reimport.ts: Status/Override/Einreicher + Variablenwert
bleiben nach Re-Import erhalten, entfernte Anforderung wird deaktiviert (nicht
gelöscht), verwaltete Register unberührt, zweiter Lauf idempotent. Browser: /policies
rendert unverändert (30 Dokumente). tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 13:46:42 +02:00
msolarczekandClaude Opus 4.8 8e4040d1da Separater Superadmin-Store + eigener Login + MFA-Pflicht (Phase-1-Härtung Paket 2)
Plattform-Administratoren sind nicht länger isPlatformAdmin-Nutzer innerhalb eines
Mandanten, sondern ein getrennter Store mit eigener Auth-Domäne — Voraussetzung
für den sicheren Betrieb beim ersten echten Kunden.

Store & Migration
- Neues Modell PlatformAdmin (kein tenant_id): Argon2id-Hash, TOTP-Secret,
  Recovery-Codes (nur SHA-256-Hashes), Fehlversuchszähler + Sperre, lastLogin.
- AuditLog.tenant_id nullable → mandantenlose Plattform-Ereignisse (scope=platform).
- Datenmigration: bestehende isPlatformAdmin-Nutzer in den neuen Store übernommen
  (gleicher Hash → Login sofort möglich), Flag mandantenweit auf false gesetzt.

Getrennter Login + MFA
- Zweite NextAuth-Instanz (server/platform-auth.ts) mit eigenem Cookie und
  eigenem basePath /api/platform-auth; Session trägt bewusst KEINEN tenantId.
- TOTP-MFA (otplib): Enrollment beim ersten Login (/platform/enroll-mfa, QR +
  Klartext-Secret), danach bei jedem Login erzwungen; 10 einmalige Recovery-Codes.
- Härtung: Konto-Sperre nach 5 Fehlversuchen (15 min), Audit aller Anmeldungen,
  Fehlversuche und Sperren (scope=platform).

Autorisierung / Trennung
- Admin-Konsole nach (platform)/admin verschoben; (platform)/layout.tsx erzwingt
  Plattform-Session + aktivierte MFA. Mandanten-Session hat KEINEN Zugriff auf /admin.
- Mandanten-Shell zeigt keinen /admin-Link mehr; admin-Actions prüfen die
  Plattform-Session statt des abgelösten Flags.
- provision/seed setzen isPlatformAdmin nicht mehr; Seed legt den Demo-Plattform-
  Admin (admin@demo.example) im getrennten Store an.

Browser-verifiziert: Plattform-Login → erzwungenes MFA-Enrollment → Recovery-Codes →
/admin; Login ohne Code scheitert (?error=1); Mandanten-Session auf /admin wird auf
/platform/login umgeleitet. tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 20:55:12 +02:00
msolarczekandClaude Opus 4.8 8348764c99 API-seitige Modul-Durchsetzung vervollständigt (§3.4, Phase-1-Härtung Paket 1)
Der requireModule-Guard war bislang nur exemplarisch in den Policy-Actions
gesetzt. Jetzt läuft jede mutierende Server-Action eines gegateten Moduls über
einen zentralen, modul- und rechteprüfenden Guard — ein für den Mandanten
deaktiviertes Modul weist damit auch Writes serverseitig ab (nicht nur Reads
über die Route-Layouts).

- action-guard.ts: moduleGuard("<key>") erzeugt je Modul einen guard(...perms),
  der Session → Modul-Aktivierung → RBAC prüft und {session, db} zurückgibt.
- modules.ts: assertModuleEnabled(session, key) wirft (statt Redirect) bei
  Deaktivierung und protokolliert die Verweigerung (Audit-Aktion "denied").
- audit.ts: Audit-Aktion "denied" + optionaler scope-Parameter.
- Alle gegateten Action-Dateien umgestellt: assets→assets, processes→bia,
  risks→risk, measures→measures, suppliers/services→suppliers, policies→policies.
  Freigabe/Ablehnung der Richtlinien laufen jetzt ebenfalls über den Modul-Guard.
- Vollständigkeitscheck scripts/check-module-guards.ts (Registry Action→Modul):
  schlägt fehl bei nicht zugeordneter Datei, fehlendem moduleGuard oder einer
  Action ohne guard(...). Als prebuild verdrahtet ⇒ Build failt bei vergessenem
  Endpoint. admin/tenant-settings sind als EXEMPT (eigene Auth) markiert.

Verifiziert: tsc sauber, lint sauber, Guard-Check grün (9 Dateien), Negativ-Probe
(ungemappte Action-Datei) failt den Check wie erwartet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 20:27:13 +02:00