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>
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
// Generator (Story A2-2): parst die C1-Scoping-Tabelle (Fachcontent) in die
|
|
// maschinenlesbare Scope-Datengrundlage `seed/scoping/c1-scope.json`.
|
|
// Lauf: npx tsx scripts/build-c1-scope.ts
|
|
//
|
|
// Spalten der C1-Tabelle: Control | Anforderungs-ID | Typ | AL2 | AL3 | Prüfziel | Scope-Bedingung(Flag)
|
|
// `condition` wird normalisiert: exaktes Feature-Flag (FLAG_*) → Flag-Name, sonst null
|
|
// ("immer im Scope" bzw. "Prüfziel … aktiv" werden allein über das Prüfziel gegatet).
|
|
|
|
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
|
|
const SRC = resolve("docs/wizard-uebergabe/02_Fachcontent_C1-C9/C1_Scoping-AL-Pruefziel.md");
|
|
const OUT = resolve("seed/scoping/c1-scope.json");
|
|
|
|
const PRUEFZIEL: Record<string, string> = {
|
|
Informationssicherheit: "informationssicherheit",
|
|
Prototypenschutz: "prototypenschutz",
|
|
Datenschutz: "datenschutz",
|
|
};
|
|
|
|
const FLAG_RE = /^FLAG_[A-Z_]+$/;
|
|
|
|
interface C1Row {
|
|
id: string;
|
|
control: string;
|
|
type: "MUSS" | "SOLL" | "HOCH" | "SEHR HOCH";
|
|
al2: boolean;
|
|
al3: boolean;
|
|
pruefziel: string;
|
|
condition: string | null;
|
|
}
|
|
|
|
const rows: C1Row[] = [];
|
|
for (const line of readFileSync(SRC, "utf8").split("\n")) {
|
|
if (!line.startsWith("| ")) continue;
|
|
const cells = line.split("|").map((c) => c.trim());
|
|
// cells[0] = "" (vor dem ersten |); Nutzdaten ab cells[1]
|
|
const [, control, id, type, al2, al3, pruefzielText, condRaw] = cells;
|
|
if (!id || id === "Anforderungs-ID" || control.startsWith("---")) continue; // Header/Separator
|
|
const pruefziel = PRUEFZIEL[pruefzielText];
|
|
if (!pruefziel) continue; // keine gültige Datenzeile
|
|
const condClean = (condRaw ?? "").replace(/`/g, "").trim();
|
|
const condition = FLAG_RE.test(condClean) ? condClean : null;
|
|
rows.push({
|
|
id,
|
|
control,
|
|
type: type as C1Row["type"],
|
|
al2: al2 === "Ja",
|
|
al3: al3 === "Ja",
|
|
pruefziel,
|
|
condition,
|
|
});
|
|
}
|
|
|
|
mkdirSync(dirname(OUT), { recursive: true });
|
|
writeFileSync(OUT, JSON.stringify(rows, null, 2) + "\n");
|
|
|
|
// Kurzstatistik zur Kontrolle
|
|
const by = (f: (r: C1Row) => string) => rows.reduce<Record<string, number>>((a, r) => ((a[f(r)] = (a[f(r)] ?? 0) + 1), a), {});
|
|
console.log(`✓ ${rows.length} Anforderungen → seed/scoping/c1-scope.json`);
|
|
console.log(" Prüfziele:", JSON.stringify(by((r) => r.pruefziel)));
|
|
console.log(" Typen:", JSON.stringify(by((r) => r.type)));
|
|
console.log(" Bedingungen:", JSON.stringify(by((r) => r.condition ?? "(immer/Prüfziel)")));
|