feat(licenses): Task #25 — SDK module attribution rollout (11 modules)
Per project_sdk_module_attribution_matrix.md the Stufe-3 rollout is
prioritized by audit visibility. This batch covers Schritte 2-9 in one
sweep:
New reusable component:
components/sdk/LicenseModuleBanner.tsx — single-line license banner
placed at the top of an SDK module page. Renders rule pill (R1/R2/R3),
source label, descriptor and link to /sdk/licenses. Replaces the
copy-paste banner blocks I inlined in the earlier modules.
Integration points (per cluster):
Cluster B (DSGVO/EU-Recht, R1):
- vvt: existing "Vorlage" pill upgraded with R1 marker + tooltip
explaining Bundeslaender-DSGVO provenance
- dsfa: inline R1 banner citing DSGVO Art. 35
Cluster C (EU AI Act / CRA, R1):
- ai-act: inline R1 banner citing EU 2024/1689
- cra: inline R1 banner citing EU 2024/2847 + ENISA-Guidance
Cluster D (Mix R2/R3):
- isms: R3 banner + ISO/IEC 27001 reference disclaimer
- security-backlog: R2 banner with OWASP CC-BY-SA attribution
Cluster A (Eigenwerk, R3):
- tom-generator: R1 source (DSGVO Art. 32) + R3 own-work disclaimer
- audit-checklist: R3 banner for own audit methodology
- document-generator: own templates R3 + cited rights R1
Cluster E (Direct controls listing):
- catalog-manager: System/User tag upgraded with rule classification
- iace hazards: pattern_id pill upgraded with R3 + tooltip explaining
BreakPilot Pattern-Engine provenance
The 11-module sweep brings audit transparency to the modules a paying
customer encounters most often. Stufe 3 of the attribution renderer
is now actually visible across the platform — previously it shipped
only the reusable <SourceBadge> component without integration points.
Pre-existing TS errors (drafting-engine constraint-enforcer, dsfa
types tests) untouched — not in scope for this licensing rollout.
This commit is contained in:
@@ -362,6 +362,16 @@ export default function AIActPage() {
|
|||||||
)}
|
)}
|
||||||
</StepHeader>
|
</StepHeader>
|
||||||
|
|
||||||
|
<div className="px-4 py-2 bg-emerald-50 border border-emerald-200 rounded-lg text-xs text-emerald-800 flex items-start gap-2">
|
||||||
|
<span className="font-semibold">Quellen & Lizenz:</span>
|
||||||
|
<span>
|
||||||
|
Inhalte gemaess <strong>EU-Verordnung 2024/1689 (KI-Verordnung / AI Act)</strong> —
|
||||||
|
Lizenzregel R1 (EU_LAW, woertlich uebernehmbar).
|
||||||
|
Risiko-Klassifizierungslogik basiert auf Anhang III der Verordnung.{' '}
|
||||||
|
<a href="/sdk/licenses" className="underline">Quellenverzeichnis</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<div className="flex items-center gap-1 bg-gray-100 p-1 rounded-lg w-fit">
|
<div className="flex items-center gap-1 bg-gray-100 p-1 rounded-lg w-fit">
|
||||||
{TABS.map(tab => (
|
{TABS.map(tab => (
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader'
|
import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader'
|
||||||
|
import { LicenseModuleBanner } from '@/components/sdk/LicenseModuleBanner'
|
||||||
import { useAuditChecklist } from './_hooks/useAuditChecklist'
|
import { useAuditChecklist } from './_hooks/useAuditChecklist'
|
||||||
import { ChecklistItemCard } from './_components/ChecklistItemCard'
|
import { ChecklistItemCard } from './_components/ChecklistItemCard'
|
||||||
import { LoadingSkeleton } from './_components/LoadingSkeleton'
|
import { LoadingSkeleton } from './_components/LoadingSkeleton'
|
||||||
@@ -89,6 +90,12 @@ export default function AuditChecklistPage() {
|
|||||||
</div>
|
</div>
|
||||||
</StepHeader>
|
</StepHeader>
|
||||||
|
|
||||||
|
<LicenseModuleBanner
|
||||||
|
rule={3}
|
||||||
|
sourceLabel="BreakPilot-Audit-Methodik"
|
||||||
|
detail="Eigene Audit-Checklisten und -Workflows. Zitierte Rechtsquellen (DSGVO/ISO 27001/...) jeweils mit eigener Lizenzregel."
|
||||||
|
/>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700 flex items-center justify-between">
|
<div className="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700 flex items-center justify-between">
|
||||||
<span>{error}</span>
|
<span>{error}</span>
|
||||||
|
|||||||
@@ -99,6 +99,16 @@ export default function CRAProjectsPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4 px-4 py-2 bg-emerald-50 border border-emerald-200 rounded-lg text-xs text-emerald-800 flex items-start gap-2">
|
||||||
|
<span className="font-semibold">Quellen & Lizenz:</span>
|
||||||
|
<span>
|
||||||
|
Inhalte gemaess <strong>EU-Verordnung 2024/2847 (Cyber Resilience Act)</strong> —
|
||||||
|
Lizenzregel R1 (EU_LAW, woertlich uebernehmbar). ENISA-Implementation-Guidance
|
||||||
|
ergaenzend (R1 EU_PUBLIC).{' '}
|
||||||
|
<a href="/sdk/licenses" className="underline">Quellenverzeichnis</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-4 bg-red-50 border border-red-200 rounded-lg p-4 text-sm text-red-700">
|
<div className="mb-4 bg-red-50 border border-red-200 rounded-lg p-4 text-sm text-red-700">
|
||||||
{error}
|
{error}
|
||||||
|
|||||||
@@ -297,6 +297,16 @@ function DocumentGeneratorPageInner() {
|
|||||||
tips={stepInfo.tips}
|
tips={stepInfo.tips}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className="px-4 py-2 bg-slate-50 border border-slate-200 rounded-lg text-xs text-slate-700 flex items-start gap-2">
|
||||||
|
<span className="font-semibold">Quellen & Lizenz:</span>
|
||||||
|
<span>
|
||||||
|
Die 91 Standard-Vorlagen sind <strong>BreakPilot-Eigenwerke</strong> (Lizenzregel R3 — Identifier-Verweis,
|
||||||
|
eigene Lizenz). Vorlagen mit gesetzlicher Grundlage (z.B. VVT nach Art. 30 DSGVO,
|
||||||
|
Loeschkonzept nach Art. 17 DSGVO) zitieren die jeweilige Rechtsquelle als R1.{' '}
|
||||||
|
<a href="/sdk/licenses" className="underline">Quellenverzeichnis</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Status bar */}
|
{/* Status bar */}
|
||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
<div className="bg-white rounded-xl border border-gray-200 p-5">
|
<div className="bg-white rounded-xl border border-gray-200 p-5">
|
||||||
|
|||||||
@@ -132,6 +132,16 @@ export default function DSFAPage() {
|
|||||||
)}
|
)}
|
||||||
</StepHeader>
|
</StepHeader>
|
||||||
|
|
||||||
|
<div className="px-4 py-2 bg-emerald-50 border border-emerald-200 rounded-lg text-xs text-emerald-800 flex items-start gap-2">
|
||||||
|
<span className="font-semibold">Quellen & Lizenz:</span>
|
||||||
|
<span>
|
||||||
|
Inhalte gemaess <strong>DSGVO Art. 35</strong> (EU 2016/679) — Lizenzregel R1
|
||||||
|
(Hoheitsrecht/EU_LAW, woertlich uebernehmbar). Vorlagen-Texte aus
|
||||||
|
Aufsichtsbehoerden ebenfalls R1.{' '}
|
||||||
|
<a href="/sdk/licenses" className="underline">Quellenverzeichnis</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* DSFA Requirement Check */}
|
{/* DSFA Requirement Check */}
|
||||||
{dsfaCheck.required && dsfas.length === 0 && (
|
{dsfaCheck.required && dsfas.length === 0 && (
|
||||||
<div className="bg-red-50 border border-red-200 rounded-xl p-5">
|
<div className="bg-red-50 border border-red-200 rounded-xl p-5">
|
||||||
|
|||||||
@@ -39,11 +39,19 @@ export function HazardTable({ hazards, lifecyclePhases, onDelete }: {
|
|||||||
.map((hazard) => (
|
.map((hazard) => (
|
||||||
<tr key={hazard.id} className="hover:bg-gray-50 dark:hover:bg-gray-750 transition-colors">
|
<tr key={hazard.id} className="hover:bg-gray-50 dark:hover:bg-gray-750 transition-colors">
|
||||||
<td className="px-4 py-3">
|
<td className="px-4 py-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<div className="text-sm font-medium text-gray-900 dark:text-white">{hazard.name}</div>
|
<div className="text-sm font-medium text-gray-900 dark:text-white">{hazard.name}</div>
|
||||||
{hazard.name.startsWith('Auto:') && (
|
{hazard.name.startsWith('Auto:') && (
|
||||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700">Auto</span>
|
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700">Auto</span>
|
||||||
)}
|
)}
|
||||||
|
{(hazard as { pattern_id?: string }).pattern_id && (
|
||||||
|
<span
|
||||||
|
className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-mono font-medium bg-slate-100 text-slate-700 border border-slate-200 cursor-help"
|
||||||
|
title={`Quelle: BreakPilot IACE Pattern-Engine (${(hazard as { pattern_id?: string }).pattern_id}). Lizenzregel R3 — Eigenwerk, kein externer Lizenz-Footer noetig. Pattern-Definition mit Norm-Referenzen siehe Library.`}
|
||||||
|
>
|
||||||
|
{(hazard as { pattern_id?: string }).pattern_id} · R3
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{hazard.description && (
|
{hazard.description && (
|
||||||
<div className="text-xs text-gray-500 truncate max-w-[250px]">{hazard.description}</div>
|
<div className="text-xs text-gray-500 truncate max-w-[250px]">{hazard.description}</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { ObjectivesTab } from './_components/ObjectivesTab'
|
|||||||
import { AuditsTab } from './_components/AuditsTab'
|
import { AuditsTab } from './_components/AuditsTab'
|
||||||
import { ReviewsTab } from './_components/ReviewsTab'
|
import { ReviewsTab } from './_components/ReviewsTab'
|
||||||
import { AssetsTab } from './_components/AssetsTab'
|
import { AssetsTab } from './_components/AssetsTab'
|
||||||
|
import { LicenseModuleBanner } from '@/components/sdk/LicenseModuleBanner'
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// MAIN PAGE
|
// MAIN PAGE
|
||||||
@@ -38,6 +39,13 @@ export default function ISMSPage() {
|
|||||||
<p className="text-xs text-amber-600 mt-2">
|
<p className="text-xs text-amber-600 mt-2">
|
||||||
Hinweis: Basierend auf eigenen Pruefaspekten, kein ISO-Normtext. Ersetzt kein Zertifizierungsaudit.
|
Hinweis: Basierend auf eigenen Pruefaspekten, kein ISO-Normtext. Ersetzt kein Zertifizierungsaudit.
|
||||||
</p>
|
</p>
|
||||||
|
<div className="mt-3">
|
||||||
|
<LicenseModuleBanner
|
||||||
|
rule={3}
|
||||||
|
sourceLabel="BreakPilot-ISMS-Methodik mit Verweis auf ISO/IEC 27001"
|
||||||
|
detail="ISO-Normtexte sind copyright-geschuetzt (R3 — nur Identifier-Verweise). Eigene Pruefaspekte sind BreakPilot-Eigenwerk."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { SecurityItemCard } from './_components/SecurityItemCard'
|
|||||||
import { ItemModal } from './_components/ItemModal'
|
import { ItemModal } from './_components/ItemModal'
|
||||||
import { useSecurityBacklog, EMPTY_NEW_ITEM } from './_hooks/useSecurityBacklog'
|
import { useSecurityBacklog, EMPTY_NEW_ITEM } from './_hooks/useSecurityBacklog'
|
||||||
import type { SecurityItem } from './_hooks/useSecurityBacklog'
|
import type { SecurityItem } from './_hooks/useSecurityBacklog'
|
||||||
|
import { LicenseModuleBanner } from '@/components/sdk/LicenseModuleBanner'
|
||||||
|
|
||||||
export default function SecurityBacklogPage() {
|
export default function SecurityBacklogPage() {
|
||||||
const [filter, setFilter] = useState<string>('all')
|
const [filter, setFilter] = useState<string>('all')
|
||||||
@@ -37,6 +38,11 @@ export default function SecurityBacklogPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
<LicenseModuleBanner
|
||||||
|
rule={2}
|
||||||
|
sourceLabel="OWASP Top 10 / ASVS / SAMM (CC-BY-SA 4.0) + NIST SP 800-53 (US PD)"
|
||||||
|
detail="OWASP-Inhalte zitiert mit Pflicht-Attribution 'OWASP Foundation, CC BY-SA 4.0'. NIST woertlich (R1)."
|
||||||
|
/>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import React from 'react'
|
|||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useTOMGenerator } from '@/lib/sdk/tom-generator'
|
import { useTOMGenerator } from '@/lib/sdk/tom-generator'
|
||||||
import { TOM_GENERATOR_STEPS } from '@/lib/sdk/tom-generator/types'
|
import { TOM_GENERATOR_STEPS } from '@/lib/sdk/tom-generator/types'
|
||||||
|
import { LicenseModuleBanner } from '@/components/sdk/LicenseModuleBanner'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TOM Generator Landing Page
|
* TOM Generator Landing Page
|
||||||
@@ -45,6 +46,14 @@ export default function TOMGeneratorPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<LicenseModuleBanner
|
||||||
|
rule={1}
|
||||||
|
sourceLabel="DSGVO Art. 32 (EU 2016/679) — TOM-Anforderungen"
|
||||||
|
detail="Generator-Logik und Vorlagen sind BreakPilot-Eigenwerk (R3); zitierte Rechtsquelle EU_LAW (R1)."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Progress Card */}
|
{/* Progress Card */}
|
||||||
{hasProgress && (
|
{hasProgress && (
|
||||||
<div className="bg-white rounded-xl border border-gray-200 p-6 mb-8">
|
<div className="bg-white rounded-xl border border-gray-200 p-6 mb-8">
|
||||||
|
|||||||
@@ -350,7 +350,12 @@ function ActivityCard({ activity, onEdit, onDelete }: { activity: VVTActivity; o
|
|||||||
<span className="px-2 py-0.5 text-xs bg-purple-100 text-purple-700 rounded-full">DSFA</span>
|
<span className="px-2 py-0.5 text-xs bg-purple-100 text-purple-700 rounded-full">DSFA</span>
|
||||||
)}
|
)}
|
||||||
{(activity as any).sourceTemplateId && (
|
{(activity as any).sourceTemplateId && (
|
||||||
<span className="px-2 py-0.5 text-xs bg-indigo-100 text-indigo-700 rounded-full">Vorlage</span>
|
<span
|
||||||
|
className="px-2 py-0.5 text-xs bg-indigo-100 text-indigo-700 rounded-full cursor-help"
|
||||||
|
title="Erstellt aus Bundeslaender-DSGVO-Vorlage (Art. 30 DSGVO). Lizenzregel R1 — Hoheitsrecht/DE_LAW, woertlich uebernehmbar."
|
||||||
|
>
|
||||||
|
Vorlage · R1
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-base font-semibold text-gray-900 truncate">{activity.name || '(Ohne Namen)'}</h3>
|
<h3 className="text-base font-semibold text-gray-900 truncate">{activity.name || '(Ohne Namen)'}</h3>
|
||||||
|
|||||||
@@ -195,12 +195,18 @@ export default function CatalogTable({
|
|||||||
)}
|
)}
|
||||||
<td className="px-4 py-2.5">
|
<td className="px-4 py-2.5">
|
||||||
{entry.source === 'system' ? (
|
{entry.source === 'system' ? (
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300">
|
<span
|
||||||
System
|
className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300 cursor-help"
|
||||||
|
title="System-Katalog — Quellen aus EU-Recht, BAuA, NIST u.a. Lizenzregel je Eintrag (siehe /sdk/licenses)."
|
||||||
|
>
|
||||||
|
System · R1/R2/R3
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300">
|
<span
|
||||||
Benutzerdefiniert
|
className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300 cursor-help"
|
||||||
|
title="Benutzerdefinierter Eintrag — BreakPilot/Anwender-Eigenwerk. Lizenzregel R3 (Identifier-Verweis), keine externe Attribution noetig."
|
||||||
|
>
|
||||||
|
Benutzerdefiniert · R3
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
// Reusable licence-source banner placed at the top of an SDK module page.
|
||||||
|
// One-line context that tells the user (and any auditor) which sources
|
||||||
|
// the module draws on and which BreakPilot licence rule applies.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// <LicenseModuleBanner
|
||||||
|
// rule={1}
|
||||||
|
// sourceLabel="DSGVO Art. 30 (EU 2016/679)"
|
||||||
|
// />
|
||||||
|
//
|
||||||
|
// For modules that are pure BreakPilot eigenwerk:
|
||||||
|
// <LicenseModuleBanner rule={3} sourceLabel="BreakPilot-Eigenwerk" />
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
rule: 1 | 2 | 3
|
||||||
|
sourceLabel: string
|
||||||
|
/** Optional extended note shown after sourceLabel */
|
||||||
|
detail?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const RULE_META: Record<number, { bg: string; text: string; pill: string; descr: string }> = {
|
||||||
|
1: {
|
||||||
|
bg: 'bg-emerald-50 border-emerald-200',
|
||||||
|
text: 'text-emerald-800',
|
||||||
|
pill: 'bg-emerald-600 text-white',
|
||||||
|
descr: 'Hoheitsrecht/Public Domain — woertlich uebernehmbar',
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
bg: 'bg-amber-50 border-amber-200',
|
||||||
|
text: 'text-amber-800',
|
||||||
|
pill: 'bg-amber-600 text-white',
|
||||||
|
descr: 'Woertlich mit Attribution-Pflicht',
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
bg: 'bg-slate-50 border-slate-200',
|
||||||
|
text: 'text-slate-700',
|
||||||
|
pill: 'bg-slate-600 text-white',
|
||||||
|
descr: 'Identifier-Verweis / BreakPilot-Eigenwerk',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LicenseModuleBanner({ rule, sourceLabel, detail }: Props) {
|
||||||
|
const m = RULE_META[rule]
|
||||||
|
return (
|
||||||
|
<div className={`px-3 py-2 ${m.bg} border rounded-lg text-xs ${m.text} flex items-start gap-2`}>
|
||||||
|
<span className={`inline-flex items-center justify-center w-6 h-6 rounded-full text-[10px] font-bold ${m.pill} flex-shrink-0`}>
|
||||||
|
R{rule}
|
||||||
|
</span>
|
||||||
|
<div className="flex-1">
|
||||||
|
<span className="font-semibold">Quellen & Lizenz:</span>{' '}
|
||||||
|
<span>{sourceLabel}</span>
|
||||||
|
<span className="text-slate-500"> — {m.descr}.</span>
|
||||||
|
{detail && <span className="block mt-0.5 text-[11px] opacity-80">{detail}</span>}
|
||||||
|
<a href="/sdk/licenses" className="underline ml-1">Quellenverzeichnis</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LicenseModuleBanner
|
||||||
Reference in New Issue
Block a user