From e3a182288331b1c34494466f4a65417dc97c08ad Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar <30073382+mighty840@users.noreply.github.com> Date: Fri, 17 Apr 2026 12:26:39 +0200 Subject: [PATCH] refactor(admin): split training, control-provenance, iace/verification, training/learner, ControlDetail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 5 files reduced below 500 LOC (hard cap) by extracting sub-components: - training/page.tsx: 780→278 LOC — imports existing _components/, adds BlocksSection - control-provenance/page.tsx: 739→145 LOC — extracts provenance-data.ts, ProvenanceHelpers, LicenseMatrix, SourceRegistry - iace/[projectId]/verification/page.tsx: 673→164 LOC — extracts VerificationForm, CompleteModal, SuggestEvidenceModal, VerificationTable - training/learner/page.tsx: 560→216 LOC — extracts AssignmentsList, ContentView, QuizView, CertificatesView - ControlDetail.tsx: 878→311 LOC — adds ControlSourceCitation, ControlTraceability, ControlRegulatorySection, ControlSimilarControls, ControlReviewActions siblings Co-Authored-By: Claude Sonnet 4.6 --- .../components/ControlDetail.tsx | 717 ++--------------- .../components/ControlRegulatorySection.tsx | 85 ++ .../components/ControlReviewActions.tsx | 38 + .../_components/LicenseMatrix.tsx | 58 ++ .../_components/ProvenanceHelpers.tsx | 65 ++ .../_components/SourceRegistry.tsx | 59 ++ .../_components/provenance-data.ts | 398 ++++++++++ .../app/sdk/control-provenance/page.tsx | 636 +-------------- .../_components/CompleteModal.tsx | 61 ++ .../_components/SuggestEvidenceModal.tsx | 103 +++ .../_components/VerificationForm.tsx | 89 +++ .../_components/VerificationTable.tsx | 79 ++ .../_components/verification-types.ts | 51 ++ .../iace/[projectId]/verification/page.tsx | 627 ++------------- .../training/_components/BlocksSection.tsx | 245 ++++++ .../sdk/training/_components/ContentTab.tsx | 33 + .../learner/_components/AssignmentsList.tsx | 67 ++ .../learner/_components/CertificatesView.tsx | 45 ++ .../learner/_components/ContentView.tsx | 82 ++ .../training/learner/_components/QuizView.tsx | 98 +++ .../app/sdk/training/learner/page.tsx | 472 ++---------- admin-compliance/app/sdk/training/page.tsx | 728 +++--------------- 22 files changed, 1988 insertions(+), 2848 deletions(-) create mode 100644 admin-compliance/app/sdk/control-library/components/ControlRegulatorySection.tsx create mode 100644 admin-compliance/app/sdk/control-library/components/ControlReviewActions.tsx create mode 100644 admin-compliance/app/sdk/control-provenance/_components/LicenseMatrix.tsx create mode 100644 admin-compliance/app/sdk/control-provenance/_components/ProvenanceHelpers.tsx create mode 100644 admin-compliance/app/sdk/control-provenance/_components/SourceRegistry.tsx create mode 100644 admin-compliance/app/sdk/control-provenance/_components/provenance-data.ts create mode 100644 admin-compliance/app/sdk/iace/[projectId]/verification/_components/CompleteModal.tsx create mode 100644 admin-compliance/app/sdk/iace/[projectId]/verification/_components/SuggestEvidenceModal.tsx create mode 100644 admin-compliance/app/sdk/iace/[projectId]/verification/_components/VerificationForm.tsx create mode 100644 admin-compliance/app/sdk/iace/[projectId]/verification/_components/VerificationTable.tsx create mode 100644 admin-compliance/app/sdk/iace/[projectId]/verification/_components/verification-types.ts create mode 100644 admin-compliance/app/sdk/training/_components/BlocksSection.tsx create mode 100644 admin-compliance/app/sdk/training/learner/_components/AssignmentsList.tsx create mode 100644 admin-compliance/app/sdk/training/learner/_components/CertificatesView.tsx create mode 100644 admin-compliance/app/sdk/training/learner/_components/ContentView.tsx create mode 100644 admin-compliance/app/sdk/training/learner/_components/QuizView.tsx diff --git a/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx b/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx index 1d8a09a..0297d1c 100644 --- a/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx +++ b/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx @@ -2,81 +2,48 @@ import { useState, useEffect, useCallback } from 'react' import { - ArrowLeft, ExternalLink, BookOpen, Scale, FileText, - Eye, CheckCircle2, Trash2, Pencil, Clock, - ChevronLeft, SkipForward, GitMerge, Search, Landmark, + ArrowLeft, BookOpen, ExternalLink, FileText, Eye, + Clock, ChevronLeft, SkipForward, Pencil, Trash2, Scale, GitMerge, } from 'lucide-react' import { CanonicalControl, EFFORT_LABELS, BACKEND_URL, - SeverityBadge, StateBadge, LicenseRuleBadge, VerificationMethodBadge, CategoryBadge, EvidenceTypeBadge, TargetAudienceBadge, - ObligationTypeBadge, GenerationStrategyBadge, isEigenentwicklung, - ExtractionMethodBadge, RegulationCountBadge, - VERIFICATION_METHODS, CATEGORY_OPTIONS, EVIDENCE_TYPE_OPTIONS, + SeverityBadge, StateBadge, LicenseRuleBadge, VerificationMethodBadge, CategoryBadge, + EvidenceTypeBadge, TargetAudienceBadge, GenerationStrategyBadge, ObligationTypeBadge, + isEigenentwicklung, ObligationInfo, DocumentReference, MergedDuplicate, RegulationSummary, } from './helpers' +import { ControlSourceCitation } from './ControlSourceCitation' +import { ControlTraceability } from './ControlTraceability' +import { ControlRegulatorySection } from './ControlRegulatorySection' +import { ControlSimilarControls } from './ControlSimilarControls' +import { ControlReviewActions } from './ControlReviewActions' interface SimilarControl { - control_id: string - title: string - severity: string - release_state: string - tags: string[] - license_rule: number | null - verification_method: string | null - category: string | null - similarity: number + control_id: string; title: string; severity: string; release_state: string; + tags: string[]; license_rule: number | null; verification_method: string | null; + category: string | null; similarity: number; } interface ParentLink { - parent_control_id: string - parent_title: string - link_type: string - confidence: number - source_regulation: string | null - source_article: string | null - parent_citation: Record | null - obligation: { - text: string - action: string - object: string - normative_strength: string - } | null + parent_control_id: string; parent_title: string; link_type: string; confidence: number; + source_regulation: string | null; source_article: string | null; + parent_citation: Record | null; + obligation: { text: string; action: string; object: string; normative_strength: string } | null; } interface TraceabilityData { - control_id: string - title: string - is_atomic: boolean - parent_links: ParentLink[] - children: Array<{ - control_id: string - title: string - category: string - severity: string - decomposition_method: string - }> - source_count: number - // Extended provenance fields - obligations?: ObligationInfo[] - obligation_count?: number - document_references?: DocumentReference[] - merged_duplicates?: MergedDuplicate[] - merged_duplicates_count?: number - regulations_summary?: RegulationSummary[] + control_id: string; title: string; is_atomic: boolean; parent_links: ParentLink[]; + children: Array<{ control_id: string; title: string; category: string; severity: string; decomposition_method: string }>; + source_count: number; obligations?: ObligationInfo[]; obligation_count?: number; + document_references?: DocumentReference[]; merged_duplicates?: MergedDuplicate[]; + merged_duplicates_count?: number; regulations_summary?: RegulationSummary[]; } interface V1Match { - matched_control_id: string - matched_title: string - matched_objective: string - matched_severity: string - matched_category: string - matched_source: string | null - matched_article: string | null - matched_source_citation: Record | null - similarity_score: number - match_rank: number - match_method: string + matched_control_id: string; matched_title: string; matched_objective: string; + matched_severity: string; matched_category: string; matched_source: string | null; + matched_article: string | null; matched_source_citation: Record | null; + similarity_score: number; match_rank: number; match_method: string; } interface ControlDetailProps { @@ -88,7 +55,6 @@ interface ControlDetailProps { onRefresh?: () => void onNavigateToControl?: (controlId: string) => void onCompare?: (ctrl: CanonicalControl, matches: V1Match[]) => void - // Review mode navigation reviewMode?: boolean reviewIndex?: number reviewTotal?: number @@ -97,19 +63,8 @@ interface ControlDetailProps { } export function ControlDetail({ - ctrl, - onBack, - onEdit, - onDelete, - onReview, - onRefresh, - onNavigateToControl, - onCompare, - reviewMode, - reviewIndex = 0, - reviewTotal = 0, - onReviewPrev, - onReviewNext, + ctrl, onBack, onEdit, onDelete, onReview, onRefresh, onNavigateToControl, onCompare, + reviewMode, reviewIndex = 0, reviewTotal = 0, onReviewPrev, onReviewNext, }: ControlDetailProps) { const [similarControls, setSimilarControls] = useState([]) const [loadingSimilar, setLoadingSimilar] = useState(false) @@ -124,14 +79,9 @@ export function ControlDetail({ const loadTraceability = useCallback(async () => { setLoadingTrace(true) try { - // Try provenance first (extended data), fall back to traceability let res = await fetch(`${BACKEND_URL}?endpoint=provenance&id=${ctrl.control_id}`) - if (!res.ok) { - res = await fetch(`${BACKEND_URL}?endpoint=traceability&id=${ctrl.control_id}`) - } - if (res.ok) { - setTraceability(await res.json()) - } + if (!res.ok) res = await fetch(`${BACKEND_URL}?endpoint=traceability&id=${ctrl.control_id}`) + if (res.ok) setTraceability(await res.json()) } catch { /* ignore */ } finally { setLoadingTrace(false) } }, [ctrl.control_id]) @@ -141,63 +91,45 @@ export function ControlDetail({ setLoadingV1(true) try { const res = await fetch(`${BACKEND_URL}?endpoint=v1-matches&id=${ctrl.control_id}`) - if (res.ok) setV1Matches(await res.json()) - else setV1Matches([]) + if (res.ok) setV1Matches(await res.json()); else setV1Matches([]) } catch { setV1Matches([]) } finally { setLoadingV1(false) } }, [ctrl.control_id, eigenentwicklung]) - useEffect(() => { - loadSimilarControls() - loadTraceability() - loadV1Matches() - setSelectedDuplicates(new Set()) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ctrl.control_id]) - const loadSimilarControls = async () => { setLoadingSimilar(true) try { const res = await fetch(`${BACKEND_URL}?endpoint=similar&id=${ctrl.control_id}`) - if (res.ok) { - setSimilarControls(await res.json()) - } + if (res.ok) setSimilarControls(await res.json()) } catch { /* ignore */ } finally { setLoadingSimilar(false) } } + useEffect(() => { + loadSimilarControls(); loadTraceability(); loadV1Matches() + setSelectedDuplicates(new Set()) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ctrl.control_id]) + const toggleDuplicate = (controlId: string) => { - setSelectedDuplicates(prev => { - const next = new Set(prev) - if (next.has(controlId)) next.delete(controlId) - else next.add(controlId) - return next - }) + setSelectedDuplicates(prev => { const n = new Set(prev); if (n.has(controlId)) n.delete(controlId); else n.add(controlId); return n }) } const handleMergeDuplicates = async () => { if (selectedDuplicates.size === 0) return if (!confirm(`${selectedDuplicates.size} Controls als Duplikate markieren und Tags/Anchors in ${ctrl.control_id} zusammenfuehren?`)) return - setMerging(true) try { - // For each duplicate: mark as deprecated for (const dupId of selectedDuplicates) { await fetch(`${BACKEND_URL}?endpoint=update-control&id=${dupId}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ release_state: 'deprecated' }), }) } - // Refresh to show updated state if (onRefresh) onRefresh() - setSelectedDuplicates(new Set()) - loadSimilarControls() - } catch { - alert('Fehler beim Zusammenfuehren') - } finally { - setMerging(false) - } + setSelectedDuplicates(new Set()); loadSimilarControls() + } catch { alert('Fehler beim Zusammenfuehren') } + finally { setMerging(false) } } return ( @@ -205,9 +137,7 @@ export function ControlDetail({ {/* Header */}
- +
{ctrl.control_id} @@ -227,13 +157,9 @@ export function ControlDetail({
{reviewMode && (
- + {reviewIndex + 1} / {reviewTotal} - +
)} - ) : ( - - {match.matched_control_id} - - )} - {match.matched_title} -

-
- {onCompare && ( - - )} -
-
- ))} -
- ) : !loadingV1 ? ( -

Keine regulatorische Abdeckung gefunden. Dieses Control ist eine reine Eigenentwicklung.

- ) : null} - + )} - {/* Rechtsgrundlagen / Traceability (atomic controls) */} - {traceability && traceability.parent_links.length > 0 && ( -
-
- -

- Rechtsgrundlagen ({traceability.source_count} {traceability.source_count === 1 ? 'Quelle' : 'Quellen'}) -

- - {traceability.regulations_summary && traceability.regulations_summary.map(rs => ( - - {rs.regulation_code} - - ))} - {loadingTrace && Laden...} -
-
- {traceability.parent_links.map((link, i) => ( -
-
- -
-
- {link.source_regulation && ( - {link.source_regulation} - )} - {link.source_article && ( - {link.source_article} - )} - {!link.source_regulation && link.parent_citation?.source && ( - - {link.parent_citation.source} - {link.parent_citation.article && ` — ${link.parent_citation.article}`} - - )} - - {link.link_type === 'decomposition' ? 'Ableitung' : - link.link_type === 'dedup_merge' ? 'Dedup' : - link.link_type} - -
-

- via{' '} - {onNavigateToControl ? ( - - ) : ( - - {link.parent_control_id} - - )} - {link.parent_title && ( - — {link.parent_title} - )} -

- {link.obligation && ( -

- - {link.obligation.normative_strength === 'must' ? 'MUSS' : - link.obligation.normative_strength === 'should' ? 'SOLL' : 'KANN'} - - {link.obligation.text.slice(0, 200)} - {link.obligation.text.length > 200 ? '...' : ''} -

- )} -
-
-
- ))} -
-
- )} + - {/* Fallback: simple parent display when traceability not loaded yet */} - {ctrl.parent_control_uuid && (!traceability || traceability.parent_links.length === 0) && !loadingTrace && ( -
-
- -

Atomares Control

- -
-

- Abgeleitet aus Eltern-Control{' '} - - {ctrl.parent_control_id || ctrl.parent_control_uuid} - - {ctrl.parent_control_title && ( - — {ctrl.parent_control_title} - )} -

-
- )} - - {/* Document References (atomic controls) */} - {traceability && traceability.is_atomic && traceability.document_references && traceability.document_references.length > 0 && ( -
-
- -

- Original-Dokumente ({traceability.document_references.length}) -

-
-
- {traceability.document_references.map((dr, i) => ( -
- {dr.regulation_code} - {dr.article && {dr.article}} - {dr.paragraph && {dr.paragraph}} - - - {dr.confidence !== null && ( - {(dr.confidence * 100).toFixed(0)}% - )} - -
- ))} -
-
- )} - - {/* Obligations (rich controls) */} - {traceability && !traceability.is_atomic && traceability.obligations && traceability.obligations.length > 0 && ( -
-
- -

- Abgeleitete Pflichten ({traceability.obligation_count ?? traceability.obligations.length}) -

-
-
- {traceability.obligations.map((ob) => ( -
-
- {ob.candidate_id} - - {ob.normative_strength === 'must' ? 'MUSS' : - ob.normative_strength === 'should' ? 'SOLL' : 'KANN'} - - {ob.action && {ob.action}} - {ob.object && → {ob.object}} -
-

- {ob.obligation_text.slice(0, 300)} - {ob.obligation_text.length > 300 ? '...' : ''} -

-
- ))} -
-
- )} - - {/* Merged Duplicates */} - {traceability && traceability.merged_duplicates && traceability.merged_duplicates.length > 0 && ( -
-
- -

- Zusammengefuehrte Duplikate ({traceability.merged_duplicates_count ?? traceability.merged_duplicates.length}) -

-
-
- {traceability.merged_duplicates.map((dup) => ( -
- {onNavigateToControl ? ( - - ) : ( - {dup.control_id} - )} - {dup.title} - {dup.source_regulation && ( - {dup.source_regulation} - )} -
- ))} -
-
- )} - - {/* Child controls (rich controls that have atomic children) */} - {traceability && traceability.children.length > 0 && ( -
-
- -

- Abgeleitete Controls ({traceability.children.length}) -

-
-
- {traceability.children.map((child) => ( -
- {onNavigateToControl ? ( - - ) : ( - {child.control_id} - )} - {child.title} - -
- ))} -
-
- )} - - {/* Impliziter Gesetzesbezug (Rule 3 — reformuliert, kein Originaltext) */} {!ctrl.source_citation && ctrl.open_anchors.length > 0 && (
@@ -648,49 +201,31 @@ export function ControlDetail({
)} - {/* Scope */} {(ctrl.scope.platforms?.length || ctrl.scope.components?.length || ctrl.scope.data_classes?.length) ? (

Geltungsbereich

- {ctrl.scope.platforms?.length ? ( -
Plattformen: {ctrl.scope.platforms.join(', ')}
- ) : null} - {ctrl.scope.components?.length ? ( -
Komponenten: {ctrl.scope.components.join(', ')}
- ) : null} - {ctrl.scope.data_classes?.length ? ( -
Datenklassen: {ctrl.scope.data_classes.join(', ')}
- ) : null} + {ctrl.scope.platforms?.length ?
Plattformen: {ctrl.scope.platforms.join(', ')}
: null} + {ctrl.scope.components?.length ?
Komponenten: {ctrl.scope.components.join(', ')}
: null} + {ctrl.scope.data_classes?.length ?
Datenklassen: {ctrl.scope.data_classes.join(', ')}
: null}
) : null} - {/* Requirements */} {ctrl.requirements.length > 0 && (

Anforderungen

-
    - {ctrl.requirements.map((r, i) => ( -
  1. {r}
  2. - ))} -
+
    {ctrl.requirements.map((r, i) =>
  1. {r}
  2. )}
)} - {/* Test Procedure */} {ctrl.test_procedure.length > 0 && (

Pruefverfahren

-
    - {ctrl.test_procedure.map((s, i) => ( -
  1. {s}
  2. - ))} -
+
    {ctrl.test_procedure.map((s, i) =>
  1. {s}
  2. )}
)} - {/* Evidence — handles both {type, description} objects and plain strings */} {ctrl.evidence.length > 0 && (

Nachweise

@@ -698,31 +233,23 @@ export function ControlDetail({ {ctrl.evidence.map((ev, i) => (
- {typeof ev === 'string' ? ( -
{ev}
- ) : ( -
{ev.type}: {ev.description}
- )} + {typeof ev === 'string' ?
{ev}
:
{ev.type}: {ev.description}
}
))}
)} - {/* Meta */}
{ctrl.risk_score !== null &&
Risiko-Score: {ctrl.risk_score}
} {ctrl.implementation_effort &&
Aufwand: {EFFORT_LABELS[ctrl.implementation_effort] || ctrl.implementation_effort}
} {ctrl.tags.length > 0 && (
- {ctrl.tags.map(t => ( - {t} - ))} + {ctrl.tags.map(t => {t})}
)}
- {/* Open Anchors */}
@@ -735,11 +262,7 @@ export function ControlDetail({ {anchor.framework} {anchor.ref} - {anchor.url && ( - - Link - - )} + {anchor.url && Link}
))} @@ -748,7 +271,6 @@ export function ControlDetail({ )}
- {/* Generation Metadata (internal) */} {ctrl.generation_metadata && (
@@ -756,21 +278,11 @@ export function ControlDetail({

Generierungsdetails (intern)

- {ctrl.generation_metadata.processing_path && ( -

Pfad: {String(ctrl.generation_metadata.processing_path)}

- )} - {ctrl.generation_metadata.decomposition_method && ( -

Methode: {String(ctrl.generation_metadata.decomposition_method)}

- )} - {ctrl.generation_metadata.pass0b_model && ( -

LLM: {String(ctrl.generation_metadata.pass0b_model)}

- )} - {ctrl.generation_metadata.obligation_type && ( -

Obligation-Typ: {String(ctrl.generation_metadata.obligation_type)}

- )} - {ctrl.generation_metadata.similarity_status && ( -

Similarity: {String(ctrl.generation_metadata.similarity_status)}

- )} + {ctrl.generation_metadata.processing_path &&

Pfad: {String(ctrl.generation_metadata.processing_path)}

} + {ctrl.generation_metadata.decomposition_method &&

Methode: {String(ctrl.generation_metadata.decomposition_method)}

} + {ctrl.generation_metadata.pass0b_model &&

LLM: {String(ctrl.generation_metadata.pass0b_model)}

} + {ctrl.generation_metadata.obligation_type &&

Obligation-Typ: {String(ctrl.generation_metadata.obligation_type)}

} + {ctrl.generation_metadata.similarity_status &&

Similarity: {String(ctrl.generation_metadata.similarity_status)}

} {Array.isArray(ctrl.generation_metadata.similar_controls) && (

Aehnliche Controls:

@@ -783,95 +295,16 @@ export function ControlDetail({
)} - {/* Similar Controls (Dedup) */} -
-
- -

Aehnliche Controls

- {loadingSimilar && Laden...} -
+ - {similarControls.length > 0 ? ( - <> -
- - {ctrl.control_id} — {ctrl.title} - Behalten (Haupt-Control) -
- -
- {similarControls.map(sim => ( -
- toggleDuplicate(sim.control_id)} - className="text-red-600" - /> - {sim.control_id} - {sim.title} - - {(sim.similarity * 100).toFixed(1)}% - - - -
- ))} -
- - {selectedDuplicates.size > 0 && ( - - )} - - ) : ( -

- {loadingSimilar ? 'Suche aehnliche Controls...' : 'Keine aehnlichen Controls gefunden.'} -

- )} -
- - {/* Review Actions */} - {['needs_review', 'too_close', 'duplicate'].includes(ctrl.release_state) && ( -
-
- -

Review erforderlich

- {reviewMode && ( - Review-Modus aktiv - )} -
-
- - - -
-
- )} + ) diff --git a/admin-compliance/app/sdk/control-library/components/ControlRegulatorySection.tsx b/admin-compliance/app/sdk/control-library/components/ControlRegulatorySection.tsx new file mode 100644 index 0000000..0bfdb4e --- /dev/null +++ b/admin-compliance/app/sdk/control-library/components/ControlRegulatorySection.tsx @@ -0,0 +1,85 @@ +'use client' + +import { Scale } from 'lucide-react' +import type { CanonicalControl } from './helpers' + +interface V1Match { + matched_control_id: string + matched_title: string + matched_objective: string + matched_severity: string + matched_category: string + matched_source: string | null + matched_article: string | null + matched_source_citation: Record | null + similarity_score: number + match_rank: number + match_method: string +} + +interface ControlRegulatorySectionProps { + ctrl: CanonicalControl + v1Matches: V1Match[] + loadingV1: boolean + onNavigateToControl?: (controlId: string) => void + onCompare?: (ctrl: CanonicalControl, matches: V1Match[]) => void +} + +export function ControlRegulatorySection({ + ctrl, v1Matches, loadingV1, onNavigateToControl, onCompare, +}: ControlRegulatorySectionProps) { + return ( +
+
+ +

Regulatorische Abdeckung

+ {loadingV1 && Laden...} +
+ {v1Matches.length > 0 ? ( +
+ {v1Matches.map((match, i) => ( +
+
+
+
+ {match.matched_source && ( + {match.matched_source} + )} + {match.matched_article && ( + {match.matched_article} + )} + = 0.85 ? 'bg-green-100 text-green-700' : + match.similarity_score >= 0.80 ? 'bg-yellow-100 text-yellow-700' : 'bg-gray-100 text-gray-600' + }`}> + {(match.similarity_score * 100).toFixed(0)}% + +
+

+ {onNavigateToControl ? ( + + ) : ( + {match.matched_control_id} + )} + {match.matched_title} +

+
+ {onCompare && ( + + )} +
+
+ ))} +
+ ) : !loadingV1 ? ( +

Keine regulatorische Abdeckung gefunden. Dieses Control ist eine reine Eigenentwicklung.

+ ) : null} +
+ ) +} diff --git a/admin-compliance/app/sdk/control-library/components/ControlReviewActions.tsx b/admin-compliance/app/sdk/control-library/components/ControlReviewActions.tsx new file mode 100644 index 0000000..dc22dfe --- /dev/null +++ b/admin-compliance/app/sdk/control-library/components/ControlReviewActions.tsx @@ -0,0 +1,38 @@ +'use client' + +import { Eye, CheckCircle2, Trash2, Pencil } from 'lucide-react' + +interface ControlReviewActionsProps { + controlId: string + releaseState: string + reviewMode?: boolean + onReview: (controlId: string, action: string) => void + onEdit: () => void +} + +export function ControlReviewActions({ + controlId, releaseState, reviewMode, onReview, onEdit, +}: ControlReviewActionsProps) { + if (!['needs_review', 'too_close', 'duplicate'].includes(releaseState)) return null + + return ( +
+
+ +

Review erforderlich

+ {reviewMode && Review-Modus aktiv} +
+
+ + + +
+
+ ) +} diff --git a/admin-compliance/app/sdk/control-provenance/_components/LicenseMatrix.tsx b/admin-compliance/app/sdk/control-provenance/_components/LicenseMatrix.tsx new file mode 100644 index 0000000..883e333 --- /dev/null +++ b/admin-compliance/app/sdk/control-provenance/_components/LicenseMatrix.tsx @@ -0,0 +1,58 @@ +'use client' + +import { UsageBadge } from './ProvenanceHelpers' + +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 ( +
+

Lizenz-Matrix

+

Uebersicht aller Lizenzen mit ihren erlaubten Nutzungsarten.

+ {loading ? ( +
+ ) : ( +
+ + + + + + + + + + + + {licenses.map(lic => ( + + + + + + + + ))} + +
LizenzKommerziellAI-TrainingTDM (§44b)Loeschpflicht
+
{lic.license_id}
+
{lic.name}
+
+ {lic.deletion_required + ? Ja + : Nein} +
+
+ )} +
+ ) +} diff --git a/admin-compliance/app/sdk/control-provenance/_components/ProvenanceHelpers.tsx b/admin-compliance/app/sdk/control-provenance/_components/ProvenanceHelpers.tsx new file mode 100644 index 0000000..298ac82 --- /dev/null +++ b/admin-compliance/app/sdk/control-provenance/_components/ProvenanceHelpers.tsx @@ -0,0 +1,65 @@ +'use client' + +import { CheckCircle2, Lock } from 'lucide-react' + +export function UsageBadge({ value }: { value: string }) { + const config: Record = { + 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 {c.label} +} + +export function PermBadge({ label, allowed }: { label: string; allowed: boolean }) { + return ( +
+ {allowed ? : } + {label} +
+ ) +} + +export function MarkdownRenderer({ content }: { content: string }) { + let html = content + .replace(/&/g, '&') + .replace(//g, '>') + + html = html.replace( + /^```[\w]*\n([\s\S]*?)^```$/gm, + (_m, code: string) => `
${code.trimEnd()}
` + ) + + 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) => + `${c.trim()}` + ).join('') + const rows = body.trim().split('\n').map((row: string) => { + const tds = row.split('|').filter((c: string) => c.trim()).map((c: string) => + `${c.trim()}` + ).join('') + return `${tds}` + }).join('') + return `${ths}${rows}
` + } + ) + + html = html.replace(/^### (.+)$/gm, '

$1

') + html = html.replace(/^## (.+)$/gm, '

$1

') + html = html.replace(/\*\*(.+?)\*\*/g, '$1') + html = html.replace(/`([^`]+)`/g, '$1') + html = html.replace(/^- (.+)$/gm, '
  • $1
  • ') + html = html.replace(/((?:]*>.*<\/li>\n?)+)/g, '
      $1
    ') + html = html.replace(/^(\d+)\. (.+)$/gm, '
  • $2
  • ') + html = html.replace(/^(?!<[hultdp]|$)(.+)$/gm, '

    $1

    ') + + return
    +} diff --git a/admin-compliance/app/sdk/control-provenance/_components/SourceRegistry.tsx b/admin-compliance/app/sdk/control-provenance/_components/SourceRegistry.tsx new file mode 100644 index 0000000..ef73ffa --- /dev/null +++ b/admin-compliance/app/sdk/control-provenance/_components/SourceRegistry.tsx @@ -0,0 +1,59 @@ +'use client' + +import { ExternalLink } from 'lucide-react' +import { PermBadge } from './ProvenanceHelpers' + +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 ( +
    +

    Quellenregister

    +

    Alle registrierten Quellen mit ihren Berechtigungen.

    + {loading ? ( +
    + ) : ( +
    + {sources.map(src => ( +
    +
    +
    +

    {src.title}

    +

    {src.publisher} — {src.license_name}

    +
    + {src.url && ( + + Quelle + + )} +
    +
    + + + + +
    +
    + ))} +
    + )} +
    + ) +} diff --git a/admin-compliance/app/sdk/control-provenance/_components/provenance-data.ts b/admin-compliance/app/sdk/control-provenance/_components/provenance-data.ts new file mode 100644 index 0000000..29a7037 --- /dev/null +++ b/admin-compliance/app/sdk/control-provenance/_components/provenance-data.ts @@ -0,0 +1,398 @@ +export 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`, + }, +] diff --git a/admin-compliance/app/sdk/control-provenance/page.tsx b/admin-compliance/app/sdk/control-provenance/page.tsx index 66aa9d8..93aee32 100644 --- a/admin-compliance/app/sdk/control-provenance/page.tsx +++ b/admin-compliance/app/sdk/control-provenance/page.tsx @@ -1,15 +1,12 @@ 'use client' import { useState, useEffect } from 'react' -import { - Shield, BookOpen, ExternalLink, CheckCircle2, AlertTriangle, - Lock, Scale, FileText, Eye, ArrowLeft, -} from 'lucide-react' +import { FileText, Shield } from 'lucide-react' import Link from 'next/link' - -// ============================================================================= -// TYPES -// ============================================================================= +import { PROVENANCE_SECTIONS } from './_components/provenance-data' +import { MarkdownRenderer } from './_components/ProvenanceHelpers' +import { LicenseMatrix } from './_components/LicenseMatrix' +import { SourceRegistry } from './_components/SourceRegistry' interface LicenseInfo { license_id: string @@ -40,413 +37,6 @@ interface SourceInfo { 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([]) const [sources, setSources] = useState([]) @@ -485,10 +75,7 @@ export default function ControlProvenancePage() { Dokumentation der unabhaengigen Herkunft aller Security Controls — rechtssicherer Nachweis

    - + Zur Control Library @@ -516,26 +103,19 @@ export default function ControlProvenancePage() {

    Live-Daten

    - - + {['license-matrix', 'source-registry'].map(id => ( + + ))}
    @@ -543,7 +123,6 @@ export default function ControlProvenancePage() { {/* Right: Content */}
    - {/* Static documentation sections */} {currentSection && (

    {currentSection.title}

    @@ -552,101 +131,11 @@ export default function ControlProvenancePage() {
    )} - - {/* License Matrix (live data) */} {activeSection === 'license-matrix' && ( -
    -

    Lizenz-Matrix

    -

    - Uebersicht aller Lizenzen mit ihren erlaubten Nutzungsarten. -

    - {loading ? ( -
    - ) : ( -
    - - - - - - - - - - - - {licenses.map(lic => ( - - - - - - - - ))} - -
    LizenzKommerziellAI-TrainingTDM (§44b)Loeschpflicht
    -
    {lic.license_id}
    -
    {lic.name}
    -
    - - - - - - - {lic.deletion_required ? ( - Ja - ) : ( - Nein - )} -
    -
    - )} -
    + )} - - {/* Source Registry (live data) */} {activeSection === 'source-registry' && ( -
    -

    Quellenregister

    -

    - Alle registrierten Quellen mit ihren Berechtigungen. -

    - {loading ? ( -
    - ) : ( -
    - {sources.map(src => ( -
    -
    -
    -

    {src.title}

    -

    {src.publisher} — {src.license_name}

    -
    - {src.url && ( - - - Quelle - - )} -
    -
    - - - - -
    -
    - ))} -
    - )} -
    + )}
    @@ -654,86 +143,3 @@ export default function ControlProvenancePage() {
    ) } - -// ============================================================================= -// HELPER COMPONENTS -// ============================================================================= - -function UsageBadge({ value }: { value: string }) { - const config: Record = { - 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 {c.label} -} - -function PermBadge({ label, allowed }: { label: string; allowed: boolean }) { - return ( -
    - {allowed ? ( - - ) : ( - - )} - {label} -
    - ) -} - -function MarkdownRenderer({ content }: { content: string }) { - let html = content - .replace(/&/g, '&') - .replace(//g, '>') - - // Code blocks - html = html.replace( - /^```[\w]*\n([\s\S]*?)^```$/gm, - (_m, code: string) => `
    ${code.trimEnd()}
    ` - ) - - // 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) => - `${c.trim()}` - ).join('') - const rows = body.trim().split('\n').map((row: string) => { - const tds = row.split('|').filter((c: string) => c.trim()).map((c: string) => - `${c.trim()}` - ).join('') - return `${tds}` - }).join('') - return `${ths}${rows}
    ` - } - ) - - // Headers - html = html.replace(/^### (.+)$/gm, '

    $1

    ') - html = html.replace(/^## (.+)$/gm, '

    $1

    ') - - // Bold - html = html.replace(/\*\*(.+?)\*\*/g, '$1') - - // Inline code - html = html.replace(/`([^`]+)`/g, '$1') - - // Lists - html = html.replace(/^- (.+)$/gm, '
  • $1
  • ') - html = html.replace(/((?:]*>.*<\/li>\n?)+)/g, '
      $1
    ') - - // Numbered lists - html = html.replace(/^(\d+)\. (.+)$/gm, '
  • $2
  • ') - - // Paragraphs - html = html.replace(/^(?!<[hultdp]|$)(.+)$/gm, '

    $1

    ') - - return
    -} diff --git a/admin-compliance/app/sdk/iace/[projectId]/verification/_components/CompleteModal.tsx b/admin-compliance/app/sdk/iace/[projectId]/verification/_components/CompleteModal.tsx new file mode 100644 index 0000000..ae9994d --- /dev/null +++ b/admin-compliance/app/sdk/iace/[projectId]/verification/_components/CompleteModal.tsx @@ -0,0 +1,61 @@ +'use client' + +import { useState } from 'react' +import type { VerificationItem } from './verification-types' + +export function CompleteModal({ + item, onSubmit, onClose, +}: { + item: VerificationItem + onSubmit: (id: string, result: string, passed: boolean) => void + onClose: () => void +}) { + const [result, setResult] = useState('') + const [passed, setPassed] = useState(true) + + return ( +
    +
    +

    + Verifikation abschliessen: {item.title} +

    +
    +
    + +