Richtlinien-Fixes: zentrale Variablen, Schutzbedarf zentral, Coverage nach Level
- Zentrale Variablen (Organisation + Rollen + Schutzbedarf-Flags, lib/policy-variables.ts) sind im Richtlinien-Editor ausgeblendet und werden nur noch in den Einstellungen gepflegt; updatePolicyVariable/updateScopedVariables blocken zentrale Keys zusätzlich serverseitig. - Schutzbedarf/TISAX wird ausschließlich zentral gesteuert (Superadmin): Override je Richtlinie entfernt (setProtectionOverride + UI weg), globaler TISAX-Schalter im Policy-Modul entfernt (setGlobalTisaxLevel weg) → nur noch Read-only-Anzeige im Editor und in der Bibliothek. Rendering nutzt stets den globalen Level. - Coverage-/Referenzmatrix zeigt nur Anforderungen des aktiven Assessment-Levels (Bedingung erfüllt): bei AL2 keine „sehr hoch"-Controls (browser-verifiziert: 297 statt 316 Anforderungen, 0 SEHR HOCH); AL3 zeigt alle. tsc + lint + build grün; Edit-Seite: Schutzbedarf read-only, zentrale Variablen gesperrt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { redirect } from "next/navigation";
|
||||
import { z } from "zod";
|
||||
import { moduleGuard } from "@/server/action-guard";
|
||||
import { type Permission } from "@/server/rbac";
|
||||
import { isCentralVariable } from "@/lib/policy-variables";
|
||||
import { writeAuditLog } from "@/server/audit";
|
||||
|
||||
const optDate = (v: FormDataEntryValue | null) => (v && String(v) ? new Date(String(v)) : null);
|
||||
@@ -179,6 +180,8 @@ export async function updatePolicyTemplate(code: string, formData: FormData) {
|
||||
/** Eine dokument-bezogene Variable ändern (eine Pflegestelle, §7/§8) — propagiert in alle Dokumente. */
|
||||
export async function updatePolicyVariable(key: string, formData: FormData) {
|
||||
const { session, db } = await guard();
|
||||
const variable = await db.policyVariable.findFirst({ where: { key }, select: { key: true, groupName: true } });
|
||||
if (variable && isCentralVariable(variable)) throw new Error("Zentrale Variablen werden ausschließlich in den Einstellungen gepflegt.");
|
||||
const value = String(formData.get("value") ?? "");
|
||||
await db.policyVariable.updateMany({ where: { key }, data: { value } });
|
||||
await writeAuditLog({ tenantId: session.user.tenantId, actorId: session.user.id, action: "update", entity: "policy_variable", after: { key, value } });
|
||||
@@ -193,8 +196,11 @@ export async function updatePolicyVariable(key: string, formData: FormData) {
|
||||
export async function updateScopedVariables(code: string, formData: FormData) {
|
||||
const { session, db } = await guard();
|
||||
const keys = String(formData.get("keys") ?? "").split(",").map((k) => k.trim()).filter(Boolean);
|
||||
// Zentrale Variablen (Organisation/Rollen) niemals aus dem Richtlinien-Editor überschreiben.
|
||||
const rows = keys.length ? await db.policyVariable.findMany({ where: { key: { in: keys } }, select: { key: true, groupName: true } }) : [];
|
||||
const centralKeys = new Set(rows.filter(isCentralVariable).map((r) => r.key));
|
||||
for (const key of keys) {
|
||||
if (!formData.has(`var_${key}`)) continue;
|
||||
if (centralKeys.has(key) || !formData.has(`var_${key}`)) continue;
|
||||
const value = String(formData.get(`var_${key}`) ?? "");
|
||||
await db.policyVariable.updateMany({ where: { key }, data: { value } });
|
||||
}
|
||||
@@ -203,31 +209,6 @@ export async function updateScopedVariables(code: string, formData: FormData) {
|
||||
redirect(`/policies/${encodeURIComponent(code)}/edit`);
|
||||
}
|
||||
|
||||
/* ── Schutzbedarf / TISAX-Level (Delta-Update) ── */
|
||||
|
||||
/** Globaler TISAX-Level: AL2 (very-high aus) / AL3 (very-high an); HIGH bleibt stets an. */
|
||||
export async function setGlobalTisaxLevel(formData: FormData) {
|
||||
const { session, db } = await guard();
|
||||
const level = String(formData.get("level")) === "AL3" ? "AL3" : "AL2";
|
||||
await db.policyVariable.updateMany({ where: { key: "FLAG_VERY_HIGH_PROTECTION" }, data: { value: level === "AL3" ? "true" : "false" } });
|
||||
await db.policyVariable.updateMany({ where: { key: "FLAG_HIGH_PROTECTION" }, data: { value: "true" } });
|
||||
await writeAuditLog({ tenantId: session.user.tenantId, actorId: session.user.id, action: "update", entity: "tisax_level", after: { level } });
|
||||
revalidatePath("/policies", "layout");
|
||||
}
|
||||
|
||||
/** Schutzbedarf-Override je Richtlinie: "" = global, "AL2", "AL3". */
|
||||
export async function setProtectionOverride(code: string, formData: FormData) {
|
||||
const { session, db } = await guard();
|
||||
const raw = String(formData.get("override") ?? "");
|
||||
const override = raw === "AL2" || raw === "AL3" ? raw : null;
|
||||
const doc = await db.policyDocument.findFirst({ where: { code } });
|
||||
if (!doc) throw new Error("Dokument nicht gefunden");
|
||||
await db.policyDocument.update({ where: { id: doc.id }, data: { protectionOverride: override } });
|
||||
await writeAuditLog({ tenantId: session.user.tenantId, actorId: session.user.id, action: "update", entity: "policy_document", entityId: doc.id, after: { protectionOverride: override } });
|
||||
revalidatePath("/policies", "layout");
|
||||
redirect(`/policies/${encodeURIComponent(code)}/edit`);
|
||||
}
|
||||
|
||||
/* ── Freigabe-Workflow (Vier-Augen, §8) ── */
|
||||
|
||||
export async function submitForApproval(code: string) {
|
||||
|
||||
Reference in New Issue
Block a user