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,67 @@
|
||||
// Generator (Story A7-2): parst die C5-Control-Belegtabelle (Fachcontent §5, IS-Controls)
|
||||
// in die maschinenlesbare Reifegrad-Datengrundlage `seed/scoping/c5-controls.json`.
|
||||
// Lauf: npx tsx scripts/build-c5-controls.ts
|
||||
//
|
||||
// Quelle §5-Zeilen: | **Control** Titel | P / V / N (mit (**A**)/(**R**)) | R2-Bed. | R3-Bed. | Ziel |
|
||||
// - policy (P): L00 | R01..R14 (zuständige Richtlinie[n], „—" = keine)
|
||||
// - verfahren (V): VA-01..VA-19 (geforderte Verfahren, „—" = in Richtlinie verankert)
|
||||
// - needsAsset/needsRisk: Belegzelle enthält (**A**) bzw. (**R**)
|
||||
// - target: Standard-Zielreifegrad der Tabelle (informativ; effektiv wird er zur Laufzeit
|
||||
// aus dem Scope nach C5 §3 abgeleitet).
|
||||
// §6 (Proto 8.x / Datenschutz 9.x) ist gruppenbasiert und wird NICHT je Control abgebildet;
|
||||
// dafür greift zur Laufzeit ein generischer Fallback-Spec.
|
||||
|
||||
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
|
||||
const SRC = resolve("docs/wizard-uebergabe/02_Fachcontent_C1-C9/C5_Reifegradlogik.md");
|
||||
const OUT = resolve("seed/scoping/c5-controls.json");
|
||||
|
||||
export interface C5ControlSpec {
|
||||
control: string;
|
||||
title: string;
|
||||
policy: string[];
|
||||
verfahren: string[];
|
||||
needsAsset: boolean;
|
||||
needsRisk: boolean;
|
||||
target: number;
|
||||
}
|
||||
|
||||
const CONTROL_RE = /^\|\s*\*\*([0-9]+\.[0-9]+\.[0-9]+(?:-[A-Z]+)?)\*\*\s*([^|]*?)\s*\|(.+)$/;
|
||||
|
||||
function codes(cell: string, re: RegExp): string[] {
|
||||
const out = new Set<string>();
|
||||
for (const m of cell.matchAll(re)) out.add(m[0]);
|
||||
return [...out];
|
||||
}
|
||||
|
||||
function parse(md: string): C5ControlSpec[] {
|
||||
const rows: C5ControlSpec[] = [];
|
||||
for (const line of md.split("\n")) {
|
||||
const m = CONTROL_RE.exec(line.trim());
|
||||
if (!m) continue;
|
||||
const [, control, title, rest] = m;
|
||||
// rest = "Belege | R2 | R3 | Ziel |"
|
||||
const cells = rest.split("|").map((c) => c.trim());
|
||||
const belege = cells[0] ?? "";
|
||||
const zielCell = cells[3] ?? cells[cells.length - 2] ?? "";
|
||||
const [pPart = "", vPart = ""] = belege.split(" / ");
|
||||
const target = Number.parseInt(zielCell.replace(/[^0-9]/g, "").charAt(0) || "3", 10);
|
||||
rows.push({
|
||||
control,
|
||||
title: title.trim(),
|
||||
policy: codes(pPart, /L00|R[0-9]{2}/g),
|
||||
verfahren: codes(vPart, /VA-[0-9]{2}/g),
|
||||
needsAsset: /\*\*A\*\*/.test(belege),
|
||||
needsRisk: /\*\*R\*\*/.test(belege),
|
||||
target: Number.isFinite(target) ? target : 3,
|
||||
});
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
const specs = parse(readFileSync(SRC, "utf8"));
|
||||
if (specs.length < 40) throw new Error(`C5 §5 unerwartet wenige Controls geparst: ${specs.length}`);
|
||||
mkdirSync(dirname(OUT), { recursive: true });
|
||||
writeFileSync(OUT, JSON.stringify(specs, null, 2) + "\n");
|
||||
console.log(`c5-controls.json geschrieben: ${specs.length} Controls`);
|
||||
Reference in New Issue
Block a user