Basis: Certvia dev@a48c5fb als Fundament für Craftvia
Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
import c5 from "../../seed/scoping/c5-controls.json";
|
||||
|
||||
/**
|
||||
* Reifegrad-Engine (Story A7-2) — regelbasierte, nachvollziehbare Herleitung eines
|
||||
* Reifegrad-Vorschlags 0–3 je Control aus dem Belegstatus (C5 §2), der Zielreifegrad
|
||||
* (C5 §3) und die „offenen Punkte" (C5 §4). Reine, seiteneffektfreie Logik; die
|
||||
* Belegstände werden vom Aufrufer aus Richtlinien-/Verfahrensdokumenten, Inventar und
|
||||
* Risikoregister abgeleitet. Der Vorschlag ist nicht bindend — die Bestätigung/
|
||||
* Überschreibung durch den Bearbeiter ist Pflicht (persistiert als ControlAssessment).
|
||||
*
|
||||
* Grundlage: VDA-ISA-Reifegradmodell 0–3, Fachcontent C5. Belegtabelle je Control:
|
||||
* `seed/scoping/c5-controls.json` (Generierung: scripts/build-c5-controls.ts).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Neutrale, framework-UNABHÄNGIGE Control-Spezifikation (Belegbasis, Feindesign §1/§2):
|
||||
* welche Richtlinie/Verfahren zuständig sind und ob Asset-/Risiko-Verknüpfung gefordert
|
||||
* ist. Eine Tatsache über die Organisation, keine Frage der Norm — daher von TISAX (C5)
|
||||
* UND ISO (mapping-iso) befüllt und von der GETEILTEN Belegauflösung (loadEvidenceResolver)
|
||||
* konsumiert. `loadEvidenceResolver` darf `ControlSpec` NICHT um ein Framework erweitern.
|
||||
*/
|
||||
export interface ControlSpec {
|
||||
control: string;
|
||||
title: string;
|
||||
/** Zuständige Richtlinie(n): L00 | R01..R14 (TISAX) bzw. R.. (ISO). Leer = keine dedizierte. */
|
||||
policy: string[];
|
||||
/** Geforderte Verfahren: VA-xx. Leer = operative Steuerung in der Richtlinie verankert. */
|
||||
verfahren: string[];
|
||||
/** Control setzt auf Inventar auf (Asset-Verknüpfung gefordert). */
|
||||
needsAsset: boolean;
|
||||
/** Control setzt auf Risikoregister auf (Risiko-Verknüpfung gefordert). */
|
||||
needsRisk: boolean;
|
||||
}
|
||||
|
||||
/** TISAX-Belegtabelle (C5 §1) = neutrale ControlSpec + Standard-Zielreifegrad (VDA-ISA-Zusatz). */
|
||||
export interface C5ControlSpec extends ControlSpec {
|
||||
/** Standard-Zielreifegrad laut Tabelle (informativ; effektiv aus Scope, s. targetMaturity). */
|
||||
target: number;
|
||||
}
|
||||
|
||||
/** Vollständige C5-Belegtabelle (45 IS-Controls). */
|
||||
export const C5_CONTROLS = c5 as C5ControlSpec[];
|
||||
const C5_BY_ID = new Map(C5_CONTROLS.map((c) => [c.control, c]));
|
||||
|
||||
/** Generischer Fallback-Spec für Controls ohne §5-Zeile (Proto 8.x / Datenschutz 9.x, C5 §6). */
|
||||
export function specForControl(control: string): C5ControlSpec {
|
||||
return (
|
||||
C5_BY_ID.get(control) ?? {
|
||||
control,
|
||||
title: control,
|
||||
policy: [],
|
||||
verfahren: [],
|
||||
needsAsset: false,
|
||||
needsRisk: false,
|
||||
target: 2, // §6-Gruppen: Standard-Zielreifegrad 2 (Ausnahmen HOCH → 3, s. targetMaturity).
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Validierungsstatus eines Belegs (C5 §1): fehlt → verknüpft (unvalidiert) → validiert. */
|
||||
export type EvidenceStatus = "fehlt" | "verknuepft" | "validiert";
|
||||
|
||||
/** Aus den Fachmodulen abgeleiteter Ist-Belegstand eines Controls. */
|
||||
export interface ControlEvidence {
|
||||
/** Status der (aggregierten) zuständigen Richtlinie(n). */
|
||||
policy: EvidenceStatus;
|
||||
/** Status der geforderten Verfahren (aggregiert, „schwächster" gewinnt). */
|
||||
verfahren: EvidenceStatus;
|
||||
/** Asset-Verknüpfung vorhanden (nur relevant, wenn spec.needsAsset). */
|
||||
assetLinked: boolean;
|
||||
/** Risiko-Verknüpfung vorhanden (nur relevant, wenn spec.needsRisk). */
|
||||
riskLinked: boolean;
|
||||
/**
|
||||
* Nur für Controls OHNE dediziertes Verfahren (C5 §2, Sonderfall): validierte,
|
||||
* dokumentierte Umsetzungsregelung/Konfiguration (N-basisch), die für Grad 2 an die
|
||||
* Stelle von (V) tritt. Für Controls mit Verfahren irrelevant.
|
||||
*/
|
||||
implementationRule?: boolean;
|
||||
/**
|
||||
* Operativer Wirksamkeitsnachweis (N) validiert UND aktuell (Aktualitätsregel ≤12 M.,
|
||||
* C5 §1) — wiederkehrender Review/Audit/Test. Grad-3-Trigger. Frühe Onboarding-Phase
|
||||
* i. d. R. false → Deckelung auf Grad 2.
|
||||
*/
|
||||
operationalProof: boolean;
|
||||
/** Nachweis widerspricht Richtlinie / offene Findings → Deckelung auf max. 1 (C5 §2). */
|
||||
contradiction?: boolean;
|
||||
/** Control enthält nur SOLL (MUSS definitionsgemäß erfüllt) → Bewertung startet bei 1 (C5 §2). */
|
||||
onlySoll?: boolean;
|
||||
}
|
||||
|
||||
export type MaturityRule = "R0" | "R1a" | "R1b" | "R1c" | "R2" | "R3" | "CAP";
|
||||
|
||||
export interface MaturitySuggestion {
|
||||
value: 0 | 1 | 2 | 3;
|
||||
rule: MaturityRule;
|
||||
/** Kurzbegründung (nachvollziehbar, an Belege gekoppelt). */
|
||||
reason: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reifegrad-Vorschlag nach C5 §2 (generische Belegkonstellations-Tabelle) inkl.
|
||||
* Sonderfälle: Controls ohne Verfahren (V-Slot durch validierte Umsetzungsregelung
|
||||
* ersetzt), nur-SOLL-Controls (Start bei 1) und Deckelung bei Widerspruch/Findings.
|
||||
*/
|
||||
export function suggestMaturity(spec: C5ControlSpec, ev: ControlEvidence): MaturitySuggestion {
|
||||
// Deckelung: Nachweis widerspricht Richtlinie / offene Findings → max. Grad 1 (C5 §2).
|
||||
if (ev.contradiction) {
|
||||
return { value: 1, rule: "CAP", reason: "Nachweis widerspricht Richtlinie bzw. offene Findings — Vorschlag gedeckelt (max. 1)." };
|
||||
}
|
||||
|
||||
const requiresProcedure = spec.verfahren.length > 0;
|
||||
// Bei Controls ohne dediziertes Verfahren tritt für Grad 2 eine validierte, dokumentierte
|
||||
// Umsetzungsregelung (implementationRule) an die Stelle von (V); der wiederkehrende
|
||||
// Wirksamkeitsnachweis (operationalProof) bleibt eigenständiger Grad-3-Trigger.
|
||||
const procedureOk = requiresProcedure ? ev.verfahren === "validiert" : ev.implementationRule === true;
|
||||
const assetOk = !spec.needsAsset || ev.assetLinked;
|
||||
const riskOk = !spec.needsRisk || ev.riskLinked;
|
||||
const policyValidated = ev.policy === "validiert";
|
||||
const policyLinked = ev.policy !== "fehlt";
|
||||
|
||||
// R3: R2 erfüllt UND mindestens ein validierter, aktueller operativer Wirksamkeitsnachweis.
|
||||
if (policyValidated && procedureOk && assetOk && riskOk && ev.operationalProof) {
|
||||
return { value: 3, rule: "R3", reason: "Richtlinie und Verfahren validiert, Verknüpfungen vorhanden und aktueller Wirksamkeitsnachweis." };
|
||||
}
|
||||
// R2: Richtlinie validiert UND alle Verfahren validiert UND (falls einschlägig) Asset-/Risiko-Verknüpfung.
|
||||
if (policyValidated && procedureOk && assetOk && riskOk) {
|
||||
return { value: 2, rule: "R2", reason: "Vorgehen dokumentiert und gesteuert; Richtlinie und Verfahren validiert." };
|
||||
}
|
||||
// R1b: Richtlinie validiert, aber ein gefordertes Verfahren fehlt/unvalidiert (oder Verknüpfung fehlt).
|
||||
if (policyValidated) {
|
||||
return { value: 1, rule: "R1b", reason: "Richtlinie validiert, aber gefordertes Verfahren bzw. Verknüpfung fehlt oder ist unvalidiert." };
|
||||
}
|
||||
// R1a: zuständige Richtlinie verknüpft, aber nicht validiert.
|
||||
if (policyLinked) {
|
||||
return { value: 1, rule: "R1a", reason: "Regelungsabsicht erkennbar (Richtlinie verknüpft), aber nicht validiert/gelebt." };
|
||||
}
|
||||
// R1c: nur operativer Nachweis/Umsetzung ohne validierte Richtlinie.
|
||||
if (ev.operationalProof || ev.implementationRule || ev.verfahren !== "fehlt") {
|
||||
return { value: 1, rule: "R1c", reason: "Tätigkeit wird durchgeführt, aber nicht dokumentiert gesteuert (keine validierte Richtlinie)." };
|
||||
}
|
||||
// nur-SOLL: MUSS definitionsgemäß erfüllt → Bewertung startet bei 1.
|
||||
if (ev.onlySoll) {
|
||||
return { value: 1, rule: "R1c", reason: "Nur-SOLL-Control: MUSS-Ebene definitionsgemäß erfüllt (Start bei Grad 1)." };
|
||||
}
|
||||
// R0: keine Belege bzw. nur unvalidierte Fragmente ohne zuständige Richtlinie.
|
||||
return { value: 0, rule: "R0", reason: "Kein belastbarer Nachweis einer geregelten Vorgehensweise." };
|
||||
}
|
||||
|
||||
export interface ScopeForTarget {
|
||||
/** Assessment-Level aus TenantSettings (A2-1): AL2 oder AL3. */
|
||||
level: "AL2" | "AL3";
|
||||
flags: Record<string, boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zielreifegrad je Control (C5 §3): Standard 3; Absenkung auf 2 nur bei reinem MUSS-/AL2-Scope
|
||||
* (kein SOLL). HOCH/SEHR-HOCH-Schutzbedarf erzwingt Grad 3 (keine Absenkung).
|
||||
*/
|
||||
export function targetMaturity(scope: ScopeForTarget): 2 | 3 {
|
||||
const high = scope.flags.FLAG_HIGH_PROTECTION || scope.flags.FLAG_VERY_HIGH_PROTECTION;
|
||||
if (scope.level === "AL3" || high || scope.flags.FLAG_INCLUDE_SHOULD) return 3;
|
||||
// reiner AL2-/MUSS-Scope (kein SOLL, kein erhöhter Schutzbedarf): Absenkung auf Grad 2.
|
||||
return 2;
|
||||
}
|
||||
|
||||
/** Ein offener Punkt (Gap) nach C5 §4 mit fehlender Belegklasse und empfohlener Maßnahme. */
|
||||
export interface OpenPoint {
|
||||
control: string;
|
||||
kind: "reifegradluecke" | "richtlinie" | "verfahren" | "nachweis" | "verknuepfung" | "widerspruch";
|
||||
actual: number;
|
||||
target: number;
|
||||
/** Fehlende Belegklasse / Kurzbeschreibung. */
|
||||
missing: string;
|
||||
/** Empfohlene Maßnahme (Aufgabentitel). */
|
||||
action: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Leitet die offenen Punkte (Gap → Aufgabe) nach C5 §4 ab: Reifegradlücke, fehlender
|
||||
* Pflichtbeleg (Richtlinie/Verfahren), fehlender/veralteter Nachweis bei Zielgrad 3,
|
||||
* fehlende Asset-/Risiko-Verknüpfung und Widerspruch/Findings.
|
||||
*/
|
||||
export function openPoints(spec: C5ControlSpec, ev: ControlEvidence, suggestion: MaturitySuggestion, target: number): OpenPoint[] {
|
||||
const out: OpenPoint[] = [];
|
||||
const base = { control: spec.control, actual: suggestion.value, target };
|
||||
|
||||
if (ev.contradiction) {
|
||||
out.push({ ...base, kind: "widerspruch", missing: "Nachweis mit Findings/Widerspruch", action: `Abweichung in Control ${spec.control} beheben` });
|
||||
}
|
||||
if (ev.policy !== "validiert" && spec.policy.length > 0) {
|
||||
out.push({ ...base, kind: "richtlinie", missing: `Richtlinie ${spec.policy.join("/")}`, action: `Richtlinie ${spec.policy.join("/")} erstellen/validieren (Control ${spec.control})` });
|
||||
}
|
||||
if (spec.verfahren.length > 0 && ev.verfahren !== "validiert") {
|
||||
out.push({ ...base, kind: "verfahren", missing: `Verfahren ${spec.verfahren.join("/")}`, action: `Verfahren ${spec.verfahren.join("/")} erstellen/validieren (Control ${spec.control})` });
|
||||
}
|
||||
if (spec.needsAsset && !ev.assetLinked) {
|
||||
out.push({ ...base, kind: "verknuepfung", missing: "Asset-Verknüpfung", action: `Asset-/Inventarverknüpfung für Control ${spec.control} herstellen` });
|
||||
}
|
||||
if (spec.needsRisk && !ev.riskLinked) {
|
||||
out.push({ ...base, kind: "verknuepfung", missing: "Risiko-Verknüpfung", action: `Risikoverknüpfung für Control ${spec.control} herstellen` });
|
||||
}
|
||||
if (target >= 3 && !ev.operationalProof && !ev.contradiction) {
|
||||
out.push({ ...base, kind: "nachweis", missing: "operativer Wirksamkeitsnachweis (aktuell)", action: `Wirksamkeitsnachweis (Review/Audit/Test) für Control ${spec.control} führen` });
|
||||
}
|
||||
// Reifegradlücke zuletzt, nur wenn nicht schon durch einen konkreten Pflichtbeleg abgedeckt.
|
||||
if (suggestion.value < target && out.length === 0) {
|
||||
out.push({ ...base, kind: "reifegradluecke", missing: `Reifegrad ${suggestion.value} < Ziel ${target}`, action: `Belege/Umsetzung für Control ${spec.control} bis Zielgrad ${target} anheben` });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export const MATURITY_LABEL: Record<0 | 1 | 2 | 3, string> = {
|
||||
0: "Grad 0 — nicht geregelt",
|
||||
1: "Grad 1 — informell",
|
||||
2: "Grad 2 — dokumentiert/gesteuert",
|
||||
3: "Grad 3 — wirksam/integriert",
|
||||
};
|
||||
Reference in New Issue
Block a user