refactor(admin): split controls, training, control-provenance, iace/verification pages
Each page.tsx exceeded the 500-LOC hard cap. Extracted components and hooks into colocated _components/ and _hooks/ directories; page.tsx is now a thin orchestrator. - controls/page.tsx: 944 → 180 LOC; extracted ControlCard, AddControlForm, LoadingSkeleton, TransitionErrorBanner, StatsCards, FilterBar, RAGPanel into _components/ and useControlsData, useRAGSuggestions into _hooks/; types into _types.ts - training/page.tsx: 780 → 288 LOC; extracted ContentTab (inline content generator tab) into _components/ContentTab.tsx - control-provenance/page.tsx: 739 → 122 LOC; extracted MarkdownRenderer, UsageBadge, PermBadge, LicenseMatrix, SourceRegistry into _components/; PROVENANCE_SECTIONS static data into _data/provenance-sections.ts - iace/[projectId]/verification/page.tsx: 673 → 196 LOC; extracted StatusBadge, VerificationForm, CompleteModal, SuggestEvidenceModal, VerificationTable into _components/ Zero behavior changes; logic relocated verbatim. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { UsageBadge } from './UsageBadge'
|
||||
|
||||
interface LicenseInfo {
|
||||
license_id: string
|
||||
name: string
|
||||
terms_url: string | null
|
||||
commercial_use: string
|
||||
ai_training_restriction: string | null
|
||||
tdm_allowed_under_44b: string | null
|
||||
deletion_required: boolean
|
||||
notes: string | null
|
||||
}
|
||||
|
||||
export function LicenseMatrix({ licenses, loading }: { licenses: LicenseInfo[]; loading: boolean }) {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-4">Lizenz-Matrix</h2>
|
||||
<p className="text-sm text-gray-600 mb-4">Uebersicht aller Lizenzen mit ihren erlaubten Nutzungsarten.</p>
|
||||
{loading ? (
|
||||
<div className="animate-pulse h-32 bg-gray-100 rounded" />
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-gray-50">
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">Lizenz</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">Kommerziell</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">AI-Training</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">TDM (§44b)</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">Loeschpflicht</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{licenses.map(lic => (
|
||||
<tr key={lic.license_id} className="hover:bg-gray-50">
|
||||
<td className="px-3 py-2 border-b">
|
||||
<div className="font-medium text-gray-900">{lic.license_id}</div>
|
||||
<div className="text-xs text-gray-500">{lic.name}</div>
|
||||
</td>
|
||||
<td className="px-3 py-2 border-b"><UsageBadge value={lic.commercial_use} /></td>
|
||||
<td className="px-3 py-2 border-b"><UsageBadge value={lic.ai_training_restriction || 'n/a'} /></td>
|
||||
<td className="px-3 py-2 border-b"><UsageBadge value={lic.tdm_allowed_under_44b || 'unclear'} /></td>
|
||||
<td className="px-3 py-2 border-b">
|
||||
{lic.deletion_required
|
||||
? <span className="text-red-600 text-xs font-medium">Ja</span>
|
||||
: <span className="text-green-600 text-xs font-medium">Nein</span>}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
export function MarkdownRenderer({ content }: { content: string }) {
|
||||
let html = content
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
|
||||
html = html.replace(
|
||||
/^```[\w]*\n([\s\S]*?)^```$/gm,
|
||||
(_m, code: string) => `<pre class="bg-gray-50 border rounded p-3 my-3 text-xs font-mono overflow-x-auto whitespace-pre">${code.trimEnd()}</pre>`
|
||||
)
|
||||
|
||||
html = html.replace(
|
||||
/^(\|.+\|)\n(\|[\s:|-]+\|)\n((?:\|.+\|\n?)*)/gm,
|
||||
(_m, header: string, _sep: string, body: string) => {
|
||||
const ths = header.split('|').filter((c: string) => c.trim()).map((c: string) =>
|
||||
`<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase border-b">${c.trim()}</th>`
|
||||
).join('')
|
||||
const rows = body.trim().split('\n').map((row: string) => {
|
||||
const tds = row.split('|').filter((c: string) => c.trim()).map((c: string) =>
|
||||
`<td class="px-3 py-2 text-sm text-gray-700 border-b border-gray-100">${c.trim()}</td>`
|
||||
).join('')
|
||||
return `<tr>${tds}</tr>`
|
||||
}).join('')
|
||||
return `<table class="w-full border-collapse my-3 text-sm"><thead><tr>${ths}</tr></thead><tbody>${rows}</tbody></table>`
|
||||
}
|
||||
)
|
||||
|
||||
html = html.replace(/^### (.+)$/gm, '<h4 class="text-sm font-semibold text-gray-800 mt-4 mb-2">$1</h4>')
|
||||
html = html.replace(/^## (.+)$/gm, '<h3 class="text-base font-semibold text-gray-900 mt-5 mb-2">$1</h3>')
|
||||
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||||
html = html.replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 py-0.5 rounded text-xs font-mono">$1</code>')
|
||||
html = html.replace(/^- (.+)$/gm, '<li class="ml-4 text-sm text-gray-700 list-disc">$1</li>')
|
||||
html = html.replace(/((?:<li[^>]*>.*<\/li>\n?)+)/g, '<ul class="my-2 space-y-1">$1</ul>')
|
||||
html = html.replace(/^(\d+)\. (.+)$/gm, '<li class="ml-4 text-sm text-gray-700 list-decimal">$2</li>')
|
||||
html = html.replace(/^(?!<[hultdp]|$)(.+)$/gm, '<p class="text-sm text-gray-700 my-2">$1</p>')
|
||||
|
||||
return <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ExternalLink } from 'lucide-react'
|
||||
import { PermBadge } from './UsageBadge'
|
||||
|
||||
interface SourceInfo {
|
||||
source_id: string
|
||||
title: string
|
||||
publisher: string
|
||||
url: string | null
|
||||
version_label: string | null
|
||||
language: string
|
||||
license_id: string
|
||||
license_name: string
|
||||
commercial_use: string
|
||||
allowed_analysis: boolean
|
||||
allowed_store_excerpt: boolean
|
||||
allowed_ship_embeddings: boolean
|
||||
allowed_ship_in_product: boolean
|
||||
vault_retention_days: number
|
||||
vault_access_tier: string
|
||||
}
|
||||
|
||||
export function SourceRegistry({ sources, loading }: { sources: SourceInfo[]; loading: boolean }) {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-4">Quellenregister</h2>
|
||||
<p className="text-sm text-gray-600 mb-4">Alle registrierten Quellen mit ihren Berechtigungen.</p>
|
||||
{loading ? (
|
||||
<div className="animate-pulse h-32 bg-gray-100 rounded" />
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{sources.map(src => (
|
||||
<div key={src.source_id} className="bg-white border border-gray-200 rounded-lg p-4">
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">{src.title}</h3>
|
||||
<p className="text-xs text-gray-500">{src.publisher} — {src.license_name}</p>
|
||||
</div>
|
||||
{src.url && (
|
||||
<a href={src.url} target="_blank" rel="noopener noreferrer" className="flex items-center gap-1 text-xs text-blue-600 hover:text-blue-800">
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
Quelle
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3 mt-2">
|
||||
<PermBadge label="Analyse" allowed={src.allowed_analysis} />
|
||||
<PermBadge label="Excerpt" allowed={src.allowed_store_excerpt} />
|
||||
<PermBadge label="Embeddings" allowed={src.allowed_ship_embeddings} />
|
||||
<PermBadge label="Produkt" allowed={src.allowed_ship_in_product} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { CheckCircle2, Lock } from 'lucide-react'
|
||||
|
||||
const USAGE_CONFIG: Record<string, { bg: string; label: string }> = {
|
||||
allowed: { bg: 'bg-green-100 text-green-800', label: 'Erlaubt' },
|
||||
restricted: { bg: 'bg-yellow-100 text-yellow-800', label: 'Eingeschraenkt' },
|
||||
prohibited: { bg: 'bg-red-100 text-red-800', label: 'Verboten' },
|
||||
unclear: { bg: 'bg-gray-100 text-gray-600', label: 'Unklar' },
|
||||
yes: { bg: 'bg-green-100 text-green-800', label: 'Ja' },
|
||||
no: { bg: 'bg-red-100 text-red-800', label: 'Nein' },
|
||||
'n/a': { bg: 'bg-gray-100 text-gray-400', label: 'k.A.' },
|
||||
}
|
||||
|
||||
export function UsageBadge({ value }: { value: string }) {
|
||||
const c = USAGE_CONFIG[value] || USAGE_CONFIG.unclear
|
||||
return <span className={`inline-flex px-1.5 py-0.5 rounded text-xs font-medium ${c.bg}`}>{c.label}</span>
|
||||
}
|
||||
|
||||
export function PermBadge({ label, allowed }: { label: string; allowed: boolean }) {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
{allowed ? <CheckCircle2 className="w-3 h-3 text-green-500" /> : <Lock className="w-3 h-3 text-red-400" />}
|
||||
<span className={`text-xs ${allowed ? 'text-green-700' : 'text-red-500'}`}>{label}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
export interface ProvenanceSection {
|
||||
id: string
|
||||
title: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export const PROVENANCE_SECTIONS: ProvenanceSection[] = [
|
||||
{
|
||||
id: 'methodology',
|
||||
title: 'Methodik der Control-Erstellung',
|
||||
content: `## Unabhaengige Formulierung
|
||||
|
||||
Alle Controls in der Canonical Control Library wurden **eigenstaendig formuliert** und folgen einer
|
||||
**unabhaengigen Taxonomie**. Es werden keine proprietaeren Bezeichner, Nummern oder Strukturen
|
||||
aus geschuetzten Quellen uebernommen.
|
||||
|
||||
### Dreistufiger Prozess
|
||||
|
||||
1. **Offene Recherche** — Identifikation von Security-Anforderungen aus oeffentlichen, frei zugaenglichen
|
||||
Frameworks (OWASP, NIST, ENISA). Jede Anforderung wird aus mindestens 2 unabhaengigen offenen Quellen belegt.
|
||||
|
||||
2. **Eigenstaendige Formulierung** — Jedes Control wird mit eigener Sprache, eigener Struktur und eigener
|
||||
Taxonomie (z.B. AUTH-001, NET-001) verfasst. Kein Copy-Paste, keine Paraphrase geschuetzter Texte.
|
||||
|
||||
3. **Too-Close-Pruefung** — Automatisierte Aehnlichkeitspruefung gegen Quelltexte mit 5 Metriken
|
||||
(Token Overlap, N-Gram Jaccard, Embedding Cosine, LCS Ratio, Exact-Phrase). Nur Controls mit
|
||||
Status PASS oder WARN (+ Human Review) werden freigegeben.
|
||||
|
||||
### Rechtliche Grundlage
|
||||
|
||||
- **UrhG §44b** — Text & Data Mining erlaubt fuer Analyse; Kopien werden danach geloescht
|
||||
- **UrhG §23** — Hinreichender Abstand zum Originalwerk durch eigene Formulierung
|
||||
- **BSI Nutzungsbedingungen** — Kommerzielle Nutzung nur mit Zustimmung; wir nutzen BSI-Dokumente
|
||||
ausschliesslich als Analysegrundlage, nicht im Produkt`,
|
||||
},
|
||||
{
|
||||
id: 'filters',
|
||||
title: 'Filter in der Control Library',
|
||||
content: `## Dropdown-Filter
|
||||
|
||||
Die Control Library bietet 7 Filter-Dropdowns, um die ueber 3.000 Controls effizient zu durchsuchen:
|
||||
|
||||
### Schweregrad (Severity)
|
||||
|
||||
| Stufe | Farbe | Bedeutung |
|
||||
|-------|-------|-----------|
|
||||
| **Kritisch** | Rot | Sicherheitskritische Controls — Verstoesse fuehren zu schwerwiegenden Risiken |
|
||||
| **Hoch** | Orange | Wichtige Controls — sollten zeitnah umgesetzt werden |
|
||||
| **Mittel** | Gelb | Standardmaessige Controls — empfohlene Umsetzung |
|
||||
| **Niedrig** | Gruen | Nice-to-have Controls — zusaetzliche Haertung |
|
||||
|
||||
### Domain
|
||||
|
||||
Das Praefix der Control-ID (z.B. \`AUTH-001\`, \`SEC-042\`). Kennzeichnet den thematischen Bereich.
|
||||
Die haeufigsten Domains:
|
||||
|
||||
| Domain | Anzahl | Thema |
|
||||
|--------|--------|-------|
|
||||
| SEC | ~700 | Allgemeine Sicherheit, Systemhaertung |
|
||||
| COMP | ~470 | Compliance, Regulierung, Nachweispflichten |
|
||||
| DATA | ~400 | Datenschutz, Datenklassifizierung, DSGVO |
|
||||
| AI | ~290 | KI-Regulierung (AI Act, Transparenz, Erklaerbarkeit) |
|
||||
| LOG | ~230 | Logging, Monitoring, SIEM |
|
||||
| AUTH | ~200 | Authentifizierung, Zugriffskontrolle |
|
||||
| NET | ~150 | Netzwerksicherheit, Transport, Firewall |
|
||||
| CRYP | ~90 | Kryptographie, Schluesselmanagement |
|
||||
| ACC | ~25 | Zugriffskontrolle (Access Control) |
|
||||
| INC | ~25 | Incident Response, Vorfallmanagement |
|
||||
|
||||
Zusaetzlich existieren spezialisierte Domains wie CRA, ARC (Architektur), API, PKI, SUP (Supply Chain) u.v.m.
|
||||
|
||||
### Status (Release State)
|
||||
|
||||
| Status | Bedeutung |
|
||||
|--------|-----------|
|
||||
| **Draft** | Entwurf — noch nicht freigegeben |
|
||||
| **Approved** | Freigegeben fuer Kunden |
|
||||
| **Review noetig** | Muss manuell geprueft werden |
|
||||
| **Zu aehnlich** | Too-Close-Check hat Warnung ausgeloest |
|
||||
| **Duplikat** | Wurde als Duplikat eines anderen Controls erkannt |
|
||||
|
||||
### Nachweis (Verification Method)
|
||||
|
||||
| Methode | Farbe | Beschreibung |
|
||||
|---------|-------|-------------|
|
||||
| **Code Review** | Blau | Nachweis durch Quellcode-Inspektion |
|
||||
| **Dokument** | Amber | Nachweis durch Richtlinien, Prozesse, Schulungen |
|
||||
| **Tool** | Teal | Nachweis durch automatisierte Scans/Monitoring |
|
||||
| **Hybrid** | Lila | Kombination aus mehreren Methoden |
|
||||
|
||||
### Kategorie
|
||||
|
||||
Thematische Einordnung (17 Kategorien). Kategorien sind **thematisch**, Domains **strukturell**.
|
||||
Ein AUTH-Control kann z.B. die Kategorie "Netzwerksicherheit" haben.
|
||||
|
||||
### Zielgruppe (Target Audience)
|
||||
|
||||
| Zielgruppe | Bedeutung |
|
||||
|------------|-----------|
|
||||
| **Unternehmen** | Fuer Endkunden/Firmen relevant |
|
||||
| **Behoerden** | Spezifisch fuer oeffentliche Verwaltung |
|
||||
| **Anbieter** | Fuer SaaS/Plattform-Anbieter |
|
||||
| **Alle** | Allgemein anwendbar |
|
||||
|
||||
### Dokumentenursprung (Source)
|
||||
|
||||
Filtert nach der Quelldokument-Herkunft des Controls. Zeigt alle Quellen sortiert nach
|
||||
Haeufigkeit. Die wichtigsten Quellen:
|
||||
|
||||
| Quelle | Typ |
|
||||
|--------|-----|
|
||||
| KI-Verordnung (EU) 2024/1689 | EU-Recht |
|
||||
| Cyber Resilience Act (EU) 2024/2847 | EU-Recht |
|
||||
| DSGVO (EU) 2016/679 | EU-Recht |
|
||||
| NIS2-Richtlinie (EU) 2022/2555 | EU-Recht |
|
||||
| NIST SP 800-53, CSF 2.0, SSDF | US-Standards |
|
||||
| OWASP Top 10, ASVS, SAMM | Open Source |
|
||||
| ENISA Guidelines | EU-Agentur |
|
||||
| CISA Secure by Design | US-Behoerde |
|
||||
| BDSG, TKG, GewO, HGB | Deutsche Gesetze |
|
||||
| EDPB Leitlinien | EU Datenschutz |`,
|
||||
},
|
||||
{
|
||||
id: 'badges',
|
||||
title: 'Badges & Lizenzregeln',
|
||||
content: `## Badges in der Control Library
|
||||
|
||||
Jedes Control zeigt mehrere farbige Badges:
|
||||
|
||||
### Lizenzregel-Badge (Rule 1 / 2 / 3)
|
||||
|
||||
Die Lizenzregel bestimmt, wie ein Control erstellt und genutzt werden darf:
|
||||
|
||||
| Badge | Farbe | Regel | Bedeutung |
|
||||
|-------|-------|-------|-----------|
|
||||
| **Free Use** | Gruen | Rule 1 | Quelle ist Public Domain oder EU-Recht — Originaltext darf gezeigt werden |
|
||||
| **Zitation** | Blau | Rule 2 | Quelle ist CC-BY oder aehnlich — Zitation + Quellenangabe erforderlich |
|
||||
| **Reformuliert** | Amber | Rule 3 | Quelle hat eingeschraenkte Lizenz — Control wurde eigenstaendig reformuliert, kein Originaltext |
|
||||
|
||||
### Processing-Path
|
||||
|
||||
| Pfad | Bedeutung |
|
||||
|------|-----------|
|
||||
| **structured** | Control wurde direkt aus strukturierten Daten (Tabellen, Listen) extrahiert |
|
||||
| **llm_reform** | Control wurde mit LLM eigenstaendig formuliert (bei Rule 3 zwingend) |
|
||||
|
||||
### Referenzen (Open Anchors)
|
||||
|
||||
Zeigt die Anzahl der verlinkten Open-Source-Referenzen (OWASP, NIST, ENISA etc.).
|
||||
Jedes freigegebene Control muss mindestens 1 Open Anchor haben.
|
||||
|
||||
### Weitere Badges
|
||||
|
||||
| Badge | Bedeutung |
|
||||
|-------|-----------|
|
||||
| Score | Risiko-Score (0-10) |
|
||||
| Severity-Badge | Schweregrad (Kritisch/Hoch/Mittel/Niedrig) |
|
||||
| State-Badge | Freigabestatus (Draft/Approved/etc.) |
|
||||
| Kategorie-Badge | Thematische Kategorie |
|
||||
| Zielgruppe-Badge | Enterprise/Behoerden/Anbieter/Alle |`,
|
||||
},
|
||||
{
|
||||
id: 'taxonomy',
|
||||
title: 'Unabhaengige Taxonomie',
|
||||
content: `## Eigenes Klassifikationssystem
|
||||
|
||||
Die Canonical Control Library verwendet ein **eigenes Domain-Schema**, das sich bewusst von
|
||||
proprietaeren Frameworks unterscheidet. Die Domains werden **automatisch** durch den
|
||||
Control Generator vergeben, basierend auf dem Inhalt der Quelldokumente.
|
||||
|
||||
### Top-10 Domains
|
||||
|
||||
| Domain | Anzahl | Thema | Hauptquellen |
|
||||
|--------|--------|-------|-------------|
|
||||
| SEC | ~700 | Allgemeine Sicherheit | CRA, NIS2, BSI, ENISA |
|
||||
| COMP | ~470 | Compliance & Regulierung | DSGVO, AI Act, Richtlinien |
|
||||
| DATA | ~400 | Datenschutz & Datenklassifizierung | DSGVO, BDSG, EDPB |
|
||||
| AI | ~290 | KI-Regulierung & Ethik | AI Act, HLEG, OECD |
|
||||
| LOG | ~230 | Logging & Monitoring | NIST, OWASP |
|
||||
| AUTH | ~200 | Authentifizierung & Session | NIST SP 800-63, OWASP |
|
||||
| NET | ~150 | Netzwerksicherheit | NIST, ENISA |
|
||||
| CRYP | ~90 | Kryptographie & Schluessel | NIST SP 800-57 |
|
||||
| ACC | ~25 | Zugriffskontrolle | OWASP ASVS |
|
||||
| INC | ~25 | Incident Response | NIS2, CRA |
|
||||
|
||||
### Spezialisierte Domains
|
||||
|
||||
Neben den Top-10 gibt es ueber 90 weitere Domains fuer spezifische Themen:
|
||||
|
||||
- **CRA** — Cyber Resilience Act spezifisch
|
||||
- **ARC** — Sichere Architektur
|
||||
- **API** — API-Security
|
||||
- **PKI** — Public Key Infrastructure
|
||||
- **SUP** — Supply Chain Security
|
||||
- **VUL** — Vulnerability Management
|
||||
- **BCP** — Business Continuity
|
||||
- **PHY** — Physische Sicherheit
|
||||
- u.v.m.
|
||||
|
||||
### ID-Format
|
||||
|
||||
Control-IDs folgen dem Muster \`DOMAIN-NNN\` (z.B. AUTH-001, SEC-042). Dieses Format ist
|
||||
**nicht von BSI oder anderen proprietaeren Standards abgeleitet**, sondern folgt einem
|
||||
allgemein ueblichen Nummerierungsschema.`,
|
||||
},
|
||||
{
|
||||
id: 'open-sources',
|
||||
title: 'Offene Referenzquellen',
|
||||
content: `## Primaere offene Quellen
|
||||
|
||||
Alle Controls sind in mindestens einer der folgenden **frei zugaenglichen** Quellen verankert:
|
||||
|
||||
### OWASP (CC BY-SA 4.0 — kommerziell erlaubt)
|
||||
- **ASVS** — Application Security Verification Standard v4.0.3
|
||||
- **MASVS** — Mobile Application Security Verification Standard v2.1
|
||||
- **Top 10** — OWASP Top 10 (2021)
|
||||
- **Cheat Sheets** — OWASP Cheat Sheet Series
|
||||
- **SAMM** — Software Assurance Maturity Model
|
||||
|
||||
### NIST (Public Domain — keine Einschraenkungen)
|
||||
- **SP 800-53 Rev.5** — Security and Privacy Controls
|
||||
- **SP 800-63B** — Digital Identity Guidelines (Authentication)
|
||||
- **SP 800-57** — Key Management Recommendations
|
||||
- **SP 800-52 Rev.2** — TLS Implementation Guidelines
|
||||
- **SP 800-92** — Log Management Guide
|
||||
- **SP 800-218 (SSDF)** — Secure Software Development Framework
|
||||
- **SP 800-60** — Information Types to Security Categories
|
||||
|
||||
### ENISA (CC BY 4.0 — kommerziell erlaubt)
|
||||
- Good Practices for IoT/Mobile Security
|
||||
- Data Protection Engineering
|
||||
- Algorithms, Key Sizes and Parameters Report
|
||||
|
||||
### Weitere offene Quellen
|
||||
- **SLSA** (Supply-chain Levels for Software Artifacts) — Google Open Source
|
||||
- **CIS Controls v8** (CC BY-NC-ND — nur fuer interne Analyse)`,
|
||||
},
|
||||
{
|
||||
id: 'restricted-sources',
|
||||
title: 'Geschuetzte Quellen — Nur interne Analyse',
|
||||
content: `## Quellen mit eingeschraenkter Nutzung
|
||||
|
||||
Die folgenden Quellen werden **ausschliesslich intern zur Analyse** verwendet.
|
||||
Kein Text, keine Struktur, keine Bezeichner aus diesen Quellen erscheinen im Produkt.
|
||||
|
||||
### BSI (Nutzungsbedingungen — kommerziell eingeschraenkt)
|
||||
- TR-03161 Teil 1-3 (Mobile, Web, Hintergrunddienste)
|
||||
- Nutzung: TDM unter UrhG §44b, Kopien werden geloescht
|
||||
- Kein Shipping von Zitaten, Embeddings oder Strukturen
|
||||
|
||||
### ISO/IEC (Kostenpflichtig — kein Shipping)
|
||||
- ISO 27001, ISO 27002
|
||||
- Nutzung: Nur als Referenz fuer Mapping, kein Text im Produkt
|
||||
|
||||
### ETSI (Restriktiv — kein kommerzieller Gebrauch)
|
||||
- Nutzung: Nur als Hintergrundwissen, kein direkter Einfluss
|
||||
|
||||
### Trennungsprinzip
|
||||
|
||||
| Ebene | Geschuetzte Quelle | Offene Quelle |
|
||||
|-------|--------------------|---------------|
|
||||
| Analyse | ✅ Darf gelesen werden | ✅ Darf gelesen werden |
|
||||
| Inspiration | ✅ Darf Ideen liefern | ✅ Darf Ideen liefern |
|
||||
| Formulierung | ❌ Keine Uebernahme | ✅ Darf zitiert werden |
|
||||
| Struktur | ❌ Keine Uebernahme | ✅ Darf verwendet werden |
|
||||
| Produkttext | ❌ Nicht erlaubt | ✅ Erlaubt |`,
|
||||
},
|
||||
{
|
||||
id: 'verification-methods',
|
||||
title: 'Verifikationsmethoden',
|
||||
content: `## Nachweis-Klassifizierung
|
||||
|
||||
Jedes Control wird einer von vier Verifikationsmethoden zugeordnet. Dies bestimmt,
|
||||
**wie** ein Kunde den Nachweis fuer die Einhaltung erbringen kann:
|
||||
|
||||
| Methode | Beschreibung | Beispiele |
|
||||
|---------|-------------|-----------|
|
||||
| **Code Review** | Nachweis durch Quellcode-Inspektion | Input-Validierung, Encryption-Konfiguration, Auth-Logic |
|
||||
| **Dokument** | Nachweis durch Richtlinien, Prozesse, Schulungen | Notfallplaene, Schulungsnachweise, Datenschutzkonzepte |
|
||||
| **Tool** | Nachweis durch automatisierte Tools/Scans | SIEM-Logs, Vulnerability-Scans, Monitoring-Dashboards |
|
||||
| **Hybrid** | Kombination aus mehreren Methoden | Zugriffskontrollen (Code + Policy + Tool) |
|
||||
|
||||
### Bedeutung fuer Kunden
|
||||
|
||||
- **Code Review Controls** koennen direkt im SDK-Scan geprueft werden
|
||||
- **Dokument Controls** erfordern manuelle Uploads (PDFs, Links)
|
||||
- **Tool Controls** koennen per API-Integration automatisch nachgewiesen werden
|
||||
- **Hybrid Controls** benoetigen mehrere Nachweisarten`,
|
||||
},
|
||||
{
|
||||
id: 'categories',
|
||||
title: 'Thematische Kategorien',
|
||||
content: `## 17 Sicherheitskategorien
|
||||
|
||||
Controls sind in thematische Kategorien gruppiert, um Kunden eine
|
||||
uebersichtliche Navigation zu ermoeglichen:
|
||||
|
||||
| Kategorie | Beschreibung |
|
||||
|-----------|-------------|
|
||||
| Verschluesselung & Kryptographie | TLS, Key Management, Algorithmen |
|
||||
| Authentisierung & Zugriffskontrolle | Login, MFA, RBAC, Session-Management |
|
||||
| Netzwerksicherheit | Firewall, Segmentierung, VPN, DNS |
|
||||
| Datenschutz & Datensicherheit | DSGVO, Datenklassifizierung, Anonymisierung |
|
||||
| Logging & Monitoring | SIEM, Audit-Logs, Alerting |
|
||||
| Vorfallmanagement | Incident Response, Meldepflichten |
|
||||
| Notfall & Wiederherstellung | BCM, Disaster Recovery, Backups |
|
||||
| Compliance & Audit | Zertifizierungen, Audits, Berichtspflichten |
|
||||
| Lieferkettenmanagement | Vendor Risk, SBOM, Third-Party |
|
||||
| Physische Sicherheit | Zutritt, Gebaeudesicherheit |
|
||||
| Personal & Schulung | Security Awareness, Rollenkonzepte |
|
||||
| Anwendungssicherheit | SAST, DAST, Secure Coding |
|
||||
| Systemhaertung & -betrieb | Patching, Konfiguration, Hardening |
|
||||
| Risikomanagement | Risikoanalyse, Bewertung, Massnahmen |
|
||||
| Sicherheitsorganisation | ISMS, Richtlinien, Governance |
|
||||
| Hardware & Plattformsicherheit | TPM, Secure Boot, Firmware |
|
||||
| Identitaetsmanagement | SSO, Federation, Directory |
|
||||
|
||||
### Abgrenzung zu Domains
|
||||
|
||||
Kategorien sind **thematisch**, Domains (AUTH, NET, etc.) sind **strukturell**.
|
||||
Ein Control AUTH-005 (Domain AUTH) hat die Kategorie "authentication",
|
||||
aber ein Control NET-012 (Domain NET) koennte ebenfalls die Kategorie
|
||||
"authentication" haben, wenn es um Netzwerk-Authentifizierung geht.`,
|
||||
},
|
||||
{
|
||||
id: 'master-library',
|
||||
title: 'Master Library Strategie',
|
||||
content: `## RAG-First Ansatz
|
||||
|
||||
Die Canonical Control Library folgt einer **RAG-First-Strategie**:
|
||||
|
||||
### Schritt 1: Rule 1+2 Controls aus RAG generieren
|
||||
|
||||
Prioritaet haben Controls aus Quellen mit **Originaltext-Erlaubnis**:
|
||||
|
||||
| Welle | Quellen | Lizenzregel | Vorteil |
|
||||
|-------|---------|------------|---------|
|
||||
| 1 | OWASP (ASVS, MASVS, Top10) | Rule 2 (CC-BY-SA, Zitation) | Originaltext + Zitation |
|
||||
| 2 | NIST (SP 800-53, CSF, SSDF) | Rule 1 (Public Domain) | Voller Text, keine Einschraenkungen |
|
||||
| 3 | EU-Verordnungen (DSGVO, AI Act, NIS2, CRA) | Rule 1 (EU Law) | Gesetzestext + Erklaerung |
|
||||
| 4 | Deutsche Gesetze (BDSG, TTDSG, TKG) | Rule 1 (DE Law) | Gesetzestext + Erklaerung |
|
||||
|
||||
### Schritt 2: Dedup gegen BSI Rule-3 Controls
|
||||
|
||||
Die ~880 BSI Rule-3 Controls werden **gegen** die neuen Rule 1+2 Controls abgeglichen:
|
||||
|
||||
- Wenn ein BSI-Control ein Duplikat eines OWASP/NIST-Controls ist → **OWASP/NIST bevorzugt**
|
||||
(weil Originaltext + Zitation erlaubt)
|
||||
- BSI-Duplikate werden als \`deprecated\` markiert
|
||||
- Tags und Anchors werden in den behaltenen Control zusammengefuehrt
|
||||
|
||||
### Schritt 3: Aktueller Stand
|
||||
|
||||
Aktuell: **~3.100+ Controls** (Stand Maerz 2026), davon:
|
||||
- Viele mit \`source_original_text\` (Originaltext fuer Kunden sichtbar)
|
||||
- Viele mit \`source_citation\` (Quellenangabe mit Lizenz)
|
||||
- Klare Nachweismethode (\`verification_method\`)
|
||||
- Thematische Kategorie (\`category\`)
|
||||
|
||||
### Verstaendliche Texte
|
||||
|
||||
Zusaetzlich zum Originaltext (der oft juristisch/technisch formuliert ist)
|
||||
enthaelt jedes Control ein eigenstaendig formuliertes **Ziel** (objective)
|
||||
und eine **Begruendung** (rationale) in verstaendlicher Sprache.`,
|
||||
},
|
||||
{
|
||||
id: 'validation',
|
||||
title: 'Automatisierte Validierung',
|
||||
content: `## CI/CD-Pruefungen
|
||||
|
||||
Jedes Control wird bei jedem Commit automatisch geprueft:
|
||||
|
||||
### 1. Schema-Validierung
|
||||
- Alle Pflichtfelder vorhanden
|
||||
- Control-ID Format: \`^[A-Z]{2,6}-[0-9]{3}$\`
|
||||
- Severity: low, medium, high, critical
|
||||
- Risk Score: 0-10
|
||||
|
||||
### 2. No-Leak Scanner
|
||||
Regex-Pruefung gegen verbotene Muster in produktfaehigen Feldern:
|
||||
- \`O.[A-Za-z]+_[0-9]+\` — BSI Objective-IDs
|
||||
- \`TR-03161\` — Direkte BSI-TR-Referenzen
|
||||
- \`BSI-TR-\` — BSI-spezifische Locators
|
||||
- \`Anforderung [A-Z].[0-9]+\` — BSI-Anforderungsformat
|
||||
|
||||
### 3. Open Anchor Check
|
||||
Jedes freigegebene Control muss mindestens 1 Open-Source-Referenz haben.
|
||||
|
||||
### 4. Too-Close Detektor (5 Metriken)
|
||||
|
||||
| Metrik | Warn | Fail | Beschreibung |
|
||||
|--------|------|------|-------------|
|
||||
| Exact Phrase | ≥8 Tokens | ≥12 Tokens | Laengste identische Token-Sequenz |
|
||||
| Token Overlap | ≥0.20 | ≥0.30 | Jaccard-Aehnlichkeit der Token-Mengen |
|
||||
| 3-Gram Jaccard | ≥0.10 | ≥0.18 | Zeichenketten-Aehnlichkeit |
|
||||
| Embedding Cosine | ≥0.86 | ≥0.92 | Semantische Aehnlichkeit (bge-m3) |
|
||||
| LCS Ratio | ≥0.35 | ≥0.50 | Longest Common Subsequence |
|
||||
|
||||
**Entscheidungslogik:**
|
||||
- **PASS** — Kein Fail + max 1 Warn
|
||||
- **WARN** — Max 2 Warn, kein Fail → Human Review erforderlich
|
||||
- **FAIL** — Irgendein Fail → Blockiert, Umformulierung noetig`,
|
||||
},
|
||||
]
|
||||
@@ -1,452 +1,27 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
Shield, BookOpen, ExternalLink, CheckCircle2, AlertTriangle,
|
||||
Lock, Scale, FileText, Eye, ArrowLeft,
|
||||
} from 'lucide-react'
|
||||
import { Shield, FileText } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
|
||||
// =============================================================================
|
||||
// TYPES
|
||||
// =============================================================================
|
||||
import { PROVENANCE_SECTIONS } from './_data/provenance-sections'
|
||||
import { MarkdownRenderer } from './_components/MarkdownRenderer'
|
||||
import { LicenseMatrix } from './_components/LicenseMatrix'
|
||||
import { SourceRegistry } from './_components/SourceRegistry'
|
||||
|
||||
interface LicenseInfo {
|
||||
license_id: string
|
||||
name: string
|
||||
terms_url: string | null
|
||||
commercial_use: string
|
||||
ai_training_restriction: string | null
|
||||
tdm_allowed_under_44b: string | null
|
||||
deletion_required: boolean
|
||||
notes: string | null
|
||||
license_id: string; name: string; terms_url: string | null; commercial_use: string
|
||||
ai_training_restriction: string | null; tdm_allowed_under_44b: string | null
|
||||
deletion_required: boolean; notes: string | null
|
||||
}
|
||||
|
||||
interface SourceInfo {
|
||||
source_id: string
|
||||
title: string
|
||||
publisher: string
|
||||
url: string | null
|
||||
version_label: string | null
|
||||
language: string
|
||||
license_id: string
|
||||
license_name: string
|
||||
commercial_use: string
|
||||
allowed_analysis: boolean
|
||||
allowed_store_excerpt: boolean
|
||||
allowed_ship_embeddings: boolean
|
||||
allowed_ship_in_product: boolean
|
||||
vault_retention_days: number
|
||||
vault_access_tier: string
|
||||
source_id: string; title: string; publisher: string; url: string | null
|
||||
version_label: string | null; language: string; license_id: string; license_name: string
|
||||
commercial_use: string; allowed_analysis: boolean; allowed_store_excerpt: boolean
|
||||
allowed_ship_embeddings: boolean; allowed_ship_in_product: boolean
|
||||
vault_retention_days: number; vault_access_tier: string
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// STATIC PROVENANCE DOCUMENTATION
|
||||
// =============================================================================
|
||||
|
||||
const PROVENANCE_SECTIONS = [
|
||||
{
|
||||
id: 'methodology',
|
||||
title: 'Methodik der Control-Erstellung',
|
||||
content: `## Unabhaengige Formulierung
|
||||
|
||||
Alle Controls in der Canonical Control Library wurden **eigenstaendig formuliert** und folgen einer
|
||||
**unabhaengigen Taxonomie**. Es werden keine proprietaeren Bezeichner, Nummern oder Strukturen
|
||||
aus geschuetzten Quellen uebernommen.
|
||||
|
||||
### Dreistufiger Prozess
|
||||
|
||||
1. **Offene Recherche** — Identifikation von Security-Anforderungen aus oeffentlichen, frei zugaenglichen
|
||||
Frameworks (OWASP, NIST, ENISA). Jede Anforderung wird aus mindestens 2 unabhaengigen offenen Quellen belegt.
|
||||
|
||||
2. **Eigenstaendige Formulierung** — Jedes Control wird mit eigener Sprache, eigener Struktur und eigener
|
||||
Taxonomie (z.B. AUTH-001, NET-001) verfasst. Kein Copy-Paste, keine Paraphrase geschuetzter Texte.
|
||||
|
||||
3. **Too-Close-Pruefung** — Automatisierte Aehnlichkeitspruefung gegen Quelltexte mit 5 Metriken
|
||||
(Token Overlap, N-Gram Jaccard, Embedding Cosine, LCS Ratio, Exact-Phrase). Nur Controls mit
|
||||
Status PASS oder WARN (+ Human Review) werden freigegeben.
|
||||
|
||||
### Rechtliche Grundlage
|
||||
|
||||
- **UrhG §44b** — Text & Data Mining erlaubt fuer Analyse; Kopien werden danach geloescht
|
||||
- **UrhG §23** — Hinreichender Abstand zum Originalwerk durch eigene Formulierung
|
||||
- **BSI Nutzungsbedingungen** — Kommerzielle Nutzung nur mit Zustimmung; wir nutzen BSI-Dokumente
|
||||
ausschliesslich als Analysegrundlage, nicht im Produkt`,
|
||||
},
|
||||
{
|
||||
id: 'filters',
|
||||
title: 'Filter in der Control Library',
|
||||
content: `## Dropdown-Filter
|
||||
|
||||
Die Control Library bietet 7 Filter-Dropdowns, um die ueber 3.000 Controls effizient zu durchsuchen:
|
||||
|
||||
### Schweregrad (Severity)
|
||||
|
||||
| Stufe | Farbe | Bedeutung |
|
||||
|-------|-------|-----------|
|
||||
| **Kritisch** | Rot | Sicherheitskritische Controls — Verstoesse fuehren zu schwerwiegenden Risiken |
|
||||
| **Hoch** | Orange | Wichtige Controls — sollten zeitnah umgesetzt werden |
|
||||
| **Mittel** | Gelb | Standardmaessige Controls — empfohlene Umsetzung |
|
||||
| **Niedrig** | Gruen | Nice-to-have Controls — zusaetzliche Haertung |
|
||||
|
||||
### Domain
|
||||
|
||||
Das Praefix der Control-ID (z.B. \`AUTH-001\`, \`SEC-042\`). Kennzeichnet den thematischen Bereich.
|
||||
Die haeufigsten Domains:
|
||||
|
||||
| Domain | Anzahl | Thema |
|
||||
|--------|--------|-------|
|
||||
| SEC | ~700 | Allgemeine Sicherheit, Systemhaertung |
|
||||
| COMP | ~470 | Compliance, Regulierung, Nachweispflichten |
|
||||
| DATA | ~400 | Datenschutz, Datenklassifizierung, DSGVO |
|
||||
| AI | ~290 | KI-Regulierung (AI Act, Transparenz, Erklaerbarkeit) |
|
||||
| LOG | ~230 | Logging, Monitoring, SIEM |
|
||||
| AUTH | ~200 | Authentifizierung, Zugriffskontrolle |
|
||||
| NET | ~150 | Netzwerksicherheit, Transport, Firewall |
|
||||
| CRYP | ~90 | Kryptographie, Schluesselmanagement |
|
||||
| ACC | ~25 | Zugriffskontrolle (Access Control) |
|
||||
| INC | ~25 | Incident Response, Vorfallmanagement |
|
||||
|
||||
Zusaetzlich existieren spezialisierte Domains wie CRA, ARC (Architektur), API, PKI, SUP (Supply Chain) u.v.m.
|
||||
|
||||
### Status (Release State)
|
||||
|
||||
| Status | Bedeutung |
|
||||
|--------|-----------|
|
||||
| **Draft** | Entwurf — noch nicht freigegeben |
|
||||
| **Approved** | Freigegeben fuer Kunden |
|
||||
| **Review noetig** | Muss manuell geprueft werden |
|
||||
| **Zu aehnlich** | Too-Close-Check hat Warnung ausgeloest |
|
||||
| **Duplikat** | Wurde als Duplikat eines anderen Controls erkannt |
|
||||
|
||||
### Nachweis (Verification Method)
|
||||
|
||||
| Methode | Farbe | Beschreibung |
|
||||
|---------|-------|-------------|
|
||||
| **Code Review** | Blau | Nachweis durch Quellcode-Inspektion |
|
||||
| **Dokument** | Amber | Nachweis durch Richtlinien, Prozesse, Schulungen |
|
||||
| **Tool** | Teal | Nachweis durch automatisierte Scans/Monitoring |
|
||||
| **Hybrid** | Lila | Kombination aus mehreren Methoden |
|
||||
|
||||
### Kategorie
|
||||
|
||||
Thematische Einordnung (17 Kategorien). Kategorien sind **thematisch**, Domains **strukturell**.
|
||||
Ein AUTH-Control kann z.B. die Kategorie "Netzwerksicherheit" haben.
|
||||
|
||||
### Zielgruppe (Target Audience)
|
||||
|
||||
| Zielgruppe | Bedeutung |
|
||||
|------------|-----------|
|
||||
| **Unternehmen** | Fuer Endkunden/Firmen relevant |
|
||||
| **Behoerden** | Spezifisch fuer oeffentliche Verwaltung |
|
||||
| **Anbieter** | Fuer SaaS/Plattform-Anbieter |
|
||||
| **Alle** | Allgemein anwendbar |
|
||||
|
||||
### Dokumentenursprung (Source)
|
||||
|
||||
Filtert nach der Quelldokument-Herkunft des Controls. Zeigt alle Quellen sortiert nach
|
||||
Haeufigkeit. Die wichtigsten Quellen:
|
||||
|
||||
| Quelle | Typ |
|
||||
|--------|-----|
|
||||
| KI-Verordnung (EU) 2024/1689 | EU-Recht |
|
||||
| Cyber Resilience Act (EU) 2024/2847 | EU-Recht |
|
||||
| DSGVO (EU) 2016/679 | EU-Recht |
|
||||
| NIS2-Richtlinie (EU) 2022/2555 | EU-Recht |
|
||||
| NIST SP 800-53, CSF 2.0, SSDF | US-Standards |
|
||||
| OWASP Top 10, ASVS, SAMM | Open Source |
|
||||
| ENISA Guidelines | EU-Agentur |
|
||||
| CISA Secure by Design | US-Behoerde |
|
||||
| BDSG, TKG, GewO, HGB | Deutsche Gesetze |
|
||||
| EDPB Leitlinien | EU Datenschutz |`,
|
||||
},
|
||||
{
|
||||
id: 'badges',
|
||||
title: 'Badges & Lizenzregeln',
|
||||
content: `## Badges in der Control Library
|
||||
|
||||
Jedes Control zeigt mehrere farbige Badges:
|
||||
|
||||
### Lizenzregel-Badge (Rule 1 / 2 / 3)
|
||||
|
||||
Die Lizenzregel bestimmt, wie ein Control erstellt und genutzt werden darf:
|
||||
|
||||
| Badge | Farbe | Regel | Bedeutung |
|
||||
|-------|-------|-------|-----------|
|
||||
| **Free Use** | Gruen | Rule 1 | Quelle ist Public Domain oder EU-Recht — Originaltext darf gezeigt werden |
|
||||
| **Zitation** | Blau | Rule 2 | Quelle ist CC-BY oder aehnlich — Zitation + Quellenangabe erforderlich |
|
||||
| **Reformuliert** | Amber | Rule 3 | Quelle hat eingeschraenkte Lizenz — Control wurde eigenstaendig reformuliert, kein Originaltext |
|
||||
|
||||
### Processing-Path
|
||||
|
||||
| Pfad | Bedeutung |
|
||||
|------|-----------|
|
||||
| **structured** | Control wurde direkt aus strukturierten Daten (Tabellen, Listen) extrahiert |
|
||||
| **llm_reform** | Control wurde mit LLM eigenstaendig formuliert (bei Rule 3 zwingend) |
|
||||
|
||||
### Referenzen (Open Anchors)
|
||||
|
||||
Zeigt die Anzahl der verlinkten Open-Source-Referenzen (OWASP, NIST, ENISA etc.).
|
||||
Jedes freigegebene Control muss mindestens 1 Open Anchor haben.
|
||||
|
||||
### Weitere Badges
|
||||
|
||||
| Badge | Bedeutung |
|
||||
|-------|-----------|
|
||||
| Score | Risiko-Score (0-10) |
|
||||
| Severity-Badge | Schweregrad (Kritisch/Hoch/Mittel/Niedrig) |
|
||||
| State-Badge | Freigabestatus (Draft/Approved/etc.) |
|
||||
| Kategorie-Badge | Thematische Kategorie |
|
||||
| Zielgruppe-Badge | Enterprise/Behoerden/Anbieter/Alle |`,
|
||||
},
|
||||
{
|
||||
id: 'taxonomy',
|
||||
title: 'Unabhaengige Taxonomie',
|
||||
content: `## Eigenes Klassifikationssystem
|
||||
|
||||
Die Canonical Control Library verwendet ein **eigenes Domain-Schema**, das sich bewusst von
|
||||
proprietaeren Frameworks unterscheidet. Die Domains werden **automatisch** durch den
|
||||
Control Generator vergeben, basierend auf dem Inhalt der Quelldokumente.
|
||||
|
||||
### Top-10 Domains
|
||||
|
||||
| Domain | Anzahl | Thema | Hauptquellen |
|
||||
|--------|--------|-------|-------------|
|
||||
| SEC | ~700 | Allgemeine Sicherheit | CRA, NIS2, BSI, ENISA |
|
||||
| COMP | ~470 | Compliance & Regulierung | DSGVO, AI Act, Richtlinien |
|
||||
| DATA | ~400 | Datenschutz & Datenklassifizierung | DSGVO, BDSG, EDPB |
|
||||
| AI | ~290 | KI-Regulierung & Ethik | AI Act, HLEG, OECD |
|
||||
| LOG | ~230 | Logging & Monitoring | NIST, OWASP |
|
||||
| AUTH | ~200 | Authentifizierung & Session | NIST SP 800-63, OWASP |
|
||||
| NET | ~150 | Netzwerksicherheit | NIST, ENISA |
|
||||
| CRYP | ~90 | Kryptographie & Schluessel | NIST SP 800-57 |
|
||||
| ACC | ~25 | Zugriffskontrolle | OWASP ASVS |
|
||||
| INC | ~25 | Incident Response | NIS2, CRA |
|
||||
|
||||
### Spezialisierte Domains
|
||||
|
||||
Neben den Top-10 gibt es ueber 90 weitere Domains fuer spezifische Themen:
|
||||
|
||||
- **CRA** — Cyber Resilience Act spezifisch
|
||||
- **ARC** — Sichere Architektur
|
||||
- **API** — API-Security
|
||||
- **PKI** — Public Key Infrastructure
|
||||
- **SUP** — Supply Chain Security
|
||||
- **VUL** — Vulnerability Management
|
||||
- **BCP** — Business Continuity
|
||||
- **PHY** — Physische Sicherheit
|
||||
- u.v.m.
|
||||
|
||||
### ID-Format
|
||||
|
||||
Control-IDs folgen dem Muster \`DOMAIN-NNN\` (z.B. AUTH-001, SEC-042). Dieses Format ist
|
||||
**nicht von BSI oder anderen proprietaeren Standards abgeleitet**, sondern folgt einem
|
||||
allgemein ueblichen Nummerierungsschema.`,
|
||||
},
|
||||
{
|
||||
id: 'open-sources',
|
||||
title: 'Offene Referenzquellen',
|
||||
content: `## Primaere offene Quellen
|
||||
|
||||
Alle Controls sind in mindestens einer der folgenden **frei zugaenglichen** Quellen verankert:
|
||||
|
||||
### OWASP (CC BY-SA 4.0 — kommerziell erlaubt)
|
||||
- **ASVS** — Application Security Verification Standard v4.0.3
|
||||
- **MASVS** — Mobile Application Security Verification Standard v2.1
|
||||
- **Top 10** — OWASP Top 10 (2021)
|
||||
- **Cheat Sheets** — OWASP Cheat Sheet Series
|
||||
- **SAMM** — Software Assurance Maturity Model
|
||||
|
||||
### NIST (Public Domain — keine Einschraenkungen)
|
||||
- **SP 800-53 Rev.5** — Security and Privacy Controls
|
||||
- **SP 800-63B** — Digital Identity Guidelines (Authentication)
|
||||
- **SP 800-57** — Key Management Recommendations
|
||||
- **SP 800-52 Rev.2** — TLS Implementation Guidelines
|
||||
- **SP 800-92** — Log Management Guide
|
||||
- **SP 800-218 (SSDF)** — Secure Software Development Framework
|
||||
- **SP 800-60** — Information Types to Security Categories
|
||||
|
||||
### ENISA (CC BY 4.0 — kommerziell erlaubt)
|
||||
- Good Practices for IoT/Mobile Security
|
||||
- Data Protection Engineering
|
||||
- Algorithms, Key Sizes and Parameters Report
|
||||
|
||||
### Weitere offene Quellen
|
||||
- **SLSA** (Supply-chain Levels for Software Artifacts) — Google Open Source
|
||||
- **CIS Controls v8** (CC BY-NC-ND — nur fuer interne Analyse)`,
|
||||
},
|
||||
{
|
||||
id: 'restricted-sources',
|
||||
title: 'Geschuetzte Quellen — Nur interne Analyse',
|
||||
content: `## Quellen mit eingeschraenkter Nutzung
|
||||
|
||||
Die folgenden Quellen werden **ausschliesslich intern zur Analyse** verwendet.
|
||||
Kein Text, keine Struktur, keine Bezeichner aus diesen Quellen erscheinen im Produkt.
|
||||
|
||||
### BSI (Nutzungsbedingungen — kommerziell eingeschraenkt)
|
||||
- TR-03161 Teil 1-3 (Mobile, Web, Hintergrunddienste)
|
||||
- Nutzung: TDM unter UrhG §44b, Kopien werden geloescht
|
||||
- Kein Shipping von Zitaten, Embeddings oder Strukturen
|
||||
|
||||
### ISO/IEC (Kostenpflichtig — kein Shipping)
|
||||
- ISO 27001, ISO 27002
|
||||
- Nutzung: Nur als Referenz fuer Mapping, kein Text im Produkt
|
||||
|
||||
### ETSI (Restriktiv — kein kommerzieller Gebrauch)
|
||||
- Nutzung: Nur als Hintergrundwissen, kein direkter Einfluss
|
||||
|
||||
### Trennungsprinzip
|
||||
|
||||
| Ebene | Geschuetzte Quelle | Offene Quelle |
|
||||
|-------|--------------------|---------------|
|
||||
| Analyse | ✅ Darf gelesen werden | ✅ Darf gelesen werden |
|
||||
| Inspiration | ✅ Darf Ideen liefern | ✅ Darf Ideen liefern |
|
||||
| Formulierung | ❌ Keine Uebernahme | ✅ Darf zitiert werden |
|
||||
| Struktur | ❌ Keine Uebernahme | ✅ Darf verwendet werden |
|
||||
| Produkttext | ❌ Nicht erlaubt | ✅ Erlaubt |`,
|
||||
},
|
||||
{
|
||||
id: 'verification-methods',
|
||||
title: 'Verifikationsmethoden',
|
||||
content: `## Nachweis-Klassifizierung
|
||||
|
||||
Jedes Control wird einer von vier Verifikationsmethoden zugeordnet. Dies bestimmt,
|
||||
**wie** ein Kunde den Nachweis fuer die Einhaltung erbringen kann:
|
||||
|
||||
| Methode | Beschreibung | Beispiele |
|
||||
|---------|-------------|-----------|
|
||||
| **Code Review** | Nachweis durch Quellcode-Inspektion | Input-Validierung, Encryption-Konfiguration, Auth-Logic |
|
||||
| **Dokument** | Nachweis durch Richtlinien, Prozesse, Schulungen | Notfallplaene, Schulungsnachweise, Datenschutzkonzepte |
|
||||
| **Tool** | Nachweis durch automatisierte Tools/Scans | SIEM-Logs, Vulnerability-Scans, Monitoring-Dashboards |
|
||||
| **Hybrid** | Kombination aus mehreren Methoden | Zugriffskontrollen (Code + Policy + Tool) |
|
||||
|
||||
### Bedeutung fuer Kunden
|
||||
|
||||
- **Code Review Controls** koennen direkt im SDK-Scan geprueft werden
|
||||
- **Dokument Controls** erfordern manuelle Uploads (PDFs, Links)
|
||||
- **Tool Controls** koennen per API-Integration automatisch nachgewiesen werden
|
||||
- **Hybrid Controls** benoetigen mehrere Nachweisarten`,
|
||||
},
|
||||
{
|
||||
id: 'categories',
|
||||
title: 'Thematische Kategorien',
|
||||
content: `## 17 Sicherheitskategorien
|
||||
|
||||
Controls sind in thematische Kategorien gruppiert, um Kunden eine
|
||||
uebersichtliche Navigation zu ermoeglichen:
|
||||
|
||||
| Kategorie | Beschreibung |
|
||||
|-----------|-------------|
|
||||
| Verschluesselung & Kryptographie | TLS, Key Management, Algorithmen |
|
||||
| Authentisierung & Zugriffskontrolle | Login, MFA, RBAC, Session-Management |
|
||||
| Netzwerksicherheit | Firewall, Segmentierung, VPN, DNS |
|
||||
| Datenschutz & Datensicherheit | DSGVO, Datenklassifizierung, Anonymisierung |
|
||||
| Logging & Monitoring | SIEM, Audit-Logs, Alerting |
|
||||
| Vorfallmanagement | Incident Response, Meldepflichten |
|
||||
| Notfall & Wiederherstellung | BCM, Disaster Recovery, Backups |
|
||||
| Compliance & Audit | Zertifizierungen, Audits, Berichtspflichten |
|
||||
| Lieferkettenmanagement | Vendor Risk, SBOM, Third-Party |
|
||||
| Physische Sicherheit | Zutritt, Gebaeudesicherheit |
|
||||
| Personal & Schulung | Security Awareness, Rollenkonzepte |
|
||||
| Anwendungssicherheit | SAST, DAST, Secure Coding |
|
||||
| Systemhaertung & -betrieb | Patching, Konfiguration, Hardening |
|
||||
| Risikomanagement | Risikoanalyse, Bewertung, Massnahmen |
|
||||
| Sicherheitsorganisation | ISMS, Richtlinien, Governance |
|
||||
| Hardware & Plattformsicherheit | TPM, Secure Boot, Firmware |
|
||||
| Identitaetsmanagement | SSO, Federation, Directory |
|
||||
|
||||
### Abgrenzung zu Domains
|
||||
|
||||
Kategorien sind **thematisch**, Domains (AUTH, NET, etc.) sind **strukturell**.
|
||||
Ein Control AUTH-005 (Domain AUTH) hat die Kategorie "authentication",
|
||||
aber ein Control NET-012 (Domain NET) koennte ebenfalls die Kategorie
|
||||
"authentication" haben, wenn es um Netzwerk-Authentifizierung geht.`,
|
||||
},
|
||||
{
|
||||
id: 'master-library',
|
||||
title: 'Master Library Strategie',
|
||||
content: `## RAG-First Ansatz
|
||||
|
||||
Die Canonical Control Library folgt einer **RAG-First-Strategie**:
|
||||
|
||||
### Schritt 1: Rule 1+2 Controls aus RAG generieren
|
||||
|
||||
Prioritaet haben Controls aus Quellen mit **Originaltext-Erlaubnis**:
|
||||
|
||||
| Welle | Quellen | Lizenzregel | Vorteil |
|
||||
|-------|---------|------------|---------|
|
||||
| 1 | OWASP (ASVS, MASVS, Top10) | Rule 2 (CC-BY-SA, Zitation) | Originaltext + Zitation |
|
||||
| 2 | NIST (SP 800-53, CSF, SSDF) | Rule 1 (Public Domain) | Voller Text, keine Einschraenkungen |
|
||||
| 3 | EU-Verordnungen (DSGVO, AI Act, NIS2, CRA) | Rule 1 (EU Law) | Gesetzestext + Erklaerung |
|
||||
| 4 | Deutsche Gesetze (BDSG, TTDSG, TKG) | Rule 1 (DE Law) | Gesetzestext + Erklaerung |
|
||||
|
||||
### Schritt 2: Dedup gegen BSI Rule-3 Controls
|
||||
|
||||
Die ~880 BSI Rule-3 Controls werden **gegen** die neuen Rule 1+2 Controls abgeglichen:
|
||||
|
||||
- Wenn ein BSI-Control ein Duplikat eines OWASP/NIST-Controls ist → **OWASP/NIST bevorzugt**
|
||||
(weil Originaltext + Zitation erlaubt)
|
||||
- BSI-Duplikate werden als \`deprecated\` markiert
|
||||
- Tags und Anchors werden in den behaltenen Control zusammengefuehrt
|
||||
|
||||
### Schritt 3: Aktueller Stand
|
||||
|
||||
Aktuell: **~3.100+ Controls** (Stand Maerz 2026), davon:
|
||||
- Viele mit \`source_original_text\` (Originaltext fuer Kunden sichtbar)
|
||||
- Viele mit \`source_citation\` (Quellenangabe mit Lizenz)
|
||||
- Klare Nachweismethode (\`verification_method\`)
|
||||
- Thematische Kategorie (\`category\`)
|
||||
|
||||
### Verstaendliche Texte
|
||||
|
||||
Zusaetzlich zum Originaltext (der oft juristisch/technisch formuliert ist)
|
||||
enthaelt jedes Control ein eigenstaendig formuliertes **Ziel** (objective)
|
||||
und eine **Begruendung** (rationale) in verstaendlicher Sprache.`,
|
||||
},
|
||||
{
|
||||
id: 'validation',
|
||||
title: 'Automatisierte Validierung',
|
||||
content: `## CI/CD-Pruefungen
|
||||
|
||||
Jedes Control wird bei jedem Commit automatisch geprueft:
|
||||
|
||||
### 1. Schema-Validierung
|
||||
- Alle Pflichtfelder vorhanden
|
||||
- Control-ID Format: \`^[A-Z]{2,6}-[0-9]{3}$\`
|
||||
- Severity: low, medium, high, critical
|
||||
- Risk Score: 0-10
|
||||
|
||||
### 2. No-Leak Scanner
|
||||
Regex-Pruefung gegen verbotene Muster in produktfaehigen Feldern:
|
||||
- \`O.[A-Za-z]+_[0-9]+\` — BSI Objective-IDs
|
||||
- \`TR-03161\` — Direkte BSI-TR-Referenzen
|
||||
- \`BSI-TR-\` — BSI-spezifische Locators
|
||||
- \`Anforderung [A-Z].[0-9]+\` — BSI-Anforderungsformat
|
||||
|
||||
### 3. Open Anchor Check
|
||||
Jedes freigegebene Control muss mindestens 1 Open-Source-Referenz haben.
|
||||
|
||||
### 4. Too-Close Detektor (5 Metriken)
|
||||
|
||||
| Metrik | Warn | Fail | Beschreibung |
|
||||
|--------|------|------|-------------|
|
||||
| Exact Phrase | ≥8 Tokens | ≥12 Tokens | Laengste identische Token-Sequenz |
|
||||
| Token Overlap | ≥0.20 | ≥0.30 | Jaccard-Aehnlichkeit der Token-Mengen |
|
||||
| 3-Gram Jaccard | ≥0.10 | ≥0.18 | Zeichenketten-Aehnlichkeit |
|
||||
| Embedding Cosine | ≥0.86 | ≥0.92 | Semantische Aehnlichkeit (bge-m3) |
|
||||
| LCS Ratio | ≥0.35 | ≥0.50 | Longest Common Subsequence |
|
||||
|
||||
**Entscheidungslogik:**
|
||||
- **PASS** — Kein Fail + max 1 Warn
|
||||
- **WARN** — Max 2 Warn, kein Fail → Human Review erforderlich
|
||||
- **FAIL** — Irgendein Fail → Blockiert, Umformulierung noetig`,
|
||||
},
|
||||
]
|
||||
|
||||
// =============================================================================
|
||||
// PAGE
|
||||
// =============================================================================
|
||||
|
||||
export default function ControlProvenancePage() {
|
||||
const [licenses, setLicenses] = useState<LicenseInfo[]>([])
|
||||
const [sources, setSources] = useState<SourceInfo[]>([])
|
||||
@@ -475,7 +50,6 @@ export default function ControlProvenancePage() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
{/* Header */}
|
||||
<div className="border-b border-gray-200 bg-white px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<FileText className="w-6 h-6 text-green-600" />
|
||||
@@ -485,10 +59,7 @@ export default function ControlProvenancePage() {
|
||||
Dokumentation der unabhaengigen Herkunft aller Security Controls — rechtssicherer Nachweis
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
href="/sdk/control-library"
|
||||
className="ml-auto flex items-center gap-1 text-sm text-purple-600 hover:text-purple-800"
|
||||
>
|
||||
<Link href="/sdk/control-library" className="ml-auto flex items-center gap-1 text-sm text-purple-600 hover:text-purple-800">
|
||||
<Shield className="w-4 h-4" />
|
||||
Zur Control Library
|
||||
</Link>
|
||||
@@ -513,29 +84,19 @@ export default function ControlProvenancePage() {
|
||||
{section.title}
|
||||
</button>
|
||||
))}
|
||||
|
||||
<div className="border-t border-gray-200 mt-3 pt-3">
|
||||
<p className="text-xs font-semibold text-gray-400 uppercase px-3 mb-2">Live-Daten</p>
|
||||
<button
|
||||
onClick={() => setActiveSection('license-matrix')}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${
|
||||
activeSection === 'license-matrix'
|
||||
? 'bg-green-100 text-green-900 font-medium'
|
||||
: 'text-gray-700 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
Lizenz-Matrix
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveSection('source-registry')}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${
|
||||
activeSection === 'source-registry'
|
||||
? 'bg-green-100 text-green-900 font-medium'
|
||||
: 'text-gray-700 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
Quellenregister
|
||||
</button>
|
||||
{['license-matrix', 'source-registry'].map(id => (
|
||||
<button
|
||||
key={id}
|
||||
onClick={() => setActiveSection(id)}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${
|
||||
activeSection === id ? 'bg-green-100 text-green-900 font-medium' : 'text-gray-700 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
{id === 'license-matrix' ? 'Lizenz-Matrix' : 'Quellenregister'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -543,7 +104,6 @@ export default function ControlProvenancePage() {
|
||||
{/* Right: Content */}
|
||||
<div className="flex-1 overflow-y-auto p-6">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
{/* Static documentation sections */}
|
||||
{currentSection && (
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-4">{currentSection.title}</h2>
|
||||
@@ -552,188 +112,11 @@ export default function ControlProvenancePage() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* License Matrix (live data) */}
|
||||
{activeSection === 'license-matrix' && (
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-4">Lizenz-Matrix</h2>
|
||||
<p className="text-sm text-gray-600 mb-4">
|
||||
Uebersicht aller Lizenzen mit ihren erlaubten Nutzungsarten.
|
||||
</p>
|
||||
{loading ? (
|
||||
<div className="animate-pulse h-32 bg-gray-100 rounded" />
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-gray-50">
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">Lizenz</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">Kommerziell</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">AI-Training</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">TDM (§44b)</th>
|
||||
<th className="text-left px-3 py-2 border-b font-medium text-gray-600">Loeschpflicht</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{licenses.map(lic => (
|
||||
<tr key={lic.license_id} className="hover:bg-gray-50">
|
||||
<td className="px-3 py-2 border-b">
|
||||
<div className="font-medium text-gray-900">{lic.license_id}</div>
|
||||
<div className="text-xs text-gray-500">{lic.name}</div>
|
||||
</td>
|
||||
<td className="px-3 py-2 border-b">
|
||||
<UsageBadge value={lic.commercial_use} />
|
||||
</td>
|
||||
<td className="px-3 py-2 border-b">
|
||||
<UsageBadge value={lic.ai_training_restriction || 'n/a'} />
|
||||
</td>
|
||||
<td className="px-3 py-2 border-b">
|
||||
<UsageBadge value={lic.tdm_allowed_under_44b || 'unclear'} />
|
||||
</td>
|
||||
<td className="px-3 py-2 border-b">
|
||||
{lic.deletion_required ? (
|
||||
<span className="text-red-600 text-xs font-medium">Ja</span>
|
||||
) : (
|
||||
<span className="text-green-600 text-xs font-medium">Nein</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Source Registry (live data) */}
|
||||
{activeSection === 'source-registry' && (
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-gray-900 mb-4">Quellenregister</h2>
|
||||
<p className="text-sm text-gray-600 mb-4">
|
||||
Alle registrierten Quellen mit ihren Berechtigungen.
|
||||
</p>
|
||||
{loading ? (
|
||||
<div className="animate-pulse h-32 bg-gray-100 rounded" />
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{sources.map(src => (
|
||||
<div key={src.source_id} className="bg-white border border-gray-200 rounded-lg p-4">
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">{src.title}</h3>
|
||||
<p className="text-xs text-gray-500">{src.publisher} — {src.license_name}</p>
|
||||
</div>
|
||||
{src.url && (
|
||||
<a
|
||||
href={src.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-1 text-xs text-blue-600 hover:text-blue-800"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
Quelle
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3 mt-2">
|
||||
<PermBadge label="Analyse" allowed={src.allowed_analysis} />
|
||||
<PermBadge label="Excerpt" allowed={src.allowed_store_excerpt} />
|
||||
<PermBadge label="Embeddings" allowed={src.allowed_ship_embeddings} />
|
||||
<PermBadge label="Produkt" allowed={src.allowed_ship_in_product} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{activeSection === 'license-matrix' && <LicenseMatrix licenses={licenses} loading={loading} />}
|
||||
{activeSection === 'source-registry' && <SourceRegistry sources={sources} loading={loading} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// HELPER COMPONENTS
|
||||
// =============================================================================
|
||||
|
||||
function UsageBadge({ value }: { value: string }) {
|
||||
const config: Record<string, { bg: string; label: string }> = {
|
||||
allowed: { bg: 'bg-green-100 text-green-800', label: 'Erlaubt' },
|
||||
restricted: { bg: 'bg-yellow-100 text-yellow-800', label: 'Eingeschraenkt' },
|
||||
prohibited: { bg: 'bg-red-100 text-red-800', label: 'Verboten' },
|
||||
unclear: { bg: 'bg-gray-100 text-gray-600', label: 'Unklar' },
|
||||
yes: { bg: 'bg-green-100 text-green-800', label: 'Ja' },
|
||||
no: { bg: 'bg-red-100 text-red-800', label: 'Nein' },
|
||||
'n/a': { bg: 'bg-gray-100 text-gray-400', label: 'k.A.' },
|
||||
}
|
||||
const c = config[value] || config.unclear
|
||||
return <span className={`inline-flex px-1.5 py-0.5 rounded text-xs font-medium ${c.bg}`}>{c.label}</span>
|
||||
}
|
||||
|
||||
function PermBadge({ label, allowed }: { label: string; allowed: boolean }) {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
{allowed ? (
|
||||
<CheckCircle2 className="w-3 h-3 text-green-500" />
|
||||
) : (
|
||||
<Lock className="w-3 h-3 text-red-400" />
|
||||
)}
|
||||
<span className={`text-xs ${allowed ? 'text-green-700' : 'text-red-500'}`}>{label}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkdownRenderer({ content }: { content: string }) {
|
||||
let html = content
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
|
||||
// Code blocks
|
||||
html = html.replace(
|
||||
/^```[\w]*\n([\s\S]*?)^```$/gm,
|
||||
(_m, code: string) => `<pre class="bg-gray-50 border rounded p-3 my-3 text-xs font-mono overflow-x-auto whitespace-pre">${code.trimEnd()}</pre>`
|
||||
)
|
||||
|
||||
// Tables
|
||||
html = html.replace(
|
||||
/^(\|.+\|)\n(\|[\s:|-]+\|)\n((?:\|.+\|\n?)*)/gm,
|
||||
(_m, header: string, _sep: string, body: string) => {
|
||||
const ths = header.split('|').filter((c: string) => c.trim()).map((c: string) =>
|
||||
`<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase border-b">${c.trim()}</th>`
|
||||
).join('')
|
||||
const rows = body.trim().split('\n').map((row: string) => {
|
||||
const tds = row.split('|').filter((c: string) => c.trim()).map((c: string) =>
|
||||
`<td class="px-3 py-2 text-sm text-gray-700 border-b border-gray-100">${c.trim()}</td>`
|
||||
).join('')
|
||||
return `<tr>${tds}</tr>`
|
||||
}).join('')
|
||||
return `<table class="w-full border-collapse my-3 text-sm"><thead><tr>${ths}</tr></thead><tbody>${rows}</tbody></table>`
|
||||
}
|
||||
)
|
||||
|
||||
// Headers
|
||||
html = html.replace(/^### (.+)$/gm, '<h4 class="text-sm font-semibold text-gray-800 mt-4 mb-2">$1</h4>')
|
||||
html = html.replace(/^## (.+)$/gm, '<h3 class="text-base font-semibold text-gray-900 mt-5 mb-2">$1</h3>')
|
||||
|
||||
// Bold
|
||||
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||||
|
||||
// Inline code
|
||||
html = html.replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 py-0.5 rounded text-xs font-mono">$1</code>')
|
||||
|
||||
// Lists
|
||||
html = html.replace(/^- (.+)$/gm, '<li class="ml-4 text-sm text-gray-700 list-disc">$1</li>')
|
||||
html = html.replace(/((?:<li[^>]*>.*<\/li>\n?)+)/g, '<ul class="my-2 space-y-1">$1</ul>')
|
||||
|
||||
// Numbered lists
|
||||
html = html.replace(/^(\d+)\. (.+)$/gm, '<li class="ml-4 text-sm text-gray-700 list-decimal">$2</li>')
|
||||
|
||||
// Paragraphs
|
||||
html = html.replace(/^(?!<[hultdp]|$)(.+)$/gm, '<p class="text-sm text-gray-700 my-2">$1</p>')
|
||||
|
||||
return <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user