Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
574 lines
19 KiB
TypeScript
574 lines
19 KiB
TypeScript
/**
|
|
* Finding Types and Templates
|
|
*
|
|
* Pre-defined finding templates for contract reviews
|
|
*/
|
|
|
|
import {
|
|
FindingType,
|
|
FindingCategory,
|
|
FindingSeverity,
|
|
LocalizedText,
|
|
} from '../types'
|
|
|
|
export interface FindingTemplate {
|
|
id: string
|
|
type: FindingType
|
|
category: FindingCategory
|
|
severity: FindingSeverity
|
|
title: LocalizedText
|
|
description: LocalizedText
|
|
recommendation: LocalizedText
|
|
affectedRequirement: string
|
|
triggerControls: string[]
|
|
}
|
|
|
|
// ==========================================
|
|
// FINDING SEVERITY DEFINITIONS
|
|
// ==========================================
|
|
|
|
export const SEVERITY_DEFINITIONS: Record<FindingSeverity, {
|
|
label: LocalizedText
|
|
description: LocalizedText
|
|
responseTime: LocalizedText
|
|
color: string
|
|
}> = {
|
|
LOW: {
|
|
label: { de: 'Niedrig', en: 'Low' },
|
|
description: {
|
|
de: 'Geringfügige Abweichung ohne wesentliche Auswirkungen',
|
|
en: 'Minor deviation without significant impact',
|
|
},
|
|
responseTime: {
|
|
de: 'Bei nächster Vertragserneuerung',
|
|
en: 'At next contract renewal',
|
|
},
|
|
color: 'blue',
|
|
},
|
|
MEDIUM: {
|
|
label: { de: 'Mittel', en: 'Medium' },
|
|
description: {
|
|
de: 'Abweichung mit potenziellen Auswirkungen auf Compliance',
|
|
en: 'Deviation with potential impact on compliance',
|
|
},
|
|
responseTime: {
|
|
de: 'Innerhalb von 90 Tagen',
|
|
en: 'Within 90 days',
|
|
},
|
|
color: 'yellow',
|
|
},
|
|
HIGH: {
|
|
label: { de: 'Hoch', en: 'High' },
|
|
description: {
|
|
de: 'Erhebliche Abweichung mit Auswirkungen auf Datenschutz-Compliance',
|
|
en: 'Significant deviation with impact on data protection compliance',
|
|
},
|
|
responseTime: {
|
|
de: 'Innerhalb von 30 Tagen',
|
|
en: 'Within 30 days',
|
|
},
|
|
color: 'orange',
|
|
},
|
|
CRITICAL: {
|
|
label: { de: 'Kritisch', en: 'Critical' },
|
|
description: {
|
|
de: 'Schwerwiegende Abweichung - unmittelbarer Handlungsbedarf',
|
|
en: 'Serious deviation - immediate action required',
|
|
},
|
|
responseTime: {
|
|
de: 'Sofort / vor Vertragsabschluss',
|
|
en: 'Immediately / before contract signing',
|
|
},
|
|
color: 'red',
|
|
},
|
|
}
|
|
|
|
// ==========================================
|
|
// FINDING TYPE DEFINITIONS
|
|
// ==========================================
|
|
|
|
export const FINDING_TYPE_DEFINITIONS: Record<FindingType, {
|
|
label: LocalizedText
|
|
description: LocalizedText
|
|
icon: string
|
|
}> = {
|
|
OK: {
|
|
label: { de: 'Erfüllt', en: 'Fulfilled' },
|
|
description: {
|
|
de: 'Anforderung ist vollständig erfüllt',
|
|
en: 'Requirement is fully met',
|
|
},
|
|
icon: 'check-circle',
|
|
},
|
|
GAP: {
|
|
label: { de: 'Lücke', en: 'Gap' },
|
|
description: {
|
|
de: 'Anforderung fehlt oder ist unvollständig',
|
|
en: 'Requirement is missing or incomplete',
|
|
},
|
|
icon: 'alert-circle',
|
|
},
|
|
RISK: {
|
|
label: { de: 'Risiko', en: 'Risk' },
|
|
description: {
|
|
de: 'Potenzielles Risiko identifiziert',
|
|
en: 'Potential risk identified',
|
|
},
|
|
icon: 'alert-triangle',
|
|
},
|
|
UNKNOWN: {
|
|
label: { de: 'Unklar', en: 'Unknown' },
|
|
description: {
|
|
de: 'Nicht eindeutig bestimmbar',
|
|
en: 'Cannot be clearly determined',
|
|
},
|
|
icon: 'help-circle',
|
|
},
|
|
}
|
|
|
|
// ==========================================
|
|
// FINDING TEMPLATES
|
|
// ==========================================
|
|
|
|
export const FINDING_TEMPLATES: FindingTemplate[] = [
|
|
// AVV_CONTENT - Weisungsgebundenheit
|
|
{
|
|
id: 'tpl-avv-instruction-missing',
|
|
type: 'GAP',
|
|
category: 'AVV_CONTENT',
|
|
severity: 'CRITICAL',
|
|
title: {
|
|
de: 'Weisungsgebundenheit fehlt',
|
|
en: 'Instruction binding missing',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag enthält keine Regelung zur Weisungsgebundenheit des Auftragsverarbeiters.',
|
|
en: 'The contract does not contain a provision on the processor\'s instruction binding.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Klausel, die den Auftragsverarbeiter verpflichtet, personenbezogene Daten nur auf dokumentierte Weisung des Verantwortlichen zu verarbeiten.',
|
|
en: 'Add a clause obligating the processor to process personal data only on documented instructions from the controller.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. a DSGVO',
|
|
triggerControls: ['VND-CON-01'],
|
|
},
|
|
{
|
|
id: 'tpl-avv-instruction-weak',
|
|
type: 'RISK',
|
|
category: 'AVV_CONTENT',
|
|
severity: 'MEDIUM',
|
|
title: {
|
|
de: 'Weisungsgebundenheit unvollständig',
|
|
en: 'Instruction binding incomplete',
|
|
},
|
|
description: {
|
|
de: 'Die Regelung zur Weisungsgebundenheit ist vorhanden, aber es fehlt die Hinweispflicht bei rechtswidrigen Weisungen.',
|
|
en: 'The instruction binding provision exists, but the obligation to notify of unlawful instructions is missing.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Pflicht des Auftragsverarbeiters, den Verantwortlichen unverzüglich zu informieren, wenn eine Weisung nach seiner Auffassung gegen Datenschutzrecht verstößt.',
|
|
en: 'Add an obligation for the processor to immediately inform the controller if an instruction, in their opinion, violates data protection law.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. a DSGVO',
|
|
triggerControls: ['VND-CON-01'],
|
|
},
|
|
|
|
// AVV_CONTENT - TOM
|
|
{
|
|
id: 'tpl-avv-tom-missing',
|
|
type: 'GAP',
|
|
category: 'TOM',
|
|
severity: 'CRITICAL',
|
|
title: {
|
|
de: 'TOM-Anlage fehlt',
|
|
en: 'TOM annex missing',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag enthält keine technischen und organisatorischen Maßnahmen (TOM) als Anlage.',
|
|
en: 'The contract does not contain technical and organizational measures (TOM) as an annex.',
|
|
},
|
|
recommendation: {
|
|
de: 'Fordern Sie eine detaillierte TOM-Anlage an, die die Maßnahmen gemäß Art. 32 DSGVO beschreibt.',
|
|
en: 'Request a detailed TOM annex describing the measures according to Art. 32 GDPR.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. c DSGVO',
|
|
triggerControls: ['VND-TOM-01'],
|
|
},
|
|
{
|
|
id: 'tpl-avv-tom-generic',
|
|
type: 'RISK',
|
|
category: 'TOM',
|
|
severity: 'MEDIUM',
|
|
title: {
|
|
de: 'TOM zu unspezifisch',
|
|
en: 'TOM too generic',
|
|
},
|
|
description: {
|
|
de: 'Die TOM-Anlage enthält nur allgemeine Aussagen ohne konkrete Maßnahmen.',
|
|
en: 'The TOM annex contains only general statements without specific measures.',
|
|
},
|
|
recommendation: {
|
|
de: 'Fordern Sie eine konkretere Beschreibung der Maßnahmen mit Bezug zum spezifischen Verarbeitungskontext an.',
|
|
en: 'Request a more specific description of measures with reference to the specific processing context.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. c DSGVO',
|
|
triggerControls: ['VND-TOM-01'],
|
|
},
|
|
|
|
// SUBPROCESSOR
|
|
{
|
|
id: 'tpl-subprocessor-no-approval',
|
|
type: 'GAP',
|
|
category: 'SUBPROCESSOR',
|
|
severity: 'CRITICAL',
|
|
title: {
|
|
de: 'Keine Genehmigungspflicht für Unterauftragnehmer',
|
|
en: 'No approval requirement for sub-processors',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag regelt nicht, ob und wie der Einsatz von Unterauftragnehmern zu genehmigen ist.',
|
|
en: 'The contract does not regulate whether and how the use of sub-processors must be approved.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Klausel, die entweder eine spezifische oder allgemeine Genehmigung für Unterauftragnehmer vorsieht, einschließlich Informations- und Einspruchsrechten.',
|
|
en: 'Add a clause providing either specific or general authorization for sub-processors, including information and objection rights.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. d DSGVO',
|
|
triggerControls: ['VND-SUB-01'],
|
|
},
|
|
{
|
|
id: 'tpl-subprocessor-no-list',
|
|
type: 'RISK',
|
|
category: 'SUBPROCESSOR',
|
|
severity: 'HIGH',
|
|
title: {
|
|
de: 'Keine Liste der Unterauftragnehmer',
|
|
en: 'No list of sub-processors',
|
|
},
|
|
description: {
|
|
de: 'Es liegt keine aktuelle Liste der eingesetzten Unterauftragnehmer vor.',
|
|
en: 'There is no current list of sub-processors used.',
|
|
},
|
|
recommendation: {
|
|
de: 'Fordern Sie eine vollständige Liste aller Unterauftragnehmer mit Name, Sitz und Verarbeitungszweck an.',
|
|
en: 'Request a complete list of all sub-processors with name, location, and processing purpose.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. d DSGVO',
|
|
triggerControls: ['VND-SUB-02'],
|
|
},
|
|
|
|
// INCIDENT
|
|
{
|
|
id: 'tpl-incident-no-notification',
|
|
type: 'GAP',
|
|
category: 'INCIDENT',
|
|
severity: 'CRITICAL',
|
|
title: {
|
|
de: 'Keine Meldepflicht bei Datenpannen',
|
|
en: 'No notification obligation for data breaches',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag enthält keine Regelung zur Meldung von Datenschutzverletzungen.',
|
|
en: 'The contract does not contain a provision for reporting data breaches.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Klausel, die den Auftragsverarbeiter verpflichtet, Datenschutzverletzungen unverzüglich (innerhalb von 24-48h) zu melden.',
|
|
en: 'Add a clause obligating the processor to report data breaches without undue delay (within 24-48h).',
|
|
},
|
|
affectedRequirement: 'Art. 33 Abs. 2 DSGVO',
|
|
triggerControls: ['VND-INC-01'],
|
|
},
|
|
{
|
|
id: 'tpl-incident-long-deadline',
|
|
type: 'RISK',
|
|
category: 'INCIDENT',
|
|
severity: 'HIGH',
|
|
title: {
|
|
de: 'Zu lange Meldefrist',
|
|
en: 'Notification deadline too long',
|
|
},
|
|
description: {
|
|
de: 'Die vereinbarte Meldefrist für Datenschutzverletzungen ist zu lang (>72h), um die eigene Meldepflicht einhalten zu können.',
|
|
en: 'The agreed notification deadline for data breaches is too long (>72h) to meet own notification obligations.',
|
|
},
|
|
recommendation: {
|
|
de: 'Verkürzen Sie die Meldefrist auf maximal 24-48 Stunden, um ausreichend Zeit für die eigene Meldung an die Aufsichtsbehörde zu haben.',
|
|
en: 'Reduce the notification deadline to a maximum of 24-48 hours to have sufficient time for own notification to the supervisory authority.',
|
|
},
|
|
affectedRequirement: 'Art. 33 DSGVO',
|
|
triggerControls: ['VND-INC-01'],
|
|
},
|
|
|
|
// AUDIT_RIGHTS
|
|
{
|
|
id: 'tpl-audit-no-right',
|
|
type: 'GAP',
|
|
category: 'AUDIT_RIGHTS',
|
|
severity: 'HIGH',
|
|
title: {
|
|
de: 'Kein Auditrecht vereinbart',
|
|
en: 'No audit right agreed',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag enthält kein Recht des Verantwortlichen auf Prüfungen und Inspektionen.',
|
|
en: 'The contract does not contain a right of the controller to audits and inspections.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie ein ausdrückliches Recht auf Vor-Ort-Inspektionen und die Einsicht in relevante Unterlagen.',
|
|
en: 'Add an explicit right to on-site inspections and access to relevant documents.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. h DSGVO',
|
|
triggerControls: ['VND-AUD-01'],
|
|
},
|
|
{
|
|
id: 'tpl-audit-restricted',
|
|
type: 'RISK',
|
|
category: 'AUDIT_RIGHTS',
|
|
severity: 'MEDIUM',
|
|
title: {
|
|
de: 'Auditrecht eingeschränkt',
|
|
en: 'Audit right restricted',
|
|
},
|
|
description: {
|
|
de: 'Das Auditrecht ist durch unangemessene Einschränkungen (z.B. sehr lange Vorlaufzeit, Ausschluss von Vor-Ort-Inspektionen) begrenzt.',
|
|
en: 'The audit right is limited by unreasonable restrictions (e.g., very long notice period, exclusion of on-site inspections).',
|
|
},
|
|
recommendation: {
|
|
de: 'Verhandeln Sie angemessene Bedingungen für Audits (max. 30 Tage Vorlaufzeit, Möglichkeit zur Vor-Ort-Inspektion).',
|
|
en: 'Negotiate reasonable audit conditions (max. 30 days notice, possibility for on-site inspection).',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. h DSGVO',
|
|
triggerControls: ['VND-AUD-01'],
|
|
},
|
|
|
|
// DELETION
|
|
{
|
|
id: 'tpl-deletion-no-clause',
|
|
type: 'GAP',
|
|
category: 'DELETION',
|
|
severity: 'CRITICAL',
|
|
title: {
|
|
de: 'Keine Lösch-/Rückgaberegelung',
|
|
en: 'No deletion/return clause',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag regelt nicht, was mit den Daten nach Vertragsende geschieht.',
|
|
en: 'The contract does not regulate what happens to the data after contract termination.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Klausel zur Löschung oder Rückgabe aller personenbezogenen Daten nach Vertragsende (max. 30 Tage).',
|
|
en: 'Add a clause for deletion or return of all personal data after contract end (max. 30 days).',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. g DSGVO',
|
|
triggerControls: ['VND-DEL-01'],
|
|
},
|
|
{
|
|
id: 'tpl-deletion-no-confirmation',
|
|
type: 'RISK',
|
|
category: 'DELETION',
|
|
severity: 'MEDIUM',
|
|
title: {
|
|
de: 'Keine Löschbestätigung vorgesehen',
|
|
en: 'No deletion confirmation provided',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag sieht keine Bestätigung der Löschung durch den Auftragsverarbeiter vor.',
|
|
en: 'The contract does not provide for confirmation of deletion by the processor.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Pflicht zur schriftlichen Bestätigung der vollständigen Löschung.',
|
|
en: 'Add an obligation for written confirmation of complete deletion.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. g DSGVO',
|
|
triggerControls: ['VND-DEL-01'],
|
|
},
|
|
|
|
// TRANSFER
|
|
{
|
|
id: 'tpl-transfer-no-basis',
|
|
type: 'GAP',
|
|
category: 'TRANSFER',
|
|
severity: 'CRITICAL',
|
|
title: {
|
|
de: 'Drittlandtransfer ohne Rechtsgrundlage',
|
|
en: 'Third country transfer without legal basis',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag erlaubt oder impliziert Transfers in Drittländer ohne geeignete Garantien.',
|
|
en: 'The contract allows or implies transfers to third countries without appropriate safeguards.',
|
|
},
|
|
recommendation: {
|
|
de: 'Vereinbaren Sie geeignete Garantien (SCC, BCR) oder beschränken Sie die Verarbeitung auf EU/EWR.',
|
|
en: 'Agree on appropriate safeguards (SCC, BCR) or restrict processing to EU/EEA.',
|
|
},
|
|
affectedRequirement: 'Art. 44-49 DSGVO',
|
|
triggerControls: ['VND-TRF-01'],
|
|
},
|
|
{
|
|
id: 'tpl-transfer-old-scc',
|
|
type: 'RISK',
|
|
category: 'TRANSFER',
|
|
severity: 'HIGH',
|
|
title: {
|
|
de: 'Veraltete Standardvertragsklauseln',
|
|
en: 'Outdated Standard Contractual Clauses',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag verwendet die alten SCC (vor 2021), die nicht mehr gültig sind.',
|
|
en: 'The contract uses old SCC (pre-2021) that are no longer valid.',
|
|
},
|
|
recommendation: {
|
|
de: 'Aktualisieren Sie auf die SCC 2021 (Durchführungsbeschluss (EU) 2021/914).',
|
|
en: 'Update to SCC 2021 (Implementing Decision (EU) 2021/914).',
|
|
},
|
|
affectedRequirement: 'Art. 46 Abs. 2 lit. c DSGVO',
|
|
triggerControls: ['VND-TRF-02'],
|
|
},
|
|
|
|
// LIABILITY
|
|
{
|
|
id: 'tpl-liability-excessive-cap',
|
|
type: 'RISK',
|
|
category: 'LIABILITY',
|
|
severity: 'MEDIUM',
|
|
title: {
|
|
de: 'Unangemessene Haftungsbegrenzung',
|
|
en: 'Inappropriate liability cap',
|
|
},
|
|
description: {
|
|
de: 'Die Haftungsbegrenzung ist sehr niedrig und könnte bei Datenschutzverletzungen problematisch sein.',
|
|
en: 'The liability cap is very low and could be problematic in case of data protection violations.',
|
|
},
|
|
recommendation: {
|
|
de: 'Prüfen Sie, ob die Haftungsbegrenzung angemessen ist. Erwägen Sie eine Ausnahme für Datenschutzverletzungen oder eine höhere Obergrenze.',
|
|
en: 'Check if the liability cap is appropriate. Consider an exception for data protection violations or a higher limit.',
|
|
},
|
|
affectedRequirement: 'Vertragliche Vereinbarung',
|
|
triggerControls: [],
|
|
},
|
|
|
|
// DATA_SUBJECT_RIGHTS
|
|
{
|
|
id: 'tpl-dsr-no-support',
|
|
type: 'GAP',
|
|
category: 'DATA_SUBJECT_RIGHTS',
|
|
severity: 'HIGH',
|
|
title: {
|
|
de: 'Keine Unterstützung bei Betroffenenrechten',
|
|
en: 'No support for data subject rights',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag enthält keine Regelung zur Unterstützung bei der Erfüllung von Betroffenenrechten.',
|
|
en: 'The contract does not contain a provision for support in fulfilling data subject rights.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Klausel zur Unterstützung bei Auskunft, Berichtigung, Löschung und anderen Betroffenenrechten.',
|
|
en: 'Add a clause for support with access, rectification, deletion, and other data subject rights.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. e DSGVO',
|
|
triggerControls: ['VND-DSR-01'],
|
|
},
|
|
|
|
// CONFIDENTIALITY
|
|
{
|
|
id: 'tpl-confidentiality-missing',
|
|
type: 'GAP',
|
|
category: 'CONFIDENTIALITY',
|
|
severity: 'HIGH',
|
|
title: {
|
|
de: 'Keine Vertraulichkeitsverpflichtung',
|
|
en: 'No confidentiality obligation',
|
|
},
|
|
description: {
|
|
de: 'Der Vertrag enthält keine Verpflichtung zur Vertraulichkeit der Mitarbeiter.',
|
|
en: 'The contract does not contain an obligation for employee confidentiality.',
|
|
},
|
|
recommendation: {
|
|
de: 'Ergänzen Sie eine Klausel, die die Verpflichtung der Mitarbeiter zur Vertraulichkeit sicherstellt.',
|
|
en: 'Add a clause ensuring the obligation of employees to confidentiality.',
|
|
},
|
|
affectedRequirement: 'Art. 28 Abs. 3 lit. b DSGVO',
|
|
triggerControls: ['VND-CON-02'],
|
|
},
|
|
]
|
|
|
|
// ==========================================
|
|
// HELPER FUNCTIONS
|
|
// ==========================================
|
|
|
|
/**
|
|
* Get finding template by ID
|
|
*/
|
|
export function getFindingTemplateById(id: string): FindingTemplate | undefined {
|
|
return FINDING_TEMPLATES.find((t) => t.id === id)
|
|
}
|
|
|
|
/**
|
|
* Get finding templates by category
|
|
*/
|
|
export function getFindingTemplatesByCategory(category: FindingCategory): FindingTemplate[] {
|
|
return FINDING_TEMPLATES.filter((t) => t.category === category)
|
|
}
|
|
|
|
/**
|
|
* Get finding templates by type
|
|
*/
|
|
export function getFindingTemplatesByType(type: FindingType): FindingTemplate[] {
|
|
return FINDING_TEMPLATES.filter((t) => t.type === type)
|
|
}
|
|
|
|
/**
|
|
* Get finding templates by severity
|
|
*/
|
|
export function getFindingTemplatesBySeverity(severity: FindingSeverity): FindingTemplate[] {
|
|
return FINDING_TEMPLATES.filter((t) => t.severity === severity)
|
|
}
|
|
|
|
/**
|
|
* Get severity color class
|
|
*/
|
|
export function getSeverityColorClass(severity: FindingSeverity): string {
|
|
return SEVERITY_DEFINITIONS[severity].color
|
|
}
|
|
|
|
/**
|
|
* Sort findings by severity (critical first)
|
|
*/
|
|
export function sortFindingsBySeverity<T extends { severity: FindingSeverity }>(
|
|
findings: T[]
|
|
): T[] {
|
|
const order: Record<FindingSeverity, number> = {
|
|
CRITICAL: 0,
|
|
HIGH: 1,
|
|
MEDIUM: 2,
|
|
LOW: 3,
|
|
}
|
|
|
|
return [...findings].sort((a, b) => order[a.severity] - order[b.severity])
|
|
}
|
|
|
|
/**
|
|
* Count findings by severity
|
|
*/
|
|
export function countFindingsBySeverity<T extends { severity: FindingSeverity }>(
|
|
findings: T[]
|
|
): Record<FindingSeverity, number> {
|
|
return findings.reduce(
|
|
(acc, f) => {
|
|
acc[f.severity] = (acc[f.severity] || 0) + 1
|
|
return acc
|
|
},
|
|
{ LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0 } as Record<FindingSeverity, number>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Get overall severity from list of findings
|
|
*/
|
|
export function getOverallSeverity(findings: { severity: FindingSeverity }[]): FindingSeverity {
|
|
if (findings.some((f) => f.severity === 'CRITICAL')) return 'CRITICAL'
|
|
if (findings.some((f) => f.severity === 'HIGH')) return 'HIGH'
|
|
if (findings.some((f) => f.severity === 'MEDIUM')) return 'MEDIUM'
|
|
return 'LOW'
|
|
}
|