feat(ucca): Pflichtendatenbank v2 (325 Obligations), Trigger-Engine, TOM-Control-Mapping
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 32s
CI / test-python-backend-compliance (push) Successful in 29s
CI / test-python-document-crawler (push) Successful in 20s
CI / test-python-dsms-gateway (push) Successful in 18s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 32s
CI / test-python-backend-compliance (push) Successful in 29s
CI / test-python-document-crawler (push) Successful in 20s
CI / test-python-dsms-gateway (push) Successful in 18s
- 9 Regulation-JSON-Dateien (DSGVO 80, AI Act 60, NIS2 40, BDSG 30, TTDSG 20, DSA 35, Data Act 25, EU-Maschinen 15, DORA 20) - Condition-Tree-Engine fuer automatische Pflichtenselektion (all_of/any_of, 80+ Field-Paths) - Generischer JSONRegulationModule-Loader mit YAML-Fallback - Bidirektionales TOM-Control-Mapping (291 Obligation→Control, 92 Control→Obligation) - Gap-Analyse-Engine (Compliance-%, Priority Actions, Domain Breakdown) - ScopeDecision→UnifiedFacts Bridge fuer Auto-Profiling - 4 neue API-Endpoints (assess-from-scope, tom-controls, gap-analysis, reverse-lookup) - Frontend: Auto-Profiling Button, Regulation-Filter Chips, TOM-Panel, Gap-Analyse-View - 18 Unit Tests (Condition Engine, v2 Loader, TOM Mapper) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
const SDK_BASE_URL = process.env.SDK_BASE_URL || 'http://localhost:8085'
|
||||
|
||||
async function proxyRequest(request: NextRequest, method: string) {
|
||||
try {
|
||||
const pathSegments = request.nextUrl.pathname.replace('/api/sdk/v1/ucca/obligations/', '')
|
||||
const targetUrl = `${SDK_BASE_URL}/sdk/v1/ucca/obligations/${pathSegments}${request.nextUrl.search}`
|
||||
|
||||
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
|
||||
const tenantId = request.headers.get('X-Tenant-ID')
|
||||
if (tenantId) headers['X-Tenant-ID'] = tenantId
|
||||
|
||||
const fetchOptions: RequestInit = { method, headers }
|
||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
||||
fetchOptions.body = await request.text()
|
||||
}
|
||||
|
||||
const response = await fetch(targetUrl, fetchOptions)
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
return NextResponse.json({ error: 'SDK backend error', details: errorText }, { status: response.status })
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return NextResponse.json(data)
|
||||
} catch (error) {
|
||||
console.error('UCCA obligations proxy error:', error)
|
||||
return NextResponse.json({ error: 'Failed to connect to SDK backend' }, { status: 503 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) { return proxyRequest(request, 'GET') }
|
||||
export async function POST(request: NextRequest) { return proxyRequest(request, 'POST') }
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import React, { useState, useEffect, useCallback } from 'react'
|
||||
import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader'
|
||||
import TOMControlPanel from '@/components/sdk/obligations/TOMControlPanel'
|
||||
import GapAnalysisView from '@/components/sdk/obligations/GapAnalysisView'
|
||||
|
||||
// =============================================================================
|
||||
// Types
|
||||
@@ -178,7 +180,7 @@ function ObligationModal({
|
||||
onChange={e => update('source', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
>
|
||||
{['DSGVO', 'AI Act', 'NIS2', 'BDSG', 'TTDSG', 'Sonstig'].map(s => (
|
||||
{['DSGVO', 'AI Act', 'NIS2', 'BDSG', 'TTDSG', 'DSA', 'Data Act', 'DORA', 'EU-Maschinen', 'Sonstig'].map(s => (
|
||||
<option key={s}>{s}</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -426,6 +428,7 @@ function ObligationCard({
|
||||
onDetails: () => void
|
||||
}) {
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [showTOM, setShowTOM] = useState(false)
|
||||
|
||||
const daysUntil = obligation.deadline
|
||||
? Math.ceil((new Date(obligation.deadline).getTime() - Date.now()) / 86400000)
|
||||
@@ -480,6 +483,13 @@ function ObligationCard({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2" onClick={e => e.stopPropagation()}>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); setShowTOM(v => !v) }}
|
||||
className="px-2 py-1 text-purple-600 hover:bg-purple-50 rounded-lg transition-colors"
|
||||
title="TOM Controls anzeigen"
|
||||
>
|
||||
TOM
|
||||
</button>
|
||||
<button
|
||||
onClick={onDetails}
|
||||
className="text-purple-600 hover:text-purple-700 font-medium"
|
||||
@@ -497,6 +507,12 @@ function ObligationCard({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showTOM && (
|
||||
<div className="mt-3" onClick={e => e.stopPropagation()}>
|
||||
<TOMControlPanel obligationId={obligation.id} onClose={() => setShowTOM(false)} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -505,16 +521,42 @@ function ObligationCard({
|
||||
// Main Page
|
||||
// =============================================================================
|
||||
|
||||
function mapPriority(p: string): 'critical' | 'high' | 'medium' | 'low' {
|
||||
const map: Record<string, 'critical' | 'high' | 'medium' | 'low'> = {
|
||||
kritisch: 'critical', hoch: 'high', mittel: 'medium', niedrig: 'low',
|
||||
critical: 'critical', high: 'high', medium: 'medium', low: 'low',
|
||||
}
|
||||
return map[p?.toLowerCase()] || 'medium'
|
||||
}
|
||||
|
||||
const REGULATION_CHIPS = [
|
||||
{ key: 'all', label: 'Alle' },
|
||||
{ key: 'DSGVO', label: 'DSGVO' },
|
||||
{ key: 'AI Act', label: 'AI Act' },
|
||||
{ key: 'NIS2', label: 'NIS2' },
|
||||
{ key: 'BDSG', label: 'BDSG' },
|
||||
{ key: 'TTDSG', label: 'TTDSG' },
|
||||
{ key: 'DSA', label: 'DSA' },
|
||||
{ key: 'Data Act', label: 'Data Act' },
|
||||
{ key: 'DORA', label: 'DORA' },
|
||||
{ key: 'EU-Maschinen', label: 'EU-Maschinen' },
|
||||
]
|
||||
|
||||
const UCCA_API = '/api/sdk/v1/ucca/obligations'
|
||||
|
||||
export default function ObligationsPage() {
|
||||
const [obligations, setObligations] = useState<Obligation[]>([])
|
||||
const [stats, setStats] = useState<ObligationStats | null>(null)
|
||||
const [filter, setFilter] = useState('all')
|
||||
const [regulationFilter, setRegulationFilter] = useState('all')
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [editObligation, setEditObligation] = useState<Obligation | null>(null)
|
||||
const [detailObligation, setDetailObligation] = useState<Obligation | null>(null)
|
||||
const [showGapAnalysis, setShowGapAnalysis] = useState(false)
|
||||
const [profiling, setProfiling] = useState(false)
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
setLoading(true)
|
||||
@@ -621,10 +663,68 @@ export default function ObligationsPage() {
|
||||
fetch(`${API}/stats`).then(r => r.json()).then(setStats).catch(() => {})
|
||||
}
|
||||
|
||||
const handleAutoProfiling = async () => {
|
||||
setProfiling(true)
|
||||
setError(null)
|
||||
try {
|
||||
const res = await fetch(`${UCCA_API}/assess-from-scope`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
employee_count: 50,
|
||||
industry: 'technology',
|
||||
processes_personal_data: true,
|
||||
is_controller: true,
|
||||
uses_processors: true,
|
||||
processes_special_categories: false,
|
||||
cross_border_transfer: true,
|
||||
uses_ai: true,
|
||||
determined_level: 'L2',
|
||||
}),
|
||||
})
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||
const data = await res.json()
|
||||
if (data.obligations?.length > 0) {
|
||||
// Merge auto-profiled obligations into the view
|
||||
const autoObls: Obligation[] = data.obligations.map((o: Record<string, unknown>) => ({
|
||||
id: o.id as string,
|
||||
title: o.title as string,
|
||||
description: (o.description as string) || '',
|
||||
source: (o.regulation_id as string || '').toUpperCase(),
|
||||
source_article: '',
|
||||
deadline: null,
|
||||
status: 'pending' as const,
|
||||
priority: mapPriority(o.priority as string),
|
||||
responsible: (o.responsible as string) || '',
|
||||
linked_systems: [],
|
||||
rule_code: 'auto-profiled',
|
||||
}))
|
||||
setObligations(prev => {
|
||||
const existingIds = new Set(prev.map(p => p.id))
|
||||
const newOnes = autoObls.filter(a => !existingIds.has(a.id))
|
||||
return [...prev, ...newOnes]
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : 'Auto-Profiling fehlgeschlagen')
|
||||
} finally {
|
||||
setProfiling(false)
|
||||
}
|
||||
}
|
||||
|
||||
const stepInfo = STEP_EXPLANATIONS['obligations']
|
||||
|
||||
const filteredObligations = obligations.filter(o => {
|
||||
if (filter === 'ai') return o.source.toLowerCase().includes('ai')
|
||||
// Status/priority filter
|
||||
if (filter === 'ai') {
|
||||
if (!o.source.toLowerCase().includes('ai')) return false
|
||||
}
|
||||
// Regulation filter
|
||||
if (regulationFilter !== 'all') {
|
||||
const src = o.source?.toLowerCase() || ''
|
||||
const key = regulationFilter.toLowerCase()
|
||||
if (!src.includes(key)) return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -679,15 +779,38 @@ export default function ObligationsPage() {
|
||||
explanation={stepInfo?.explanation || ''}
|
||||
tips={stepInfo?.tips || []}
|
||||
>
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors text-sm"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||
</svg>
|
||||
Pflicht hinzufuegen
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={handleAutoProfiling}
|
||||
disabled={profiling}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-white border border-purple-300 text-purple-700 rounded-lg hover:bg-purple-50 transition-colors text-sm disabled:opacity-50"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
{profiling ? 'Profiling...' : 'Auto-Profiling'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowGapAnalysis(v => !v)}
|
||||
className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-colors text-sm ${
|
||||
showGapAnalysis ? 'bg-purple-100 text-purple-700' : 'bg-white border border-gray-300 text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
Gap-Analyse
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowModal(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors text-sm"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||
</svg>
|
||||
Pflicht hinzufuegen
|
||||
</button>
|
||||
</div>
|
||||
</StepHeader>
|
||||
|
||||
{/* Error */}
|
||||
@@ -725,7 +848,28 @@ export default function ObligationsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Search + Filter */}
|
||||
{/* Gap Analysis View */}
|
||||
{showGapAnalysis && (
|
||||
<GapAnalysisView />
|
||||
)}
|
||||
|
||||
{/* Regulation Filter Chips */}
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<span className="text-xs text-gray-500 mr-1">Regulation:</span>
|
||||
{REGULATION_CHIPS.map(r => (
|
||||
<button
|
||||
key={r.key}
|
||||
onClick={() => setRegulationFilter(r.key)}
|
||||
className={`px-3 py-1 text-xs rounded-full transition-colors ${
|
||||
regulationFilter === r.key ? 'bg-purple-600 text-white' : 'bg-purple-50 text-purple-700 hover:bg-purple-100'
|
||||
}`}
|
||||
>
|
||||
{r.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Search + Status Filter */}
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-3">
|
||||
<input
|
||||
type="text"
|
||||
@@ -735,7 +879,7 @@ export default function ObligationsPage() {
|
||||
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500"
|
||||
/>
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{['all', 'overdue', 'pending', 'in-progress', 'completed', 'critical', 'ai'].map(f => (
|
||||
{['all', 'overdue', 'pending', 'in-progress', 'completed', 'critical'].map(f => (
|
||||
<button
|
||||
key={f}
|
||||
onClick={() => setFilter(f)}
|
||||
@@ -743,7 +887,7 @@ export default function ObligationsPage() {
|
||||
filter === f ? 'bg-purple-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
||||
}`}
|
||||
>
|
||||
{f === 'all' ? 'Alle' : f === 'in-progress' ? 'In Bearbeitung' : f === 'overdue' ? 'Ueberfaellig' : f === 'pending' ? 'Ausstehend' : f === 'completed' ? 'Abgeschlossen' : f === 'critical' ? 'Kritisch' : 'AI Act'}
|
||||
{f === 'all' ? 'Alle' : f === 'in-progress' ? 'In Bearbeitung' : f === 'overdue' ? 'Ueberfaellig' : f === 'pending' ? 'Ausstehend' : f === 'completed' ? 'Abgeschlossen' : 'Kritisch'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
226
admin-compliance/components/sdk/obligations/GapAnalysisView.tsx
Normal file
226
admin-compliance/components/sdk/obligations/GapAnalysisView.tsx
Normal file
@@ -0,0 +1,226 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
|
||||
interface GapItem {
|
||||
control_id: string
|
||||
control_title: string
|
||||
control_domain: string
|
||||
status: string
|
||||
priority: string
|
||||
obligation_ids: string[]
|
||||
required_by_count: number
|
||||
}
|
||||
|
||||
interface PriorityAction {
|
||||
rank: number
|
||||
action: string
|
||||
control_ids: string[]
|
||||
impact: string
|
||||
effort: string
|
||||
}
|
||||
|
||||
interface DomainGap {
|
||||
domain_id: string
|
||||
domain_name: string
|
||||
total_controls: number
|
||||
implemented_controls: number
|
||||
compliance_percent: number
|
||||
}
|
||||
|
||||
interface GapAnalysisResult {
|
||||
compliance_percent: number
|
||||
total_controls: number
|
||||
implemented_controls: number
|
||||
partial_controls: number
|
||||
missing_controls: number
|
||||
gaps: GapItem[]
|
||||
priority_actions: PriorityAction[]
|
||||
by_domain: Record<string, DomainGap>
|
||||
}
|
||||
|
||||
const UCCA_API = '/api/sdk/v1/ucca/obligations'
|
||||
|
||||
const DOMAIN_LABELS: Record<string, string> = {
|
||||
GOV: 'Governance', HR: 'Human Resources', IAM: 'Identity & Access',
|
||||
AC: 'Access Control', CRYPTO: 'Kryptographie', LOG: 'Logging & Monitoring',
|
||||
SDLC: 'Softwareentwicklung', OPS: 'Betrieb', NET: 'Netzwerk',
|
||||
BCP: 'Business Continuity', VENDOR: 'Lieferanten', DATA: 'Datenschutz',
|
||||
}
|
||||
|
||||
const IMPACT_COLORS: Record<string, string> = {
|
||||
critical: 'text-red-700 bg-red-50',
|
||||
high: 'text-orange-700 bg-orange-50',
|
||||
medium: 'text-yellow-700 bg-yellow-50',
|
||||
low: 'text-green-700 bg-green-50',
|
||||
}
|
||||
|
||||
export default function GapAnalysisView() {
|
||||
const [result, setResult] = useState<GapAnalysisResult | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
const runAnalysis = async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
try {
|
||||
const res = await fetch(`${UCCA_API}/gap-analysis`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ control_status_map: {} }),
|
||||
})
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||
setResult(await res.json())
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : 'Analyse fehlgeschlagen')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-6 text-center">
|
||||
<div className="w-12 h-12 mx-auto bg-purple-50 rounded-full flex items-center justify-center mb-3">
|
||||
<svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-sm font-semibold text-gray-900">TOM Gap-Analyse</h3>
|
||||
<p className="text-xs text-gray-500 mt-1 mb-4">
|
||||
Vergleicht erforderliche TOM Controls mit dem aktuellen Implementierungsstatus.
|
||||
</p>
|
||||
{error && <p className="text-xs text-red-600 mb-3">{error}</p>}
|
||||
<button
|
||||
onClick={runAnalysis}
|
||||
disabled={loading}
|
||||
className="px-5 py-2 bg-purple-600 text-white text-sm rounded-lg hover:bg-purple-700 disabled:opacity-50"
|
||||
>
|
||||
{loading ? 'Analysiere...' : 'Gap-Analyse starten'}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const domains = Object.values(result.by_domain).sort((a, b) => a.compliance_percent - b.compliance_percent)
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Compliance Score */}
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-sm font-semibold text-gray-900">Compliance-Status</h3>
|
||||
<button
|
||||
onClick={runAnalysis}
|
||||
disabled={loading}
|
||||
className="text-xs text-purple-600 hover:text-purple-700"
|
||||
>
|
||||
{loading ? 'Aktualisiere...' : 'Aktualisieren'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex-shrink-0">
|
||||
<div className={`text-4xl font-bold ${result.compliance_percent >= 80 ? 'text-green-600' : result.compliance_percent >= 50 ? 'text-yellow-600' : 'text-red-600'}`}>
|
||||
{Math.round(result.compliance_percent)}%
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">Compliance</p>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="w-full bg-gray-200 rounded-full h-3">
|
||||
<div
|
||||
className={`h-3 rounded-full transition-all ${result.compliance_percent >= 80 ? 'bg-green-500' : result.compliance_percent >= 50 ? 'bg-yellow-500' : 'bg-red-500'}`}
|
||||
style={{ width: `${Math.min(result.compliance_percent, 100)}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between mt-2 text-xs text-gray-500">
|
||||
<span>{result.implemented_controls} implementiert</span>
|
||||
<span>{result.partial_controls} teilweise</span>
|
||||
<span>{result.missing_controls} fehlend</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Breakdown */}
|
||||
{domains.length > 0 && (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-5">
|
||||
<h4 className="text-sm font-semibold text-gray-900 mb-3">Nach Domaene</h4>
|
||||
<div className="space-y-2">
|
||||
{domains.map(d => (
|
||||
<div key={d.domain_id} className="flex items-center gap-3">
|
||||
<span className="text-xs text-gray-600 w-32 flex-shrink-0 truncate">
|
||||
{DOMAIN_LABELS[d.domain_id] || d.domain_id}
|
||||
</span>
|
||||
<div className="flex-1 bg-gray-100 rounded-full h-2">
|
||||
<div
|
||||
className={`h-2 rounded-full ${d.compliance_percent >= 80 ? 'bg-green-400' : d.compliance_percent >= 50 ? 'bg-yellow-400' : 'bg-red-400'}`}
|
||||
style={{ width: `${Math.min(d.compliance_percent, 100)}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xs text-gray-500 w-14 text-right">
|
||||
{d.implemented_controls}/{d.total_controls}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Priority Actions */}
|
||||
{result.priority_actions.length > 0 && (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-5">
|
||||
<h4 className="text-sm font-semibold text-gray-900 mb-3">Prioritaere Massnahmen</h4>
|
||||
<div className="space-y-2">
|
||||
{result.priority_actions.slice(0, 5).map(a => (
|
||||
<div key={a.rank} className="flex items-start gap-3 p-3 bg-gray-50 rounded-lg">
|
||||
<span className="text-xs font-bold text-purple-600 bg-purple-50 rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0">
|
||||
{a.rank}
|
||||
</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm text-gray-900">{a.action}</p>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className={`text-[10px] px-1.5 py-0.5 rounded ${IMPACT_COLORS[a.impact] || 'bg-gray-100 text-gray-600'}`}>
|
||||
{a.impact}
|
||||
</span>
|
||||
<span className="text-[10px] text-gray-400">
|
||||
Aufwand: {a.effort}
|
||||
</span>
|
||||
<span className="text-[10px] text-gray-400">
|
||||
{a.control_ids.length} Controls
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Gap List */}
|
||||
{result.gaps.length > 0 && (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-5">
|
||||
<h4 className="text-sm font-semibold text-gray-900 mb-3">
|
||||
Offene Gaps ({result.gaps.length})
|
||||
</h4>
|
||||
<div className="space-y-1 max-h-64 overflow-y-auto">
|
||||
{result.gaps.map(g => (
|
||||
<div key={g.control_id} className="flex items-center justify-between py-2 px-3 hover:bg-gray-50 rounded text-xs">
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="font-mono text-purple-600 flex-shrink-0">{g.control_id}</span>
|
||||
<span className="text-gray-700 truncate">{g.control_title}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-shrink-0">
|
||||
<span className={`px-1.5 py-0.5 rounded ${g.status === 'NOT_IMPLEMENTED' ? 'bg-red-50 text-red-600' : 'bg-yellow-50 text-yellow-600'}`}>
|
||||
{g.status === 'NOT_IMPLEMENTED' ? 'Fehlend' : 'Teilweise'}
|
||||
</span>
|
||||
<span className="text-gray-400">{g.required_by_count}x</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
105
admin-compliance/components/sdk/obligations/TOMControlPanel.tsx
Normal file
105
admin-compliance/components/sdk/obligations/TOMControlPanel.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
interface TOMControl {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
domain_id: string
|
||||
priority: string
|
||||
gdpr_articles: string[]
|
||||
}
|
||||
|
||||
interface TOMControlPanelProps {
|
||||
obligationId: string
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const UCCA_API = '/api/sdk/v1/ucca/obligations'
|
||||
|
||||
const DOMAIN_LABELS: Record<string, string> = {
|
||||
GOV: 'Governance',
|
||||
HR: 'Human Resources',
|
||||
IAM: 'Identity & Access',
|
||||
AC: 'Access Control',
|
||||
CRYPTO: 'Kryptographie',
|
||||
LOG: 'Logging & Monitoring',
|
||||
SDLC: 'Softwareentwicklung',
|
||||
OPS: 'Betrieb',
|
||||
NET: 'Netzwerk',
|
||||
BCP: 'Business Continuity',
|
||||
VENDOR: 'Lieferanten',
|
||||
DATA: 'Datenschutz',
|
||||
}
|
||||
|
||||
const PRIORITY_COLORS: Record<string, string> = {
|
||||
kritisch: 'bg-red-100 text-red-700',
|
||||
hoch: 'bg-orange-100 text-orange-700',
|
||||
mittel: 'bg-yellow-100 text-yellow-700',
|
||||
niedrig: 'bg-green-100 text-green-700',
|
||||
}
|
||||
|
||||
export default function TOMControlPanel({ obligationId, onClose }: TOMControlPanelProps) {
|
||||
const [controls, setControls] = useState<TOMControl[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
try {
|
||||
const res = await fetch(`${UCCA_API}/${obligationId}/tom-controls`)
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||
const data = await res.json()
|
||||
setControls(data.controls || [])
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : 'Laden fehlgeschlagen')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
load()
|
||||
}, [obligationId])
|
||||
|
||||
return (
|
||||
<div className="bg-white border border-gray-200 rounded-xl overflow-hidden">
|
||||
<div className="flex items-center justify-between px-5 py-3 bg-gray-50 border-b">
|
||||
<h3 className="text-sm font-semibold text-gray-900">TOM Controls</h3>
|
||||
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 text-xs">Schliessen</button>
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
{loading && <p className="text-xs text-gray-500">Lade Controls...</p>}
|
||||
{error && <p className="text-xs text-red-600">{error}</p>}
|
||||
|
||||
{!loading && !error && controls.length === 0 && (
|
||||
<p className="text-xs text-gray-400">Keine TOM Controls verknuepft</p>
|
||||
)}
|
||||
|
||||
{!loading && controls.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
{controls.map(c => (
|
||||
<div key={c.id} className="border border-gray-100 rounded-lg p-3 hover:bg-gray-50 transition-colors">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="text-xs font-mono text-purple-600">{c.id}</span>
|
||||
<span className="text-xs text-gray-400">{DOMAIN_LABELS[c.domain_id] || c.domain_id}</span>
|
||||
{c.priority && (
|
||||
<span className={`px-1.5 py-0.5 text-[10px] rounded ${PRIORITY_COLORS[c.priority] || 'bg-gray-100 text-gray-600'}`}>
|
||||
{c.priority}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm font-medium text-gray-900">{c.title}</p>
|
||||
{c.description && (
|
||||
<p className="text-xs text-gray-500 mt-1 line-clamp-2">{c.description}</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -123,6 +123,10 @@ func main() {
|
||||
trainingHandlers := handlers.NewTrainingHandlers(trainingStore, contentGenerator)
|
||||
ragHandlers := handlers.NewRAGHandlers(corpusVersionStore)
|
||||
|
||||
// Initialize obligations framework (v2 with TOM mapping)
|
||||
obligationsStore := ucca.NewObligationsStore(pool)
|
||||
obligationsHandlers := handlers.NewObligationsHandlersWithStore(obligationsStore)
|
||||
|
||||
// Initialize middleware
|
||||
rbacMiddleware := rbac.NewMiddleware(rbacService, policyEngine)
|
||||
|
||||
@@ -346,6 +350,9 @@ func main() {
|
||||
// DSB Pool management
|
||||
uccaRoutes.GET("/dsb-pool", escalationHandlers.ListDSBPool)
|
||||
uccaRoutes.POST("/dsb-pool", escalationHandlers.AddDSBPoolMember)
|
||||
|
||||
// Obligations framework (v2 with TOM mapping)
|
||||
obligationsHandlers.RegisterRoutes(uccaRoutes)
|
||||
}
|
||||
|
||||
// RAG routes - Legal Corpus Search & Versioning
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -14,23 +15,60 @@ import (
|
||||
|
||||
// ObligationsHandlers handles API requests for the generic obligations framework
|
||||
type ObligationsHandlers struct {
|
||||
registry *ucca.ObligationsRegistry
|
||||
store *ucca.ObligationsStore // Optional: for persisting assessments
|
||||
registry *ucca.ObligationsRegistry
|
||||
store *ucca.ObligationsStore // Optional: for persisting assessments
|
||||
tomIndex *ucca.TOMControlIndex
|
||||
tomMapper *ucca.TOMObligationMapper
|
||||
gapAnalyzer *ucca.TOMGapAnalyzer
|
||||
}
|
||||
|
||||
// NewObligationsHandlers creates a new ObligationsHandlers instance
|
||||
func NewObligationsHandlers() *ObligationsHandlers {
|
||||
return &ObligationsHandlers{
|
||||
h := &ObligationsHandlers{
|
||||
registry: ucca.NewObligationsRegistry(),
|
||||
}
|
||||
h.initTOM()
|
||||
return h
|
||||
}
|
||||
|
||||
// NewObligationsHandlersWithStore creates a new ObligationsHandlers with a store
|
||||
func NewObligationsHandlersWithStore(store *ucca.ObligationsStore) *ObligationsHandlers {
|
||||
return &ObligationsHandlers{
|
||||
h := &ObligationsHandlers{
|
||||
registry: ucca.NewObligationsRegistry(),
|
||||
store: store,
|
||||
}
|
||||
h.initTOM()
|
||||
return h
|
||||
}
|
||||
|
||||
// initTOM initializes TOM control index, mapper, and gap analyzer
|
||||
func (h *ObligationsHandlers) initTOM() {
|
||||
tomIndex, err := ucca.LoadTOMControls()
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: Could not load TOM controls: %v\n", err)
|
||||
return
|
||||
}
|
||||
h.tomIndex = tomIndex
|
||||
|
||||
// Try to load v2 TOM mapping
|
||||
mapping, err := ucca.LoadV2TOMMapping()
|
||||
if err != nil {
|
||||
// Build mapping from v2 regulation files
|
||||
regs, err2 := ucca.LoadAllV2Regulations()
|
||||
if err2 == nil {
|
||||
var allObligations []ucca.V2Obligation
|
||||
for _, reg := range regs {
|
||||
allObligations = append(allObligations, reg.Obligations...)
|
||||
}
|
||||
h.tomMapper = ucca.NewTOMObligationMapperFromObligations(tomIndex, allObligations)
|
||||
}
|
||||
} else {
|
||||
h.tomMapper = ucca.NewTOMObligationMapper(tomIndex, mapping)
|
||||
}
|
||||
|
||||
if h.tomMapper != nil {
|
||||
h.gapAnalyzer = ucca.NewTOMGapAnalyzer(h.tomMapper, tomIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterRoutes registers all obligations-related routes
|
||||
@@ -56,6 +94,14 @@ func (h *ObligationsHandlers) RegisterRoutes(r *gin.RouterGroup) {
|
||||
|
||||
// Quick check endpoint (no persistence)
|
||||
obligations.POST("/quick-check", h.QuickCheck)
|
||||
|
||||
// v2: Scope-based assessment
|
||||
obligations.POST("/assess-from-scope", h.AssessFromScope)
|
||||
|
||||
// v2: TOM Control endpoints
|
||||
obligations.GET("/:id/tom-controls", h.GetTOMControlsForObligation)
|
||||
obligations.POST("/gap-analysis", h.GapAnalysis)
|
||||
obligations.GET("/tom-controls/:controlId/obligations", h.GetObligationsForControl)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,6 +469,106 @@ func (h *ObligationsHandlers) QuickCheck(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// AssessFromScope assesses obligations from a ScopeDecision
|
||||
// POST /sdk/v1/ucca/obligations/assess-from-scope
|
||||
func (h *ObligationsHandlers) AssessFromScope(c *gin.Context) {
|
||||
tenantID := rbac.GetTenantID(c)
|
||||
if tenantID == uuid.Nil {
|
||||
tenantID = uuid.New()
|
||||
}
|
||||
|
||||
var scope ucca.ScopeDecision
|
||||
if err := c.ShouldBindJSON(&scope); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert scope to facts
|
||||
facts := ucca.MapScopeToFacts(&scope)
|
||||
|
||||
// Evaluate
|
||||
overview := h.registry.EvaluateAll(tenantID, facts, "")
|
||||
|
||||
// Enrich with TOM control requirements if available
|
||||
if h.tomMapper != nil {
|
||||
overview.TOMControlRequirements = h.tomMapper.DeriveControlsFromObligations(overview.Obligations)
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
if len(overview.ApplicableRegulations) == 0 {
|
||||
warnings = append(warnings, "Keine anwendbaren Regulierungen gefunden. Pruefen Sie die Scope-Angaben.")
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, ucca.ObligationsAssessResponse{
|
||||
Overview: overview,
|
||||
Warnings: warnings,
|
||||
})
|
||||
}
|
||||
|
||||
// GetTOMControlsForObligation returns TOM controls linked to an obligation
|
||||
// GET /sdk/v1/ucca/obligations/:id/tom-controls
|
||||
func (h *ObligationsHandlers) GetTOMControlsForObligation(c *gin.Context) {
|
||||
obligationID := c.Param("id")
|
||||
|
||||
if h.tomMapper == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "TOM mapping not available"})
|
||||
return
|
||||
}
|
||||
|
||||
controls := h.tomMapper.GetControlsForObligation(obligationID)
|
||||
controlIDs := h.tomMapper.GetControlIDsForObligation(obligationID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"obligation_id": obligationID,
|
||||
"control_ids": controlIDs,
|
||||
"controls": controls,
|
||||
"count": len(controls),
|
||||
})
|
||||
}
|
||||
|
||||
// GapAnalysis performs a TOM control gap analysis
|
||||
// POST /sdk/v1/ucca/obligations/gap-analysis
|
||||
func (h *ObligationsHandlers) GapAnalysis(c *gin.Context) {
|
||||
if h.gapAnalyzer == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Gap analysis not available"})
|
||||
return
|
||||
}
|
||||
|
||||
var req ucca.GapAnalysisRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
result := h.gapAnalyzer.Analyze(&req)
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// GetObligationsForControl returns obligations linked to a TOM control
|
||||
// GET /sdk/v1/ucca/obligations/tom-controls/:controlId/obligations
|
||||
func (h *ObligationsHandlers) GetObligationsForControl(c *gin.Context) {
|
||||
controlID := c.Param("controlId")
|
||||
|
||||
if h.tomMapper == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "TOM mapping not available"})
|
||||
return
|
||||
}
|
||||
|
||||
obligationIDs := h.tomMapper.GetObligationsForControl(controlID)
|
||||
|
||||
var control *ucca.TOMControl
|
||||
if h.tomIndex != nil {
|
||||
control, _ = h.tomIndex.GetControl(controlID)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"control_id": controlID,
|
||||
"control": control,
|
||||
"obligation_ids": obligationIDs,
|
||||
"count": len(obligationIDs),
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions
|
||||
// ============================================================================
|
||||
|
||||
301
ai-compliance-sdk/internal/ucca/json_regulation_module.go
Normal file
301
ai-compliance-sdk/internal/ucca/json_regulation_module.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// JSONRegulationModule implements RegulationModule from a v2 JSON file
|
||||
type JSONRegulationModule struct {
|
||||
regFile *V2RegulationFile
|
||||
conditionEngine *ObligationConditionEngine
|
||||
applicability func(*UnifiedFacts) bool
|
||||
}
|
||||
|
||||
// NewJSONRegulationModule creates a RegulationModule from a v2 JSON regulation file
|
||||
func NewJSONRegulationModule(regFile *V2RegulationFile) *JSONRegulationModule {
|
||||
m := &JSONRegulationModule{
|
||||
regFile: regFile,
|
||||
conditionEngine: NewObligationConditionEngine(),
|
||||
}
|
||||
// Set regulation-level applicability check
|
||||
m.applicability = m.defaultApplicability
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *JSONRegulationModule) ID() string { return m.regFile.Regulation }
|
||||
func (m *JSONRegulationModule) Name() string { return m.regFile.Name }
|
||||
func (m *JSONRegulationModule) Description() string { return m.regFile.Description }
|
||||
|
||||
// IsApplicable checks regulation-level applicability
|
||||
func (m *JSONRegulationModule) IsApplicable(facts *UnifiedFacts) bool {
|
||||
return m.applicability(facts)
|
||||
}
|
||||
|
||||
// defaultApplicability determines if the regulation applies based on regulation ID
|
||||
func (m *JSONRegulationModule) defaultApplicability(facts *UnifiedFacts) bool {
|
||||
switch m.regFile.Regulation {
|
||||
case "dsgvo":
|
||||
return facts.DataProtection.ProcessesPersonalData &&
|
||||
(facts.Organization.EUMember || facts.DataProtection.OffersToEU || facts.DataProtection.MonitorsEUIndividuals)
|
||||
case "ai_act":
|
||||
return facts.AIUsage.UsesAI
|
||||
case "nis2":
|
||||
return facts.Sector.PrimarySector != "" && facts.Sector.PrimarySector != "other" &&
|
||||
(facts.Organization.MeetsNIS2SizeThreshold() || len(facts.Sector.SpecialServices) > 0)
|
||||
case "bdsg":
|
||||
return facts.DataProtection.ProcessesPersonalData && facts.Organization.Country == "DE"
|
||||
case "ttdsg":
|
||||
return (facts.DataProtection.UsesCookies || facts.DataProtection.UsesTracking) &&
|
||||
facts.Organization.Country == "DE"
|
||||
case "dsa":
|
||||
return facts.DataProtection.OperatesPlatform && facts.Organization.EUMember
|
||||
case "data_act":
|
||||
return facts.Organization.EUMember
|
||||
case "eu_machinery":
|
||||
return facts.Organization.EUMember && facts.AIUsage.UsesAI
|
||||
case "dora":
|
||||
return facts.Financial.DORAApplies || facts.Financial.IsRegulated
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// DeriveObligations derives applicable obligations from the JSON data
|
||||
func (m *JSONRegulationModule) DeriveObligations(facts *UnifiedFacts) []Obligation {
|
||||
var result []Obligation
|
||||
|
||||
for _, v2Obl := range m.regFile.Obligations {
|
||||
// Check condition
|
||||
if v2Obl.AppliesWhenCondition != nil {
|
||||
if !m.conditionEngine.Evaluate(v2Obl.AppliesWhenCondition, facts) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// Fall back to legacy applies_when string matching
|
||||
if !m.evaluateLegacyCondition(v2Obl.AppliesWhen, facts) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, m.convertObligation(v2Obl))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// DeriveControls derives applicable controls
|
||||
func (m *JSONRegulationModule) DeriveControls(facts *UnifiedFacts) []ObligationControl {
|
||||
var result []ObligationControl
|
||||
for _, ctrl := range m.regFile.Controls {
|
||||
result = append(result, ObligationControl{
|
||||
ID: ctrl.ID,
|
||||
RegulationID: m.regFile.Regulation,
|
||||
Name: ctrl.Name,
|
||||
Description: ctrl.Description,
|
||||
Category: ctrl.Category,
|
||||
WhatToDo: ctrl.WhatToDo,
|
||||
ISO27001Mapping: ctrl.ISO27001Mapping,
|
||||
Priority: ObligationPriority(mapPriority(ctrl.Priority)),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *JSONRegulationModule) GetDecisionTree() *DecisionTree { return nil }
|
||||
|
||||
func (m *JSONRegulationModule) GetIncidentDeadlines(facts *UnifiedFacts) []IncidentDeadline {
|
||||
var result []IncidentDeadline
|
||||
for _, dl := range m.regFile.IncidentDL {
|
||||
var legalBasis []LegalReference
|
||||
for _, lb := range dl.LegalBasis {
|
||||
legalBasis = append(legalBasis, LegalReference{
|
||||
Norm: lb.Norm,
|
||||
Article: lb.Article,
|
||||
Title: lb.Title,
|
||||
})
|
||||
}
|
||||
result = append(result, IncidentDeadline{
|
||||
RegulationID: m.regFile.Regulation,
|
||||
Phase: dl.Phase,
|
||||
Deadline: dl.Deadline,
|
||||
Content: dl.Content,
|
||||
Recipient: dl.Recipient,
|
||||
LegalBasis: legalBasis,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *JSONRegulationModule) GetClassification(facts *UnifiedFacts) string {
|
||||
switch m.regFile.Regulation {
|
||||
case "nis2":
|
||||
if facts.Organization.MeetsNIS2LargeThreshold() || facts.Sector.IsKRITIS {
|
||||
return string(NIS2EssentialEntity)
|
||||
}
|
||||
if facts.Organization.MeetsNIS2SizeThreshold() {
|
||||
return string(NIS2ImportantEntity)
|
||||
}
|
||||
if len(facts.Sector.SpecialServices) > 0 {
|
||||
return string(NIS2EssentialEntity)
|
||||
}
|
||||
return string(NIS2NotAffected)
|
||||
case "ai_act":
|
||||
if facts.AIUsage.HasHighRiskAI {
|
||||
return "hochrisiko"
|
||||
}
|
||||
if facts.AIUsage.HasLimitedRiskAI {
|
||||
return "begrenztes_risiko"
|
||||
}
|
||||
return "minimales_risiko"
|
||||
case "dsgvo":
|
||||
if facts.DataProtection.IsController {
|
||||
if facts.DataProtection.LargeScaleProcessing || facts.DataProtection.ProcessesSpecialCategories {
|
||||
return "verantwortlicher_hochrisiko"
|
||||
}
|
||||
return "verantwortlicher"
|
||||
}
|
||||
return "auftragsverarbeiter"
|
||||
default:
|
||||
return "anwendbar"
|
||||
}
|
||||
}
|
||||
|
||||
// convertObligation converts a V2Obligation to the framework Obligation struct
|
||||
func (m *JSONRegulationModule) convertObligation(v2 V2Obligation) Obligation {
|
||||
obl := Obligation{
|
||||
ID: v2.ID,
|
||||
RegulationID: m.regFile.Regulation,
|
||||
Title: v2.Title,
|
||||
Description: v2.Description,
|
||||
Category: ObligationCategory(v2.Category),
|
||||
Responsible: ResponsibleRole(v2.Responsible),
|
||||
Priority: ObligationPriority(mapPriority(v2.Priority)),
|
||||
AppliesWhen: v2.AppliesWhen,
|
||||
ISO27001Mapping: v2.ISO27001Mapping,
|
||||
HowToImplement: v2.HowToImplement,
|
||||
BreakpilotFeature: v2.BreakpilotFeature,
|
||||
}
|
||||
|
||||
// Legal basis
|
||||
for _, lb := range v2.LegalBasis {
|
||||
obl.LegalBasis = append(obl.LegalBasis, LegalReference{
|
||||
Norm: lb.Norm,
|
||||
Article: lb.Article,
|
||||
Title: lb.Title,
|
||||
})
|
||||
}
|
||||
|
||||
// Sanctions
|
||||
if v2.Sanctions != nil {
|
||||
obl.Sanctions = &SanctionInfo{
|
||||
MaxFine: v2.Sanctions.MaxFine,
|
||||
PersonalLiability: v2.Sanctions.PersonalLiability,
|
||||
CriminalLiability: v2.Sanctions.CriminalLiability,
|
||||
Description: v2.Sanctions.Description,
|
||||
}
|
||||
}
|
||||
|
||||
// Deadline
|
||||
if v2.Deadline != nil {
|
||||
obl.Deadline = m.convertDeadline(v2.Deadline)
|
||||
}
|
||||
|
||||
// Evidence
|
||||
for _, ev := range v2.Evidence {
|
||||
switch e := ev.(type) {
|
||||
case string:
|
||||
obl.Evidence = append(obl.Evidence, EvidenceItem{Name: e, Required: true})
|
||||
case map[string]interface{}:
|
||||
name, _ := e["name"].(string)
|
||||
required, _ := e["required"].(bool)
|
||||
format, _ := e["format"].(string)
|
||||
obl.Evidence = append(obl.Evidence, EvidenceItem{
|
||||
Name: name,
|
||||
Required: required,
|
||||
Format: format,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Store TOM control IDs in ExternalResources for now
|
||||
obl.ExternalResources = v2.TOMControlIDs
|
||||
|
||||
return obl
|
||||
}
|
||||
|
||||
func (m *JSONRegulationModule) convertDeadline(dl *V2Deadline) *Deadline {
|
||||
d := &Deadline{
|
||||
Type: DeadlineType(dl.Type),
|
||||
Duration: dl.Duration,
|
||||
Interval: dl.Interval,
|
||||
Event: dl.Event,
|
||||
}
|
||||
if dl.Date != "" {
|
||||
t, err := time.Parse("2006-01-02", dl.Date)
|
||||
if err == nil {
|
||||
d.Date = &t
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// evaluateLegacyCondition evaluates the legacy applies_when string
|
||||
func (m *JSONRegulationModule) evaluateLegacyCondition(condition string, facts *UnifiedFacts) bool {
|
||||
switch condition {
|
||||
case "always":
|
||||
return true
|
||||
case "controller":
|
||||
return facts.DataProtection.IsController
|
||||
case "processor":
|
||||
return facts.DataProtection.IsProcessor
|
||||
case "high_risk":
|
||||
return facts.DataProtection.LargeScaleProcessing || facts.DataProtection.SystematicMonitoring || facts.DataProtection.ProcessesSpecialCategories
|
||||
case "needs_dpo":
|
||||
return facts.DataProtection.RequiresDSBByLaw || facts.Organization.IsPublicAuthority || facts.Organization.EmployeeCount >= 20
|
||||
case "uses_processors":
|
||||
return facts.DataProtection.UsesExternalProcessor
|
||||
case "cross_border":
|
||||
return facts.DataProtection.TransfersToThirdCountries || facts.DataProtection.CrossBorderProcessing
|
||||
case "uses_ai":
|
||||
return facts.AIUsage.UsesAI
|
||||
case "high_risk_provider":
|
||||
return facts.AIUsage.HasHighRiskAI && facts.AIUsage.IsAIProvider
|
||||
case "high_risk_deployer":
|
||||
return facts.AIUsage.HasHighRiskAI && facts.AIUsage.IsAIDeployer
|
||||
case "high_risk_deployer_fria":
|
||||
return facts.AIUsage.HasHighRiskAI && facts.AIUsage.IsAIDeployer && (facts.Organization.IsPublicAuthority || facts.AIUsage.EducationAccess || facts.AIUsage.EmploymentDecisions)
|
||||
case "limited_risk":
|
||||
return facts.AIUsage.HasLimitedRiskAI || facts.AIUsage.AIInteractsWithNaturalPersons
|
||||
case "gpai_provider":
|
||||
return facts.AIUsage.UsesGPAI && facts.AIUsage.IsAIProvider
|
||||
case "gpai_systemic_risk":
|
||||
return facts.AIUsage.GPAIWithSystemicRisk
|
||||
default:
|
||||
// For NIS2-style conditions with classification
|
||||
if condition == "classification != 'nicht_betroffen'" {
|
||||
return true // if module is applicable, classification is not "nicht_betroffen"
|
||||
}
|
||||
if condition == "classification == 'besonders_wichtige_einrichtung'" {
|
||||
return facts.Organization.MeetsNIS2LargeThreshold() || facts.Sector.IsKRITIS
|
||||
}
|
||||
fmt.Printf("Warning: unknown legacy condition: %s\n", condition)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// mapPriority normalizes priority strings to standard enum values
|
||||
func mapPriority(p string) string {
|
||||
switch p {
|
||||
case "kritisch", "critical":
|
||||
return "critical"
|
||||
case "hoch", "high":
|
||||
return "high"
|
||||
case "mittel", "medium":
|
||||
return "medium"
|
||||
case "niedrig", "low":
|
||||
return "low"
|
||||
default:
|
||||
return p
|
||||
}
|
||||
}
|
||||
300
ai-compliance-sdk/internal/ucca/obligation_condition_engine.go
Normal file
300
ai-compliance-sdk/internal/ucca/obligation_condition_engine.go
Normal file
@@ -0,0 +1,300 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ObligationConditionEngine evaluates condition trees against UnifiedFacts
|
||||
type ObligationConditionEngine struct {
|
||||
fieldMap map[string]func(*UnifiedFacts) interface{}
|
||||
}
|
||||
|
||||
// NewObligationConditionEngine creates a new condition engine with all field mappings
|
||||
func NewObligationConditionEngine() *ObligationConditionEngine {
|
||||
e := &ObligationConditionEngine{}
|
||||
e.fieldMap = e.buildFieldMap()
|
||||
return e
|
||||
}
|
||||
|
||||
// Evaluate evaluates a condition node against facts
|
||||
func (e *ObligationConditionEngine) Evaluate(node *ConditionNode, facts *UnifiedFacts) bool {
|
||||
if node == nil {
|
||||
return true // nil condition = always applies
|
||||
}
|
||||
|
||||
// Composite: all_of (AND)
|
||||
if len(node.AllOf) > 0 {
|
||||
for _, child := range node.AllOf {
|
||||
if !e.Evaluate(&child, facts) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Composite: any_of (OR)
|
||||
if len(node.AnyOf) > 0 {
|
||||
for _, child := range node.AnyOf {
|
||||
if e.Evaluate(&child, facts) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Leaf node: field + operator + value
|
||||
if node.Field != "" {
|
||||
return e.evaluateLeaf(node, facts)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) evaluateLeaf(node *ConditionNode, facts *UnifiedFacts) bool {
|
||||
getter, ok := e.fieldMap[node.Field]
|
||||
if !ok {
|
||||
fmt.Printf("Warning: unknown field in condition: %s\n", node.Field)
|
||||
return false
|
||||
}
|
||||
|
||||
actual := getter(facts)
|
||||
return e.compare(actual, node.Operator, node.Value)
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) compare(actual interface{}, operator string, expected interface{}) bool {
|
||||
switch strings.ToUpper(operator) {
|
||||
case "EQUALS":
|
||||
return e.equals(actual, expected)
|
||||
case "NOT_EQUALS":
|
||||
return !e.equals(actual, expected)
|
||||
case "GREATER_THAN":
|
||||
return e.toFloat(actual) > e.toFloat(expected)
|
||||
case "LESS_THAN":
|
||||
return e.toFloat(actual) < e.toFloat(expected)
|
||||
case "GREATER_OR_EQUAL":
|
||||
return e.toFloat(actual) >= e.toFloat(expected)
|
||||
case "LESS_OR_EQUAL":
|
||||
return e.toFloat(actual) <= e.toFloat(expected)
|
||||
case "IN":
|
||||
return e.inSlice(actual, expected)
|
||||
case "NOT_IN":
|
||||
return !e.inSlice(actual, expected)
|
||||
case "CONTAINS":
|
||||
return e.contains(actual, expected)
|
||||
case "EXISTS":
|
||||
return actual != nil && actual != "" && actual != false && actual != 0
|
||||
default:
|
||||
fmt.Printf("Warning: unknown operator: %s\n", operator)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) equals(a, b interface{}) bool {
|
||||
// Handle bool comparisons
|
||||
aBool, aIsBool := e.toBool(a)
|
||||
bBool, bIsBool := e.toBool(b)
|
||||
if aIsBool && bIsBool {
|
||||
return aBool == bBool
|
||||
}
|
||||
|
||||
// Handle numeric comparisons
|
||||
aFloat, aIsNum := e.toFloatOk(a)
|
||||
bFloat, bIsNum := e.toFloatOk(b)
|
||||
if aIsNum && bIsNum {
|
||||
return aFloat == bFloat
|
||||
}
|
||||
|
||||
// String comparison
|
||||
return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) toBool(v interface{}) (bool, bool) {
|
||||
switch b := v.(type) {
|
||||
case bool:
|
||||
return b, true
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) toFloat(v interface{}) float64 {
|
||||
f, _ := e.toFloatOk(v)
|
||||
return f
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) toFloatOk(v interface{}) (float64, bool) {
|
||||
switch n := v.(type) {
|
||||
case int:
|
||||
return float64(n), true
|
||||
case int64:
|
||||
return float64(n), true
|
||||
case float64:
|
||||
return n, true
|
||||
case float32:
|
||||
return float64(n), true
|
||||
case json.Number:
|
||||
f, err := n.Float64()
|
||||
return f, err == nil
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) inSlice(actual, expected interface{}) bool {
|
||||
actualStr := fmt.Sprintf("%v", actual)
|
||||
switch v := expected.(type) {
|
||||
case []interface{}:
|
||||
for _, item := range v {
|
||||
if fmt.Sprintf("%v", item) == actualStr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case []string:
|
||||
for _, item := range v {
|
||||
if item == actualStr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *ObligationConditionEngine) contains(actual, expected interface{}) bool {
|
||||
// Check if actual (slice) contains expected
|
||||
switch v := actual.(type) {
|
||||
case []string:
|
||||
exp := fmt.Sprintf("%v", expected)
|
||||
for _, item := range v {
|
||||
if item == exp {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case string:
|
||||
return strings.Contains(v, fmt.Sprintf("%v", expected))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// buildFieldMap creates the mapping from JSON field paths to Go struct accessors
|
||||
func (e *ObligationConditionEngine) buildFieldMap() map[string]func(*UnifiedFacts) interface{} {
|
||||
return map[string]func(*UnifiedFacts) interface{}{
|
||||
// Organization
|
||||
"organization.employee_count": func(f *UnifiedFacts) interface{} { return f.Organization.EmployeeCount },
|
||||
"organization.annual_revenue": func(f *UnifiedFacts) interface{} { return f.Organization.AnnualRevenue },
|
||||
"organization.country": func(f *UnifiedFacts) interface{} { return f.Organization.Country },
|
||||
"organization.eu_member": func(f *UnifiedFacts) interface{} { return f.Organization.EUMember },
|
||||
"organization.is_public_authority": func(f *UnifiedFacts) interface{} { return f.Organization.IsPublicAuthority },
|
||||
"organization.legal_form": func(f *UnifiedFacts) interface{} { return f.Organization.LegalForm },
|
||||
"organization.size_category": func(f *UnifiedFacts) interface{} { return f.Organization.CalculateSizeCategory() },
|
||||
"organization.is_part_of_group": func(f *UnifiedFacts) interface{} { return f.Organization.IsPartOfGroup },
|
||||
|
||||
// Data Protection
|
||||
"data_protection.processes_personal_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesPersonalData },
|
||||
"data_protection.is_controller": func(f *UnifiedFacts) interface{} { return f.DataProtection.IsController },
|
||||
"data_protection.is_processor": func(f *UnifiedFacts) interface{} { return f.DataProtection.IsProcessor },
|
||||
"data_protection.processes_special_categories": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesSpecialCategories },
|
||||
"data_protection.processes_children_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesMinorData },
|
||||
"data_protection.processes_minor_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesMinorData },
|
||||
"data_protection.processes_criminal_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesCriminalData },
|
||||
"data_protection.large_scale": func(f *UnifiedFacts) interface{} { return f.DataProtection.LargeScaleProcessing },
|
||||
"data_protection.large_scale_processing": func(f *UnifiedFacts) interface{} { return f.DataProtection.LargeScaleProcessing },
|
||||
"data_protection.systematic_monitoring": func(f *UnifiedFacts) interface{} { return f.DataProtection.SystematicMonitoring },
|
||||
"data_protection.uses_automated_decisions": func(f *UnifiedFacts) interface{} { return f.DataProtection.AutomatedDecisionMaking },
|
||||
"data_protection.automated_decision_making": func(f *UnifiedFacts) interface{} { return f.DataProtection.AutomatedDecisionMaking },
|
||||
"data_protection.cross_border_transfer": func(f *UnifiedFacts) interface{} { return f.DataProtection.TransfersToThirdCountries },
|
||||
"data_protection.transfers_to_third_countries": func(f *UnifiedFacts) interface{} { return f.DataProtection.TransfersToThirdCountries },
|
||||
"data_protection.cross_border_processing": func(f *UnifiedFacts) interface{} { return f.DataProtection.CrossBorderProcessing },
|
||||
"data_protection.uses_processors": func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesExternalProcessor },
|
||||
"data_protection.uses_external_processor": func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesExternalProcessor },
|
||||
"data_protection.high_risk": func(f *UnifiedFacts) interface{} { return f.DataProtection.LargeScaleProcessing || f.DataProtection.SystematicMonitoring || f.DataProtection.ProcessesSpecialCategories },
|
||||
"data_protection.uses_profiling": func(f *UnifiedFacts) interface{} { return f.DataProtection.Profiling },
|
||||
"data_protection.profiling": func(f *UnifiedFacts) interface{} { return f.DataProtection.Profiling },
|
||||
"data_protection.requires_dsb": func(f *UnifiedFacts) interface{} { return f.DataProtection.RequiresDSBByLaw },
|
||||
"data_protection.needs_dpo": func(f *UnifiedFacts) interface{} { return f.DataProtection.RequiresDSBByLaw },
|
||||
"data_protection.has_appointed_dsb": func(f *UnifiedFacts) interface{} { return f.DataProtection.HasAppointedDSB },
|
||||
"data_protection.data_subject_count": func(f *UnifiedFacts) interface{} { return f.DataProtection.DataSubjectCount },
|
||||
"data_protection.sccs_in_place": func(f *UnifiedFacts) interface{} { return f.DataProtection.SCCsInPlace },
|
||||
"data_protection.binding_corporate_rules": func(f *UnifiedFacts) interface{} { return f.DataProtection.BindingCorporateRules },
|
||||
"data_protection.special_categories": func(f *UnifiedFacts) interface{} { return f.DataProtection.SpecialCategories },
|
||||
"data_protection.processes_employee_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesEmployeeData },
|
||||
"data_protection.processes_health_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesHealthData },
|
||||
"data_protection.processes_financial_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesFinancialData },
|
||||
"data_protection.uses_cookies": func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesCookies },
|
||||
"data_protection.uses_tracking": func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesTracking },
|
||||
"data_protection.uses_video_surveillance": func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesVideoSurveillance },
|
||||
"data_protection.processes_biometric_data": func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesBiometricData },
|
||||
"data_protection.operates_platform": func(f *UnifiedFacts) interface{} { return f.DataProtection.OperatesPlatform },
|
||||
"data_protection.platform_user_count": func(f *UnifiedFacts) interface{} { return f.DataProtection.PlatformUserCount },
|
||||
|
||||
// AI Usage
|
||||
"ai_usage.uses_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.UsesAI },
|
||||
"ai_usage.is_ai_provider": func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIProvider },
|
||||
"ai_usage.is_ai_deployer": func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIDeployer },
|
||||
"ai_usage.is_ai_distributor": func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIDistributor },
|
||||
"ai_usage.is_ai_importer": func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIImporter },
|
||||
"ai_usage.high_risk_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.HasHighRiskAI },
|
||||
"ai_usage.has_high_risk_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.HasHighRiskAI },
|
||||
"ai_usage.limited_risk_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.HasLimitedRiskAI },
|
||||
"ai_usage.has_limited_risk_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.HasLimitedRiskAI },
|
||||
"ai_usage.minimal_risk_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.HasMinimalRiskAI },
|
||||
"ai_usage.is_gpai_provider": func(f *UnifiedFacts) interface{} { return f.AIUsage.UsesGPAI },
|
||||
"ai_usage.gpai_systemic_risk": func(f *UnifiedFacts) interface{} { return f.AIUsage.GPAIWithSystemicRisk },
|
||||
"ai_usage.uses_biometric_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.BiometricIdentification },
|
||||
"ai_usage.biometric_identification": func(f *UnifiedFacts) interface{} { return f.AIUsage.BiometricIdentification },
|
||||
"ai_usage.uses_emotion_recognition": func(f *UnifiedFacts) interface{} { return f.AIUsage.EmotionRecognition },
|
||||
"ai_usage.ai_in_education": func(f *UnifiedFacts) interface{} { return f.AIUsage.EducationAccess },
|
||||
"ai_usage.ai_in_employment": func(f *UnifiedFacts) interface{} { return f.AIUsage.EmploymentDecisions },
|
||||
"ai_usage.ai_in_critical_infrastructure": func(f *UnifiedFacts) interface{} { return f.AIUsage.CriticalInfrastructure },
|
||||
"ai_usage.ai_in_law_enforcement": func(f *UnifiedFacts) interface{} { return f.AIUsage.LawEnforcement },
|
||||
"ai_usage.ai_in_justice": func(f *UnifiedFacts) interface{} { return f.AIUsage.JusticeAdministration },
|
||||
"ai_usage.uses_generative_ai": func(f *UnifiedFacts) interface{} { return f.AIUsage.AIInteractsWithNaturalPersons },
|
||||
"ai_usage.uses_deepfakes": func(f *UnifiedFacts) interface{} { return f.AIUsage.GeneratesDeepfakes },
|
||||
"ai_usage.ai_makes_decisions": func(f *UnifiedFacts) interface{} { return f.DataProtection.AutomatedDecisionMaking },
|
||||
"ai_usage.ai_interacts_with_persons": func(f *UnifiedFacts) interface{} { return f.AIUsage.AIInteractsWithNaturalPersons },
|
||||
|
||||
// Sector
|
||||
"sector.primary_sector": func(f *UnifiedFacts) interface{} { return f.Sector.PrimarySector },
|
||||
"sector.is_kritis": func(f *UnifiedFacts) interface{} { return f.Sector.IsKRITIS },
|
||||
"sector.nis2_applicable": func(f *UnifiedFacts) interface{} { return f.Sector.PrimarySector != "" && f.Sector.PrimarySector != "other" },
|
||||
"sector.nis2_classification": func(f *UnifiedFacts) interface{} { return f.Sector.NIS2Classification },
|
||||
"sector.is_annex_i": func(f *UnifiedFacts) interface{} { return f.Sector.IsAnnexI },
|
||||
"sector.is_annex_ii": func(f *UnifiedFacts) interface{} { return f.Sector.IsAnnexII },
|
||||
"sector.provides_dns": func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "dns") },
|
||||
"sector.provides_cloud": func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "cloud") },
|
||||
"sector.provides_cdn": func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "cdn") },
|
||||
"sector.provides_data_center": func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "datacenter") },
|
||||
"sector.provides_managed_services": func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "msp") || containsString(f.Sector.SpecialServices, "mssp") },
|
||||
"sector.is_financial_institution": func(f *UnifiedFacts) interface{} { return f.Sector.IsFinancialInstitution },
|
||||
"sector.is_healthcare_provider": func(f *UnifiedFacts) interface{} { return f.Sector.IsHealthcareProvider },
|
||||
|
||||
// IT Security
|
||||
"it_security.has_isms": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasISMS },
|
||||
"it_security.iso27001_certified": func(f *UnifiedFacts) interface{} { return f.ITSecurity.ISO27001Certified },
|
||||
"it_security.has_incident_process": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasIncidentProcess },
|
||||
"it_security.has_mfa": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasMFA },
|
||||
"it_security.has_encryption": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasEncryption },
|
||||
"it_security.has_backup": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasBackup },
|
||||
"it_security.has_bcm": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasBCM },
|
||||
"it_security.has_siem": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasSecurityMonitoring },
|
||||
"it_security.has_network_segmentation": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasNetworkSegmentation },
|
||||
"it_security.has_vulnerability_mgmt": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasVulnerabilityMgmt },
|
||||
|
||||
// Financial
|
||||
"financial.dora_applies": func(f *UnifiedFacts) interface{} { return f.Financial.DORAApplies },
|
||||
"financial.is_regulated": func(f *UnifiedFacts) interface{} { return f.Financial.IsRegulated },
|
||||
"financial.has_critical_ict": func(f *UnifiedFacts) interface{} { return f.Financial.HasCriticalICT },
|
||||
"financial.ict_outsourced": func(f *UnifiedFacts) interface{} { return f.Financial.ICTOutsourced },
|
||||
"financial.concentration_risk": func(f *UnifiedFacts) interface{} { return f.Financial.ConcentrationRisk },
|
||||
|
||||
// Supply Chain
|
||||
"supply_chain.has_risk_management": func(f *UnifiedFacts) interface{} { return f.SupplyChain.HasSupplyChainRiskMgmt },
|
||||
"supply_chain.supplier_count": func(f *UnifiedFacts) interface{} { return f.SupplyChain.SupplierCount },
|
||||
|
||||
// Personnel
|
||||
"personnel.has_ciso": func(f *UnifiedFacts) interface{} { return f.Personnel.HasCISO },
|
||||
"personnel.has_dpo": func(f *UnifiedFacts) interface{} { return f.Personnel.HasDPO },
|
||||
"personnel.has_ai_competence": func(f *UnifiedFacts) interface{} { return f.Personnel.HasAICompetence },
|
||||
"personnel.has_ai_governance": func(f *UnifiedFacts) interface{} { return f.Personnel.HasAIGovernance },
|
||||
"personnel.has_compliance_officer": func(f *UnifiedFacts) interface{} { return f.Personnel.HasComplianceOfficer },
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConditionEngine_NilNode(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
facts := NewUnifiedFacts()
|
||||
if !engine.Evaluate(nil, facts) {
|
||||
t.Error("nil node should return true (always applies)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConditionEngine_LeafEquals(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
field string
|
||||
value interface{}
|
||||
facts func() *UnifiedFacts
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "is_controller true",
|
||||
field: "data_protection.is_controller", value: true,
|
||||
facts: func() *UnifiedFacts {
|
||||
f := NewUnifiedFacts()
|
||||
f.DataProtection.IsController = true
|
||||
return f
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "is_controller false mismatch",
|
||||
field: "data_protection.is_controller", value: true,
|
||||
facts: func() *UnifiedFacts { return NewUnifiedFacts() },
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "employee_count equals",
|
||||
field: "organization.employee_count", value: float64(50),
|
||||
facts: func() *UnifiedFacts {
|
||||
f := NewUnifiedFacts()
|
||||
f.Organization.EmployeeCount = 50
|
||||
return f
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "uses_ai true",
|
||||
field: "ai_usage.uses_ai", value: true,
|
||||
facts: func() *UnifiedFacts {
|
||||
f := NewUnifiedFacts()
|
||||
f.AIUsage.UsesAI = true
|
||||
return f
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
node := &ConditionNode{
|
||||
Field: tt.field,
|
||||
Operator: "EQUALS",
|
||||
Value: tt.value,
|
||||
}
|
||||
result := engine.Evaluate(node, tt.facts())
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConditionEngine_GreaterThan(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
facts := NewUnifiedFacts()
|
||||
facts.Organization.EmployeeCount = 50
|
||||
|
||||
node := &ConditionNode{
|
||||
Field: "organization.employee_count",
|
||||
Operator: "GREATER_THAN",
|
||||
Value: float64(19),
|
||||
}
|
||||
if !engine.Evaluate(node, facts) {
|
||||
t.Error("50 > 19 should be true")
|
||||
}
|
||||
|
||||
facts.Organization.EmployeeCount = 10
|
||||
if engine.Evaluate(node, facts) {
|
||||
t.Error("10 > 19 should be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConditionEngine_AllOf(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
facts := NewUnifiedFacts()
|
||||
facts.DataProtection.IsController = true
|
||||
facts.DataProtection.ProcessesSpecialCategories = true
|
||||
|
||||
node := &ConditionNode{
|
||||
AllOf: []ConditionNode{
|
||||
{Field: "data_protection.is_controller", Operator: "EQUALS", Value: true},
|
||||
{Field: "data_protection.processes_special_categories", Operator: "EQUALS", Value: true},
|
||||
},
|
||||
}
|
||||
|
||||
if !engine.Evaluate(node, facts) {
|
||||
t.Error("all_of with both true should be true")
|
||||
}
|
||||
|
||||
facts.DataProtection.ProcessesSpecialCategories = false
|
||||
if engine.Evaluate(node, facts) {
|
||||
t.Error("all_of with one false should be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConditionEngine_AnyOf(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
facts := NewUnifiedFacts()
|
||||
facts.DataProtection.RequiresDSBByLaw = false
|
||||
|
||||
node := &ConditionNode{
|
||||
AnyOf: []ConditionNode{
|
||||
{Field: "data_protection.needs_dpo", Operator: "EQUALS", Value: true},
|
||||
{Field: "organization.employee_count", Operator: "GREATER_THAN", Value: float64(19)},
|
||||
},
|
||||
}
|
||||
|
||||
if engine.Evaluate(node, facts) {
|
||||
t.Error("any_of with both false should be false")
|
||||
}
|
||||
|
||||
facts.Organization.EmployeeCount = 25
|
||||
if !engine.Evaluate(node, facts) {
|
||||
t.Error("any_of with one true should be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConditionEngine_UnknownField(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
facts := NewUnifiedFacts()
|
||||
|
||||
node := &ConditionNode{
|
||||
Field: "nonexistent.field",
|
||||
Operator: "EQUALS",
|
||||
Value: true,
|
||||
}
|
||||
|
||||
if engine.Evaluate(node, facts) {
|
||||
t.Error("unknown field should return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConditionEngine_NotEquals(t *testing.T) {
|
||||
engine := NewObligationConditionEngine()
|
||||
facts := NewUnifiedFacts()
|
||||
facts.Organization.Country = "DE"
|
||||
|
||||
node := &ConditionNode{
|
||||
Field: "organization.country",
|
||||
Operator: "NOT_EQUALS",
|
||||
Value: "US",
|
||||
}
|
||||
if !engine.Evaluate(node, facts) {
|
||||
t.Error("DE != US should be true")
|
||||
}
|
||||
|
||||
node.Value = "DE"
|
||||
if engine.Evaluate(node, facts) {
|
||||
t.Error("DE != DE should be false")
|
||||
}
|
||||
}
|
||||
@@ -296,6 +296,9 @@ type ManagementObligationsOverview struct {
|
||||
|
||||
// Executive summary for C-Level
|
||||
ExecutiveSummary ExecutiveSummary `json:"executive_summary"`
|
||||
|
||||
// TOM Control Requirements (derived from obligations, v2)
|
||||
TOMControlRequirements []TOMControlRequirement `json:"tom_control_requirements,omitempty"`
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -22,43 +22,64 @@ type ObligationsRegistry struct {
|
||||
modules map[string]RegulationModule
|
||||
}
|
||||
|
||||
// NewObligationsRegistry creates a new registry and registers all default modules
|
||||
// NewObligationsRegistry creates a new registry and registers all default modules.
|
||||
// It loads v2 JSON modules first; for regulations without v2 JSON, falls back to YAML modules.
|
||||
func NewObligationsRegistry() *ObligationsRegistry {
|
||||
r := &ObligationsRegistry{
|
||||
modules: make(map[string]RegulationModule),
|
||||
}
|
||||
|
||||
// Register default modules
|
||||
// NIS2 module
|
||||
nis2Module, err := NewNIS2Module()
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: Could not load NIS2 module: %v\n", err)
|
||||
} else {
|
||||
r.Register(nis2Module)
|
||||
// Try to load v2 JSON modules first
|
||||
v2Loaded := r.loadV2Modules()
|
||||
|
||||
// Fall back to YAML modules for regulations not covered by v2
|
||||
if !v2Loaded["nis2"] {
|
||||
if nis2Module, err := NewNIS2Module(); err == nil {
|
||||
r.Register(nis2Module)
|
||||
} else {
|
||||
fmt.Printf("Warning: Could not load NIS2 module: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DSGVO module
|
||||
dsgvoModule, err := NewDSGVOModule()
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: Could not load DSGVO module: %v\n", err)
|
||||
} else {
|
||||
r.Register(dsgvoModule)
|
||||
if !v2Loaded["dsgvo"] {
|
||||
if dsgvoModule, err := NewDSGVOModule(); err == nil {
|
||||
r.Register(dsgvoModule)
|
||||
} else {
|
||||
fmt.Printf("Warning: Could not load DSGVO module: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// AI Act module
|
||||
aiActModule, err := NewAIActModule()
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: Could not load AI Act module: %v\n", err)
|
||||
} else {
|
||||
r.Register(aiActModule)
|
||||
if !v2Loaded["ai_act"] {
|
||||
if aiActModule, err := NewAIActModule(); err == nil {
|
||||
r.Register(aiActModule)
|
||||
} else {
|
||||
fmt.Printf("Warning: Could not load AI Act module: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Future modules will be registered here:
|
||||
// r.Register(NewDORAModule())
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// loadV2Modules attempts to load all v2 JSON regulation modules
|
||||
func (r *ObligationsRegistry) loadV2Modules() map[string]bool {
|
||||
loaded := make(map[string]bool)
|
||||
|
||||
regulations, err := LoadAllV2Regulations()
|
||||
if err != nil {
|
||||
fmt.Printf("Info: No v2 regulations found, using YAML modules: %v\n", err)
|
||||
return loaded
|
||||
}
|
||||
|
||||
for regID, regFile := range regulations {
|
||||
module := NewJSONRegulationModule(regFile)
|
||||
r.Register(module)
|
||||
loaded[regID] = true
|
||||
fmt.Printf("Loaded v2 regulation module: %s (%d obligations)\n", regID, len(regFile.Obligations))
|
||||
}
|
||||
|
||||
return loaded
|
||||
}
|
||||
|
||||
// NewObligationsRegistryWithModules creates a registry with specific modules
|
||||
func NewObligationsRegistryWithModules(modules ...RegulationModule) *ObligationsRegistry {
|
||||
r := &ObligationsRegistry{
|
||||
|
||||
128
ai-compliance-sdk/internal/ucca/scope_facts_mapper.go
Normal file
128
ai-compliance-sdk/internal/ucca/scope_facts_mapper.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package ucca
|
||||
|
||||
// ScopeDecision represents the output from the frontend Scope Wizard
|
||||
type ScopeDecision struct {
|
||||
// Company profile
|
||||
EmployeeCount int `json:"employee_count"`
|
||||
AnnualRevenue float64 `json:"annual_revenue"`
|
||||
Country string `json:"country"`
|
||||
Industry string `json:"industry"`
|
||||
LegalForm string `json:"legal_form,omitempty"`
|
||||
|
||||
// Scope wizard answers
|
||||
ProcessesPersonalData bool `json:"processes_personal_data"`
|
||||
IsController bool `json:"is_controller"`
|
||||
IsProcessor bool `json:"is_processor"`
|
||||
DataArt9 bool `json:"data_art9"`
|
||||
DataMinors bool `json:"data_minors"`
|
||||
LargeScale bool `json:"large_scale"`
|
||||
SystematicMonitoring bool `json:"systematic_monitoring"`
|
||||
CrossBorderTransfer bool `json:"cross_border_transfer"`
|
||||
UsesProcessors bool `json:"uses_processors"`
|
||||
AutomatedDecisions bool `json:"automated_decisions"`
|
||||
ProcessesEmployeeData bool `json:"processes_employee_data"`
|
||||
ProcessesHealthData bool `json:"processes_health_data"`
|
||||
ProcessesFinancialData bool `json:"processes_financial_data"`
|
||||
UsesCookies bool `json:"uses_cookies"`
|
||||
UsesTracking bool `json:"uses_tracking"`
|
||||
UsesVideoSurveillance bool `json:"uses_video_surveillance"`
|
||||
OperatesPlatform bool `json:"operates_platform"`
|
||||
PlatformUserCount int `json:"platform_user_count,omitempty"`
|
||||
|
||||
// AI usage
|
||||
ProcAIUsage bool `json:"proc_ai_usage"`
|
||||
IsAIProvider bool `json:"is_ai_provider"`
|
||||
IsAIDeployer bool `json:"is_ai_deployer"`
|
||||
HighRiskAI bool `json:"high_risk_ai"`
|
||||
LimitedRiskAI bool `json:"limited_risk_ai"`
|
||||
|
||||
// Sector / NIS2
|
||||
Sector string `json:"sector,omitempty"`
|
||||
SpecialServices []string `json:"special_services,omitempty"`
|
||||
IsKRITIS bool `json:"is_kritis"`
|
||||
IsFinancialInstitution bool `json:"is_financial_institution"`
|
||||
|
||||
// Scope engine results
|
||||
DeterminedLevel string `json:"determined_level,omitempty"` // L1-L4
|
||||
TriggeredRules []string `json:"triggered_rules,omitempty"`
|
||||
RequiredDocuments []string `json:"required_documents,omitempty"`
|
||||
CertTarget string `json:"cert_target,omitempty"`
|
||||
}
|
||||
|
||||
// MapScopeToFacts converts a ScopeDecision to UnifiedFacts
|
||||
func MapScopeToFacts(scope *ScopeDecision) *UnifiedFacts {
|
||||
facts := NewUnifiedFacts()
|
||||
|
||||
// Organization
|
||||
facts.Organization.EmployeeCount = scope.EmployeeCount
|
||||
facts.Organization.AnnualRevenue = scope.AnnualRevenue
|
||||
facts.Organization.Country = scope.Country
|
||||
facts.Organization.LegalForm = scope.LegalForm
|
||||
if scope.Country != "" {
|
||||
facts.Organization.EUMember = isEUCountryScope(scope.Country)
|
||||
}
|
||||
|
||||
// Data Protection
|
||||
facts.DataProtection.ProcessesPersonalData = scope.ProcessesPersonalData
|
||||
facts.DataProtection.IsController = scope.IsController
|
||||
facts.DataProtection.IsProcessor = scope.IsProcessor
|
||||
facts.DataProtection.ProcessesSpecialCategories = scope.DataArt9
|
||||
facts.DataProtection.ProcessesMinorData = scope.DataMinors
|
||||
facts.DataProtection.LargeScaleProcessing = scope.LargeScale
|
||||
facts.DataProtection.SystematicMonitoring = scope.SystematicMonitoring
|
||||
facts.DataProtection.TransfersToThirdCountries = scope.CrossBorderTransfer
|
||||
facts.DataProtection.CrossBorderProcessing = scope.CrossBorderTransfer
|
||||
facts.DataProtection.UsesExternalProcessor = scope.UsesProcessors
|
||||
facts.DataProtection.AutomatedDecisionMaking = scope.AutomatedDecisions
|
||||
facts.DataProtection.AutomatedDecisions = scope.AutomatedDecisions
|
||||
facts.DataProtection.ProcessesEmployeeData = scope.ProcessesEmployeeData
|
||||
facts.DataProtection.ProcessesHealthData = scope.ProcessesHealthData
|
||||
facts.DataProtection.ProcessesFinancialData = scope.ProcessesFinancialData
|
||||
facts.DataProtection.UsesCookies = scope.UsesCookies
|
||||
facts.DataProtection.UsesTracking = scope.UsesTracking
|
||||
facts.DataProtection.UsesVideoSurveillance = scope.UsesVideoSurveillance
|
||||
facts.DataProtection.OperatesPlatform = scope.OperatesPlatform
|
||||
facts.DataProtection.PlatformUserCount = scope.PlatformUserCount
|
||||
|
||||
// DPO requirement (German law: >= 20 employees processing personal data)
|
||||
if scope.EmployeeCount >= 20 && scope.ProcessesPersonalData {
|
||||
facts.DataProtection.RequiresDSBByLaw = true
|
||||
}
|
||||
|
||||
// AI Usage
|
||||
facts.AIUsage.UsesAI = scope.ProcAIUsage
|
||||
facts.AIUsage.IsAIProvider = scope.IsAIProvider
|
||||
facts.AIUsage.IsAIDeployer = scope.IsAIDeployer
|
||||
facts.AIUsage.HasHighRiskAI = scope.HighRiskAI
|
||||
facts.AIUsage.HasLimitedRiskAI = scope.LimitedRiskAI
|
||||
|
||||
// Sector
|
||||
if scope.Sector != "" {
|
||||
facts.Sector.PrimarySector = scope.Sector
|
||||
} else if scope.Industry != "" {
|
||||
facts.MapDomainToSector(scope.Industry)
|
||||
}
|
||||
facts.Sector.SpecialServices = scope.SpecialServices
|
||||
facts.Sector.IsKRITIS = scope.IsKRITIS
|
||||
facts.Sector.KRITISThresholdMet = scope.IsKRITIS
|
||||
facts.Sector.IsFinancialInstitution = scope.IsFinancialInstitution
|
||||
|
||||
// Financial
|
||||
if scope.IsFinancialInstitution {
|
||||
facts.Financial.IsRegulated = true
|
||||
facts.Financial.DORAApplies = true
|
||||
}
|
||||
|
||||
return facts
|
||||
}
|
||||
|
||||
func isEUCountryScope(country string) bool {
|
||||
euCountries := map[string]bool{
|
||||
"DE": true, "AT": true, "BE": true, "BG": true, "HR": true, "CY": true,
|
||||
"CZ": true, "DK": true, "EE": true, "FI": true, "FR": true, "GR": true,
|
||||
"HU": true, "IE": true, "IT": true, "LV": true, "LT": true, "LU": true,
|
||||
"MT": true, "NL": true, "PL": true, "PT": true, "RO": true, "SK": true,
|
||||
"SI": true, "ES": true, "SE": true,
|
||||
}
|
||||
return euCountries[country]
|
||||
}
|
||||
160
ai-compliance-sdk/internal/ucca/tom_control_loader.go
Normal file
160
ai-compliance-sdk/internal/ucca/tom_control_loader.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// TOMControl represents a single TOM control from the control library
|
||||
type TOMControl struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"` // ORGANIZATIONAL, TECHNICAL
|
||||
ImplementationGuidance string `json:"implementation_guidance,omitempty"`
|
||||
Evidence []string `json:"evidence,omitempty"`
|
||||
AppliesIf *TOMAppliesIf `json:"applies_if,omitempty"`
|
||||
RiskTier string `json:"risk_tier"` // BASELINE, ENHANCED, ADVANCED
|
||||
Mappings TOMControlMapping `json:"mappings,omitempty"`
|
||||
ReviewFrequency string `json:"review_frequency,omitempty"`
|
||||
Priority string `json:"priority"` // CRITICAL, HIGH, MEDIUM, LOW
|
||||
Complexity string `json:"complexity,omitempty"`
|
||||
DomainID string `json:"domain_id,omitempty"` // set during loading
|
||||
}
|
||||
|
||||
// TOMAppliesIf defines when a control applies
|
||||
type TOMAppliesIf struct {
|
||||
Field string `json:"field"`
|
||||
Operator string `json:"operator"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
// TOMControlMapping maps a control to various standards
|
||||
type TOMControlMapping struct {
|
||||
GDPR []string `json:"gdpr,omitempty"`
|
||||
ISO27001 []string `json:"iso27001,omitempty"`
|
||||
BSI []string `json:"bsi,omitempty"`
|
||||
SDM []string `json:"sdm,omitempty"`
|
||||
NIS2 []string `json:"nis2,omitempty"`
|
||||
}
|
||||
|
||||
// TOMControlDomain represents a domain of controls
|
||||
type TOMControlDomain struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Objective string `json:"objective"`
|
||||
Controls []TOMControl `json:"controls"`
|
||||
}
|
||||
|
||||
// TOMControlLibrary is the top-level structure of the control library
|
||||
type TOMControlLibrary struct {
|
||||
Schema string `json:"schema"`
|
||||
Version string `json:"version"`
|
||||
Domains []TOMControlDomain `json:"domains"`
|
||||
}
|
||||
|
||||
// TOMControlIndex provides fast lookup of controls
|
||||
type TOMControlIndex struct {
|
||||
ByID map[string]*TOMControl
|
||||
ByDomain map[string][]*TOMControl
|
||||
ByGDPRArticle map[string][]*TOMControl
|
||||
AllControls []*TOMControl
|
||||
}
|
||||
|
||||
// LoadTOMControls loads the TOM control library from JSON
|
||||
func LoadTOMControls() (*TOMControlIndex, error) {
|
||||
data, err := readTOMControlsFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var library TOMControlLibrary
|
||||
if err := json.Unmarshal(data, &library); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse TOM controls: %w", err)
|
||||
}
|
||||
|
||||
return buildTOMIndex(&library), nil
|
||||
}
|
||||
|
||||
func readTOMControlsFile() ([]byte, error) {
|
||||
// Try multiple candidate paths
|
||||
candidates := []string{
|
||||
"policies/tom_controls_v1.json",
|
||||
"../policies/tom_controls_v1.json",
|
||||
"../../policies/tom_controls_v1.json",
|
||||
}
|
||||
|
||||
// Also try relative to source file
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
if ok {
|
||||
srcDir := filepath.Dir(filename)
|
||||
candidates = append(candidates,
|
||||
filepath.Join(srcDir, "../../policies/tom_controls_v1.json"),
|
||||
)
|
||||
}
|
||||
|
||||
for _, p := range candidates {
|
||||
abs, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
data, err := os.ReadFile(abs)
|
||||
if err == nil {
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("tom_controls_v1.json not found in any candidate path")
|
||||
}
|
||||
|
||||
func buildTOMIndex(library *TOMControlLibrary) *TOMControlIndex {
|
||||
idx := &TOMControlIndex{
|
||||
ByID: make(map[string]*TOMControl),
|
||||
ByDomain: make(map[string][]*TOMControl),
|
||||
ByGDPRArticle: make(map[string][]*TOMControl),
|
||||
}
|
||||
|
||||
for i := range library.Domains {
|
||||
domain := &library.Domains[i]
|
||||
for j := range domain.Controls {
|
||||
ctrl := &domain.Controls[j]
|
||||
ctrl.DomainID = domain.ID
|
||||
|
||||
idx.ByID[ctrl.ID] = ctrl
|
||||
idx.ByDomain[domain.ID] = append(idx.ByDomain[domain.ID], ctrl)
|
||||
idx.AllControls = append(idx.AllControls, ctrl)
|
||||
|
||||
// Index by GDPR article
|
||||
for _, article := range ctrl.Mappings.GDPR {
|
||||
idx.ByGDPRArticle[article] = append(idx.ByGDPRArticle[article], ctrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idx
|
||||
}
|
||||
|
||||
// GetControl returns a control by ID
|
||||
func (idx *TOMControlIndex) GetControl(id string) (*TOMControl, bool) {
|
||||
ctrl, ok := idx.ByID[id]
|
||||
return ctrl, ok
|
||||
}
|
||||
|
||||
// GetControlsByDomain returns all controls for a domain
|
||||
func (idx *TOMControlIndex) GetControlsByDomain(domain string) []*TOMControl {
|
||||
return idx.ByDomain[domain]
|
||||
}
|
||||
|
||||
// GetControlsByGDPRArticle returns controls mapped to a GDPR article
|
||||
func (idx *TOMControlIndex) GetControlsByGDPRArticle(article string) []*TOMControl {
|
||||
return idx.ByGDPRArticle[article]
|
||||
}
|
||||
|
||||
// ValidateControlID checks if a control ID exists
|
||||
func (idx *TOMControlIndex) ValidateControlID(id string) bool {
|
||||
_, ok := idx.ByID[id]
|
||||
return ok
|
||||
}
|
||||
259
ai-compliance-sdk/internal/ucca/tom_gap_analysis.go
Normal file
259
ai-compliance-sdk/internal/ucca/tom_gap_analysis.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// ControlStatus represents the implementation status of a control
|
||||
type ControlStatus string
|
||||
|
||||
const (
|
||||
ControlImplemented ControlStatus = "IMPLEMENTED"
|
||||
ControlPartial ControlStatus = "PARTIAL"
|
||||
ControlNotImplemented ControlStatus = "NOT_IMPLEMENTED"
|
||||
ControlNotApplicable ControlStatus = "NOT_APPLICABLE"
|
||||
)
|
||||
|
||||
// GapAnalysisRequest is the input for gap analysis
|
||||
type GapAnalysisRequest struct {
|
||||
// Obligations that apply (from assessment)
|
||||
Obligations []Obligation `json:"obligations"`
|
||||
// Current implementation status of controls
|
||||
ControlStatusMap map[string]ControlStatus `json:"control_status_map"` // control_id -> status
|
||||
}
|
||||
|
||||
// GapAnalysisResult is the output of gap analysis
|
||||
type GapAnalysisResult struct {
|
||||
CompliancePercent float64 `json:"compliance_percent"` // 0-100
|
||||
TotalControls int `json:"total_controls"`
|
||||
ImplementedControls int `json:"implemented_controls"`
|
||||
PartialControls int `json:"partial_controls"`
|
||||
MissingControls int `json:"missing_controls"`
|
||||
Gaps []GapItem `json:"gaps"`
|
||||
PriorityActions []PriorityAction `json:"priority_actions"`
|
||||
ByDomain map[string]DomainGap `json:"by_domain"`
|
||||
}
|
||||
|
||||
// GapItem represents a single compliance gap
|
||||
type GapItem struct {
|
||||
ControlID string `json:"control_id"`
|
||||
ControlTitle string `json:"control_title"`
|
||||
ControlDomain string `json:"control_domain"`
|
||||
Status ControlStatus `json:"status"`
|
||||
Priority string `json:"priority"`
|
||||
ObligationIDs []string `json:"obligation_ids"`
|
||||
RequiredByCount int `json:"required_by_count"`
|
||||
Impact string `json:"impact"` // "critical", "high", "medium", "low"
|
||||
}
|
||||
|
||||
// PriorityAction is a recommended action to close gaps
|
||||
type PriorityAction struct {
|
||||
Rank int `json:"rank"`
|
||||
Action string `json:"action"`
|
||||
ControlIDs []string `json:"control_ids"`
|
||||
Impact string `json:"impact"`
|
||||
Effort string `json:"effort"` // "low", "medium", "high"
|
||||
}
|
||||
|
||||
// DomainGap summarizes gaps per TOM domain
|
||||
type DomainGap struct {
|
||||
DomainID string `json:"domain_id"`
|
||||
DomainName string `json:"domain_name"`
|
||||
TotalControls int `json:"total_controls"`
|
||||
ImplementedControls int `json:"implemented_controls"`
|
||||
CompliancePercent float64 `json:"compliance_percent"`
|
||||
}
|
||||
|
||||
// TOMGapAnalyzer performs gap analysis between obligations and control implementation
|
||||
type TOMGapAnalyzer struct {
|
||||
mapper *TOMObligationMapper
|
||||
tomIndex *TOMControlIndex
|
||||
}
|
||||
|
||||
// NewTOMGapAnalyzer creates a new gap analyzer
|
||||
func NewTOMGapAnalyzer(mapper *TOMObligationMapper, tomIndex *TOMControlIndex) *TOMGapAnalyzer {
|
||||
return &TOMGapAnalyzer{
|
||||
mapper: mapper,
|
||||
tomIndex: tomIndex,
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze performs gap analysis
|
||||
func (g *TOMGapAnalyzer) Analyze(req *GapAnalysisRequest) *GapAnalysisResult {
|
||||
result := &GapAnalysisResult{
|
||||
Gaps: []GapItem{},
|
||||
PriorityActions: []PriorityAction{},
|
||||
ByDomain: make(map[string]DomainGap),
|
||||
}
|
||||
|
||||
// Derive required controls from obligations
|
||||
requirements := g.mapper.DeriveControlsFromObligations(req.Obligations)
|
||||
result.TotalControls = len(requirements)
|
||||
|
||||
// Track domain stats
|
||||
domainTotal := make(map[string]int)
|
||||
domainImplemented := make(map[string]int)
|
||||
|
||||
for _, ctrl := range requirements {
|
||||
controlID := ctrl.Control.ID
|
||||
domain := ctrl.Control.DomainID
|
||||
|
||||
domainTotal[domain]++
|
||||
|
||||
status, hasStatus := req.ControlStatusMap[controlID]
|
||||
if !hasStatus {
|
||||
status = ControlNotImplemented
|
||||
}
|
||||
|
||||
switch status {
|
||||
case ControlImplemented:
|
||||
result.ImplementedControls++
|
||||
domainImplemented[domain]++
|
||||
case ControlPartial:
|
||||
result.PartialControls++
|
||||
// Count partial as 0.5 for domain
|
||||
domainImplemented[domain]++ // simplified
|
||||
result.Gaps = append(result.Gaps, GapItem{
|
||||
ControlID: controlID,
|
||||
ControlTitle: ctrl.Control.Title,
|
||||
ControlDomain: domain,
|
||||
Status: ControlPartial,
|
||||
Priority: ctrl.Priority,
|
||||
ObligationIDs: ctrl.ObligationIDs,
|
||||
RequiredByCount: ctrl.RequiredByCount,
|
||||
Impact: ctrl.Priority,
|
||||
})
|
||||
case ControlNotImplemented:
|
||||
result.MissingControls++
|
||||
result.Gaps = append(result.Gaps, GapItem{
|
||||
ControlID: controlID,
|
||||
ControlTitle: ctrl.Control.Title,
|
||||
ControlDomain: domain,
|
||||
Status: ControlNotImplemented,
|
||||
Priority: ctrl.Priority,
|
||||
ObligationIDs: ctrl.ObligationIDs,
|
||||
RequiredByCount: ctrl.RequiredByCount,
|
||||
Impact: ctrl.Priority,
|
||||
})
|
||||
case ControlNotApplicable:
|
||||
result.TotalControls-- // Don't count N/A
|
||||
domainTotal[domain]--
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate compliance percent
|
||||
if result.TotalControls > 0 {
|
||||
implemented := float64(result.ImplementedControls) + float64(result.PartialControls)*0.5
|
||||
result.CompliancePercent = (implemented / float64(result.TotalControls)) * 100
|
||||
} else {
|
||||
result.CompliancePercent = 100
|
||||
}
|
||||
|
||||
// Sort gaps by priority
|
||||
priorityRank := map[string]int{"critical": 0, "high": 1, "medium": 2, "low": 3}
|
||||
sort.Slice(result.Gaps, func(i, j int) bool {
|
||||
ri := priorityRank[result.Gaps[i].Priority]
|
||||
rj := priorityRank[result.Gaps[j].Priority]
|
||||
if ri != rj {
|
||||
return ri < rj
|
||||
}
|
||||
return result.Gaps[i].RequiredByCount > result.Gaps[j].RequiredByCount
|
||||
})
|
||||
|
||||
// Build domain gaps
|
||||
for domain, total := range domainTotal {
|
||||
if total <= 0 {
|
||||
continue
|
||||
}
|
||||
impl := domainImplemented[domain]
|
||||
pct := float64(impl) / float64(total) * 100
|
||||
domainName := domain
|
||||
if ctrls := g.tomIndex.GetControlsByDomain(domain); len(ctrls) > 0 {
|
||||
domainName = domain // Use domain ID as name
|
||||
}
|
||||
result.ByDomain[domain] = DomainGap{
|
||||
DomainID: domain,
|
||||
DomainName: domainName,
|
||||
TotalControls: total,
|
||||
ImplementedControls: impl,
|
||||
CompliancePercent: pct,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate priority actions
|
||||
result.PriorityActions = g.generatePriorityActions(result.Gaps)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (g *TOMGapAnalyzer) generatePriorityActions(gaps []GapItem) []PriorityAction {
|
||||
var actions []PriorityAction
|
||||
rank := 1
|
||||
|
||||
// Group critical gaps by domain
|
||||
domainGaps := make(map[string][]GapItem)
|
||||
for _, gap := range gaps {
|
||||
if gap.Status == ControlNotImplemented {
|
||||
domainGaps[gap.ControlDomain] = append(domainGaps[gap.ControlDomain], gap)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate actions for domains with most critical gaps
|
||||
type domainPriority struct {
|
||||
domain string
|
||||
gaps []GapItem
|
||||
critCount int
|
||||
}
|
||||
var dp []domainPriority
|
||||
for domain, gs := range domainGaps {
|
||||
crit := 0
|
||||
for _, g := range gs {
|
||||
if g.Priority == "critical" {
|
||||
crit++
|
||||
}
|
||||
}
|
||||
dp = append(dp, domainPriority{domain, gs, crit})
|
||||
}
|
||||
sort.Slice(dp, func(i, j int) bool {
|
||||
if dp[i].critCount != dp[j].critCount {
|
||||
return dp[i].critCount > dp[j].critCount
|
||||
}
|
||||
return len(dp[i].gaps) > len(dp[j].gaps)
|
||||
})
|
||||
|
||||
for _, d := range dp {
|
||||
if rank > 10 {
|
||||
break
|
||||
}
|
||||
var controlIDs []string
|
||||
for _, g := range d.gaps {
|
||||
controlIDs = append(controlIDs, g.ControlID)
|
||||
}
|
||||
|
||||
impact := "medium"
|
||||
if d.critCount > 0 {
|
||||
impact = "critical"
|
||||
} else if len(d.gaps) > 3 {
|
||||
impact = "high"
|
||||
}
|
||||
|
||||
effort := "medium"
|
||||
if len(d.gaps) > 5 {
|
||||
effort = "high"
|
||||
} else if len(d.gaps) <= 2 {
|
||||
effort = "low"
|
||||
}
|
||||
|
||||
actions = append(actions, PriorityAction{
|
||||
Rank: rank,
|
||||
Action: fmt.Sprintf("Domain %s: %d fehlende Controls implementieren", d.domain, len(d.gaps)),
|
||||
ControlIDs: controlIDs,
|
||||
Impact: impact,
|
||||
Effort: effort,
|
||||
})
|
||||
rank++
|
||||
}
|
||||
|
||||
return actions
|
||||
}
|
||||
175
ai-compliance-sdk/internal/ucca/tom_mapper_test.go
Normal file
175
ai-compliance-sdk/internal/ucca/tom_mapper_test.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTOMControlLoader(t *testing.T) {
|
||||
index, err := LoadTOMControls()
|
||||
if err != nil {
|
||||
t.Skipf("TOM controls not found: %v", err)
|
||||
}
|
||||
|
||||
if len(index.ByID) == 0 {
|
||||
t.Error("expected controls indexed by ID")
|
||||
}
|
||||
if len(index.ByDomain) == 0 {
|
||||
t.Error("expected controls indexed by domain")
|
||||
}
|
||||
t.Logf("Loaded %d TOM controls across %d domains", len(index.ByID), len(index.ByDomain))
|
||||
|
||||
// Check known control
|
||||
ctrl, ok := index.GetControl("TOM.GOV.01")
|
||||
if !ok || ctrl == nil {
|
||||
t.Error("expected TOM.GOV.01 to exist")
|
||||
} else if ctrl.Title == "" {
|
||||
t.Error("expected TOM.GOV.01 to have a title")
|
||||
}
|
||||
|
||||
// Check domain
|
||||
govCtrls := index.GetControlsByDomain("GOV")
|
||||
if len(govCtrls) == 0 {
|
||||
t.Error("expected GOV domain to have controls")
|
||||
}
|
||||
|
||||
// Validate known ID
|
||||
if !index.ValidateControlID("TOM.GOV.01") {
|
||||
t.Error("TOM.GOV.01 should be valid")
|
||||
}
|
||||
if index.ValidateControlID("TOM.FAKE.99") {
|
||||
t.Error("TOM.FAKE.99 should be invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTOMObligationMapper_FromObligations(t *testing.T) {
|
||||
index, err := LoadTOMControls()
|
||||
if err != nil {
|
||||
t.Skipf("TOM controls not found: %v", err)
|
||||
}
|
||||
|
||||
// Create test obligations with tom_control_ids
|
||||
obligations := []V2Obligation{
|
||||
{
|
||||
ID: "TEST-OBL-001",
|
||||
TOMControlIDs: []string{"TOM.GOV.01", "TOM.GOV.02"},
|
||||
Priority: "kritisch",
|
||||
},
|
||||
{
|
||||
ID: "TEST-OBL-002",
|
||||
TOMControlIDs: []string{"TOM.GOV.01", "TOM.CRYPTO.01"},
|
||||
Priority: "hoch",
|
||||
},
|
||||
}
|
||||
|
||||
mapper := NewTOMObligationMapperFromObligations(index, obligations)
|
||||
|
||||
// Check obligation->control
|
||||
controls := mapper.GetControlsForObligation("TEST-OBL-001")
|
||||
if len(controls) != 2 {
|
||||
t.Errorf("expected 2 controls for TEST-OBL-001, got %d", len(controls))
|
||||
}
|
||||
|
||||
// Check control->obligation (reverse)
|
||||
oblIDs := mapper.GetObligationsForControl("TOM.GOV.01")
|
||||
if len(oblIDs) != 2 {
|
||||
t.Errorf("expected 2 obligations for TOM.GOV.01, got %d", len(oblIDs))
|
||||
}
|
||||
|
||||
// Check deduplicated requirements
|
||||
frameworkObls := make([]Obligation, len(obligations))
|
||||
for i, o := range obligations {
|
||||
frameworkObls[i] = Obligation{
|
||||
ID: o.ID,
|
||||
Priority: ObligationPriority(o.Priority),
|
||||
ExternalResources: o.TOMControlIDs,
|
||||
}
|
||||
}
|
||||
reqs := mapper.DeriveControlsFromObligations(frameworkObls)
|
||||
if len(reqs) == 0 {
|
||||
t.Error("expected derived control requirements")
|
||||
}
|
||||
|
||||
// GOV.01 should appear once but with 2 obligation references
|
||||
for _, req := range reqs {
|
||||
if req.Control != nil && req.Control.ID == "TOM.GOV.01" {
|
||||
if req.RequiredByCount != 2 {
|
||||
t.Errorf("expected TOM.GOV.01 required by 2, got %d", req.RequiredByCount)
|
||||
}
|
||||
if req.Priority != "kritisch" {
|
||||
t.Errorf("expected highest priority 'kritisch', got '%s'", req.Priority)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Error("TOM.GOV.01 not found in derived requirements")
|
||||
}
|
||||
|
||||
func TestTOMGapAnalysis(t *testing.T) {
|
||||
index, err := LoadTOMControls()
|
||||
if err != nil {
|
||||
t.Skipf("TOM controls not found: %v", err)
|
||||
}
|
||||
|
||||
obligations := []V2Obligation{
|
||||
{ID: "T-001", TOMControlIDs: []string{"TOM.GOV.01"}, Priority: "kritisch"},
|
||||
{ID: "T-002", TOMControlIDs: []string{"TOM.GOV.01", "TOM.CRYPTO.01"}, Priority: "hoch"},
|
||||
}
|
||||
mapper := NewTOMObligationMapperFromObligations(index, obligations)
|
||||
analyzer := NewTOMGapAnalyzer(mapper, index)
|
||||
|
||||
frameworkObls := []Obligation{
|
||||
{ID: "T-001", Priority: "kritisch", ExternalResources: []string{"TOM.GOV.01"}},
|
||||
{ID: "T-002", Priority: "hoch", ExternalResources: []string{"TOM.GOV.01", "TOM.CRYPTO.01"}},
|
||||
}
|
||||
|
||||
result := analyzer.Analyze(&GapAnalysisRequest{
|
||||
Obligations: frameworkObls,
|
||||
ControlStatusMap: map[string]ControlStatus{
|
||||
"TOM.GOV.01": ControlImplemented,
|
||||
"TOM.CRYPTO.01": ControlNotImplemented,
|
||||
},
|
||||
})
|
||||
|
||||
if result.TotalControls != 2 {
|
||||
t.Errorf("expected 2 total controls, got %d", result.TotalControls)
|
||||
}
|
||||
if result.ImplementedControls != 1 {
|
||||
t.Errorf("expected 1 implemented, got %d", result.ImplementedControls)
|
||||
}
|
||||
if result.MissingControls != 1 {
|
||||
t.Errorf("expected 1 missing, got %d", result.MissingControls)
|
||||
}
|
||||
if result.CompliancePercent != 50 {
|
||||
t.Errorf("expected 50%% compliance, got %.1f%%", result.CompliancePercent)
|
||||
}
|
||||
if len(result.Gaps) != 1 {
|
||||
t.Errorf("expected 1 gap, got %d", len(result.Gaps))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTOMGapAnalysis_AllImplemented(t *testing.T) {
|
||||
index, err := LoadTOMControls()
|
||||
if err != nil {
|
||||
t.Skipf("TOM controls not found: %v", err)
|
||||
}
|
||||
|
||||
obligations := []V2Obligation{
|
||||
{ID: "T-001", TOMControlIDs: []string{"TOM.GOV.01"}, Priority: "hoch"},
|
||||
}
|
||||
mapper := NewTOMObligationMapperFromObligations(index, obligations)
|
||||
analyzer := NewTOMGapAnalyzer(mapper, index)
|
||||
|
||||
result := analyzer.Analyze(&GapAnalysisRequest{
|
||||
Obligations: []Obligation{{ID: "T-001", Priority: "hoch", ExternalResources: []string{"TOM.GOV.01"}}},
|
||||
ControlStatusMap: map[string]ControlStatus{
|
||||
"TOM.GOV.01": ControlImplemented,
|
||||
},
|
||||
})
|
||||
|
||||
if result.CompliancePercent != 100 {
|
||||
t.Errorf("expected 100%% compliance, got %.1f%%", result.CompliancePercent)
|
||||
}
|
||||
if len(result.Gaps) != 0 {
|
||||
t.Errorf("expected 0 gaps, got %d", len(result.Gaps))
|
||||
}
|
||||
}
|
||||
150
ai-compliance-sdk/internal/ucca/tom_obligation_mapper.go
Normal file
150
ai-compliance-sdk/internal/ucca/tom_obligation_mapper.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// TOMObligationMapper provides bidirectional mapping between obligations and TOM controls
|
||||
type TOMObligationMapper struct {
|
||||
tomIndex *TOMControlIndex
|
||||
obligationToControl map[string][]string // obligation_id -> []control_id
|
||||
controlToObligation map[string][]string // control_id -> []obligation_id
|
||||
}
|
||||
|
||||
// TOMControlRequirement represents a required TOM control with context
|
||||
type TOMControlRequirement struct {
|
||||
Control *TOMControl `json:"control"`
|
||||
ObligationIDs []string `json:"obligation_ids"`
|
||||
Priority string `json:"priority"` // highest priority from linked obligations
|
||||
RequiredByCount int `json:"required_by_count"` // number of obligations requiring this
|
||||
}
|
||||
|
||||
// NewTOMObligationMapper creates a new mapper from TOM index and v2 mapping
|
||||
func NewTOMObligationMapper(tomIndex *TOMControlIndex, mapping *V2TOMMapping) *TOMObligationMapper {
|
||||
m := &TOMObligationMapper{
|
||||
tomIndex: tomIndex,
|
||||
obligationToControl: make(map[string][]string),
|
||||
controlToObligation: make(map[string][]string),
|
||||
}
|
||||
|
||||
if mapping != nil {
|
||||
m.obligationToControl = mapping.ObligationToControl
|
||||
m.controlToObligation = mapping.ControlToObligation
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// NewTOMObligationMapperFromObligations builds the mapper from obligations' tom_control_ids
|
||||
func NewTOMObligationMapperFromObligations(tomIndex *TOMControlIndex, obligations []V2Obligation) *TOMObligationMapper {
|
||||
m := &TOMObligationMapper{
|
||||
tomIndex: tomIndex,
|
||||
obligationToControl: make(map[string][]string),
|
||||
controlToObligation: make(map[string][]string),
|
||||
}
|
||||
|
||||
for _, obl := range obligations {
|
||||
for _, controlID := range obl.TOMControlIDs {
|
||||
m.obligationToControl[obl.ID] = append(m.obligationToControl[obl.ID], controlID)
|
||||
m.controlToObligation[controlID] = append(m.controlToObligation[controlID], obl.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// GetControlsForObligation returns TOM controls linked to an obligation
|
||||
func (m *TOMObligationMapper) GetControlsForObligation(obligationID string) []*TOMControl {
|
||||
controlIDs := m.obligationToControl[obligationID]
|
||||
var result []*TOMControl
|
||||
for _, id := range controlIDs {
|
||||
if ctrl, ok := m.tomIndex.GetControl(id); ok {
|
||||
result = append(result, ctrl)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetControlIDsForObligation returns control IDs for an obligation
|
||||
func (m *TOMObligationMapper) GetControlIDsForObligation(obligationID string) []string {
|
||||
return m.obligationToControl[obligationID]
|
||||
}
|
||||
|
||||
// GetObligationsForControl returns obligation IDs linked to a control
|
||||
func (m *TOMObligationMapper) GetObligationsForControl(controlID string) []string {
|
||||
return m.controlToObligation[controlID]
|
||||
}
|
||||
|
||||
// DeriveControlsFromObligations takes a list of applicable obligations and returns
|
||||
// deduplicated, priority-sorted TOM control requirements
|
||||
func (m *TOMObligationMapper) DeriveControlsFromObligations(obligations []Obligation) []TOMControlRequirement {
|
||||
// Collect all required controls with their linking obligations
|
||||
controlMap := make(map[string]*TOMControlRequirement)
|
||||
|
||||
priorityRank := map[string]int{"critical": 0, "high": 1, "medium": 2, "low": 3}
|
||||
|
||||
for _, obl := range obligations {
|
||||
// Get control IDs from ExternalResources (where tom_control_ids are stored)
|
||||
controlIDs := obl.ExternalResources
|
||||
if len(controlIDs) == 0 {
|
||||
controlIDs = m.obligationToControl[obl.ID]
|
||||
}
|
||||
|
||||
for _, controlID := range controlIDs {
|
||||
ctrl, ok := m.tomIndex.GetControl(controlID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if existing, found := controlMap[controlID]; found {
|
||||
existing.ObligationIDs = append(existing.ObligationIDs, obl.ID)
|
||||
existing.RequiredByCount++
|
||||
// Keep highest priority
|
||||
if rank, ok := priorityRank[string(obl.Priority)]; ok {
|
||||
if existingRank, ok2 := priorityRank[existing.Priority]; ok2 && rank < existingRank {
|
||||
existing.Priority = string(obl.Priority)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
controlMap[controlID] = &TOMControlRequirement{
|
||||
Control: ctrl,
|
||||
ObligationIDs: []string{obl.ID},
|
||||
Priority: string(obl.Priority),
|
||||
RequiredByCount: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to slice and sort by priority then required_by_count
|
||||
var result []TOMControlRequirement
|
||||
for _, req := range controlMap {
|
||||
result = append(result, *req)
|
||||
}
|
||||
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
ri := priorityRank[result[i].Priority]
|
||||
rj := priorityRank[result[j].Priority]
|
||||
if ri != rj {
|
||||
return ri < rj
|
||||
}
|
||||
return result[i].RequiredByCount > result[j].RequiredByCount
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// AddMapping adds a single obligation->control mapping
|
||||
func (m *TOMObligationMapper) AddMapping(obligationID, controlID string) {
|
||||
m.obligationToControl[obligationID] = appendUnique(m.obligationToControl[obligationID], controlID)
|
||||
m.controlToObligation[controlID] = appendUnique(m.controlToObligation[controlID], obligationID)
|
||||
}
|
||||
|
||||
func appendUnique(slice []string, item string) []string {
|
||||
for _, s := range slice {
|
||||
if s == item {
|
||||
return slice
|
||||
}
|
||||
}
|
||||
return append(slice, item)
|
||||
}
|
||||
@@ -85,6 +85,11 @@ type SectorFacts struct {
|
||||
IsPublicAdministration bool `json:"is_public_administration"`
|
||||
PublicAdminLevel string `json:"public_admin_level,omitempty"` // "federal", "state", "municipal"
|
||||
|
||||
// NIS2 classification (v2)
|
||||
NIS2Classification string `json:"nis2_classification,omitempty"` // wichtige_einrichtung, besonders_wichtige_einrichtung, nicht_betroffen
|
||||
IsAnnexI bool `json:"is_annex_i"`
|
||||
IsAnnexII bool `json:"is_annex_ii"`
|
||||
|
||||
// Healthcare specific
|
||||
IsHealthcareProvider bool `json:"is_healthcare_provider"`
|
||||
HasPatientData bool `json:"has_patient_data"`
|
||||
@@ -141,6 +146,19 @@ type DataProtectionFacts struct {
|
||||
RequiresDSBByLaw bool `json:"requires_dsb_by_law"`
|
||||
HasAppointedDSB bool `json:"has_appointed_dsb"`
|
||||
DSBIsInternal bool `json:"dsb_is_internal"`
|
||||
|
||||
// Extended data categories (v2)
|
||||
ProcessesEmployeeData bool `json:"processes_employee_data"`
|
||||
ProcessesFinancialData bool `json:"processes_financial_data"`
|
||||
ProcessesHealthData bool `json:"processes_health_data"`
|
||||
ProcessesBiometricData bool `json:"processes_biometric_data"`
|
||||
|
||||
// Online / Platform processing (v2)
|
||||
UsesCookies bool `json:"uses_cookies"`
|
||||
UsesTracking bool `json:"uses_tracking"`
|
||||
UsesVideoSurveillance bool `json:"uses_video_surveillance"`
|
||||
OperatesPlatform bool `json:"operates_platform"`
|
||||
PlatformUserCount int `json:"platform_user_count,omitempty"`
|
||||
}
|
||||
|
||||
// AIUsageFacts contains AI Act relevant information
|
||||
|
||||
233
ai-compliance-sdk/internal/ucca/v2_loader.go
Normal file
233
ai-compliance-sdk/internal/ucca/v2_loader.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// V2Manifest represents the registry of all v2 obligation files
|
||||
type V2Manifest struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
Regulations []V2RegulationEntry `json:"regulations"`
|
||||
TOMMappingFile string `json:"tom_mapping_file"`
|
||||
TotalObl int `json:"total_obligations"`
|
||||
}
|
||||
|
||||
// V2RegulationEntry is a single regulation in the manifest
|
||||
type V2RegulationEntry struct {
|
||||
ID string `json:"id"`
|
||||
File string `json:"file"`
|
||||
Version string `json:"version"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
// V2RegulationFile is the top-level structure of a v2 regulation JSON file
|
||||
type V2RegulationFile struct {
|
||||
Regulation string `json:"regulation"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
EffectiveDate string `json:"effective_date,omitempty"`
|
||||
Obligations []V2Obligation `json:"obligations"`
|
||||
Controls []V2Control `json:"controls,omitempty"`
|
||||
IncidentDL []V2IncidentDL `json:"incident_deadlines,omitempty"`
|
||||
}
|
||||
|
||||
// V2Obligation is the extended obligation structure
|
||||
type V2Obligation struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
AppliesWhen string `json:"applies_when"`
|
||||
AppliesWhenCondition *ConditionNode `json:"applies_when_condition,omitempty"`
|
||||
LegalBasis []V2LegalBasis `json:"legal_basis"`
|
||||
Sources []V2Source `json:"sources,omitempty"`
|
||||
Category string `json:"category"`
|
||||
Responsible string `json:"responsible"`
|
||||
Deadline *V2Deadline `json:"deadline,omitempty"`
|
||||
Sanctions *V2Sanctions `json:"sanctions,omitempty"`
|
||||
Evidence []interface{} `json:"evidence,omitempty"`
|
||||
Priority string `json:"priority"`
|
||||
TOMControlIDs []string `json:"tom_control_ids,omitempty"`
|
||||
BreakpilotFeature string `json:"breakpilot_feature,omitempty"`
|
||||
ValidFrom string `json:"valid_from,omitempty"`
|
||||
ValidUntil *string `json:"valid_until"`
|
||||
Version string `json:"version,omitempty"`
|
||||
ISO27001Mapping []string `json:"iso27001_mapping,omitempty"`
|
||||
HowToImplement string `json:"how_to_implement,omitempty"`
|
||||
}
|
||||
|
||||
// V2LegalBasis is a legal reference in v2 format
|
||||
type V2LegalBasis struct {
|
||||
Norm string `json:"norm"`
|
||||
Article string `json:"article"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Erwaegungsgrund string `json:"erwaegungsgrund,omitempty"`
|
||||
}
|
||||
|
||||
// V2Source is an external source reference
|
||||
type V2Source struct {
|
||||
Type string `json:"type"`
|
||||
Ref string `json:"ref"`
|
||||
}
|
||||
|
||||
// V2Deadline is a deadline in v2 format
|
||||
type V2Deadline struct {
|
||||
Type string `json:"type"`
|
||||
Date string `json:"date,omitempty"`
|
||||
Duration string `json:"duration,omitempty"`
|
||||
Interval string `json:"interval,omitempty"`
|
||||
Event string `json:"event,omitempty"`
|
||||
}
|
||||
|
||||
// V2Sanctions is sanctions info in v2 format
|
||||
type V2Sanctions struct {
|
||||
MaxFine string `json:"max_fine,omitempty"`
|
||||
PersonalLiability bool `json:"personal_liability,omitempty"`
|
||||
CriminalLiability bool `json:"criminal_liability,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// V2Control is a control in v2 format
|
||||
type V2Control struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Category string `json:"category"`
|
||||
WhatToDo string `json:"what_to_do,omitempty"`
|
||||
ISO27001Mapping []string `json:"iso27001_mapping,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
// V2IncidentDL is an incident deadline in v2 format
|
||||
type V2IncidentDL struct {
|
||||
Phase string `json:"phase"`
|
||||
Deadline string `json:"deadline"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Recipient string `json:"recipient,omitempty"`
|
||||
LegalBasis []V2LegalBasis `json:"legal_basis,omitempty"`
|
||||
}
|
||||
|
||||
// ConditionNode represents a condition tree node for obligation applicability
|
||||
type ConditionNode struct {
|
||||
AllOf []ConditionNode `json:"all_of,omitempty"`
|
||||
AnyOf []ConditionNode `json:"any_of,omitempty"`
|
||||
Field string `json:"field,omitempty"`
|
||||
Operator string `json:"operator,omitempty"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// V2TOMMapping is the bidirectional mapping file
|
||||
type V2TOMMapping struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
ObligationToControl map[string][]string `json:"obligation_to_control"`
|
||||
ControlToObligation map[string][]string `json:"control_to_obligation"`
|
||||
}
|
||||
|
||||
// getV2BasePath returns the base path for v2 obligation files
|
||||
func getV2BasePath() string {
|
||||
// Try relative to the binary
|
||||
candidates := []string{
|
||||
"policies/obligations/v2",
|
||||
"../policies/obligations/v2",
|
||||
"../../policies/obligations/v2",
|
||||
}
|
||||
|
||||
// Also try relative to the source file
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
if ok {
|
||||
srcDir := filepath.Dir(filename)
|
||||
candidates = append(candidates,
|
||||
filepath.Join(srcDir, "../../policies/obligations/v2"),
|
||||
)
|
||||
}
|
||||
|
||||
for _, p := range candidates {
|
||||
abs, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if info, err := os.Stat(abs); err == nil && info.IsDir() {
|
||||
return abs
|
||||
}
|
||||
}
|
||||
|
||||
return "policies/obligations/v2"
|
||||
}
|
||||
|
||||
// LoadV2Manifest loads the v2 manifest file
|
||||
func LoadV2Manifest() (*V2Manifest, error) {
|
||||
basePath := getV2BasePath()
|
||||
manifestPath := filepath.Join(basePath, "_manifest.json")
|
||||
|
||||
data, err := os.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read v2 manifest: %w", err)
|
||||
}
|
||||
|
||||
var manifest V2Manifest
|
||||
if err := json.Unmarshal(data, &manifest); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse v2 manifest: %w", err)
|
||||
}
|
||||
|
||||
return &manifest, nil
|
||||
}
|
||||
|
||||
// LoadV2RegulationFile loads a single v2 regulation JSON file
|
||||
func LoadV2RegulationFile(filename string) (*V2RegulationFile, error) {
|
||||
basePath := getV2BasePath()
|
||||
filePath := filepath.Join(basePath, filename)
|
||||
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read v2 regulation file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
var regFile V2RegulationFile
|
||||
if err := json.Unmarshal(data, ®File); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse v2 regulation file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
return ®File, nil
|
||||
}
|
||||
|
||||
// LoadV2TOMMapping loads the bidirectional TOM mapping
|
||||
func LoadV2TOMMapping() (*V2TOMMapping, error) {
|
||||
basePath := getV2BasePath()
|
||||
mappingPath := filepath.Join(basePath, "_tom_mapping.json")
|
||||
|
||||
data, err := os.ReadFile(mappingPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read TOM mapping: %w", err)
|
||||
}
|
||||
|
||||
var mapping V2TOMMapping
|
||||
if err := json.Unmarshal(data, &mapping); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse TOM mapping: %w", err)
|
||||
}
|
||||
|
||||
return &mapping, nil
|
||||
}
|
||||
|
||||
// LoadAllV2Regulations loads all v2 regulation files from the manifest
|
||||
func LoadAllV2Regulations() (map[string]*V2RegulationFile, error) {
|
||||
manifest, err := LoadV2Manifest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]*V2RegulationFile)
|
||||
for _, entry := range manifest.Regulations {
|
||||
regFile, err := LoadV2RegulationFile(entry.File)
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: Could not load v2 regulation %s: %v\n", entry.ID, err)
|
||||
continue
|
||||
}
|
||||
result[entry.ID] = regFile
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
137
ai-compliance-sdk/internal/ucca/v2_loader_test.go
Normal file
137
ai-compliance-sdk/internal/ucca/v2_loader_test.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadV2Manifest(t *testing.T) {
|
||||
manifest, err := LoadV2Manifest()
|
||||
if err != nil {
|
||||
t.Skipf("v2 manifest not found (expected in CI): %v", err)
|
||||
}
|
||||
|
||||
if manifest.SchemaVersion != "2.0" {
|
||||
t.Errorf("expected schema_version 2.0, got %s", manifest.SchemaVersion)
|
||||
}
|
||||
if len(manifest.Regulations) == 0 {
|
||||
t.Error("expected at least one regulation in manifest")
|
||||
}
|
||||
|
||||
// Check known regulations
|
||||
regIDs := make(map[string]bool)
|
||||
for _, r := range manifest.Regulations {
|
||||
regIDs[r.ID] = true
|
||||
}
|
||||
for _, expected := range []string{"dsgvo", "ai_act", "nis2"} {
|
||||
if !regIDs[expected] {
|
||||
t.Errorf("expected regulation %s in manifest", expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadV2RegulationFile_DSGVO(t *testing.T) {
|
||||
basePath := getV2BasePath()
|
||||
if _, err := os.Stat(basePath + "/dsgvo_v2.json"); os.IsNotExist(err) {
|
||||
t.Skip("dsgvo_v2.json not found")
|
||||
}
|
||||
|
||||
data, err := LoadV2RegulationFile("dsgvo_v2.json")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load dsgvo_v2.json: %v", err)
|
||||
}
|
||||
|
||||
if data.Regulation != "dsgvo" {
|
||||
t.Errorf("expected regulation dsgvo, got %s", data.Regulation)
|
||||
}
|
||||
if len(data.Obligations) < 11 {
|
||||
t.Errorf("expected at least 11 DSGVO obligations (existing), got %d", len(data.Obligations))
|
||||
}
|
||||
|
||||
// Verify first obligation preserves existing ID
|
||||
if data.Obligations[0].ID != "DSGVO-OBL-001" {
|
||||
t.Errorf("expected first obligation DSGVO-OBL-001, got %s", data.Obligations[0].ID)
|
||||
}
|
||||
|
||||
// Verify v2 fields are present
|
||||
obl := data.Obligations[0]
|
||||
if obl.ValidFrom == "" {
|
||||
t.Error("expected valid_from on first obligation")
|
||||
}
|
||||
if len(obl.TOMControlIDs) == 0 {
|
||||
t.Error("expected tom_control_ids on first obligation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadV2RegulationFile_AIAct(t *testing.T) {
|
||||
basePath := getV2BasePath()
|
||||
if _, err := os.Stat(basePath + "/ai_act_v2.json"); os.IsNotExist(err) {
|
||||
t.Skip("ai_act_v2.json not found")
|
||||
}
|
||||
|
||||
data, err := LoadV2RegulationFile("ai_act_v2.json")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load: %v", err)
|
||||
}
|
||||
|
||||
if len(data.Obligations) < 15 {
|
||||
t.Errorf("expected at least 15 AI Act obligations (existing), got %d", len(data.Obligations))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadV2RegulationFile_NIS2(t *testing.T) {
|
||||
basePath := getV2BasePath()
|
||||
if _, err := os.Stat(basePath + "/nis2_v2.json"); os.IsNotExist(err) {
|
||||
t.Skip("nis2_v2.json not found")
|
||||
}
|
||||
|
||||
data, err := LoadV2RegulationFile("nis2_v2.json")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load: %v", err)
|
||||
}
|
||||
|
||||
if len(data.Obligations) < 14 {
|
||||
t.Errorf("expected at least 14 NIS2 obligations (existing), got %d", len(data.Obligations))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadAllV2Regulations(t *testing.T) {
|
||||
regs, err := LoadAllV2Regulations()
|
||||
if err != nil {
|
||||
t.Skipf("v2 regulations not found: %v", err)
|
||||
}
|
||||
|
||||
if len(regs) < 3 {
|
||||
t.Errorf("expected at least 3 loaded regulations, got %d", len(regs))
|
||||
}
|
||||
|
||||
totalObl := 0
|
||||
for _, r := range regs {
|
||||
totalObl += len(r.Obligations)
|
||||
}
|
||||
if totalObl < 40 {
|
||||
t.Errorf("expected at least 40 total obligations, got %d", totalObl)
|
||||
}
|
||||
t.Logf("Loaded %d regulations with %d total obligations", len(regs), totalObl)
|
||||
}
|
||||
|
||||
func TestLoadV2TOMMapping(t *testing.T) {
|
||||
basePath := getV2BasePath()
|
||||
if _, err := os.Stat(basePath + "/_tom_mapping.json"); os.IsNotExist(err) {
|
||||
t.Skip("_tom_mapping.json not found")
|
||||
}
|
||||
|
||||
mapping, err := LoadV2TOMMapping()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load TOM mapping: %v", err)
|
||||
}
|
||||
|
||||
if len(mapping.ObligationToControl) == 0 {
|
||||
t.Error("expected obligation_to_control mappings")
|
||||
}
|
||||
if len(mapping.ControlToObligation) == 0 {
|
||||
t.Error("expected control_to_obligation mappings")
|
||||
}
|
||||
t.Logf("TOM mapping: %d obligation->control, %d control->obligation",
|
||||
len(mapping.ObligationToControl), len(mapping.ControlToObligation))
|
||||
}
|
||||
61
ai-compliance-sdk/policies/obligations/v2/_manifest.json
Normal file
61
ai-compliance-sdk/policies/obligations/v2/_manifest.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"schema_version": "2.0",
|
||||
"regulations": [
|
||||
{
|
||||
"id": "dsgvo",
|
||||
"file": "dsgvo_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 80
|
||||
},
|
||||
{
|
||||
"id": "ai_act",
|
||||
"file": "ai_act_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 60
|
||||
},
|
||||
{
|
||||
"id": "nis2",
|
||||
"file": "nis2_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 40
|
||||
},
|
||||
{
|
||||
"id": "bdsg",
|
||||
"file": "bdsg_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 30
|
||||
},
|
||||
{
|
||||
"id": "ttdsg",
|
||||
"file": "ttdsg_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 20
|
||||
},
|
||||
{
|
||||
"id": "dsa",
|
||||
"file": "dsa_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 35
|
||||
},
|
||||
{
|
||||
"id": "data_act",
|
||||
"file": "data_act_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 25
|
||||
},
|
||||
{
|
||||
"id": "eu_machinery",
|
||||
"file": "eu_machinery_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 15
|
||||
},
|
||||
{
|
||||
"id": "dora",
|
||||
"file": "dora_v2.json",
|
||||
"version": "1.0",
|
||||
"count": 20
|
||||
}
|
||||
],
|
||||
"tom_mapping_file": "_tom_mapping.json",
|
||||
"total_obligations": 325
|
||||
}
|
||||
162
ai-compliance-sdk/policies/obligations/v2/_schema.json
Normal file
162
ai-compliance-sdk/policies/obligations/v2/_schema.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Obligation v2 Schema",
|
||||
"description": "Schema fuer maschinenlesbare Compliance-Pflichten",
|
||||
"type": "object",
|
||||
"required": ["regulation", "name", "version", "obligations"],
|
||||
"properties": {
|
||||
"regulation": { "type": "string", "description": "Regulation-Key (z.B. dsgvo, ai_act, nis2)" },
|
||||
"name": { "type": "string" },
|
||||
"description": { "type": "string" },
|
||||
"version": { "type": "string" },
|
||||
"effective_date": { "type": "string", "format": "date" },
|
||||
"obligations": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/obligation" }
|
||||
},
|
||||
"controls": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/control" }
|
||||
},
|
||||
"incident_deadlines": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/incident_deadline" }
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"obligation": {
|
||||
"type": "object",
|
||||
"required": ["id", "title", "description", "applies_when", "legal_basis", "category", "priority"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[A-Z0-9_-]+-OBL-[0-9]{3}$" },
|
||||
"title": { "type": "string" },
|
||||
"description": { "type": "string" },
|
||||
"applies_when": { "type": "string", "description": "Legacy condition string for backwards compat" },
|
||||
"applies_when_condition": { "$ref": "#/$defs/condition_node" },
|
||||
"legal_basis": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["norm", "article"],
|
||||
"properties": {
|
||||
"norm": { "type": "string" },
|
||||
"article": { "type": "string" },
|
||||
"title": { "type": "string" },
|
||||
"erwaegungsgrund": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"sources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["type", "ref"],
|
||||
"properties": {
|
||||
"type": { "type": "string", "enum": ["article", "erwaegungsgrund", "edpb_guideline", "dsk_kurzpapier", "bsi_standard", "eu_guidance", "national_law", "case_law"] },
|
||||
"ref": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"category": { "type": "string", "enum": ["Governance", "Technisch", "Organisatorisch", "Meldepflicht", "Dokumentation", "Schulung", "Audit", "Compliance"] },
|
||||
"responsible": { "type": "string" },
|
||||
"deadline": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "type": "string", "enum": ["absolute", "relative", "recurring", "on_event"] },
|
||||
"date": { "type": "string", "format": "date" },
|
||||
"duration": { "type": "string" },
|
||||
"interval": { "type": "string" },
|
||||
"event": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"sanctions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"max_fine": { "type": "string" },
|
||||
"min_fine": { "type": "string" },
|
||||
"personal_liability": { "type": "boolean" },
|
||||
"criminal_liability": { "type": "boolean" },
|
||||
"description": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"evidence": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"required": { "type": "boolean" },
|
||||
"format": { "type": "string" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"priority": { "type": "string", "enum": ["kritisch", "hoch", "mittel", "niedrig"] },
|
||||
"tom_control_ids": {
|
||||
"type": "array",
|
||||
"items": { "type": "string", "pattern": "^TOM\\.[A-Z]+\\.[0-9]{2}$" }
|
||||
},
|
||||
"breakpilot_feature": { "type": "string", "description": "Link to SDK module (e.g. /sdk/dsfa)" },
|
||||
"valid_from": { "type": "string", "format": "date" },
|
||||
"valid_until": { "type": ["string", "null"], "format": "date" },
|
||||
"version": { "type": "string" },
|
||||
"iso27001_mapping": { "type": "array", "items": { "type": "string" } },
|
||||
"how_to_implement": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"condition_node": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"all_of": { "type": "array", "items": { "$ref": "#/$defs/condition_node" } }
|
||||
},
|
||||
"required": ["all_of"]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"any_of": { "type": "array", "items": { "$ref": "#/$defs/condition_node" } }
|
||||
},
|
||||
"required": ["any_of"]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"field": { "type": "string" },
|
||||
"operator": { "type": "string", "enum": ["EQUALS", "NOT_EQUALS", "GREATER_THAN", "LESS_THAN", "GREATER_OR_EQUAL", "LESS_OR_EQUAL", "IN", "NOT_IN", "CONTAINS", "EXISTS"] },
|
||||
"value": {}
|
||||
},
|
||||
"required": ["field", "operator", "value"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"control": {
|
||||
"type": "object",
|
||||
"required": ["id", "name", "category"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" },
|
||||
"description": { "type": "string" },
|
||||
"category": { "type": "string" },
|
||||
"what_to_do": { "type": "string" },
|
||||
"iso27001_mapping": { "type": "array", "items": { "type": "string" } },
|
||||
"priority": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"incident_deadline": {
|
||||
"type": "object",
|
||||
"required": ["phase", "deadline"],
|
||||
"properties": {
|
||||
"phase": { "type": "string" },
|
||||
"deadline": { "type": "string" },
|
||||
"content": { "type": "string" },
|
||||
"recipient": { "type": "string" },
|
||||
"legal_basis": { "type": "array", "items": { "type": "object" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1923
ai-compliance-sdk/policies/obligations/v2/_tom_mapping.json
Normal file
1923
ai-compliance-sdk/policies/obligations/v2/_tom_mapping.json
Normal file
File diff suppressed because it is too large
Load Diff
1935
ai-compliance-sdk/policies/obligations/v2/ai_act_v2.json
Normal file
1935
ai-compliance-sdk/policies/obligations/v2/ai_act_v2.json
Normal file
File diff suppressed because it is too large
Load Diff
668
ai-compliance-sdk/policies/obligations/v2/bdsg_v2.json
Normal file
668
ai-compliance-sdk/policies/obligations/v2/bdsg_v2.json
Normal file
@@ -0,0 +1,668 @@
|
||||
{
|
||||
"regulation": "bdsg",
|
||||
"regulation_full_name": "Bundesdatenschutzgesetz (BDSG)",
|
||||
"version": "1.0",
|
||||
"obligations": [
|
||||
{
|
||||
"id": "BDSG-OBL-001",
|
||||
"title": "Videoueberwachung oeffentlicher Raeume",
|
||||
"description": "Videoueberwachung oeffentlich zugaenglicher Raeume ist nur zulaessig, wenn sie zur Aufgabenerfuellung oeffentlicher Stellen, zur Wahrnehmung des Hausrechts oder zur Wahrnehmung berechtigter Interessen erforderlich ist.",
|
||||
"applies_when": "organization uses video surveillance in public areas",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.video_surveillance", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 4 Abs. 1", "title": "Videoueberwachung oeffentlich zugaenglicher Raeume" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 4 BDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor Inbetriebnahme der Videoueberwachung" },
|
||||
"sanctions": { "max_fine": "50.000 EUR (§ 43 BDSG a.F.) bzw. DSGVO-Bussgeld" },
|
||||
"evidence": [{ "name": "Videoueberwachungskonzept", "required": true }, "Beschilderung/Hinweisschilder"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.PHY.01", "TOM.GOV.03"],
|
||||
"breakpilot_feature": "/sdk/tom",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-002",
|
||||
"title": "Kennzeichnungspflicht Videoueberwachung",
|
||||
"description": "Der Umstand der Beobachtung und der Verantwortliche sind durch geeignete Massnahmen zum fruehestmoeglichen Zeitpunkt erkennbar zu machen.",
|
||||
"applies_when": "organization uses video surveillance",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.video_surveillance", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 4 Abs. 2", "title": "Kennzeichnungspflicht bei Videoueberwachung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 4 Abs. 2 BDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Verantwortlicher",
|
||||
"deadline": { "type": "on_event", "event": "Vor Inbetriebnahme" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Fotodokumentation Beschilderung", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.PHY.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-003",
|
||||
"title": "Loeschpflicht Videomaterial",
|
||||
"description": "Videoaufzeichnungen sind unverzueglich zu loeschen, wenn sie zur Erreichung des Zwecks nicht mehr erforderlich sind oder schutzwuerdige Interessen der Betroffenen entgegenstehen.",
|
||||
"applies_when": "organization stores video surveillance recordings",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.video_surveillance", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 4 Abs. 5", "title": "Loeschung von Videomaterial" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 4 Abs. 5 BDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Sicherheitsbeauftragter",
|
||||
"deadline": { "type": "relative", "duration": "P72H" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Loeschkonzept Videodaten", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.PHY.01", "TOM.DEL.01"],
|
||||
"breakpilot_feature": "/sdk/loeschfristen",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-004",
|
||||
"title": "Verarbeitung besonderer Kategorien — Angemessene Massnahmen",
|
||||
"description": "Bei Verarbeitung besonderer Kategorien personenbezogener Daten sind angemessene und spezifische Massnahmen zur Wahrung der Interessen der betroffenen Person vorzusehen.",
|
||||
"applies_when": "organization processes special category data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.special_categories", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 22 Abs. 1", "title": "Verarbeitung besonderer Kategorien personenbezogener Daten" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 22 BDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Schutzkonzept besondere Datenkategorien", "required": true }, "DSFA"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.AC.01", "TOM.CRY.01", "TOM.GOV.04"],
|
||||
"breakpilot_feature": "/sdk/dsfa",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-005",
|
||||
"title": "Massnahmenkatalog § 22 Abs. 2",
|
||||
"description": "Der Verantwortliche hat technische und organisatorische Massnahmen nach § 22 Abs. 2 BDSG umzusetzen, darunter Pseudonymisierung, Verschluesselung, Zugriffskontrolle und Sensibilisierung.",
|
||||
"applies_when": "organization processes special category data under BDSG",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.special_categories", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 22 Abs. 2", "title": "Spezifische Massnahmen" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 22 Abs. 2 BDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Sicherheitsbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "TOM-Dokumentation § 22", "required": true }, "Pseudonymisierungskonzept"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.CRY.01", "TOM.CRY.02", "TOM.AC.01"],
|
||||
"breakpilot_feature": "/sdk/tom",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-006",
|
||||
"title": "Datenverarbeitung fuer Zwecke des Beschaeftigungsverhaeltnisses",
|
||||
"description": "Personenbezogene Daten von Beschaeftigten duerfen nur verarbeitet werden, wenn dies fuer die Begruendung, Durchfuehrung oder Beendigung des Beschaeftigungsverhaeltnisses erforderlich ist.",
|
||||
"applies_when": "organization processes employee data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_employees", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 26 Abs. 1", "title": "Datenverarbeitung fuer Zwecke des Beschaeftigungsverhaeltnisses" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 26 BDSG" }, { "type": "case_law", "ref": "BAG Urt. v. 29.06.2023 – 2 AZR 296/22" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Personalleitung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Beschaeftigtendatenschutzkonzept", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.HR.01", "TOM.GOV.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-007",
|
||||
"title": "Einwilligung im Beschaeftigungsverhaeltnis",
|
||||
"description": "Einwilligungen von Beschaeftigten sind nur wirksam, wenn sie auf Freiwilligkeit beruhen. Die Freiwilligkeit ist besonders zu dokumentieren und zu pruefen.",
|
||||
"applies_when": "organization collects consent from employees",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_employees", "operator": "EQUALS", "value": true }, { "field": "data_protection.employee_consent", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 26 Abs. 2", "title": "Einwilligung Beschaeftigte" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 26 Abs. 2 BDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Personalleitung",
|
||||
"deadline": { "type": "on_event", "event": "Vor Datenerhebung" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Einwilligungsformulare Beschaeftigte", "required": true }, "Freiwilligkeitsnachweis"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.HR.01", "TOM.HR.02"],
|
||||
"breakpilot_feature": "/sdk/consent",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-008",
|
||||
"title": "Kollektivvereinbarungen Beschaeftigtendatenschutz",
|
||||
"description": "Verarbeitung von Beschaeftigtendaten kann auf Grundlage von Kollektivvereinbarungen (Betriebsvereinbarung, Tarifvertrag) erfolgen, sofern diese Art. 88 Abs. 2 DSGVO genuegen.",
|
||||
"applies_when": "organization has collective agreements for data processing",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_employees", "operator": "EQUALS", "value": true }, { "field": "organization.has_works_council", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 26 Abs. 4", "title": "Kollektivvereinbarungen" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 26 Abs. 4 BDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Personalleitung",
|
||||
"deadline": { "type": "recurring", "interval": "jaehrlich" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Betriebsvereinbarung Datenschutz", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.HR.01", "TOM.GOV.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-009",
|
||||
"title": "Aufbewahrung Beschaeftigtendaten nach Verhaeltnisende",
|
||||
"description": "Personenbezogene Daten von Beschaeftigten sind nach Beendigung des Beschaeftigungsverhaeltnisses zu loeschen, soweit keine gesetzlichen Aufbewahrungspflichten bestehen.",
|
||||
"applies_when": "organization stores former employee data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_employees", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 26 Abs. 1", "title": "Zweckbindung Beschaeftigtendaten" }, { "norm": "DSGVO", "article": "Art. 17", "title": "Recht auf Loeschung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 26 BDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Personalleitung",
|
||||
"deadline": { "type": "on_event", "event": "Beendigung Beschaeftigungsverhaeltnis" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Loeschkonzept Personalakten", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.HR.01", "TOM.DEL.01"],
|
||||
"breakpilot_feature": "/sdk/loeschfristen",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-010",
|
||||
"title": "Informationspflicht gegenueber Betroffenen",
|
||||
"description": "Die betroffene Person ist ueber die Verarbeitung ihrer Daten gemaess §§ 32-33 BDSG zu informieren, sofern keine Ausnahmen nach § 29 greifen.",
|
||||
"applies_when": "always",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_personal_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 29", "title": "Rechte der betroffenen Person und aufsichtsbehoerdliche Befugnisse" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 29 BDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Bei Datenerhebung" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Datenschutzerklaerung", "required": true }, "Informationsblaetter"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/dsr",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-011",
|
||||
"title": "Ausnahmen von Betroffenenrechten dokumentieren",
|
||||
"description": "Einschraenkungen der Betroffenenrechte nach § 29 BDSG (z.B. bei oeffentlichem Interesse, Strafverfolgung) muessen dokumentiert und begruendet werden.",
|
||||
"applies_when": "organization restricts data subject rights under BDSG § 29",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.restricts_data_subject_rights", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 29 Abs. 1", "title": "Beschraenkung Betroffenenrechte" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 29 BDSG" }],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Bei Einschraenkung der Rechte" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Dokumentation Rechteeinschraenkung", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.02", "TOM.GOV.03"],
|
||||
"breakpilot_feature": "/sdk/dsr",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-012",
|
||||
"title": "Recht auf Loeschung — BDSG-Einschraenkungen",
|
||||
"description": "Das Recht auf Loeschung kann nach § 35 BDSG eingeschraenkt sein, wenn die Loeschung wegen der besonderen Art der Speicherung nicht oder nur mit unverhaeltnismaessigem Aufwand moeglich ist.",
|
||||
"applies_when": "organization processes data where deletion is disproportionate",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.complex_storage", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 35 Abs. 1", "title": "Recht auf Loeschung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 35 BDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leitung",
|
||||
"deadline": { "type": "on_event", "event": "Bei Loeschantrag" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Nachweis unverhaeltnismaessiger Aufwand", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.DEL.01"],
|
||||
"breakpilot_feature": "/sdk/loeschfristen",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-013",
|
||||
"title": "Verarbeitungseinschraenkung statt Loeschung",
|
||||
"description": "Wenn die Loeschung nicht moeglich ist, tritt an die Stelle der Loeschung die Einschraenkung der Verarbeitung gemaess § 35 Abs. 1 BDSG.",
|
||||
"applies_when": "organization cannot delete data due to storage constraints",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.complex_storage", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 35 Abs. 1 S. 2", "title": "Verarbeitungseinschraenkung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 35 BDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leitung",
|
||||
"deadline": { "type": "on_event", "event": "Bei Loeschantrag" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Sperrkonzept/Einschraenkungskonzept", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.DEL.01", "TOM.AC.02"],
|
||||
"breakpilot_feature": "/sdk/loeschfristen",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-014",
|
||||
"title": "Benennung Datenschutzbeauftragter",
|
||||
"description": "Der Verantwortliche hat einen Datenschutzbeauftragten zu benennen, wenn mindestens 20 Personen staendig mit der automatisierten Verarbeitung personenbezogener Daten beschaeftigt sind.",
|
||||
"applies_when": "organization has 20+ employees processing personal data",
|
||||
"applies_when_condition": { "any_of": [{ "field": "organization.employees_processing_data", "operator": "GREATER_OR_EQUAL", "value": 20 }, { "field": "data_protection.special_categories", "operator": "EQUALS", "value": true }, { "field": "data_protection.core_activity_monitoring", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 38 Abs. 1", "title": "Datenschutzbeauftragte nichtoeffentlicher Stellen" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 38 BDSG" }, { "type": "dsk_kurzpapier", "ref": "DSK KP Nr. 12" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "on_event", "event": "Unverzueglich bei Erreichen der Schwelle" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz", "personal_liability": true },
|
||||
"evidence": [{ "name": "Benennungsurkunde DSB", "required": true }, { "name": "Meldung an Aufsichtsbehoerde", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.05"],
|
||||
"breakpilot_feature": "/sdk/dsb-portal",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-015",
|
||||
"title": "Kuendigungsschutz DSB",
|
||||
"description": "Der Datenschutzbeauftragte darf wegen der Erfuellung seiner Aufgaben nicht abberufen oder benachteiligt werden. Ein besonderer Kuendigungsschutz gilt nach § 38 Abs. 2 i.V.m. § 6 Abs. 4 BDSG.",
|
||||
"applies_when": "organization has appointed a DPO",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_dpo", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 38 Abs. 2", "title": "Kuendigungsschutz DSB" }, { "norm": "BDSG", "article": "§ 6 Abs. 4", "title": "Stellung des DSB" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 38 Abs. 2 BDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz", "personal_liability": true },
|
||||
"evidence": [{ "name": "Arbeitsvertrag/Bestellungsurkunde DSB", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.05"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-016",
|
||||
"title": "Geheimhaltungspflicht DSB",
|
||||
"description": "Der Datenschutzbeauftragte ist zur Geheimhaltung ueber die Identitaet betroffener Personen und Umstaende verpflichtet, die Rueckschluesse auf diese zulassen (§ 38 Abs. 2 i.V.m. § 6 Abs. 5 BDSG).",
|
||||
"applies_when": "organization has appointed a DPO",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_dpo", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 6 Abs. 5", "title": "Geheimhaltungspflicht DSB" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 6 Abs. 5 BDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "personal_liability": true, "criminal_liability": true },
|
||||
"evidence": [{ "name": "Verschwiegenheitserklaerung DSB", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.05"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-017",
|
||||
"title": "Zustaendigkeit der Aufsichtsbehoerden",
|
||||
"description": "Die Aufsichtsbehoerden ueberwachen die Einhaltung des BDSG und der DSGVO. Der Verantwortliche muss mit der zustaendigen Aufsichtsbehoerde kooperieren (§§ 40-41 BDSG).",
|
||||
"applies_when": "always",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_personal_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 40", "title": "Aufsichtsbehoerden der Laender" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 40 BDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Dokumentierte Aufsichtsbehoerdenkontakte", "required": false }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-018",
|
||||
"title": "Anwendung der Bussgeldvorschriften",
|
||||
"description": "Ordnungswidrig handelt, wer gegen Vorschriften des BDSG verstoesst. Die Aufsichtsbehoerden koennen Bussgelder verhaengen (§ 43 BDSG ergaenzend zu Art. 83 DSGVO).",
|
||||
"applies_when": "always",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_personal_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 43", "title": "Bussgeldvorschriften" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 43 BDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "50.000 EUR (national) bzw. 20 Mio. EUR (DSGVO)", "personal_liability": true },
|
||||
"evidence": [{ "name": "Compliance-Management-System", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/risk-assessment",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-019",
|
||||
"title": "Verarbeitung fuer Forschungszwecke",
|
||||
"description": "Bei Verarbeitung personenbezogener Daten fuer wissenschaftliche oder historische Forschungszwecke gelten die Sonderregelungen des § 27 BDSG einschliesslich Pseudonymisierung.",
|
||||
"applies_when": "organization processes data for research purposes",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.research_processing", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 27", "title": "Datenverarbeitung zu Forschungszwecken" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 27 BDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Forschungsleitung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "20 Mio. EUR oder 4% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Forschungsdatenschutzkonzept", "required": true }, "Pseudonymisierungsnachweis"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.CRY.02", "TOM.GOV.04"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-020",
|
||||
"title": "Verarbeitung fuer statistische Zwecke",
|
||||
"description": "Bei Verarbeitung fuer statistische Zwecke sind die besonderen Anforderungen des § 27 Abs. 1 BDSG zu beachten, insbesondere Pseudonymisierung und Anonymisierung.",
|
||||
"applies_when": "organization processes data for statistical purposes",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.statistical_processing", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 27 Abs. 1", "title": "Statistische Zwecke" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 27 BDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "Datenanalyst",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Anonymisierungskonzept", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.CRY.02"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-021",
|
||||
"title": "Verarbeitung durch Polizei/Strafverfolgung — Rechtsgrundlage",
|
||||
"description": "Personenbezogene Daten duerfen von Polizei und Strafverfolgungsbehoerden nur verarbeitet werden, wenn dies fuer die Erfuellung ihrer Aufgaben erforderlich ist (§§ 46 ff. BDSG).",
|
||||
"applies_when": "organization is law enforcement or cooperates with law enforcement",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.sector", "operator": "IN", "value": ["law_enforcement", "public_authority"] }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 46", "title": "Begriffsbestimmungen Strafverfolgung" }, { "norm": "BDSG", "article": "§ 47", "title": "Allgemeine Grundsaetze" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§§ 46-47 BDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Behoerdenleitung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "Disziplinarmassnahmen", "personal_liability": true },
|
||||
"evidence": [{ "name": "Verarbeitungskonzept Strafverfolgung", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.AC.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-022",
|
||||
"title": "Protokollierungspflicht bei Strafverfolgung",
|
||||
"description": "Zugriffe und Uebermittlungen personenbezogener Daten zu Strafverfolgungszwecken sind zu protokollieren (§ 51 BDSG).",
|
||||
"applies_when": "organization processes data for law enforcement purposes",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.sector", "operator": "IN", "value": ["law_enforcement", "public_authority"] }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 51", "title": "Verarbeitungssicherheit" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 51 BDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Sicherheitsbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "personal_liability": true },
|
||||
"evidence": [{ "name": "Protokollierungsrichtlinie", "required": true }, "Zugriffsprotokolle"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.LOG.01", "TOM.AC.01"],
|
||||
"breakpilot_feature": "/sdk/audit",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-023",
|
||||
"title": "Betroffenenrechte bei Strafverfolgung",
|
||||
"description": "Auch im Bereich der Strafverfolgung bestehen Auskunfts-, Berichtigungs- und Loeschungsrechte der Betroffenen nach §§ 53-54 BDSG, ggf. mit Einschraenkungen.",
|
||||
"applies_when": "law enforcement data processing",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.sector", "operator": "IN", "value": ["law_enforcement", "public_authority"] }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 53", "title": "Auskunftsrecht" }, { "norm": "BDSG", "article": "§ 54", "title": "Berichtigung und Loeschung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§§ 53-54 BDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "relative", "duration": "P30D" },
|
||||
"sanctions": { "personal_liability": true },
|
||||
"evidence": [{ "name": "Betroffenenrechte-Prozess Strafverfolgung", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/dsr",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-024",
|
||||
"title": "Datenuebermittlung an Drittstaaten — besondere Voraussetzungen",
|
||||
"description": "Die Uebermittlung personenbezogener Daten an Drittstaaten durch Polizei-/Justizbehoerden ist nur bei Vorliegen eines Angemessenheitsbeschlusses oder geeigneter Garantien zulaessig (§§ 62 ff. BDSG).",
|
||||
"applies_when": "law enforcement transfers data to third countries",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.sector", "operator": "IN", "value": ["law_enforcement", "public_authority"] }, { "field": "data_protection.third_country_transfer", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 62", "title": "Uebermittlung bei Angemessenheitsbeschluss" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§§ 62-66 BDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor jeder Drittstaatenuebermittlung" },
|
||||
"sanctions": { "personal_liability": true, "criminal_liability": true },
|
||||
"evidence": [{ "name": "Angemessenheitsbeschluss-Pruefung", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.03", "TOM.CRY.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-025",
|
||||
"title": "Datenuebermittlung ohne Angemessenheitsbeschluss",
|
||||
"description": "Ohne Angemessenheitsbeschluss ist eine Uebermittlung an Drittstaaten nur bei geeigneten Garantien oder in Ausnahmefaellen nach § 63 BDSG zulaessig.",
|
||||
"applies_when": "law enforcement transfers data to third country without adequacy decision",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.sector", "operator": "IN", "value": ["law_enforcement", "public_authority"] }, { "field": "data_protection.third_country_transfer", "operator": "EQUALS", "value": true }, { "field": "data_protection.adequacy_decision", "operator": "EQUALS", "value": false }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 63", "title": "Uebermittlung bei geeigneten Garantien" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 63 BDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor jeder Uebermittlung" },
|
||||
"sanctions": { "personal_liability": true, "criminal_liability": true },
|
||||
"evidence": [{ "name": "Geeignete Garantien dokumentiert", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.03"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-026",
|
||||
"title": "Strafvorschriften — unbefugte Datenverarbeitung",
|
||||
"description": "Wer wissentlich nicht allgemein zugaengliche personenbezogene Daten unbefugt verarbeitet, wird mit Freiheitsstrafe bis zu drei Jahren oder Geldstrafe bestraft (§ 42 BDSG).",
|
||||
"applies_when": "always",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_personal_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 42", "title": "Strafvorschriften" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 42 BDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "Freiheitsstrafe bis 3 Jahre oder Geldstrafe", "personal_liability": true, "criminal_liability": true },
|
||||
"evidence": [{ "name": "Datenschutzschulungsnachweis", "required": true }, "Zugriffsberechtigungskonzept"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.AC.01", "TOM.GOV.01"],
|
||||
"breakpilot_feature": "/sdk/training",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-027",
|
||||
"title": "Bussgeld bei Verstoessen gegen Auskunftspflicht",
|
||||
"description": "Ordnungswidrig handelt, wer einer vollziehbaren Anordnung der Aufsichtsbehoerde nach § 43 Abs. 1 BDSG zuwiderhandelt. Bussgelder bis 50.000 EUR.",
|
||||
"applies_when": "always",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_personal_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 43 Abs. 1", "title": "Bussgeldvorschriften" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 43 BDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "on_event", "event": "Bei Anordnung der Aufsichtsbehoerde" },
|
||||
"sanctions": { "max_fine": "50.000 EUR" },
|
||||
"evidence": [{ "name": "Korrespondenz Aufsichtsbehoerde", "required": false }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-028",
|
||||
"title": "Akkreditierung Zertifizierungsstellen",
|
||||
"description": "Zertifizierungsstellen nach Art. 43 DSGVO beduerfern der Akkreditierung durch die zustaendige Aufsichtsbehoerde oder die DAkkS (§ 39 BDSG).",
|
||||
"applies_when": "organization is or uses a certification body",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.certification_body", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 39", "title": "Akkreditierung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 39 BDSG" }],
|
||||
"category": "Audit",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "5 Jahre" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Akkreditierungsurkunde", "required": true }],
|
||||
"priority": "niedrig",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"breakpilot_feature": "/sdk/audit",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-029",
|
||||
"title": "Geheimhaltungspflicht und Datengeheimnis",
|
||||
"description": "Personen, die bei der Datenverarbeitung taetig sind, duerfen personenbezogene Daten nicht unbefugt verarbeiten. Sie sind auf das Datengeheimnis zu verpflichten (§ 53 BDSG analog).",
|
||||
"applies_when": "always",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.has_employees", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 53", "title": "Datengeheimnis" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 53 BDSG" }],
|
||||
"category": "Schulung",
|
||||
"responsible": "Personalleitung",
|
||||
"deadline": { "type": "on_event", "event": "Bei Arbeitsaufnahme" },
|
||||
"sanctions": { "personal_liability": true, "criminal_liability": true },
|
||||
"evidence": [{ "name": "Verpflichtungserklaerung Datengeheimnis", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.HR.02", "TOM.GOV.05"],
|
||||
"breakpilot_feature": "/sdk/training",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-OBL-030",
|
||||
"title": "Verarbeitung im Auftrag — Vertragspflicht",
|
||||
"description": "Die Auftragsverarbeitung ist durch einen Vertrag nach Art. 28 DSGVO i.V.m. § 29 BDSG zu regeln. Der Auftraggeber muss die TOM des Auftragsverarbeiters ueberpruefen.",
|
||||
"applies_when": "organization uses data processors",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.uses_processors", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 29", "title": "Auftragsverarbeitung" }, { "norm": "DSGVO", "article": "Art. 28", "title": "Auftragsverarbeiter" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 29 BDSG" }, { "type": "article", "ref": "Art. 28 DSGVO" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor Beginn der Auftragsverarbeitung" },
|
||||
"sanctions": { "max_fine": "10 Mio. EUR oder 2% Jahresumsatz" },
|
||||
"evidence": [{ "name": "Auftragsverarbeitungsvertrag (AVV)", "required": true }, { "name": "TOM-Pruefbericht Auftragsverarbeiter", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.03", "TOM.VEN.01"],
|
||||
"breakpilot_feature": "/sdk/vendor-compliance",
|
||||
"valid_from": "2018-05-25",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "BDSG-CTRL-001",
|
||||
"name": "Videoueberwachungs-Compliance",
|
||||
"description": "Kontrolle zur Sicherstellung der Einhaltung der Anforderungen an Videoueberwachung nach § 4 BDSG.",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Videoueberwachungskonzept erstellen, Beschilderung pruefen, Loeschfristen einhalten, DSFA durchfuehren.",
|
||||
"iso27001_mapping": ["A.7.4"],
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-CTRL-002",
|
||||
"name": "Beschaeftigtendatenschutz-Kontrolle",
|
||||
"description": "Kontrolle zur Pruefung der Einhaltung des § 26 BDSG bei der Verarbeitung von Beschaeftigtendaten.",
|
||||
"category": "Organisatorisch",
|
||||
"what_to_do": "Beschaeftigtendatenschutzrichtlinie erstellen, Einwilligungen pruefen, Betriebsvereinbarungen aktualisieren.",
|
||||
"iso27001_mapping": ["A.6.1", "A.6.2"],
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-CTRL-003",
|
||||
"name": "DSB-Governance-Kontrolle",
|
||||
"description": "Kontrolle zur Sicherstellung der ordnungsgemaessen Benennung und Unterstuetzung des Datenschutzbeauftragten.",
|
||||
"category": "Governance",
|
||||
"what_to_do": "DSB-Benennung pruefen, Ressourcen sicherstellen, Unabhaengigkeit gewaehrleisten, Schulung nachweisen.",
|
||||
"iso27001_mapping": ["A.5.1"],
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "BDSG-CTRL-004",
|
||||
"name": "Bussgeld-Praevention und Compliance-Monitoring",
|
||||
"description": "Kontrolle zur Vermeidung von Bussgeldern und strafrechtlichen Konsequenzen durch proaktives Compliance-Monitoring.",
|
||||
"category": "Compliance",
|
||||
"what_to_do": "Regelmaessige Compliance-Audits durchfuehren, Schulungen sicherstellen, Aufsichtsbehoerden-Anfragen zeitnah bearbeiten.",
|
||||
"iso27001_mapping": ["A.5.36"],
|
||||
"priority": "kritisch"
|
||||
}
|
||||
],
|
||||
"incident_deadlines": [
|
||||
{
|
||||
"phase": "Erstmeldung an Aufsichtsbehoerde",
|
||||
"deadline": "72 Stunden (gemaess DSGVO Art. 33, konkretisiert durch BDSG)",
|
||||
"content": "Art der Verletzung, betroffene Datenkategorien und Personen, wahrscheinliche Folgen, ergriffene Massnahmen",
|
||||
"recipient": "Zustaendige Landesdatenschutzbehoerde",
|
||||
"legal_basis": [{ "norm": "DSGVO", "article": "Art. 33" }, { "norm": "BDSG", "article": "§ 40" }]
|
||||
},
|
||||
{
|
||||
"phase": "Benachrichtigung Betroffener",
|
||||
"deadline": "Unverzueglich bei hohem Risiko",
|
||||
"content": "Art der Verletzung, Kontaktdaten DSB, wahrscheinliche Folgen, ergriffene Massnahmen",
|
||||
"recipient": "Betroffene Personen",
|
||||
"legal_basis": [{ "norm": "DSGVO", "article": "Art. 34" }]
|
||||
},
|
||||
{
|
||||
"phase": "Meldung Strafverfolgungsbehoerden",
|
||||
"deadline": "Unverzueglich bei Verdacht auf Straftat nach § 42 BDSG",
|
||||
"content": "Sachverhaltsbeschreibung, beteiligte Personen, betroffene Daten",
|
||||
"recipient": "Staatsanwaltschaft",
|
||||
"legal_basis": [{ "norm": "BDSG", "article": "§ 42" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
535
ai-compliance-sdk/policies/obligations/v2/data_act_v2.json
Normal file
535
ai-compliance-sdk/policies/obligations/v2/data_act_v2.json
Normal file
@@ -0,0 +1,535 @@
|
||||
{
|
||||
"regulation": "data_act",
|
||||
"name": "Data Act (EU) 2023/2854",
|
||||
"description": "Verordnung ueber harmonisierte Vorschriften fuer einen fairen Datenzugang und eine faire Datennutzung — Regelt den Zugang zu und die Nutzung von Daten, die durch vernetzte Produkte und verbundene Dienste erzeugt werden",
|
||||
"version": "2.0",
|
||||
"effective_date": "2025-09-12",
|
||||
"obligations": [
|
||||
{
|
||||
"id": "DATAACT-OBL-001",
|
||||
"title": "Datenzugangsrecht fuer Nutzer — Design-Pflicht",
|
||||
"description": "Vernetzte Produkte und verbundene Dienste muessen so konzipiert und hergestellt werden, dass die bei der Nutzung erzeugten Daten dem Nutzer standardmaessig leicht, sicher und unentgeltlich zugaenglich sind.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 3", "title": "Pflicht zur Zugaenglichmachung von Daten"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 3 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Design-Dokumentation Data-by-Design", "Technische Zugangsspezifikation"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-002",
|
||||
"title": "Vorvertragliche Informationspflicht",
|
||||
"description": "Vor Vertragsschluss muessen Nutzer klar und verstaendlich darueber informiert werden, welche Daten erzeugt werden, wie sie darauf zugreifen koennen und ob der Dateninhaber die Daten fuer eigene Zwecke nutzt.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 4", "title": "Vorvertragliche Informationspflichten"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 4 Data Act"}],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Produktinformationsblatt", "AGB mit Dateninformationen"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-003",
|
||||
"title": "Recht auf Datenzugang des Nutzers",
|
||||
"description": "Nutzer haben das Recht, auf die durch die Nutzung eines vernetzten Produkts erzeugten Daten unverzueglich, unentgeltlich und in einem umfassenden, strukturierten, gaengigen und maschinenlesbaren Format zuzugreifen.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 5", "title": "Recht auf Zugang zu Daten"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 5 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"deadline": {"type": "on_event", "event": "Anfrage des Nutzers"},
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Datenzugangs-API", "Exportfunktion im Produkt", "Nachweis maschinenlesbares Format"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.OPS.02"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-004",
|
||||
"title": "Schutz von Geschaeftsgeheimnissen beim Datenzugang",
|
||||
"description": "Dateninhaber duerfen den Datenzugang nur einschraenken, soweit dies zum Schutz von Geschaeftsgeheimnissen erforderlich ist. Massnahmen muessen verhaeltnismaessig sein und duerfen den Zugang nicht unzumutbar erschweren.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 5 Abs. 8", "title": "Schutz von Geschaeftsgeheimnissen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 5 Abs. 8 Data Act"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Geschaeftsgeheimnis-Schutzkonzept", "Verhaeltnismaessigkeitspruefung"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-005",
|
||||
"title": "Datenweitergabe an Dritte auf Wunsch des Nutzers",
|
||||
"description": "Auf Antrag des Nutzers muessen Dateninhaber die erzeugten Daten an einen vom Nutzer benannten Dritten unverzueglich, unentgeltlich und in gleicher Qualitaet wie dem Nutzer bereitstellen.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 6", "title": "Pflicht zur Bereitstellung von Daten an Dritte"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 6 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"deadline": {"type": "on_event", "event": "Antrag des Nutzers auf Datenweitergabe"},
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Datenweitergabe-Prozess", "Nutzerantragsformular", "Weitergabeprotokoll"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.OPS.02"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-006",
|
||||
"title": "Pflichten des Datenempfaengers (Dritter)",
|
||||
"description": "Datenempfaenger duerfen die erhaltenen Daten nur fuer die vereinbarten Zwecke nutzen. Sie duerfen die Daten nicht zur Entwicklung eines konkurrierenden Produkts verwenden und muessen sie nach Zweckerfuellung loeschen.",
|
||||
"applies_when": "organization.receives_product_data == true",
|
||||
"applies_when_condition": {"field": "organization.receives_product_data", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 7", "title": "Pflichten der Datenempfaenger"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 7 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Zweckbindungsvereinbarung", "Loeschnachweis nach Zweckerfuellung"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-007",
|
||||
"title": "Angemessene Verguetung fuer Datenweitergabe",
|
||||
"description": "Bei Datenweitergabe an Dritte duerfen Dateninhaber eine angemessene Verguetung verlangen. Gegenueber KMU darf die Verguetung die Kosten der Bereitstellung nicht uebersteigen.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 8", "title": "Verguetung fuer die Bereitstellung von Daten"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 8 Data Act"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Finanzabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Verguetungsmodell", "Kostenkalkulation", "KMU-Sondertarife"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-008",
|
||||
"title": "Faire Vertragsbedingungen fuer Datenzugang",
|
||||
"description": "Vertragsbedingungen fuer den Datenzugang und die Datennutzung muessen fair, angemessen und nicht-diskriminierend sein. Einseitig benachteiligende Klauseln sind unwirksam.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 9", "title": "Missbr. Vertragsklauseln in Bezug auf Datenzugang und -nutzung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 9 Data Act"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Vertragspruefung auf Fairness", "AGB-Klauselkontrolle"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-009",
|
||||
"title": "Unwirksamkeit missbraeuchlicher Vertragsklauseln",
|
||||
"description": "Vertragsklauseln, die den Datenzugang oder die Datennutzung unangemessen einschraenken, sind nicht bindend. Die Beweislast fuer die Angemessenheit liegt beim Dateninhaber.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 10", "title": "Anwendung der Vorschriften fuer missbr. Vertragsklauseln"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 10 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Klauselregister mit Fairness-Bewertung"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-010",
|
||||
"title": "Mustervertragsbedingungen beachten",
|
||||
"description": "Die Kommission erstellt Mustervertragsbedingungen fuer faire Datenzugangsvereinbarungen. Dateninhaber sollten diese bei der Gestaltung ihrer Vertraege beruecksichtigen.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 12", "title": "Mustervertragsbedingungen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 12 Data Act"}],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Keine direkte Sanktion (empfohlen)", "personal_liability": false},
|
||||
"evidence": ["Verwendung von EU-Musterklauseln", "Dokumentation Abweichungen"],
|
||||
"priority": "niedrig",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-011",
|
||||
"title": "Wechsel von Cloud-Diensten — Vertragliche Mindestanforderungen",
|
||||
"description": "Vertraege ueber Datenverarbeitungsdienste (Cloud, SaaS, IaaS, PaaS) muessen klare Bestimmungen zum Anbieterwechsel enthalten, einschliesslich Kuendigungsfristen, Datenexport und Uebergangsunterstuetzung.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 13", "title": "Vertragliche Rechte betreffend den Wechsel"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 13 Data Act"}],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Vertragliche Wechselklauseln", "Datenexport-SLA"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.OPS.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-012",
|
||||
"title": "Technische Pflichten beim Cloud-Wechsel",
|
||||
"description": "Cloud-Anbieter muessen technische Massnahmen bereitstellen, um den Wechsel zu erleichtern: Datenexport in strukturiertem Format, API-Zugang waehrend der Uebergangsphase und Loeschung nach Abschluss des Wechsels.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 14", "title": "Technische Aspekte des Wechsels"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 14 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Datenexport-API-Dokumentation", "Migrationsleitfaden", "Loeschbestaetigung"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.OPS.02"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-013",
|
||||
"title": "Schrittweiser Abbau von Wechselgebuehren",
|
||||
"description": "Wechselgebuehren muessen ab dem 12. Januar 2027 schrittweise abgebaut und ab dem 12. Januar 2027 vollstaendig abgeschafft werden. Bis dahin duerfen nur kostenbasierte Gebuehren erhoben werden.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 16", "title": "Wechselgebuehren"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 16 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Finanzabteilung",
|
||||
"deadline": {"type": "absolute", "date": "2027-01-12"},
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Gebuehrenmodell-Dokumentation", "Nachweis schrittweiser Abbau"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-014",
|
||||
"title": "Interoperabilitaet von Datenverarbeitungsdiensten",
|
||||
"description": "Anbieter von Datenverarbeitungsdiensten muessen offene Schnittstellen und Standards unterstuetzen, um die Interoperabilitaet zwischen verschiedenen Diensten zu gewaehrleisten.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 17", "title": "Offene Interoperabilitaetsspezifikationen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 17 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Interoperabilitaets-Spezifikation", "Offene API-Dokumentation"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-015",
|
||||
"title": "Wesentliche Anforderungen an Interoperabilitaet",
|
||||
"description": "Interoperabilitaetsspezifikationen muessen transparent, offen, fair und nicht-diskriminierend sein. Sie muessen die Portabilitaet von Daten, Anwendungen und digitalen Assets ermoeglichen.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 18", "title": "Wesentliche Anforderungen fuer Interoperabilitaet"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 18 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Konformitaetsbewertung Interoperabilitaet", "Standardkonformitaet"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-016",
|
||||
"title": "Datenzugang fuer oeffentliche Stellen bei aussergewoehnlichem Bedarf",
|
||||
"description": "Dateninhaber muessen oeffentlichen Stellen und EU-Organen bei aussergewoehnlichem Bedarf (Notfaelle, Statistiken) Daten zur Verfuegung stellen. Der Bedarf muss begruendet und verhaeltnismaessig sein.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 20", "title": "Recht auf Zugang fuer oeffentliche Stellen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 20 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": {"type": "on_event", "event": "Begruendetes Ersuchen einer oeffentlichen Stelle"},
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Prozess fuer Behoerdenanfragen", "Anfragenregister"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.OPS.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-017",
|
||||
"title": "Begruendungspflicht bei Ablehnung des Datenzugangs",
|
||||
"description": "Dateninhaber koennen ein Ersuchen einer oeffentlichen Stelle nur aus eng begrenzten Gruenden ablehnen. Die Ablehnung muss begruendet werden und der oeffentlichen Stelle mitgeteilt werden.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 21", "title": "Pflichten bei der Bereitstellung an oeffentliche Stellen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 21 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Ablehnungsbegruendungen dokumentiert", "Kommunikationsprotokoll mit Behoerden"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-018",
|
||||
"title": "Unentgeltlichkeit bei Notfaellen",
|
||||
"description": "Bei oeffentlichen Notfaellen (Pandemie, Naturkatastrophe) muessen Daten oeffentlichen Stellen unentgeltlich bereitgestellt werden. In anderen Faellen kann eine angemessene Verguetung verlangt werden.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 22", "title": "Verguetung bei aussergewoehnlichem Bedarf"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 22 Data Act"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Finanzabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Notfall-Datenzugangs-Protokoll", "Verguetungsmodell fuer Nicht-Notfaelle"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-019",
|
||||
"title": "Schutz vor internationalem Datenzugriff",
|
||||
"description": "Anbieter von Datenverarbeitungsdiensten muessen angemessene Massnahmen ergreifen, um den unrechtmaessigen internationalen Zugriff auf nicht-personenbezogene Daten durch Drittstaaten zu verhindern.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 23", "title": "Internationale Datenuebermittlung — Schutzmassnahmen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 23 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CISO",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Schutzkonzept gegen Drittstaaten-Zugriff", "Standortdokumentation der Datenzentren"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-020",
|
||||
"title": "Beachtung internationaler Abkommen",
|
||||
"description": "Datenuebermittlungen an Drittstaaten duerfen nur auf Grundlage internationaler Abkommen oder anerkannter Angemessenheitsbeschluesse erfolgen. Anfragen von Drittstaaten-Gerichten oder -Behoerden muessen dem EU-Recht entsprechen.",
|
||||
"applies_when": "organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 25", "title": "Internationale Zusammenarbeit"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 25 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Pruefung internationaler Anfragen", "Dokumentation der Rechtsgrundlagen"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-021",
|
||||
"title": "Benennung einer zustaendigen Behoerde",
|
||||
"description": "Unternehmen muessen die fuer sie zustaendige nationale Durchsetzungsbehoerde kennen und mit ihr kooperieren. Anfragen der Behoerde muessen fristgerecht beantwortet werden.",
|
||||
"applies_when": "organization.manufactures_connected_products == true OR organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {
|
||||
"any_of": [
|
||||
{"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
{"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 27", "title": "Zustaendige Behoerden"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 27 Data Act"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Kenntnis der zustaendigen Behoerde", "Kooperationsprotokoll"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-022",
|
||||
"title": "Sanktionsvermeidung — Rechtskonformitaetsprogramm",
|
||||
"description": "Mitgliedstaaten legen wirksame, verhaeltnismaessige und abschreckende Sanktionen fest. Unternehmen muessen ein Rechtskonformitaetsprogramm implementieren, um Verstoesse zu vermeiden.",
|
||||
"applies_when": "organization.manufactures_connected_products == true OR organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {
|
||||
"any_of": [
|
||||
{"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
{"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 30", "title": "Sanktionen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 30 Data Act"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Compliance-Programm-Dokumentation", "Schulungsnachweise"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/compliance-hub",
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-023",
|
||||
"title": "Smart-Contract-Konformitaet",
|
||||
"description": "Anbieter von Smart Contracts fuer die Datenweitergabe muessen sicherstellen, dass diese den Anforderungen des Data Act entsprechen, einschliesslich Zugangskontrollen, Kuendigungsmoeglichkeiten und Datensicherheit.",
|
||||
"applies_when": "organization.uses_smart_contracts_for_data == true",
|
||||
"applies_when_condition": {"field": "organization.uses_smart_contracts_for_data", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 28", "title": "Wesentliche Anforderungen an Smart Contracts"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 28 Data Act"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Smart-Contract-Audit", "Konformitaetsbewertung"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-024",
|
||||
"title": "Verbot von Gatekeeper-Verhalten bei Daten",
|
||||
"description": "Dateninhaber duerfen den Datenzugang nicht nutzen, um ihre Marktposition zu missbrauchen. Insbesondere darf der Zugang zu Reparatur- und Wartungsdaten fuer vernetzte Produkte nicht unangemessen verweigert werden.",
|
||||
"applies_when": "organization.manufactures_connected_products == true",
|
||||
"applies_when_condition": {"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 6 Abs. 2", "title": "Verbot des Missbrauchs der Datenposition"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 6 Abs. 2 Data Act"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Wirksam, verhaeltnismaessig und abschreckend (nationale Festlegung)", "personal_liability": false},
|
||||
"evidence": ["Marktmissbrauchs-Pruefung", "Zugangsrichtlinie fuer Reparaturdaten"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-OBL-025",
|
||||
"title": "Streitbeilegungsmechanismus",
|
||||
"description": "Dateninhaber und Datenempfaenger muessen Zugang zu Streitbeilegungsstellen haben. Die Mitgliedstaaten benennen zertifizierte Stellen fuer aussergerichtliche Streitbeilegung bei Data-Act-Streitigkeiten.",
|
||||
"applies_when": "organization.manufactures_connected_products == true OR organization.provides_cloud_services == true",
|
||||
"applies_when_condition": {
|
||||
"any_of": [
|
||||
{"field": "organization.manufactures_connected_products", "operator": "EQUALS", "value": true},
|
||||
{"field": "organization.provides_cloud_services", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 29", "title": "Streitbeilegung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 29 Data Act"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "Keine direkte Sanktion (Verfahrensrecht)", "personal_liability": false},
|
||||
"evidence": ["Hinweis auf Streitbeilegungsstellen", "Interne Eskalationsprozesse"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2025-09-12",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "DATAACT-CTRL-001",
|
||||
"name": "Data-by-Design-Produktentwicklung",
|
||||
"description": "Systematischer Prozess zur Sicherstellung, dass vernetzte Produkte den Datenzugang standardmaessig ermoeglichen",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Integration von Datenzugangs-APIs in die Produktarchitektur, maschinenlesbare Exportformate und Zugangsmanagement ab der Design-Phase",
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-CTRL-002",
|
||||
"name": "Cloud-Portabilitaets-Framework",
|
||||
"description": "Technisches und vertragliches Framework zur Erleichterung des Wechsels zwischen Cloud-Anbietern",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Bereitstellung von Datenexport-APIs, Migrationswerkzeugen, standardisierten Formaten und Uebergangsunterstuetzung gemaess den Data-Act-Anforderungen",
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "DATAACT-CTRL-003",
|
||||
"name": "Behoerden-Datenzugangs-Prozess",
|
||||
"description": "Standardisierter Prozess zur Bearbeitung von Datenzugangsanfragen oeffentlicher Stellen",
|
||||
"category": "Organisatorisch",
|
||||
"what_to_do": "Einrichtung eines Anfragenmanagements mit Pruefung der Rechtsgrundlage, Verhaeltnismaessigkeitstest, Anonymisierung und fristgerechter Bereitstellung",
|
||||
"priority": "hoch"
|
||||
}
|
||||
],
|
||||
"incident_deadlines": [
|
||||
{
|
||||
"phase": "Datenzugangsanfrage des Nutzers",
|
||||
"deadline": "Unverzueglich, ohne ungebuehrliche Verzoegerung",
|
||||
"content": "Bereitstellung der angeforderten Daten in maschinenlesbarem Format",
|
||||
"recipient": "Antragstellender Nutzer",
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 5"}]
|
||||
},
|
||||
{
|
||||
"phase": "Datenweitergabe an Dritte",
|
||||
"deadline": "Unverzueglich nach Antrag des Nutzers",
|
||||
"content": "Weitergabe der Daten an den vom Nutzer benannten Dritten",
|
||||
"recipient": "Benannter Dritter",
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 6"}]
|
||||
},
|
||||
{
|
||||
"phase": "Ersuchen einer oeffentlichen Stelle (Notfall)",
|
||||
"deadline": "Unverzueglich, spaetestens innerhalb der in der Anfrage gesetzten Frist",
|
||||
"content": "Bereitstellung der angeforderten Daten an die oeffentliche Stelle",
|
||||
"recipient": "Ersuchende oeffentliche Stelle",
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 20"}]
|
||||
},
|
||||
{
|
||||
"phase": "Cloud-Wechsel — Datenexport",
|
||||
"deadline": "Maximal 30 Tage nach Kuendigung",
|
||||
"content": "Vollstaendiger Export aller Daten, Anwendungen und digitalen Assets an den neuen Anbieter",
|
||||
"recipient": "Kunde / neuer Cloud-Anbieter",
|
||||
"legal_basis": [{"norm": "Data Act", "article": "Art. 14"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
569
ai-compliance-sdk/policies/obligations/v2/dora_v2.json
Normal file
569
ai-compliance-sdk/policies/obligations/v2/dora_v2.json
Normal file
@@ -0,0 +1,569 @@
|
||||
{
|
||||
"regulation": "dora",
|
||||
"name": "Digital Operational Resilience Act (EU) 2022/2554",
|
||||
"description": "Verordnung (EU) 2022/2554 ueber die digitale operationale Resilienz im Finanzsektor — einheitliche Anforderungen an IKT-Risikomanagement, Vorfallmeldung, Resilienz-Tests und Drittparteienrisiko",
|
||||
"version": "1.0",
|
||||
"effective_date": "2025-01-17",
|
||||
"obligations": [
|
||||
{
|
||||
"id": "DORA-OBL-001",
|
||||
"title": "IKT-Risikomanagement-Rahmen einrichten",
|
||||
"description": "Einrichtung eines umfassenden IKT-Risikomanagement-Rahmens mit Strategien, Leitlinien und Verfahren zum Schutz aller IKT-Assets. Der Rahmen muss jaehrlich ueberprueft und nach schwerwiegenden Vorfaellen aktualisiert werden.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 5", "title": "Governance und Organisation"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 5 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"sanctions": {"max_fine": "Bussgeld nach nationalem Recht", "personal_liability": true},
|
||||
"evidence": ["IKT-Risikomanagement-Rahmen", "Jaehrlicher Review-Bericht"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-002",
|
||||
"title": "IKT-Governance durch Leitungsorgan",
|
||||
"description": "Das Leitungsorgan traegt die Gesamtverantwortung fuer das IKT-Risikomanagement. Es muss IKT-Strategien genehmigen, Rollen definieren, Budget zuweisen und sich regelmaessig ueber IKT-Risiken informieren lassen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 5 Abs. 2", "title": "Verantwortung des Leitungsorgans"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 5 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Governance",
|
||||
"responsible": "Vorstand/Geschaeftsfuehrung",
|
||||
"evidence": ["Vorstandsbeschluss IKT-Strategie", "Schulungsnachweise Leitungsorgan"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-003",
|
||||
"title": "IKT-Risikomanagement-Funktion einrichten",
|
||||
"description": "Einrichtung einer unabhaengigen IKT-Risikomanagement-Kontrollfunktion (oder Beauftragung eines externen Dienstleisters bei kleinen Instituten). Die Funktion muss ueber ausreichende Ressourcen und Befugnisse verfuegen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true},
|
||||
{"field": "financial.is_regulated", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 6", "title": "IKT-Risikomanagement-Rahmen"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 6 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "CISO/IKT-Risikomanager",
|
||||
"evidence": ["Stellenbeschreibung IKT-Risikomanager", "Organigramm", "Ressourcenplan"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-004",
|
||||
"title": "Identifikation aller IKT-Assets und -Risiken",
|
||||
"description": "Vollstaendige Identifikation, Klassifizierung und Dokumentation aller IKT-gestuetzten Geschaeftsfunktionen, IKT-Assets, Informationsquellen und deren Abhaengigkeiten. Regelmnaessige Aktualisierung des IKT-Asset-Inventars.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 7", "title": "IKT-Systeme, -Protokolle und -Tools"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 7 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leiter",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"evidence": ["IKT-Asset-Inventar", "Abhaengigkeitsanalyse", "Klassifizierungsmatrix"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-005",
|
||||
"title": "IKT-Schutzmassnahmen implementieren",
|
||||
"description": "Implementierung von Schutz- und Praeventionsmassnahmen fuer IKT-Systeme: Sicherheitsrichtlinien, Zugriffskontrollen, Verschluesselung, Netzwerksicherheit, Patch-Management und sichere Konfiguration.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 8", "title": "Schutz und Praevention"},
|
||||
{"norm": "DORA", "article": "Art. 9", "title": "Erkennung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 8-9 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "CISO",
|
||||
"evidence": ["Sicherheitsrichtlinien", "Zugriffsmatrix", "Patch-Management-Bericht"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.CRY.01", "TOM.ACC.01"],
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-006",
|
||||
"title": "Anomalie-Erkennung und -Ueberwachung",
|
||||
"description": "Einrichtung von Mechanismen zur Erkennung anomaler Aktivitaeten in IKT-Systemen einschliesslich Netzwerk-Performance, IKT-bezogener Vorfaelle und potenzieller Cyberbedrohungen. Mehrere Kontrollschichten implementieren.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 9", "title": "Erkennung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 9 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "SOC-Leiter",
|
||||
"evidence": ["SIEM-Konfiguration", "Anomalie-Erkennungs-Berichte", "Monitoring-Dashboard"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-007",
|
||||
"title": "IKT-Vorfall-Reaktionsplaene",
|
||||
"description": "Festlegung von Reaktions- und Wiederherstellungsplaenen fuer IKT-bezogene Vorfaelle mit klaren Rollen, Eskalationsverfahren und Kommunikationsplaenen. Regelmaessige Tests der Plaene durch Simulationen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 10", "title": "Reaktion und Wiederherstellung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 10 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "CISO",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y", "event": "Jaehrlicher Test"},
|
||||
"evidence": ["Incident-Response-Plan", "Testbericht Simulation", "Eskalationsmatrix"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-008",
|
||||
"title": "Backup- und Wiederherstellungsrichtlinien",
|
||||
"description": "Erstellung und Umsetzung von Backup-Richtlinien mit festgelegten Umfang, Haeufigkeit und Aufbewahrungsfristen. Regelmaessige Tests der Wiederherstellung einschliesslich Systemwiederanlauf und Datenintegritaetspruefung.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 11", "title": "Backup-Strategien und Wiederherstellung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 11 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leiter",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"evidence": ["Backup-Richtlinie", "Wiederherstellungstest-Protokoll", "RPO/RTO-Dokumentation"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-009",
|
||||
"title": "Redundanz und Geschaeftskontinuitaet",
|
||||
"description": "Sicherstellung der Geschaeftskontinuitaet durch redundante IKT-Kapazitaeten. Business-Continuity-Plaene muessen IKT-Ausfallszenarien abdecken und regelmaessig getestet werden.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true},
|
||||
{"field": "financial.has_critical_ict", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 12", "title": "Geschaeftskontinuitaetsmanagement"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 12 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leiter",
|
||||
"evidence": ["BCP-Plan", "Redundanz-Architektur", "BCP-Testbericht"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-010",
|
||||
"title": "Krisenkommunikation bei IKT-Vorfaellen",
|
||||
"description": "Etablierung von Kommunikationsplaenen fuer IKT-bezogene Vorfaelle und Krisen: interne Kommunikation, Kommunikation mit Kunden und Gegenparteien, Medien und Aufsichtsbehoerden.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 13", "title": "Kommunikation"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 13 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Kommunikationsabteilung",
|
||||
"evidence": ["Krisenkommunikationsplan", "Kontaktlisten Behoerden", "Vorlagen Kundeninformation"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-011",
|
||||
"title": "Lessons Learned aus IKT-Vorfaellen",
|
||||
"description": "Systematische Analyse und Aufarbeitung von IKT-bezogenen Vorfaellen. Erkenntnisse muessen dokumentiert und in die Verbesserung des IKT-Risikomanagement-Rahmens einfliessen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 14", "title": "Lernen und Weiterentwicklung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 14 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "CISO",
|
||||
"evidence": ["Post-Incident-Reviews", "Massnahmenplan", "Schulungsunterlagen"],
|
||||
"priority": "mittel",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-012",
|
||||
"title": "IKT-Vorfallmanagement-Prozess",
|
||||
"description": "Einrichtung eines Prozesses zur Erkennung, Verwaltung und Meldung IKT-bezogener Vorfaelle mit Fruehwarnindikatoren, Klassifizierungskriterien und Eskalationsverfahren.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 15", "title": "IKT-bezogenes Vorfallmanagement"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 15 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "CISO",
|
||||
"evidence": ["Vorfallmanagement-Prozess", "Klassifizierungsschema", "Eskalationsmatrix"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-013",
|
||||
"title": "Klassifizierung von IKT-Vorfaellen",
|
||||
"description": "Klassifizierung aller IKT-bezogenen Vorfaelle nach definierten Kriterien: betroffene Kunden, Dauer, geografische Ausbreitung, Datenverluste, Kritikalitaet der Dienste und wirtschaftliche Auswirkungen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 16", "title": "Klassifizierung IKT-bezogener Vorfaelle"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 16 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "CISO",
|
||||
"evidence": ["Klassifizierungskriterien", "Vorfall-Register", "Schwellenwert-Dokumentation"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-014",
|
||||
"title": "Schwerwiegende IKT-Vorfaelle melden",
|
||||
"description": "Schwerwiegende IKT-bezogene Vorfaelle muessen der zustaendigen Aufsichtsbehoerde gemeldet werden: Erstmeldung, Zwischenmeldung und Abschlussbericht innerhalb der vorgegebenen Fristen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true},
|
||||
{"field": "financial.is_regulated", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 17", "title": "Meldung schwerwiegender IKT-bezogener Vorfaelle"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 17 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Meldepflicht",
|
||||
"responsible": "CISO",
|
||||
"deadline": {"type": "on_event", "event": "Schwerwiegender IKT-Vorfall", "duration": "PT4H"},
|
||||
"sanctions": {"max_fine": "Bussgeld nach nationalem Recht", "personal_liability": true},
|
||||
"evidence": ["Erstmeldung", "Zwischenmeldung", "Abschlussbericht"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-015",
|
||||
"title": "Freiwillige Meldung erheblicher Cyberbedrohungen",
|
||||
"description": "Finanzunternehmen koennen erhebliche Cyberbedrohungen freiwillig der Aufsichtsbehoerde melden, wenn sie die Bedrohung als relevant fuer das Finanzsystem erachten. Standardisiertes Meldeformat verwenden.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 18", "title": "Freiwillige Meldung erheblicher Cyberbedrohungen"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 18 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Meldepflicht",
|
||||
"responsible": "CISO",
|
||||
"evidence": ["Meldeformular Cyberbedrohung", "Bedrohungsanalyse"],
|
||||
"priority": "niedrig",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-016",
|
||||
"title": "Programm fuer Tests der digitalen Resilienz",
|
||||
"description": "Einrichtung eines umfassenden Programms fuer Tests der digitalen operationalen Resilienz: Schwachstellenscans, Open-Source-Analysen, Netzwerksicherheitsbewertungen, Penetrationstests und szenariobasierte Tests.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 19", "title": "Allgemeine Anforderungen an Tests"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 19 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Audit",
|
||||
"responsible": "CISO",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"evidence": ["Testprogramm", "Schwachstellenscan-Berichte", "Penetrationstest-Bericht"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-017",
|
||||
"title": "Bedrohungsorientierte Penetrationstests (TLPT)",
|
||||
"description": "Durchfuehrung bedrohungsorientierter Penetrationstests (Threat-Led Penetration Testing) mindestens alle 3 Jahre fuer bedeutende Finanzunternehmen. Tests muessen von qualifizierten externen Pruefern durchgefuehrt werden.",
|
||||
"applies_when": "significant_financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true},
|
||||
{"field": "financial.has_critical_ict", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 22", "title": "Bedrohungsorientierte Penetrationstests"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 22 VO (EU) 2022/2554"},
|
||||
{"type": "eu_guidance", "ref": "TIBER-EU Framework"}
|
||||
],
|
||||
"category": "Audit",
|
||||
"responsible": "CISO",
|
||||
"deadline": {"type": "recurring", "interval": "P3Y"},
|
||||
"evidence": ["TLPT-Bericht", "Qualifikationsnachweis Pruefer", "Massnahmenplan"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-018",
|
||||
"title": "IKT-Drittparteienrisiko-Management",
|
||||
"description": "Verwaltung der Risiken aus der Nutzung von IKT-Drittdienstleistern: Risikoanalyse vor Vertragsschluss, vertragliche Mindestanforderungen, laufende Ueberwachung und Exit-Strategien fuer kritische IKT-Dienste.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 28", "title": "Allgemeine Grundsaetze"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 28 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Governance",
|
||||
"responsible": "Einkauf/Vendor-Management",
|
||||
"evidence": ["IKT-Drittanbieter-Register", "Risikoanalyse je Anbieter", "Exit-Strategie"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-019",
|
||||
"title": "Vertragliche Anforderungen an IKT-Drittanbieter",
|
||||
"description": "IKT-Dienstleistungsvertraege muessen Mindestanforderungen enthalten: SLA-Definitionen, Zugriffsrechte, Datenlokalisierung, Unterstuetzung bei Vorfaellen, Kuendigungsrechte und Audit-Rechte.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 28 Abs. 7-8", "title": "Vertragliche Anforderungen"},
|
||||
{"norm": "DORA", "article": "Art. 30", "title": "Wesentliche Vertragsbestimmungen"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 28, 30 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Governance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"evidence": ["Vertragsvorlage IKT-Dienste", "SLA-Dokumentation", "Audit-Klausel"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DORA-OBL-020",
|
||||
"title": "Register aller IKT-Drittanbieter-Vertraege",
|
||||
"description": "Fuehrung eines vollstaendigen Registers aller vertraglichen Vereinbarungen ueber IKT-Dienstleistungen. Das Register muss auf Anfrage der Aufsichtsbehoerde bereitgestellt werden und kritische IKT-Drittanbieter kennzeichnen.",
|
||||
"applies_when": "financial_institution",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "financial.dora_applies", "operator": "EQUALS", "value": true},
|
||||
{"field": "sector.is_financial_institution", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "DORA", "article": "Art. 28 Abs. 3", "title": "Informationsregister"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 28 VO (EU) 2022/2554"}
|
||||
],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Vendor-Management",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"evidence": ["IKT-Vertragsregister", "Kritikalitaetsbewertung Anbieter"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2025-01-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "DORA-CTRL-001",
|
||||
"name": "IKT-Risikobewertung und -Ueberwachung",
|
||||
"description": "Kontinuierliche Bewertung und Ueberwachung von IKT-Risiken mit automatisiertem Monitoring, regelmaessigen Schwachstellenscans und Risiko-Reporting an das Leitungsorgan.",
|
||||
"category": "Governance",
|
||||
"what_to_do": "SIEM/SOC einrichten, Risiko-Dashboard implementieren, quartalsweises Reporting an Vorstand etablieren.",
|
||||
"iso27001_mapping": ["A.5.7", "A.8.8", "A.8.16"],
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "DORA-CTRL-002",
|
||||
"name": "IKT-Vorfallmelde-Prozess",
|
||||
"description": "Standardisierter Prozess fuer die Klassifizierung und Meldung schwerwiegender IKT-Vorfaelle an die zustaendige Aufsichtsbehoerde innerhalb der vorgeschriebenen Fristen.",
|
||||
"category": "Meldepflicht",
|
||||
"what_to_do": "Meldevorlagen erstellen, Eskalationsketten definieren, Klassifizierungskriterien dokumentieren, Testmeldungen durchfuehren.",
|
||||
"iso27001_mapping": ["A.5.24", "A.5.25", "A.5.26"],
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "DORA-CTRL-003",
|
||||
"name": "Resilienz-Testprogramm",
|
||||
"description": "Jaehrliches Programm zur Pruefung der digitalen operationalen Resilienz: Vulnerability Assessments, Penetrationstests, Szenario-Tests und fuer bedeutende Institute TLPT alle 3 Jahre.",
|
||||
"category": "Audit",
|
||||
"what_to_do": "Testplan erstellen, qualifizierte Pruefer beauftragen, Ergebnisse dokumentieren und Massnahmen nachverfolgen.",
|
||||
"iso27001_mapping": ["A.5.35", "A.5.36", "A.8.8"],
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "DORA-CTRL-004",
|
||||
"name": "IKT-Drittanbieter-Due-Diligence",
|
||||
"description": "Strukturierter Prozess zur Bewertung und laufenden Ueberwachung von IKT-Drittdienstleistern: Risikobewertung vor Vertragsschluss, SLA-Monitoring, Audit-Rechte und Exit-Planung.",
|
||||
"category": "Governance",
|
||||
"what_to_do": "Vendor-Assessment-Framework einrichten, Kritikalitaets-Klassifizierung durchfuehren, jaehrliche Reviews durchfuehren.",
|
||||
"iso27001_mapping": ["A.5.19", "A.5.20", "A.5.21", "A.5.22"],
|
||||
"priority": "hoch"
|
||||
}
|
||||
],
|
||||
"incident_deadlines": [
|
||||
{
|
||||
"phase": "Erstmeldung",
|
||||
"deadline": "4 Stunden nach Klassifizierung als schwerwiegend",
|
||||
"content": "Erste Meldung mit grundlegenden Informationen: Art des Vorfalls, betroffene Dienste, erste Auswirkungseinschaetzung",
|
||||
"recipient": "Zustaendige Aufsichtsbehoerde (BaFin/EZB)",
|
||||
"legal_basis": [{"norm": "DORA", "article": "Art. 17"}]
|
||||
},
|
||||
{
|
||||
"phase": "Zwischenmeldung",
|
||||
"deadline": "72 Stunden nach Erstmeldung (oder bei wesentlicher Aenderung)",
|
||||
"content": "Aktualisierte Informationen zu Ursache, Auswirkungen, ergriffenen Massnahmen und voraussichtlicher Wiederherstellung",
|
||||
"recipient": "Zustaendige Aufsichtsbehoerde (BaFin/EZB)",
|
||||
"legal_basis": [{"norm": "DORA", "article": "Art. 17"}]
|
||||
},
|
||||
{
|
||||
"phase": "Abschlussbericht",
|
||||
"deadline": "1 Monat nach Wiederherstellung des Normalbetriebs",
|
||||
"content": "Vollstaendiger Bericht: Ursachenanalyse, Gesamtauswirkungen, ergriffene und geplante Massnahmen, Lessons Learned",
|
||||
"recipient": "Zustaendige Aufsichtsbehoerde (BaFin/EZB)",
|
||||
"legal_basis": [{"norm": "DORA", "article": "Art. 17"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
742
ai-compliance-sdk/policies/obligations/v2/dsa_v2.json
Normal file
742
ai-compliance-sdk/policies/obligations/v2/dsa_v2.json
Normal file
@@ -0,0 +1,742 @@
|
||||
{
|
||||
"regulation": "dsa",
|
||||
"name": "Digital Services Act (EU) 2022/2065",
|
||||
"description": "Verordnung ueber einen Binnenmarkt fuer digitale Dienste — Pflichten fuer Anbieter digitaler Dienste, Plattformen und sehr grosse Online-Plattformen (VLOPs/VLOSEs)",
|
||||
"version": "2.0",
|
||||
"effective_date": "2024-02-17",
|
||||
"obligations": [
|
||||
{
|
||||
"id": "DSA-OBL-001",
|
||||
"title": "Haftungsprivileg — Mere Conduit",
|
||||
"description": "Vermittlungsdienste (reine Durchleitung) muessen sicherstellen, dass sie keine Kenntnis von rechtswidrigen Inhalten haben und bei Kenntnis unverzueglich handeln, um das Haftungsprivileg zu bewahren.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 6", "title": "Reine Durchleitung (Mere Conduit)"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 6 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Dokumentation der Vermittlungstaetigkeiten", "Nachweise ueber fehlende Kenntnis"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-002",
|
||||
"title": "Haftungsprivileg — Caching",
|
||||
"description": "Caching-Dienste muessen bei Kenntniserlangung rechtswidriger Inhalte unverzueglich taetig werden, um diese zu entfernen oder den Zugang zu sperren.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 7", "title": "Caching"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 7 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Caching-Richtlinie", "Reaktionsprotokolle bei Kenntniserlangung"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-003",
|
||||
"title": "Haftungsprivileg — Hosting",
|
||||
"description": "Hosting-Dienste muessen bei tatsaechlicher Kenntnis rechtswidriger Inhalte oder Taetigkeiten unverzueglich handeln, um diese zu entfernen oder den Zugang zu sperren.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 8", "title": "Hosting"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 8 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Notice-and-Action-Protokolle", "Nachweis unverzueglicher Reaktion"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-004",
|
||||
"title": "Keine allgemeine Ueberwachungspflicht",
|
||||
"description": "Anbietern darf keine allgemeine Verpflichtung zur Ueberwachung der uebermittelten oder gespeicherten Informationen auferlegt werden. Freiwillige Eigeninitiative fuehrt nicht zum Verlust des Haftungsprivilegs.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 9", "title": "Keine allgemeine Ueberwachungspflicht"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 9 DSA"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Dokumentation Moderationsrichtlinie", "Nachweis keine allgemeine Ueberwachung"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-005",
|
||||
"title": "Zentrale Kontaktstelle",
|
||||
"description": "Benennung einer zentralen Kontaktstelle fuer die Kommunikation mit Behoerden der Mitgliedstaaten, der Kommission und dem Gremium fuer digitale Dienste. Die Kontaktstelle muss in einer Amtssprache erreichbar sein.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 11", "title": "Kontaktstellen fuer Behoerden"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 11 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"sanctions": {"max_fine": "1% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Benennungsdokument Kontaktstelle", "Veroeffentlichte Kontaktdaten"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.02"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-006",
|
||||
"title": "Gesetzlicher Vertreter",
|
||||
"description": "Anbieter ohne Niederlassung in der EU muessen einen gesetzlichen Vertreter in einem Mitgliedstaat benennen, in dem sie Dienste anbieten.",
|
||||
"applies_when": "organization.eu_member == false AND organization.operates_platform == true",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.eu_member", "operator": "EQUALS", "value": false},
|
||||
{"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 12", "title": "Gesetzlicher Vertreter"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 12 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Benennungsurkunde gesetzlicher Vertreter", "Veroeffentlichung auf der Webseite"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-007",
|
||||
"title": "Allgemeine Geschaeftsbedingungen — Inhaltsmoderation",
|
||||
"description": "In den AGB muessen Informationen zu Beschraenkungen enthalten sein, die Anbieter in Bezug auf von Nutzern bereitgestellte Inhalte auferlegen. Dies umfasst Moderationsrichtlinien, algorithmische Entscheidungsfindung und Beschwerdemechanismen.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 13", "title": "Allgemeine Geschaeftsbedingungen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 13 DSA"}],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Aktuelle AGB mit Moderationsrichtlinien", "Verstaendliche Darstellung der Beschraenkungen"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"breakpilot_feature": "/sdk/policy-generator",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-008",
|
||||
"title": "Transparenzbericht — Vermittlungsdienste",
|
||||
"description": "Jaehrliche Veroeffentlichung eines Transparenzberichts ueber Inhaltsmoderation, behoerdliche Anordnungen und Notice-and-Action-Verfahren. Der Bericht muss maschinenlesbar und oeffentlich zugaenglich sein.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 14", "title": "Transparenzberichterstattungspflichten fuer Anbieter von Vermittlungsdiensten"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 14 DSA"}],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Veroeffentlichter Transparenzbericht", "Maschinenlesbares Format"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.03"],
|
||||
"breakpilot_feature": "/sdk/reporting",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-009",
|
||||
"title": "Transparenzbericht — erweitert fuer Online-Plattformen",
|
||||
"description": "Online-Plattformen muessen zusaetzlich Informationen ueber Streitbeilegungsverfahren, Aussetzungen, automatisierte Inhaltserkennung und Trusted Flagger in ihren Transparenzbericht aufnehmen.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 15", "title": "Transparenzberichterstattungspflichten fuer Anbieter von Online-Plattformen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 15 DSA"}],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"deadline": {"type": "recurring", "interval": "P6M"},
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Erweiterter Transparenzbericht", "Statistik automatisierter Moderation"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.03"],
|
||||
"breakpilot_feature": "/sdk/reporting",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-010",
|
||||
"title": "Melde- und Abhilfeverfahren (Notice-and-Action)",
|
||||
"description": "Einrichtung eines leicht zugaenglichen und benutzerfreundlichen Mechanismus, der es jeder Person ermoeglicht, mutmasslich rechtswidrige Inhalte zu melden. Meldungen muessen elektronisch moeglich sein und eine Bestaetigung ausloesen.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 16", "title": "Melde- und Abhilfeverfahren"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 16 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Implementiertes Meldeformular", "Bestaetigung der Eingangsbehandlung", "Verarbeitungsprotokoll"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.OPS.02"],
|
||||
"breakpilot_feature": "/sdk/incident-response",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-011",
|
||||
"title": "Begruendungspflicht bei Inhaltsentfernung",
|
||||
"description": "Bei Entfernung oder Sperrung von Inhalten muss dem betroffenen Nutzer eine klare und spezifische Begruendung mitgeteilt werden, einschliesslich der angewandten Rechtsgrundlage und der Rechtsbehelfsmoeglichkeiten.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 17", "title": "Begruendung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 17 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Content-Moderation-Team",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Begruendungsvorlagen", "Muster-Benachrichtigungen", "Zustellungsnachweise"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-012",
|
||||
"title": "Meldung strafbarer Inhalte an Behoerden",
|
||||
"description": "Bei Verdacht auf Straftaten, die das Leben oder die Sicherheit von Personen bedrohen, muessen die zustaendigen Strafverfolgungsbehoerden des betreffenden Mitgliedstaats unverzueglich informiert werden.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 18", "title": "Meldung von Verdacht auf Straftaten"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 18 DSA"}],
|
||||
"category": "Meldepflicht",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"deadline": {"type": "on_event", "event": "Kenntniserlangung strafbarer Inhalte"},
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": true, "criminal_liability": true},
|
||||
"evidence": ["Eskalationsprozess-Dokumentation", "Meldungsprotokolle an Behoerden"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-013",
|
||||
"title": "Trusted Flaggers",
|
||||
"description": "Vorrangige Bearbeitung von Meldungen vertrauenswuerdiger Hinweisgeber (Trusted Flaggers), die vom Koordinator fuer digitale Dienste zertifiziert wurden. Entscheidungen ueber Meldungen von Trusted Flaggers muessen zeitnah erfolgen.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 19", "title": "Vertrauenswuerdige Hinweisgeber"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 19 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Content-Moderation-Team",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Priorisierungsprozess fuer Trusted Flaggers", "SLA-Dokumentation"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.OPS.02"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-014",
|
||||
"title": "Schutz vor Missbrauch des Meldesystems",
|
||||
"description": "Aussetzung der Bearbeitung von Meldungen und Beschwerden von Personen oder Stellen, die haeufig offensichtlich unbegruendete Meldungen oder Beschwerden einreichen.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 20", "title": "Schutz vor Missbrauch"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 20 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Content-Moderation-Team",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Anti-Missbrauchs-Richtlinie", "Dokumentation der Aussetzungsentscheidungen"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-015",
|
||||
"title": "Aussetzung wegen Missbrauch durch Nutzer",
|
||||
"description": "Anbieter von Online-Plattformen setzen die Erbringung ihrer Dienste fuer Nutzer aus, die haeufig offensichtlich rechtswidrige Inhalte bereitstellen. Vorherige Warnung erforderlich.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 21", "title": "Aussetzung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 21 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Content-Moderation-Team",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Eskalationsstufenmodell", "Warnprotokolle", "Aussetzungsentscheidungen"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-016",
|
||||
"title": "Internes Beschwerdemanagementsystem",
|
||||
"description": "Bereitstellung eines elektronischen und benutzerfreundlichen internen Beschwerdemanagementsystems, ueber das Nutzer Entscheidungen zur Inhaltsmoderation anfechten koennen. Entscheidungen duerfen nicht ausschliesslich automatisiert getroffen werden.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 22", "title": "Internes Beschwerdemanagementsystem"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 22 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Implementiertes Beschwerdesystem", "Verarbeitungsstatistik", "Human-Review-Nachweis"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.OPS.02"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-017",
|
||||
"title": "Aussergerichtliche Streitbeilegung",
|
||||
"description": "Nutzer muessen die Moeglichkeit haben, sich an eine zertifizierte aussergerichtliche Streitbeilegungsstelle zu wenden. Plattformen muessen mit diesen Stellen zusammenarbeiten.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 23", "title": "Aussergerichtliche Streitbeilegung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 23 DSA"}],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Hinweis auf Streitbeilegungsstellen in AGB", "Kooperationsvereinbarungen"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-018",
|
||||
"title": "Vorrang behoerdlicher Anordnungen",
|
||||
"description": "Online-Plattformen muessen behoerdliche Anordnungen gegen rechtswidrige Inhalte vorrangig bearbeiten und den behoerdlichen Anweisungen fristgerecht Folge leisten.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 24", "title": "Pflichten im Zusammenhang mit Anordnungen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 24 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Rechtsabteilung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": true},
|
||||
"evidence": ["Anordnungsregister", "Fristeinhaltungsprotokolle"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-019",
|
||||
"title": "Werbetransparenz — Kennzeichnungspflicht",
|
||||
"description": "Jede Werbung auf der Plattform muss klar und eindeutig als Werbung gekennzeichnet sein. Der Auftraggeber und die Finanzierungsquelle muessen erkennbar sein.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 26", "title": "Werbung auf Online-Plattformen"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 26 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Werbekennzeichnungs-Implementierung", "Audit der Werbeanzeigen"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-020",
|
||||
"title": "Verbot von Dark Patterns",
|
||||
"description": "Gestaltung der Online-Schnittstelle darf Nutzer nicht taueschen, manipulieren oder in ihrer Entscheidungsfreiheit beeintraechtigen (Verbot von Dark Patterns).",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 27", "title": "Verbot taeuschender Gestaltung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 27 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "UX-Team",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["UX-Audit auf Dark Patterns", "Design-Review-Protokolle"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-021",
|
||||
"title": "Transparenz von Empfehlungssystemen",
|
||||
"description": "Plattformen muessen in ihren AGB die Hauptparameter der Empfehlungssysteme und die Moeglichkeit fuer Nutzer, diese zu beeinflussen, darlegen. Mindestens eine nicht-profilbasierte Option muss angeboten werden.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 28", "title": "Empfehlungssysteme"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 28 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Dokumentation der Empfehlungsparameter", "Nutzerwahlmoeglichkeit implementiert"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-022",
|
||||
"title": "Minderjaehrigenschutz auf Plattformen",
|
||||
"description": "Online-Plattformen muessen geeignete Massnahmen zum Schutz Minderjaehriger treffen, einschliesslich altersgerechter Datenschutzeinstellungen. Werbung auf Basis von Profiling Minderjaehriger ist verboten.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 29", "title": "Schutz Minderjaehriger"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 29 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Jugendschutzkonzept", "Altersverifikationslogik", "Profiling-Ausschluss fuer Minderjaehrige"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-023",
|
||||
"title": "VLOP/VLOSE — Zusaetzliche Transparenz Werbearchiv",
|
||||
"description": "Sehr grosse Online-Plattformen muessen ein oeffentlich zugaengliches Werbearchiv fuehren, das alle geschalteten Werbeanzeigen mit Targeting-Parametern, Auftraggeber und Laufzeit enthaelt.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 30", "title": "Zusaetzliche Transparenz der Online-Werbung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 30 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Implementiertes Werbearchiv", "API-Zugang fuer Forscher"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.03"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-024",
|
||||
"title": "VLOP/VLOSE — Empfehlungssystem Nutzerwahlrecht",
|
||||
"description": "Sehr grosse Plattformen muessen Nutzern mindestens eine Option zur Verfuegung stellen, bei der das Empfehlungssystem nicht auf Profiling basiert.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 31", "title": "Empfehlungssysteme fuer VLOPs"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 31 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Nicht-profilbasierte Empfehlungsoption", "Nutzerauswahl-UI"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-025",
|
||||
"title": "VLOP/VLOSE — Datenzugang fuer Forscher",
|
||||
"description": "Sehr grosse Plattformen muessen zugelassenen Forschern auf Antrag Zugang zu Daten gewaehren, um systemische Risiken zu erforschen. Der Zugang erfolgt ueber technische Schnittstellen.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 32", "title": "Datenzugang fuer Forscher"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 32 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Forschungsdaten-API", "Antragsverfahren dokumentiert", "Datenschutzkonzept fuer Forschungsdaten"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.03"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-026",
|
||||
"title": "VLOP/VLOSE — Systemische Risikobewertung",
|
||||
"description": "Jaehrliche Bewertung systemischer Risiken wie illegale Inhalte, Grundrechtsbeeintraechtigungen, Manipulation von Wahlen und Auswirkungen auf Minderjaehrige. Die Bewertung muss dokumentiert und der Aufsichtsbehoerde vorgelegt werden.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 33", "title": "Bewertung systemischer Risiken"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 33 DSA"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": true},
|
||||
"evidence": ["Systemische Risikobewertung", "Massnahmenplan", "Vorlage bei Aufsichtsbehoerde"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.02", "TOM.GOV.03"],
|
||||
"breakpilot_feature": "/sdk/risk-assessment",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-027",
|
||||
"title": "VLOP/VLOSE — Risikominderungsmassnahmen",
|
||||
"description": "Ergreifung angemessener, verhaeltnismaessiger und wirksamer Risikominderungsmassnahmen fuer die identifizierten systemischen Risiken. Massnahmen muessen regelmaessig ueberprueft und angepasst werden.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 34", "title": "Risikominderung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 34 DSA"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": true},
|
||||
"evidence": ["Risikominderungsplan", "Wirksamkeitsbewertung", "Anpassungsdokumentation"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/risk-assessment",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-028",
|
||||
"title": "VLOP/VLOSE — Unabhaengige Audits",
|
||||
"description": "Jaehrliche unabhaengige Audits auf eigene Kosten zur Bewertung der Einhaltung der DSA-Pflichten. Der Auditbericht wird der Aufsichtsbehoerde uebermittelt und ein Zusammenfassung veroeffentlicht.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 35", "title": "Unabhaengige Pruefung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 35 DSA"}],
|
||||
"category": "Audit",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": true},
|
||||
"evidence": ["Auditbericht", "Massnahmenplan aus Audit-Ergebnissen", "Veroeffentlichte Zusammenfassung"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.03"],
|
||||
"breakpilot_feature": "/sdk/audit",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-029",
|
||||
"title": "Compliance-Beauftragter (VLOP/VLOSE)",
|
||||
"description": "Sehr grosse Plattformen muessen einen oder mehrere Compliance-Beauftragte benennen, die die Einhaltung des DSA ueberwachen. Der Beauftragte berichtet direkt an die Leitungsebene.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 37", "title": "Compliance-Funktion"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 37 DSA"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Benennungsurkunde", "Berichtsstruktur", "Kompetenznachweis"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.GOV.02"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-030",
|
||||
"title": "Datenzugang fuer Aufsichtsbehoerden",
|
||||
"description": "Auf Anfrage muessen Plattformen den Koordinatoren fuer digitale Dienste und der Kommission Zugang zu relevanten Daten gewaehren, die zur Ueberwachung der DSA-Einhaltung erforderlich sind.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 38", "title": "Datenzugang und Datenueberpruefung"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 38 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Datenzugangsprozess dokumentiert", "Technische Schnittstelle fuer Behoerden"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.OPS.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-031",
|
||||
"title": "VLOP/VLOSE — Datenzugang fuer ueberprueften Forscher",
|
||||
"description": "Gewaehrung eines angemessenen Datenzugangs fuer von der Aufsichtsbehoerde ueberprueften Forscher zur Erforschung systemischer Risiken. Personenbezogene Daten nur anonymisiert oder pseudonymisiert.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 39", "title": "Datenzugang fuer ueberprueften Forscher"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 39 DSA"}],
|
||||
"category": "Technisch",
|
||||
"responsible": "CTO",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Pseudonymisierungskonzept", "Forschungsdaten-Zugangsverfahren"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.OPS.01", "TOM.GOV.03"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-032",
|
||||
"title": "Verhaltenskodizes",
|
||||
"description": "Unterstuetzung und Einhaltung freiwilliger Verhaltenskodizes auf EU-Ebene zur Bekaempfung rechtswidriger Inhalte und zum Schutz der Nutzer. Die Kommission foerdert die Erarbeitung solcher Kodizes.",
|
||||
"applies_when": "organization.operates_platform == true",
|
||||
"applies_when_condition": {"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 40", "title": "Verhaltenskodizes"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 40 DSA"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"sanctions": {"max_fine": "1% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Beitrittserklarung zu Verhaltenskodizes", "Umsetzungsbericht"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-033",
|
||||
"title": "Krisenreaktionsprotokolle",
|
||||
"description": "Bei aussergewoehnlichen Umstaenden (z.B. Pandemie, bewaffnete Konflikte) kann die Kommission VLOPs/VLOSEs zur Teilnahme an Krisenprotokollen verpflichten. Schnelle Reaktionsmechanismen muessen vorbereitet sein.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 42", "title": "Krisenreaktionsprotokolle"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 42 DSA"}],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": true},
|
||||
"evidence": ["Krisenreaktionsplan", "Ansprechpartner fuer Krisenkoordination"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.OPS.01"],
|
||||
"breakpilot_feature": "/sdk/notfallplan",
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-034",
|
||||
"title": "Koordinator fuer digitale Dienste — Kooperation",
|
||||
"description": "Plattformen muessen mit dem nationalen Koordinator fuer digitale Dienste (DSC) kooperieren, Informationen bereitstellen und Anordnungen fristgerecht umsetzen.",
|
||||
"applies_when": "organization.operates_platform == true AND organization.eu_member == true",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "data_protection.operates_platform", "operator": "EQUALS", "value": true},
|
||||
{"field": "organization.eu_member", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 44", "title": "Koordinatoren fuer digitale Dienste"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 44 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Compliance-Beauftragter",
|
||||
"sanctions": {"max_fine": "6% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Kooperationsprotokolle mit DSC", "Fristenkontrolle fuer Anordnungen"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "DSA-OBL-035",
|
||||
"title": "Aufsichtsgebuehr (VLOP/VLOSE)",
|
||||
"description": "Sehr grosse Plattformen und Suchmaschinen muessen eine jaehrliche Aufsichtsgebuehr an die Kommission entrichten. Die Hoehe wird auf Basis des Umsatzes berechnet.",
|
||||
"applies_when": "platform_user_count >= 45000000",
|
||||
"applies_when_condition": {"field": "data_protection.platform_user_count", "operator": "GREATER_OR_EQUAL", "value": 45000000},
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 47", "title": "Aufsichtsgebuehr"}],
|
||||
"sources": [{"type": "article", "ref": "Art. 47 DSA"}],
|
||||
"category": "Compliance",
|
||||
"responsible": "Finanzabteilung",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y"},
|
||||
"sanctions": {"max_fine": "1% des weltweiten Jahresumsatzes", "personal_liability": false},
|
||||
"evidence": ["Zahlungsnachweis Aufsichtsgebuehr", "Umsatzberechnung"],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"valid_from": "2024-02-17",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "DSA-CTRL-001",
|
||||
"name": "Notice-and-Action-System",
|
||||
"description": "Technisches System zur Entgegennahme, Bearbeitung und Dokumentation von Meldungen rechtswidriger Inhalte",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Implementierung eines elektronischen Meldeformulars mit Eingangsbestaetigung, Bearbeitungs-Tracking und Begruendungsgenerierung",
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "DSA-CTRL-002",
|
||||
"name": "Transparenzberichts-Framework",
|
||||
"description": "Prozess und Tooling fuer die regelmaessige Erstellung und Veroeffentlichung von Transparenzberichten",
|
||||
"category": "Organisatorisch",
|
||||
"what_to_do": "Aufbau eines Daten-Pipelines zur automatisierten Erfassung von Moderationsstatistiken, Beschwerden und behoerdlichen Anordnungen",
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "DSA-CTRL-003",
|
||||
"name": "Internes Beschwerdemanagement",
|
||||
"description": "Elektronisches System fuer Nutzerbeschwerden gegen Moderationsentscheidungen mit Human-Review-Garantie",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Bereitstellung eines Beschwerdeformulars mit Eskalationsstufen, SLA-Tracking und Nachweis menschlicher Ueberpruefung",
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "DSA-CTRL-004",
|
||||
"name": "Werbetransparenz-Archiv",
|
||||
"description": "Oeffentlich zugaengliches Repository aller geschalteten Werbeanzeigen mit Targeting- und Auftraggeberinformationen",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Implementierung eines durchsuchbaren Werbearchivs mit API-Zugang, Aufbewahrungsfrist mindestens 1 Jahr nach letzter Ausspielung",
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "DSA-CTRL-005",
|
||||
"name": "Systemische Risikobewertung",
|
||||
"description": "Jaehrlicher Prozess zur Identifikation und Bewertung systemischer Risiken fuer VLOPs/VLOSEs",
|
||||
"category": "Governance",
|
||||
"what_to_do": "Durchfuehrung einer strukturierten Risikobewertung zu illegalen Inhalten, Grundrechtsbeeintraechtigungen, Wahlmanipulation und Auswirkungen auf Minderjaehrige",
|
||||
"priority": "kritisch"
|
||||
}
|
||||
],
|
||||
"incident_deadlines": [
|
||||
{
|
||||
"phase": "Kenntniserlangung rechtswidriger Inhalte",
|
||||
"deadline": "Unverzueglich (ohne schuldhaftes Zoegern)",
|
||||
"content": "Entfernung oder Sperrung des Zugangs zu rechtswidrigen Inhalten",
|
||||
"recipient": "Intern — Content-Moderation-Team",
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 8"}]
|
||||
},
|
||||
{
|
||||
"phase": "Meldung strafbarer Inhalte",
|
||||
"deadline": "Unverzueglich nach Kenntniserlangung",
|
||||
"content": "Information der zustaendigen Strafverfolgungsbehoerden bei Verdacht auf Straftaten gegen Leben oder Sicherheit",
|
||||
"recipient": "Zustaendige Strafverfolgungsbehoerde",
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 18"}]
|
||||
},
|
||||
{
|
||||
"phase": "Reaktion auf behoerdliche Anordnung",
|
||||
"deadline": "Frist gemaess Anordnung, spaetestens 72 Stunden",
|
||||
"content": "Umsetzung der angeordneten Massnahme und Bestaetigung an die anordnende Behoerde",
|
||||
"recipient": "Anordnende Behoerde / DSC",
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 24"}]
|
||||
},
|
||||
{
|
||||
"phase": "Transparenzbericht (Vermittlungsdienste)",
|
||||
"deadline": "Jaehrlich, spaetestens 2 Monate nach Berichtszeitraum",
|
||||
"content": "Veroeffentlichung des Transparenzberichts zu Inhaltsmoderation, Anordnungen und Beschwerden",
|
||||
"recipient": "Oeffentlichkeit / DSC",
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 14"}]
|
||||
},
|
||||
{
|
||||
"phase": "Transparenzbericht (VLOP/VLOSE)",
|
||||
"deadline": "Halbjaehrlich",
|
||||
"content": "Erweiterter Transparenzbericht mit automatisierter Moderation, Trusted Flagger und Forschungsdaten",
|
||||
"recipient": "Oeffentlichkeit / Kommission / DSC",
|
||||
"legal_basis": [{"norm": "DSA", "article": "Art. 15"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
4678
ai-compliance-sdk/policies/obligations/v2/dsgvo_v2.json
Normal file
4678
ai-compliance-sdk/policies/obligations/v2/dsgvo_v2.json
Normal file
File diff suppressed because it is too large
Load Diff
426
ai-compliance-sdk/policies/obligations/v2/eu_machinery_v2.json
Normal file
426
ai-compliance-sdk/policies/obligations/v2/eu_machinery_v2.json
Normal file
@@ -0,0 +1,426 @@
|
||||
{
|
||||
"regulation": "eu_machinery",
|
||||
"name": "EU-Maschinenverordnung (EU) 2023/1230",
|
||||
"description": "Verordnung (EU) 2023/1230 ueber Maschinen und zur Aufhebung der Richtlinie 2006/42/EG — harmonisierte Vorschriften fuer das Inverkehrbringen und die Inbetriebnahme von Maschinen und zugehoerigen Produkten im Binnenmarkt",
|
||||
"version": "1.0",
|
||||
"effective_date": "2027-01-20",
|
||||
"obligations": [
|
||||
{
|
||||
"id": "EUMACH-OBL-001",
|
||||
"title": "Inverkehrbringen von Maschinen",
|
||||
"description": "Sicherstellung, dass nur konforme Maschinen auf dem Unionsmarkt bereitgestellt werden. Maschinen duerfen nur in Verkehr gebracht werden, wenn sie bei ordnungsgemaesser Installation, Wartung und bestimmungsgemaesser Verwendung die Sicherheits- und Gesundheitsanforderungen erfuellen.",
|
||||
"applies_when": "manufacturer_or_importer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 4", "title": "Anforderungen an das Inverkehrbringen"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 4 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"sanctions": {"max_fine": "Marktzuruecknahme, Vertriebsverbot", "personal_liability": true},
|
||||
"evidence": ["Konformitaetsbewertung", "Technische Dokumentation"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-002",
|
||||
"title": "Inbetriebnahme konformer Maschinen",
|
||||
"description": "Maschinen duerfen erst in Betrieb genommen werden, wenn die Konformitaet nachgewiesen ist und alle Sicherheitsanforderungen laut Anhang III erfuellt sind. Betreiber muessen vor der Inbetriebnahme die Konformitaetserklaerung und CE-Kennzeichnung pruefen.",
|
||||
"applies_when": "operator",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 5", "title": "Inbetriebnahme"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 5 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Compliance",
|
||||
"responsible": "Betriebsleiter",
|
||||
"evidence": ["Inbetriebnahmeprotokoll", "CE-Konformitaetserklaerung"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-003",
|
||||
"title": "Freier Warenverkehr sicherstellen",
|
||||
"description": "Mitgliedstaaten duerfen das Inverkehrbringen konformer Maschinen nicht behindern. Hersteller muessen sicherstellen, dass ihre Produkte die harmonisierten Normen einhalten, um den freien Warenverkehr zu gewaehrleisten.",
|
||||
"applies_when": "manufacturer_eu_market",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 6", "title": "Freier Warenverkehr"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 6 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Compliance",
|
||||
"responsible": "Regulatory-Affairs",
|
||||
"evidence": ["Nachweis harmonisierter Normen", "EU-Konformitaetserklaerung"],
|
||||
"priority": "mittel",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-004",
|
||||
"title": "Konformitaetsvermutung durch harmonisierte Normen",
|
||||
"description": "Anwendung harmonisierter Normen begruendet eine Konformitaetsvermutung. Hersteller sollen relevante EN-Normen anwenden und dokumentieren, welche Normen angewandt wurden und wo Abweichungen bestehen.",
|
||||
"applies_when": "manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 7", "title": "Konformitaetsvermutung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 7 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Qualitaetsmanagement",
|
||||
"evidence": ["Normenverzeichnis", "Abweichungsanalyse"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-005",
|
||||
"title": "Allgemeine Herstellerpflichten",
|
||||
"description": "Hersteller muessen sicherstellen, dass Maschinen in Uebereinstimmung mit den grundlegenden Sicherheits- und Gesundheitsanforderungen entworfen und gebaut werden. Erstellung der technischen Dokumentation, Konformitaetsbewertung und CE-Kennzeichnung.",
|
||||
"applies_when": "manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 10", "title": "Pflichten der Hersteller"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 10 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"sanctions": {"max_fine": "Marktzuruecknahme, Bussgeld nach nationalem Recht", "personal_liability": true},
|
||||
"evidence": ["Technische Dokumentation", "Konformitaetsbewertung", "Betriebsanleitung"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-006",
|
||||
"title": "Technische Dokumentation erstellen",
|
||||
"description": "Erstellung und Pflege der technischen Dokumentation gemaess Anhang IV: Konstruktionsunterlagen, Risikobeurteilung, angewandte Normen, Pruefberichte. Dokumentation muss 10 Jahre nach Inverkehrbringen aufbewahrt werden.",
|
||||
"applies_when": "manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 10 Abs. 2", "title": "Technische Dokumentation"},
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 11", "title": "Verfahren der Konformitaetsbewertung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 10-11 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Konstruktionsleiter",
|
||||
"deadline": {"type": "recurring", "interval": "P1Y", "event": "Jaehrliche Aktualisierung"},
|
||||
"evidence": ["Technische Dokumentation Anhang IV", "Risikobeurteilung", "Pruefberichte"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-007",
|
||||
"title": "Konformitaetsbewertung durchfuehren",
|
||||
"description": "Durchfuehrung des geeigneten Konformitaetsbewertungsverfahrens gemaess Art. 12 und Anhang V-IX. Fuer bestimmte Maschinenkategorien (Anhang I) ist die Einschaltung einer notifizierten Stelle erforderlich.",
|
||||
"applies_when": "manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 12", "title": "Konformitaetsbewertungsverfahren"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 12 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Audit",
|
||||
"responsible": "Qualitaetsmanagement",
|
||||
"evidence": ["Konformitaetszertifikat", "Pruefbericht notifizierte Stelle"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-008",
|
||||
"title": "Bevollmaechtigter im EU-Raum",
|
||||
"description": "Hersteller ausserhalb der EU muessen einen Bevollmaechtigten in der Union benennen. Dieser ist verantwortlich fuer die Bereitstellung der Konformitaetserklaerung und technischen Dokumentation an Marktaufsichtsbehoerden.",
|
||||
"applies_when": "non_eu_manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]},
|
||||
{"field": "organization.hq_outside_eu", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 13", "title": "Bevollmaechtigte"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 13 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Governance",
|
||||
"responsible": "Regulatory-Affairs",
|
||||
"evidence": ["Bevollmaechtigungsvertrag", "Kontaktdaten Bevollmaechtigter"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-009",
|
||||
"title": "Einfuehrerpflichten",
|
||||
"description": "Einfuehrer muessen vor dem Inverkehrbringen pruefen, dass der Hersteller die Konformitaetsbewertung durchgefuehrt hat, die technische Dokumentation vorliegt und die CE-Kennzeichnung angebracht ist. Name und Anschrift des Einfuehrers muessen auf der Maschine angegeben sein.",
|
||||
"applies_when": "importer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "import_trade"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 14", "title": "Pflichten der Einfuehrer"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 14 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Compliance",
|
||||
"responsible": "Importleiter",
|
||||
"evidence": ["Einfuehrerpruefprotokoll", "Kopie der Konformitaetserklaerung"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-010",
|
||||
"title": "EU-Konformitaetserklaerung ausstellen",
|
||||
"description": "Ausstellung der EU-Konformitaetserklaerung gemaess Anhang V mit Angaben zu Hersteller, Maschine, angewandten Normen und notifizierter Stelle. Die Erklaerung muss in der Amtssprache des Mitgliedstaats verfuegbar sein.",
|
||||
"applies_when": "manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 18", "title": "EU-Konformitaetserklaerung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 18 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Qualitaetsmanagement",
|
||||
"evidence": ["EU-Konformitaetserklaerung", "Uebersetzungen Amtssprachen"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-011",
|
||||
"title": "CE-Kennzeichnung anbringen",
|
||||
"description": "Anbringung der CE-Kennzeichnung auf der Maschine gemaess Art. 19 — sichtbar, lesbar und dauerhaft. Die CE-Kennzeichnung wird vor dem Inverkehrbringen angebracht und setzt die Konformitaetsbewertung voraus.",
|
||||
"applies_when": "manufacturer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 19", "title": "CE-Kennzeichnung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 19 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Compliance",
|
||||
"responsible": "Produktion",
|
||||
"evidence": ["Foto CE-Kennzeichnung", "Pruefprotokoll Kennzeichnung"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-012",
|
||||
"title": "KI-Systeme in Maschinen — besondere Anforderungen",
|
||||
"description": "Maschinen mit eingebetteten KI-Systemen muessen zusaetzliche Anforderungen erfuellen: Sicherheitsfunktionen duerfen nicht allein von KI abhaengen, Mensch-Maschine-Interaktion muss transparent sein, KI-bedingte Risiken muessen in der Risikobeurteilung beruecksichtigt werden.",
|
||||
"applies_when": "ai_machinery",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]},
|
||||
{"field": "ai_usage.uses_ai", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 21", "title": "KI-Systeme in Maschinen"},
|
||||
{"norm": "AI Act", "article": "Art. 6", "title": "Klassifikation Hochrisiko-KI"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 21 VO (EU) 2023/1230"},
|
||||
{"type": "eu_guidance", "ref": "Leitlinien KI in Maschinen"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "KI-Verantwortlicher",
|
||||
"sanctions": {"max_fine": "Marktzuruecknahme, Bussgeld", "personal_liability": true},
|
||||
"evidence": ["KI-Risikobeurteilung", "Sicherheitskonzept KI-Funktionen", "Human-Oversight-Nachweis"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-013",
|
||||
"title": "Sicherheitsbauteile mit digitaler Funktion",
|
||||
"description": "Sicherheitsbauteile mit Software oder digitalen Elementen muessen ueber ihren Lebenszyklus aktuell gehalten werden. Sicherheitsupdates sind bereitzustellen und Cybersecurity-Risiken in der Risikobeurteilung zu beruecksichtigen.",
|
||||
"applies_when": "digital_safety_components",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment"]},
|
||||
{"field": "ai_usage.uses_ai", "operator": "EQUALS", "value": true}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 22", "title": "Sicherheitsbauteile"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 22 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Technisch",
|
||||
"responsible": "Entwicklungsleiter",
|
||||
"evidence": ["Sicherheitsbauteil-Register", "Update-Konzept", "Cybersecurity-Risikobeurteilung"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-014",
|
||||
"title": "Zusammenarbeit mit Marktueberwachungsbehoerden",
|
||||
"description": "Wirtschaftsakteure muessen mit Marktueberwachungsbehoerden zusammenarbeiten und auf Verlangen alle erforderlichen Informationen und Unterlagen bereitstellen. Bei Nichtkonformitaet sind unverzueglich Korrekturmassnahmen zu ergreifen.",
|
||||
"applies_when": "all_economic_operators",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment", "import_trade"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 25", "title": "Marktueberwachung"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 25 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Regulatory-Affairs",
|
||||
"evidence": ["Kommunikationsprotokoll Behoerden", "Korrekturmassnahmenplan"],
|
||||
"priority": "hoch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-OBL-015",
|
||||
"title": "Meldepflicht bei Nichtkonformitaet",
|
||||
"description": "Hersteller und Einfuehrer muessen die Marktueberwachungsbehoerden unverzueglich informieren, wenn sie Grund zur Annahme haben, dass eine Maschine nicht konform ist oder ein Risiko darstellt. Dokumentation aller Korrekturmassnahmen.",
|
||||
"applies_when": "manufacturer_or_importer",
|
||||
"applies_when_condition": {
|
||||
"all_of": [
|
||||
{"field": "organization.industry", "operator": "IN", "value": ["manufacturing", "machinery", "industrial_equipment", "import_trade"]}
|
||||
]
|
||||
},
|
||||
"legal_basis": [
|
||||
{"norm": "EU-Maschinenverordnung", "article": "Art. 25 Abs. 4", "title": "Meldepflicht Nichtkonformitaet"}
|
||||
],
|
||||
"sources": [
|
||||
{"type": "article", "ref": "Art. 25 VO (EU) 2023/1230"}
|
||||
],
|
||||
"category": "Meldepflicht",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": {"type": "on_event", "event": "Feststellung der Nichtkonformitaet", "duration": "P0D"},
|
||||
"sanctions": {"max_fine": "Bussgeld nach nationalem Recht, Marktzuruecknahme", "personal_liability": true},
|
||||
"evidence": ["Meldung an Behoerde", "Korrekturmassnahmen-Dokumentation"],
|
||||
"priority": "kritisch",
|
||||
"valid_from": "2027-01-20",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "EUMACH-CTRL-001",
|
||||
"name": "Risikobeurteilung Maschinen",
|
||||
"description": "Systematische Risikobeurteilung aller Maschinen nach EN ISO 12100 mit Dokumentation der Gefahrenanalyse, Risikoeinschaetzung und Risikominderungsmassnahmen.",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "EN ISO 12100 Risikobeurteilung fuer jede Maschine durchfuehren, Ergebnisse dokumentieren und Schutzmassnahmen implementieren.",
|
||||
"iso27001_mapping": [],
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-CTRL-002",
|
||||
"name": "Technische Dokumentation Lifecycle",
|
||||
"description": "Verwaltung der technischen Dokumentation ueber den gesamten Produktlebenszyklus: Erstellung, Aktualisierung, Archivierung (mind. 10 Jahre), Bereitstellung fuer Behoerden.",
|
||||
"category": "Dokumentation",
|
||||
"what_to_do": "Dokumentenmanagementsystem einrichten, Verantwortlichkeiten definieren, Aufbewahrungsfristen ueberwachen.",
|
||||
"iso27001_mapping": ["A.5.37"],
|
||||
"priority": "hoch"
|
||||
},
|
||||
{
|
||||
"id": "EUMACH-CTRL-003",
|
||||
"name": "KI-Sicherheitsvalidierung",
|
||||
"description": "Spezifische Validierung von KI-Komponenten in Maschinen: Funktionale Sicherheit, Robustheit gegen Stoerungen, Nachvollziehbarkeit von KI-Entscheidungen in sicherheitsrelevanten Funktionen.",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "KI-Sicherheitstests definieren und durchfuehren, Human-Oversight fuer sicherheitskritische KI-Funktionen implementieren.",
|
||||
"iso27001_mapping": ["A.8.25", "A.8.29"],
|
||||
"priority": "kritisch"
|
||||
}
|
||||
],
|
||||
"incident_deadlines": [
|
||||
{
|
||||
"phase": "Sofortmeldung",
|
||||
"deadline": "Unverzueglich nach Kenntnis",
|
||||
"content": "Meldung an zustaendige Marktueberwachungsbehoerde bei Kenntnis eines schwerwiegenden Unfalls oder einer Nichtkonformitaet",
|
||||
"recipient": "Marktueberwachungsbehoerde",
|
||||
"legal_basis": [{"norm": "EU-Maschinenverordnung", "article": "Art. 25"}]
|
||||
},
|
||||
{
|
||||
"phase": "Korrekturmassnahmen",
|
||||
"deadline": "Ohne ungebuerliche Verzoegerung",
|
||||
"content": "Ergreifen aller erforderlichen Korrekturmassnahmen zur Herstellung der Konformitaet oder Ruecknahme/Rueckruf",
|
||||
"recipient": "Marktueberwachungsbehoerde + betroffene Wirtschaftsakteure",
|
||||
"legal_basis": [{"norm": "EU-Maschinenverordnung", "article": "Art. 25"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
1425
ai-compliance-sdk/policies/obligations/v2/nis2_v2.json
Normal file
1425
ai-compliance-sdk/policies/obligations/v2/nis2_v2.json
Normal file
File diff suppressed because it is too large
Load Diff
459
ai-compliance-sdk/policies/obligations/v2/ttdsg_v2.json
Normal file
459
ai-compliance-sdk/policies/obligations/v2/ttdsg_v2.json
Normal file
@@ -0,0 +1,459 @@
|
||||
{
|
||||
"regulation": "ttdsg",
|
||||
"regulation_full_name": "Telekommunikation-Telemedien-Datenschutz-Gesetz (TTDSG)",
|
||||
"version": "1.0",
|
||||
"obligations": [
|
||||
{
|
||||
"id": "TTDSG-OBL-001",
|
||||
"title": "Wahrung des Fernmeldegeheimnisses",
|
||||
"description": "Der Inhalt der Telekommunikation und ihre naeheren Umstaende unterliegen dem Fernmeldegeheimnis. Diensteanbieter sind zur Wahrung verpflichtet.",
|
||||
"applies_when": "organization provides telecommunication services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 3", "title": "Vertraulichkeit der Kommunikation" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 3 TTDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR", "criminal_liability": true },
|
||||
"evidence": [{ "name": "Fernmeldegeheimnis-Richtlinie", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.CRY.01", "TOM.AC.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-002",
|
||||
"title": "Technische Schutzmassnahmen Fernmeldegeheimnis",
|
||||
"description": "Diensteanbieter muessen technische Vorkehrungen zum Schutz des Fernmeldegeheimnisses treffen, insbesondere gegen unbefugtes Abhoeren und Mitlesen.",
|
||||
"applies_when": "organization provides telecommunication services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 4", "title": "Durchsetzung des Fernmeldegeheimnisses" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 4 TTDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Sicherheitsbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Verschluesselungskonzept TK", "required": true }, "Penetrationstest-Bericht"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.CRY.01", "TOM.NET.01"],
|
||||
"breakpilot_feature": "/sdk/tom",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-003",
|
||||
"title": "Bestandsdatenauskunft TK-Dienste",
|
||||
"description": "Bestandsdaten der Teilnehmer duerfen nur erhoben und verwendet werden, soweit dies zur Begruendung, Ausgestaltung oder Aenderung eines Vertragsverhaeltnisses erforderlich ist.",
|
||||
"applies_when": "organization provides telecommunication services with subscriber data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 7", "title": "Bestandsdaten TK-Anbieter" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 7 TTDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Bestandsdaten-Verarbeitungskonzept", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.AC.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-004",
|
||||
"title": "Bestandsdatenauskunft an Behoerden",
|
||||
"description": "Die Erteilung von Auskuenften ueber Bestandsdaten an Sicherheitsbehoerden ist nur unter den Voraussetzungen des § 8 TTDSG zulaessig.",
|
||||
"applies_when": "organization provides telecom and receives authority requests",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 8", "title": "Bestandsdatenauskunft Behoerden" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 8 TTDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Bei Behoerdenanfrage" },
|
||||
"sanctions": { "max_fine": "300.000 EUR", "personal_liability": true },
|
||||
"evidence": [{ "name": "Auskunftserteilungs-Protokoll", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.02", "TOM.LOG.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-005",
|
||||
"title": "Verkehrsdaten — Zweckbindung und Loeschung",
|
||||
"description": "Verkehrsdaten duerfen nur fuer Abrechnungszwecke, Stoerungsbeseitigung und Missbrauchsbekaempfung gespeichert werden und sind nach Zweckerfuellung unverzueglich zu loeschen.",
|
||||
"applies_when": "organization collects traffic data from telecom services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }, { "field": "data_protection.collects_traffic_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 9", "title": "Verkehrsdaten" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 9 TTDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leitung",
|
||||
"deadline": { "type": "on_event", "event": "Nach Rechnungsstellung/Zweckerfuellung" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Loeschkonzept Verkehrsdaten", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.DEL.01", "TOM.GOV.01"],
|
||||
"breakpilot_feature": "/sdk/loeschfristen",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-006",
|
||||
"title": "Standortdaten — Einwilligung erforderlich",
|
||||
"description": "Standortdaten duerfen nur mit ausdruecklicher Einwilligung des Nutzers verarbeitet werden. Die Einwilligung muss jederzeit widerrufbar sein.",
|
||||
"applies_when": "organization processes location data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_location_data", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 10", "title": "Standortdaten" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 10 TTDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor Verarbeitung von Standortdaten" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Einwilligungsnachweis Standortdaten", "required": true }, "Widerrufsmechanismus"],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/consent",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-007",
|
||||
"title": "Anonymisierung von Standortdaten",
|
||||
"description": "Wenn Standortdaten fuer Mehrwertdienste verwendet werden, muessen sie anonymisiert oder pseudonymisiert werden, sofern der Zweck dies erlaubt.",
|
||||
"applies_when": "organization uses location data for value-added services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.processes_location_data", "operator": "EQUALS", "value": true }, { "field": "organization.offers_value_added_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 10 Abs. 2", "title": "Standortdaten Mehrwertdienste" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 10 TTDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Sicherheitsbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Anonymisierungskonzept Standortdaten", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.CRY.02"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-008",
|
||||
"title": "Bestandsdaten Telemedien — Erhebung und Verwendung",
|
||||
"description": "Anbieter von Telemedien duerfen Bestandsdaten nur erheben und verwenden, soweit sie fuer die Begruendung, Ausgestaltung oder Aenderung eines Vertragsverhaeltnisses erforderlich sind.",
|
||||
"applies_when": "organization provides telemedia services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telemedia_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 13", "title": "Bestandsdaten Telemedien" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 13 TTDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Datenschutzerklaerung Telemedien", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-009",
|
||||
"title": "Nutzungsdaten Telemedien — Zweckbindung",
|
||||
"description": "Nutzungsdaten duerfen nur erhoben werden, soweit dies zur Ermogeglichung der Inanspruchnahme von Telemedien erforderlich ist. Profilerstellung bedarf der Einwilligung.",
|
||||
"applies_when": "organization collects telemedia usage data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telemedia_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 15", "title": "Nutzungsdaten Telemedien" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 15 TTDSG" }],
|
||||
"category": "Governance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Nutzungsdaten-Konzept", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01", "TOM.DEL.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-010",
|
||||
"title": "Vertraulichkeit Nachrichteninhalte",
|
||||
"description": "Anbieter von interpersonellen TK-Diensten muessen die Vertraulichkeit der uebermittelten Nachrichteninhalte gewaehrleisten (§ 19 TTDSG).",
|
||||
"applies_when": "organization provides messaging or communication services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_messaging_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 19", "title": "Nachrichteninhalte" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 19 TTDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Sicherheitsbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR", "criminal_liability": true },
|
||||
"evidence": [{ "name": "Ende-zu-Ende-Verschluesselungsnachweis", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.CRY.01", "TOM.NET.01"],
|
||||
"breakpilot_feature": "/sdk/tom",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-011",
|
||||
"title": "Schutz vor Spam und unerwuenschten Nachrichten",
|
||||
"description": "Anbieter nummernunabhaengiger interpersoneller TK-Dienste muessen Massnahmen gegen unerwuenschte Nachrichten (Spam) ergreifen.",
|
||||
"applies_when": "organization provides interpersonal communication services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_messaging_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 19 Abs. 2", "title": "Spam-Schutz" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 19 TTDSG" }],
|
||||
"category": "Technisch",
|
||||
"responsible": "IT-Leitung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Anti-Spam-Massnahmen Dokumentation", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.NET.01"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-012",
|
||||
"title": "Einwilligung fuer Cookies und Tracking",
|
||||
"description": "Die Speicherung von Informationen in der Endeinrichtung des Nutzers oder der Zugriff auf dort gespeicherte Informationen ist nur mit Einwilligung des Nutzers zulaessig (§ 25 Abs. 1 TTDSG).",
|
||||
"applies_when": "organization uses cookies or similar tracking technologies",
|
||||
"applies_when_condition": { "any_of": [{ "field": "data_protection.uses_cookies", "operator": "EQUALS", "value": true }, { "field": "data_protection.uses_tracking", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 25 Abs. 1", "title": "Schutz der Privatsphaere bei Endeinrichtungen" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 25 TTDSG" }, { "type": "eu_guidance", "ref": "ePrivacy-Richtlinie Art. 5 Abs. 3" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor Setzen von Cookies/Trackern" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Cookie-Consent-Banner", "required": true }, { "name": "Consent-Management-Platform Nachweis", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.GOV.02", "TOM.WEB.01"],
|
||||
"breakpilot_feature": "/sdk/cookie-banner",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-013",
|
||||
"title": "Ausnahmen von der Cookie-Einwilligung",
|
||||
"description": "Keine Einwilligung ist erforderlich, wenn die Speicherung/der Zugriff technisch erforderlich ist, um den vom Nutzer ausdruecklich gewuenschten Dienst bereitzustellen (§ 25 Abs. 2 TTDSG).",
|
||||
"applies_when": "organization uses technically necessary cookies",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.uses_cookies", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 25 Abs. 2", "title": "Ausnahme technisch notwendige Cookies" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 25 Abs. 2 TTDSG" }, { "type": "dsk_kurzpapier", "ref": "DSK Orientierungshilfe Telemedien 2021" }],
|
||||
"category": "Dokumentation",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "jaehrlich" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Cookie-Klassifizierung (notwendig vs. optional)", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.WEB.01"],
|
||||
"breakpilot_feature": "/sdk/cookie-banner",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-014",
|
||||
"title": "Cookie-Consent Anforderungen — Informiertheit",
|
||||
"description": "Die Einwilligung nach § 25 Abs. 1 TTDSG muss informiert erfolgen. Der Nutzer muss klar und umfassend ueber Zweck, Dauer und Empfaenger informiert werden.",
|
||||
"applies_when": "organization collects cookie consent",
|
||||
"applies_when_condition": { "all_of": [{ "field": "data_protection.uses_cookies", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 25 Abs. 1", "title": "Informierte Einwilligung" }, { "norm": "DSGVO", "article": "Art. 7", "title": "Bedingungen fuer die Einwilligung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 25 TTDSG" }, { "type": "case_law", "ref": "BGH I ZR 7/16 — Planet49" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Cookie-Banner mit vollstaendiger Information", "required": true }, "Dokumentation Consent-Flow"],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.WEB.01", "TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/cookie-banner",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-015",
|
||||
"title": "Anerkannte Dienste zur Einwilligungsverwaltung",
|
||||
"description": "Die Bundesregierung kann durch Rechtsverordnung Anforderungen an anerkannte Dienste zur Einwilligungsverwaltung (PIMS) festlegen (§ 26 TTDSG).",
|
||||
"applies_when": "organization provides or uses a Personal Information Management Service",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.uses_pims", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 26", "title": "Anerkannte Dienste zur Einwilligungsverwaltung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 26 TTDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "recurring", "interval": "jaehrlich" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "PIMS-Zertifizierung/Anerkennung", "required": false }],
|
||||
"priority": "niedrig",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/consent",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-016",
|
||||
"title": "Endnutzerinformation bei Rufnummernanzeige",
|
||||
"description": "Bei der Anzeige von Rufnummern muessen Diensteanbieter den Endnutzer ueber die Moeglichkeit der Unterdrueckung informieren (§ 11 TTDSG).",
|
||||
"applies_when": "organization provides telephony services with caller ID",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 11", "title": "Rufnummernanzeige" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 11 TTDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"deadline": { "type": "on_event", "event": "Bei Vertragsschluss" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Kundeninformation Rufnummernanzeige", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-017",
|
||||
"title": "Automatische Anrufweiterleitung — Einwilligung",
|
||||
"description": "Automatische Anrufweiterleitungen duerfen nur mit Einwilligung des Anschlussinhabers eingerichtet werden (§ 12 TTDSG).",
|
||||
"applies_when": "organization provides call forwarding services",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 12", "title": "Anrufweiterschaltung" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 12 TTDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Produktmanagement",
|
||||
"deadline": { "type": "on_event", "event": "Vor Einrichtung der Weiterleitung" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Einwilligungsnachweis Anrufweiterleitung", "required": true }],
|
||||
"priority": "niedrig",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": null,
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-018",
|
||||
"title": "Bussgeldvorschriften TTDSG",
|
||||
"description": "Verstoesse gegen die Vorschriften des TTDSG koennen als Ordnungswidrigkeiten mit Bussgeldern bis zu 300.000 EUR geahndet werden (§ 28 TTDSG).",
|
||||
"applies_when": "always for organizations under TTDSG scope",
|
||||
"applies_when_condition": { "any_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }, { "field": "organization.provides_telemedia_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 28", "title": "Bussgeldvorschriften" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 28 TTDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "300.000 EUR", "personal_liability": true },
|
||||
"evidence": [{ "name": "TTDSG-Compliance-Pruefbericht", "required": true }],
|
||||
"priority": "hoch",
|
||||
"tom_control_ids": ["TOM.GOV.01"],
|
||||
"breakpilot_feature": "/sdk/risk-assessment",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-019",
|
||||
"title": "Strafvorschriften — Verstoesse Fernmeldegeheimnis",
|
||||
"description": "Wer unbefugt einer anderen Person Kenntnis vom Inhalt oder den naeheren Umstaenden der Telekommunikation verschafft, wird strafrechtlich verfolgt (§ 27 TTDSG).",
|
||||
"applies_when": "organization handles telecommunication data",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 27", "title": "Strafvorschriften" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 27 TTDSG" }],
|
||||
"category": "Compliance",
|
||||
"responsible": "Geschaeftsfuehrung",
|
||||
"deadline": { "type": "recurring", "interval": "laufend" },
|
||||
"sanctions": { "max_fine": "Freiheitsstrafe bis 2 Jahre oder Geldstrafe", "personal_liability": true, "criminal_liability": true },
|
||||
"evidence": [{ "name": "Schulungsnachweis Fernmeldegeheimnis", "required": true }],
|
||||
"priority": "kritisch",
|
||||
"tom_control_ids": ["TOM.HR.02", "TOM.AC.01"],
|
||||
"breakpilot_feature": "/sdk/training",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-OBL-020",
|
||||
"title": "Teilnehmerverzeichnisse — Einwilligung",
|
||||
"description": "Die Aufnahme in oeffentliche Teilnehmerverzeichnisse und die Bereitstellung von Auskunftsdiensten bedarf der vorherigen Einwilligung des Teilnehmers (§ 17 TTDSG).",
|
||||
"applies_when": "organization maintains subscriber directories",
|
||||
"applies_when_condition": { "all_of": [{ "field": "organization.provides_telecom_services", "operator": "EQUALS", "value": true }, { "field": "organization.maintains_directories", "operator": "EQUALS", "value": true }] },
|
||||
"legal_basis": [{ "norm": "TTDSG", "article": "§ 17", "title": "Teilnehmerverzeichnisse" }],
|
||||
"sources": [{ "type": "national_law", "ref": "§ 17 TTDSG" }],
|
||||
"category": "Organisatorisch",
|
||||
"responsible": "Datenschutzbeauftragter",
|
||||
"deadline": { "type": "on_event", "event": "Vor Aufnahme in Verzeichnis" },
|
||||
"sanctions": { "max_fine": "300.000 EUR" },
|
||||
"evidence": [{ "name": "Einwilligungsnachweis Verzeichniseintrag", "required": true }],
|
||||
"priority": "mittel",
|
||||
"tom_control_ids": ["TOM.GOV.02"],
|
||||
"breakpilot_feature": "/sdk/consent",
|
||||
"valid_from": "2021-12-01",
|
||||
"valid_until": null,
|
||||
"version": "1.0"
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "TTDSG-CTRL-001",
|
||||
"name": "Cookie-Consent-Management",
|
||||
"description": "Kontrolle zur Sicherstellung der gesetzeskonformen Einholung und Verwaltung von Cookie-Einwilligungen nach § 25 TTDSG.",
|
||||
"category": "Organisatorisch",
|
||||
"what_to_do": "Cookie-Banner implementieren, Cookie-Klassifizierung durchfuehren, Consent-Log fuehren, regelmaessige Audits der Cookie-Nutzung.",
|
||||
"iso27001_mapping": ["A.5.34"],
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-CTRL-002",
|
||||
"name": "Fernmeldegeheimnis-Schutz",
|
||||
"description": "Kontrolle zur Gewaehrleistung des Fernmeldegeheimnisses durch technische und organisatorische Massnahmen.",
|
||||
"category": "Technisch",
|
||||
"what_to_do": "Verschluesselung implementieren, Zugriffskontrolle auf TK-Daten, Mitarbeiterschulung zum Fernmeldegeheimnis, Protokollierung.",
|
||||
"iso27001_mapping": ["A.8.24", "A.5.14"],
|
||||
"priority": "kritisch"
|
||||
},
|
||||
{
|
||||
"id": "TTDSG-CTRL-003",
|
||||
"name": "Verkehrs- und Standortdaten-Governance",
|
||||
"description": "Kontrolle zur Einhaltung der Zweckbindung und Loeschpflichten fuer Verkehrs- und Standortdaten.",
|
||||
"category": "Governance",
|
||||
"what_to_do": "Datenklassifizierung erstellen, automatische Loeschmechanismen implementieren, Einwilligungsprozesse fuer Standortdaten pruefen.",
|
||||
"iso27001_mapping": ["A.5.33", "A.8.10"],
|
||||
"priority": "hoch"
|
||||
}
|
||||
],
|
||||
"incident_deadlines": [
|
||||
{
|
||||
"phase": "Meldung TK-Sicherheitsvorfall an BNetzA",
|
||||
"deadline": "Unverzueglich (i.d.R. 24 Stunden)",
|
||||
"content": "Art und Umfang des Vorfalls, betroffene Dienste, ergriffene Massnahmen",
|
||||
"recipient": "Bundesnetzagentur (BNetzA)",
|
||||
"legal_basis": [{ "norm": "TKG", "article": "§ 168" }]
|
||||
},
|
||||
{
|
||||
"phase": "Benachrichtigung betroffener Teilnehmer",
|
||||
"deadline": "Unverzueglich bei Risiko fuer persoenliche Daten",
|
||||
"content": "Art des Vorfalls, Kontaktdaten, empfohlene Schutzmassnahmen",
|
||||
"recipient": "Betroffene Teilnehmer",
|
||||
"legal_basis": [{ "norm": "DSGVO", "article": "Art. 34" }]
|
||||
},
|
||||
{
|
||||
"phase": "Meldung an BSI bei erheblichen Stoerungen",
|
||||
"deadline": "Unverzueglich",
|
||||
"content": "Technische Rahmenbedingungen, vermutete Ursache, Auswirkungen",
|
||||
"recipient": "Bundesamt fuer Sicherheit in der Informationstechnik (BSI)",
|
||||
"legal_basis": [{ "norm": "TKG", "article": "§ 169" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
6523
ai-compliance-sdk/policies/tom_controls_v1.json
Normal file
6523
ai-compliance-sdk/policies/tom_controls_v1.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user