Basis: Certvia dev@a48c5fb als Fundament für Craftvia
CI / build-and-check (push) Canceled after 0s
CI / audit (push) Canceled after 0s
CI / sbom (push) Canceled after 0s

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:
2026-09-14 11:05:39 +02:00
co-authored by Claude Opus 5
commit c8e6f30a27
720 changed files with 140143 additions and 0 deletions
+217
View File
@@ -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",
};