Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Vue 3 Composables for BreakPilot Compliance SDK
|
||||
*/
|
||||
|
||||
export { useCompliance, type UseComplianceReturn } from './useCompliance'
|
||||
export { useDSGVO, type UseDSGVOReturn } from './useDSGVO'
|
||||
export { useRAG, type UseRAGReturn } from './useRAG'
|
||||
export { useControls, type UseControlsReturn } from './useControls'
|
||||
export { useSecurity, type UseSecurityReturn, type ScanOptions } from './useSecurity'
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Main compliance composable
|
||||
*/
|
||||
|
||||
import { computed, type ComputedRef } from 'vue'
|
||||
import { useComplianceStore, type ComplianceStore } from '../plugin'
|
||||
import type { SDKState, SDKAction, SDKStep } from '@breakpilot/compliance-sdk-types'
|
||||
import { SDK_STEPS } from '@breakpilot/compliance-sdk-types'
|
||||
|
||||
export interface UseComplianceReturn {
|
||||
// Store
|
||||
state: SDKState
|
||||
dispatch: (action: SDKAction) => void
|
||||
store: ComplianceStore
|
||||
|
||||
// Status
|
||||
isReady: ComputedRef<boolean>
|
||||
error: ComputedRef<Error | null>
|
||||
|
||||
// Progress
|
||||
completionPercentage: ComputedRef<number>
|
||||
phase1Completion: ComputedRef<number>
|
||||
phase2Completion: ComputedRef<number>
|
||||
completedSteps: ComputedRef<string[]>
|
||||
|
||||
// Navigation
|
||||
currentStep: ComputedRef<SDKStep | undefined>
|
||||
nextStep: ComputedRef<SDKStep | undefined>
|
||||
previousStep: ComputedRef<SDKStep | undefined>
|
||||
canGoNext: ComputedRef<boolean>
|
||||
canGoPrevious: ComputedRef<boolean>
|
||||
goToStep: (stepId: string) => void
|
||||
goNext: () => void
|
||||
goPrevious: () => void
|
||||
|
||||
// Actions
|
||||
completeStep: (stepId: string) => void
|
||||
resetProgress: () => void
|
||||
saveState: () => Promise<void>
|
||||
}
|
||||
|
||||
export function useCompliance(): UseComplianceReturn {
|
||||
const store = useComplianceStore()
|
||||
const { state, dispatch, client } = store
|
||||
|
||||
// Status
|
||||
const isReady = computed(() => store.isReady)
|
||||
const error = computed(() => store.error)
|
||||
|
||||
// Progress calculations
|
||||
const completedSteps = computed(() => state.completedSteps)
|
||||
|
||||
const completionPercentage = computed(() => {
|
||||
return Math.round((state.completedSteps.length / SDK_STEPS.length) * 100)
|
||||
})
|
||||
|
||||
const phase1Completion = computed(() => {
|
||||
const phase1Steps = SDK_STEPS.filter(s => s.phase === 1)
|
||||
const completed = phase1Steps.filter(s => state.completedSteps.includes(s.id))
|
||||
return Math.round((completed.length / phase1Steps.length) * 100)
|
||||
})
|
||||
|
||||
const phase2Completion = computed(() => {
|
||||
const phase2Steps = SDK_STEPS.filter(s => s.phase === 2)
|
||||
const completed = phase2Steps.filter(s => state.completedSteps.includes(s.id))
|
||||
return Math.round((completed.length / phase2Steps.length) * 100)
|
||||
})
|
||||
|
||||
// Navigation
|
||||
const currentStep = computed(() => SDK_STEPS.find(s => s.id === state.currentStep))
|
||||
|
||||
const currentIndex = computed(() => SDK_STEPS.findIndex(s => s.id === state.currentStep))
|
||||
|
||||
const nextStep = computed(() => {
|
||||
const idx = currentIndex.value
|
||||
return idx < SDK_STEPS.length - 1 ? SDK_STEPS[idx + 1] : undefined
|
||||
})
|
||||
|
||||
const previousStep = computed(() => {
|
||||
const idx = currentIndex.value
|
||||
return idx > 0 ? SDK_STEPS[idx - 1] : undefined
|
||||
})
|
||||
|
||||
const canGoNext = computed(() => currentIndex.value < SDK_STEPS.length - 1)
|
||||
const canGoPrevious = computed(() => currentIndex.value > 0)
|
||||
|
||||
const goToStep = (stepId: string): void => {
|
||||
dispatch({ type: 'SET_CURRENT_STEP', payload: stepId })
|
||||
}
|
||||
|
||||
const goNext = (): void => {
|
||||
if (nextStep.value) {
|
||||
goToStep(nextStep.value.id)
|
||||
}
|
||||
}
|
||||
|
||||
const goPrevious = (): void => {
|
||||
if (previousStep.value) {
|
||||
goToStep(previousStep.value.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
const completeStep = (stepId: string): void => {
|
||||
if (!state.completedSteps.includes(stepId)) {
|
||||
dispatch({ type: 'COMPLETE_STEP', payload: stepId })
|
||||
}
|
||||
}
|
||||
|
||||
const resetProgress = (): void => {
|
||||
dispatch({ type: 'RESET_PROGRESS' })
|
||||
}
|
||||
|
||||
const saveState = async (): Promise<void> => {
|
||||
await client.saveState(state)
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
dispatch,
|
||||
store,
|
||||
isReady,
|
||||
error,
|
||||
completionPercentage,
|
||||
phase1Completion,
|
||||
phase2Completion,
|
||||
completedSteps,
|
||||
currentStep,
|
||||
nextStep,
|
||||
previousStep,
|
||||
canGoNext,
|
||||
canGoPrevious,
|
||||
goToStep,
|
||||
goNext,
|
||||
goPrevious,
|
||||
completeStep,
|
||||
resetProgress,
|
||||
saveState,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* Controls composable for compliance controls management
|
||||
*/
|
||||
|
||||
import { computed, type ComputedRef, type Ref, ref } from 'vue'
|
||||
import { useComplianceStore } from '../plugin'
|
||||
import type {
|
||||
Control,
|
||||
Evidence,
|
||||
Risk,
|
||||
ControlDomain,
|
||||
ImplementationStatus,
|
||||
EvidenceType,
|
||||
RiskLikelihood,
|
||||
RiskImpact,
|
||||
} from '@breakpilot/compliance-sdk-types'
|
||||
|
||||
export interface UseControlsReturn {
|
||||
// Controls
|
||||
controls: ComputedRef<Control[]>
|
||||
controlsByDomain: ComputedRef<Record<ControlDomain, Control[]>>
|
||||
implementedControls: ComputedRef<Control[]>
|
||||
pendingControls: ComputedRef<Control[]>
|
||||
getControl: (id: string) => Control | undefined
|
||||
addControl: (control: Omit<Control, 'id' | 'createdAt' | 'updatedAt'>) => void
|
||||
updateControl: (id: string, updates: Partial<Control>) => void
|
||||
deleteControl: (id: string) => void
|
||||
setControlStatus: (id: string, status: ImplementationStatus) => void
|
||||
|
||||
// Evidence
|
||||
evidence: ComputedRef<Evidence[]>
|
||||
validEvidence: ComputedRef<Evidence[]>
|
||||
expiredEvidence: ComputedRef<Evidence[]>
|
||||
getEvidenceForControl: (controlId: string) => Evidence[]
|
||||
addEvidence: (evidence: Omit<Evidence, 'id' | 'uploadedAt'>) => void
|
||||
updateEvidence: (id: string, updates: Partial<Evidence>) => void
|
||||
deleteEvidence: (id: string) => void
|
||||
|
||||
// Risks
|
||||
risks: ComputedRef<Risk[]>
|
||||
criticalRisks: ComputedRef<Risk[]>
|
||||
unmitigatedRisks: ComputedRef<Risk[]>
|
||||
getRisksForControl: (controlId: string) => Risk[]
|
||||
addRisk: (risk: Omit<Risk, 'id' | 'createdAt' | 'updatedAt'>) => void
|
||||
updateRisk: (id: string, updates: Partial<Risk>) => void
|
||||
deleteRisk: (id: string) => void
|
||||
assessRisk: (id: string, likelihood: RiskLikelihood, impact: RiskImpact) => void
|
||||
|
||||
// Compliance Score
|
||||
complianceScore: ComputedRef<number>
|
||||
scoreByDomain: ComputedRef<Record<ControlDomain, number>>
|
||||
}
|
||||
|
||||
export function useControls(): UseControlsReturn {
|
||||
const store = useComplianceStore()
|
||||
const { state, dispatch, compliance } = store
|
||||
|
||||
// Controls
|
||||
const controls = computed(() => state.controls)
|
||||
|
||||
const controlsByDomain = computed(() => {
|
||||
const domains: ControlDomain[] = [
|
||||
'ACCESS_CONTROL',
|
||||
'DATA_PROTECTION',
|
||||
'NETWORK_SECURITY',
|
||||
'INCIDENT_RESPONSE',
|
||||
'BUSINESS_CONTINUITY',
|
||||
'COMPLIANCE',
|
||||
'RISK_MANAGEMENT',
|
||||
'ASSET_MANAGEMENT',
|
||||
'HUMAN_RESOURCES',
|
||||
]
|
||||
|
||||
return domains.reduce(
|
||||
(acc, domain) => {
|
||||
acc[domain] = state.controls.filter(c => c.domain === domain)
|
||||
return acc
|
||||
},
|
||||
{} as Record<ControlDomain, Control[]>
|
||||
)
|
||||
})
|
||||
|
||||
const implementedControls = computed(() =>
|
||||
state.controls.filter(c => c.implementationStatus === 'IMPLEMENTED')
|
||||
)
|
||||
|
||||
const pendingControls = computed(() =>
|
||||
state.controls.filter(c => c.implementationStatus === 'NOT_IMPLEMENTED')
|
||||
)
|
||||
|
||||
const getControl = (id: string): Control | undefined => {
|
||||
return state.controls.find(c => c.id === id)
|
||||
}
|
||||
|
||||
const addControl = (control: Omit<Control, 'id' | 'createdAt' | 'updatedAt'>): void => {
|
||||
dispatch({ type: 'ADD_CONTROL', payload: control })
|
||||
}
|
||||
|
||||
const updateControl = (id: string, updates: Partial<Control>): void => {
|
||||
dispatch({ type: 'UPDATE_CONTROL', payload: { id, updates } })
|
||||
}
|
||||
|
||||
const deleteControl = (id: string): void => {
|
||||
dispatch({ type: 'DELETE_CONTROL', payload: id })
|
||||
}
|
||||
|
||||
const setControlStatus = (id: string, status: ImplementationStatus): void => {
|
||||
dispatch({
|
||||
type: 'UPDATE_CONTROL',
|
||||
payload: { id, updates: { implementationStatus: status } },
|
||||
})
|
||||
}
|
||||
|
||||
// Evidence
|
||||
const evidence = computed(() => state.evidence)
|
||||
|
||||
const validEvidence = computed(() => {
|
||||
const now = new Date()
|
||||
return state.evidence.filter(e => !e.validUntil || new Date(e.validUntil) > now)
|
||||
})
|
||||
|
||||
const expiredEvidence = computed(() => {
|
||||
const now = new Date()
|
||||
return state.evidence.filter(e => e.validUntil && new Date(e.validUntil) <= now)
|
||||
})
|
||||
|
||||
const getEvidenceForControl = (controlId: string): Evidence[] => {
|
||||
return state.evidence.filter(e => e.controlIds.includes(controlId))
|
||||
}
|
||||
|
||||
const addEvidence = (ev: Omit<Evidence, 'id' | 'uploadedAt'>): void => {
|
||||
dispatch({ type: 'ADD_EVIDENCE', payload: ev })
|
||||
}
|
||||
|
||||
const updateEvidence = (id: string, updates: Partial<Evidence>): void => {
|
||||
dispatch({ type: 'UPDATE_EVIDENCE', payload: { id, updates } })
|
||||
}
|
||||
|
||||
const deleteEvidence = (id: string): void => {
|
||||
dispatch({ type: 'DELETE_EVIDENCE', payload: id })
|
||||
}
|
||||
|
||||
// Risks
|
||||
const risks = computed(() => state.risks)
|
||||
|
||||
const criticalRisks = computed(() => compliance.getCriticalRisks())
|
||||
|
||||
const unmitigatedRisks = computed(() =>
|
||||
state.risks.filter(r => r.status === 'IDENTIFIED' || r.status === 'ANALYZED')
|
||||
)
|
||||
|
||||
const getRisksForControl = (controlId: string): Risk[] => {
|
||||
return state.risks.filter(r => r.controlIds?.includes(controlId))
|
||||
}
|
||||
|
||||
const addRisk = (risk: Omit<Risk, 'id' | 'createdAt' | 'updatedAt'>): void => {
|
||||
dispatch({ type: 'ADD_RISK', payload: risk })
|
||||
}
|
||||
|
||||
const updateRisk = (id: string, updates: Partial<Risk>): void => {
|
||||
dispatch({ type: 'UPDATE_RISK', payload: { id, updates } })
|
||||
}
|
||||
|
||||
const deleteRisk = (id: string): void => {
|
||||
dispatch({ type: 'DELETE_RISK', payload: id })
|
||||
}
|
||||
|
||||
const assessRisk = (id: string, likelihood: RiskLikelihood, impact: RiskImpact): void => {
|
||||
const severity = likelihood * impact
|
||||
let severityLevel: Risk['severity']
|
||||
|
||||
if (severity >= 20) severityLevel = 'CRITICAL'
|
||||
else if (severity >= 12) severityLevel = 'HIGH'
|
||||
else if (severity >= 6) severityLevel = 'MEDIUM'
|
||||
else severityLevel = 'LOW'
|
||||
|
||||
dispatch({
|
||||
type: 'UPDATE_RISK',
|
||||
payload: {
|
||||
id,
|
||||
updates: {
|
||||
likelihood,
|
||||
impact,
|
||||
severity: severityLevel,
|
||||
status: 'ANALYZED',
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Compliance Score
|
||||
const complianceScore = computed(() => {
|
||||
const score = compliance.calculateComplianceScore()
|
||||
return score.overall
|
||||
})
|
||||
|
||||
const scoreByDomain = computed(() => {
|
||||
const domains: ControlDomain[] = [
|
||||
'ACCESS_CONTROL',
|
||||
'DATA_PROTECTION',
|
||||
'NETWORK_SECURITY',
|
||||
'INCIDENT_RESPONSE',
|
||||
'BUSINESS_CONTINUITY',
|
||||
'COMPLIANCE',
|
||||
'RISK_MANAGEMENT',
|
||||
'ASSET_MANAGEMENT',
|
||||
'HUMAN_RESOURCES',
|
||||
]
|
||||
|
||||
return domains.reduce(
|
||||
(acc, domain) => {
|
||||
const domainControls = state.controls.filter(c => c.domain === domain)
|
||||
if (domainControls.length === 0) {
|
||||
acc[domain] = 0
|
||||
return acc
|
||||
}
|
||||
|
||||
const implemented = domainControls.filter(c => c.implementationStatus === 'IMPLEMENTED')
|
||||
const partial = domainControls.filter(c => c.implementationStatus === 'PARTIAL')
|
||||
|
||||
acc[domain] = Math.round(
|
||||
((implemented.length + partial.length * 0.5) / domainControls.length) * 100
|
||||
)
|
||||
return acc
|
||||
},
|
||||
{} as Record<ControlDomain, number>
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
controls,
|
||||
controlsByDomain,
|
||||
implementedControls,
|
||||
pendingControls,
|
||||
getControl,
|
||||
addControl,
|
||||
updateControl,
|
||||
deleteControl,
|
||||
setControlStatus,
|
||||
evidence,
|
||||
validEvidence,
|
||||
expiredEvidence,
|
||||
getEvidenceForControl,
|
||||
addEvidence,
|
||||
updateEvidence,
|
||||
deleteEvidence,
|
||||
risks,
|
||||
criticalRisks,
|
||||
unmitigatedRisks,
|
||||
getRisksForControl,
|
||||
addRisk,
|
||||
updateRisk,
|
||||
deleteRisk,
|
||||
assessRisk,
|
||||
complianceScore,
|
||||
scoreByDomain,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* DSGVO/GDPR composable
|
||||
*/
|
||||
|
||||
import { computed, type ComputedRef, type Ref, ref } from 'vue'
|
||||
import { useComplianceStore } from '../plugin'
|
||||
import type {
|
||||
DSRRequest,
|
||||
DSRRequestType,
|
||||
ConsentRecord,
|
||||
ConsentPurpose,
|
||||
ProcessingActivity,
|
||||
TOM,
|
||||
TOMCategory,
|
||||
DSFA,
|
||||
RetentionPolicy,
|
||||
} from '@breakpilot/compliance-sdk-types'
|
||||
|
||||
export interface UseDSGVOReturn {
|
||||
// DSR
|
||||
dsrRequests: ComputedRef<DSRRequest[]>
|
||||
pendingDSRCount: ComputedRef<number>
|
||||
submitDSR: (type: DSRRequestType, email: string, name: string) => Promise<DSRRequest>
|
||||
updateDSRStatus: (
|
||||
requestId: string,
|
||||
status: DSRRequest['status'],
|
||||
notes?: string
|
||||
) => Promise<void>
|
||||
|
||||
// Consent
|
||||
consents: ComputedRef<ConsentRecord[]>
|
||||
activeConsents: ComputedRef<ConsentRecord[]>
|
||||
hasConsent: (purpose: ConsentPurpose) => boolean
|
||||
recordConsent: (
|
||||
purpose: ConsentPurpose,
|
||||
granted: boolean,
|
||||
source: string
|
||||
) => Promise<ConsentRecord>
|
||||
revokeConsent: (consentId: string) => Promise<void>
|
||||
|
||||
// VVT (Processing Activities)
|
||||
processingActivities: ComputedRef<ProcessingActivity[]>
|
||||
addProcessingActivity: (activity: Omit<ProcessingActivity, 'id' | 'createdAt'>) => void
|
||||
updateProcessingActivity: (id: string, updates: Partial<ProcessingActivity>) => void
|
||||
deleteProcessingActivity: (id: string) => void
|
||||
|
||||
// TOM
|
||||
toms: ComputedRef<TOM[]>
|
||||
tomsByCategory: ComputedRef<Record<TOMCategory, TOM[]>>
|
||||
addTOM: (tom: Omit<TOM, 'id' | 'createdAt' | 'updatedAt'>) => void
|
||||
updateTOM: (id: string, updates: Partial<TOM>) => void
|
||||
deleteTOM: (id: string) => void
|
||||
|
||||
// DSFA
|
||||
dsfas: ComputedRef<DSFA[]>
|
||||
createDSFA: (title: string, description: string) => DSFA
|
||||
updateDSFA: (id: string, updates: Partial<DSFA>) => void
|
||||
|
||||
// Retention
|
||||
retentionPolicies: ComputedRef<RetentionPolicy[]>
|
||||
addRetentionPolicy: (policy: Omit<RetentionPolicy, 'id'>) => void
|
||||
updateRetentionPolicy: (id: string, updates: Partial<RetentionPolicy>) => void
|
||||
deleteRetentionPolicy: (id: string) => void
|
||||
|
||||
// Loading state
|
||||
isLoading: Ref<boolean>
|
||||
}
|
||||
|
||||
export function useDSGVO(): UseDSGVOReturn {
|
||||
const store = useComplianceStore()
|
||||
const { state, dispatch, dsgvo } = store
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
||||
// DSR
|
||||
const dsrRequests = computed(() => state.dsrRequests)
|
||||
|
||||
const pendingDSRCount = computed(
|
||||
() => state.dsrRequests.filter(r => r.status === 'PENDING' || r.status === 'IN_PROGRESS').length
|
||||
)
|
||||
|
||||
const submitDSR = async (
|
||||
type: DSRRequestType,
|
||||
email: string,
|
||||
name: string
|
||||
): Promise<DSRRequest> => {
|
||||
isLoading.value = true
|
||||
try {
|
||||
return await dsgvo.submitDSR(type, email, name)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateDSRStatus = async (
|
||||
requestId: string,
|
||||
status: DSRRequest['status'],
|
||||
notes?: string
|
||||
): Promise<void> => {
|
||||
isLoading.value = true
|
||||
try {
|
||||
await dsgvo.updateDSRStatus(requestId, status, notes)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Consent
|
||||
const consents = computed(() => state.consents)
|
||||
|
||||
const activeConsents = computed(() =>
|
||||
state.consents.filter(c => c.status === 'ACTIVE' && !c.revokedAt)
|
||||
)
|
||||
|
||||
const hasConsent = (purpose: ConsentPurpose): boolean => {
|
||||
return dsgvo.hasActiveConsent(purpose)
|
||||
}
|
||||
|
||||
const recordConsent = async (
|
||||
purpose: ConsentPurpose,
|
||||
granted: boolean,
|
||||
source: string
|
||||
): Promise<ConsentRecord> => {
|
||||
isLoading.value = true
|
||||
try {
|
||||
return await dsgvo.recordConsent(purpose, granted, source)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const revokeConsent = async (consentId: string): Promise<void> => {
|
||||
isLoading.value = true
|
||||
try {
|
||||
await dsgvo.revokeConsent(consentId)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// VVT
|
||||
const processingActivities = computed(() => state.processingActivities)
|
||||
|
||||
const addProcessingActivity = (activity: Omit<ProcessingActivity, 'id' | 'createdAt'>): void => {
|
||||
dispatch({ type: 'ADD_PROCESSING_ACTIVITY', payload: activity })
|
||||
}
|
||||
|
||||
const updateProcessingActivity = (id: string, updates: Partial<ProcessingActivity>): void => {
|
||||
dispatch({ type: 'UPDATE_PROCESSING_ACTIVITY', payload: { id, updates } })
|
||||
}
|
||||
|
||||
const deleteProcessingActivity = (id: string): void => {
|
||||
dispatch({ type: 'DELETE_PROCESSING_ACTIVITY', payload: id })
|
||||
}
|
||||
|
||||
// TOM
|
||||
const toms = computed(() => state.toms)
|
||||
|
||||
const tomsByCategory = computed(() => {
|
||||
const categories: TOMCategory[] = [
|
||||
'ZUTRITTSKONTROLLE',
|
||||
'ZUGANGSKONTROLLE',
|
||||
'ZUGRIFFSKONTROLLE',
|
||||
'WEITERGABEKONTROLLE',
|
||||
'EINGABEKONTROLLE',
|
||||
'AUFTRAGSKONTROLLE',
|
||||
'VERFUEGBARKEITSKONTROLLE',
|
||||
'TRENNUNGSGEBOT',
|
||||
]
|
||||
|
||||
return categories.reduce(
|
||||
(acc, cat) => {
|
||||
acc[cat] = state.toms.filter(t => t.category === cat)
|
||||
return acc
|
||||
},
|
||||
{} as Record<TOMCategory, TOM[]>
|
||||
)
|
||||
})
|
||||
|
||||
const addTOM = (tom: Omit<TOM, 'id' | 'createdAt' | 'updatedAt'>): void => {
|
||||
dispatch({ type: 'ADD_TOM', payload: tom })
|
||||
}
|
||||
|
||||
const updateTOM = (id: string, updates: Partial<TOM>): void => {
|
||||
dispatch({ type: 'UPDATE_TOM', payload: { id, updates } })
|
||||
}
|
||||
|
||||
const deleteTOM = (id: string): void => {
|
||||
dispatch({ type: 'DELETE_TOM', payload: id })
|
||||
}
|
||||
|
||||
// DSFA
|
||||
const dsfas = computed(() => state.dsfas)
|
||||
|
||||
const createDSFA = (title: string, description: string): DSFA => {
|
||||
return dsgvo.createDSFA(title, description)
|
||||
}
|
||||
|
||||
const updateDSFA = (id: string, updates: Partial<DSFA>): void => {
|
||||
dispatch({ type: 'UPDATE_DSFA', payload: { id, updates } })
|
||||
}
|
||||
|
||||
// Retention
|
||||
const retentionPolicies = computed(() => state.retentionPolicies)
|
||||
|
||||
const addRetentionPolicy = (policy: Omit<RetentionPolicy, 'id'>): void => {
|
||||
dispatch({ type: 'ADD_RETENTION_POLICY', payload: policy })
|
||||
}
|
||||
|
||||
const updateRetentionPolicy = (id: string, updates: Partial<RetentionPolicy>): void => {
|
||||
dispatch({ type: 'UPDATE_RETENTION_POLICY', payload: { id, updates } })
|
||||
}
|
||||
|
||||
const deleteRetentionPolicy = (id: string): void => {
|
||||
dispatch({ type: 'DELETE_RETENTION_POLICY', payload: id })
|
||||
}
|
||||
|
||||
return {
|
||||
dsrRequests,
|
||||
pendingDSRCount,
|
||||
submitDSR,
|
||||
updateDSRStatus,
|
||||
consents,
|
||||
activeConsents,
|
||||
hasConsent,
|
||||
recordConsent,
|
||||
revokeConsent,
|
||||
processingActivities,
|
||||
addProcessingActivity,
|
||||
updateProcessingActivity,
|
||||
deleteProcessingActivity,
|
||||
toms,
|
||||
tomsByCategory,
|
||||
addTOM,
|
||||
updateTOM,
|
||||
deleteTOM,
|
||||
dsfas,
|
||||
createDSFA,
|
||||
updateDSFA,
|
||||
retentionPolicies,
|
||||
addRetentionPolicy,
|
||||
updateRetentionPolicy,
|
||||
deleteRetentionPolicy,
|
||||
isLoading,
|
||||
}
|
||||
}
|
||||
136
breakpilot-compliance-sdk/packages/vue/src/composables/useRAG.ts
Normal file
136
breakpilot-compliance-sdk/packages/vue/src/composables/useRAG.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* RAG (Retrieval-Augmented Generation) composable
|
||||
*/
|
||||
|
||||
import { computed, type ComputedRef, type Ref, ref, reactive } from 'vue'
|
||||
import { useComplianceStore } from '../plugin'
|
||||
import type {
|
||||
SearchResponse,
|
||||
AssistantResponse,
|
||||
ChatMessage,
|
||||
LegalDocument,
|
||||
} from '@breakpilot/compliance-sdk-types'
|
||||
|
||||
export interface UseRAGReturn {
|
||||
// Search
|
||||
search: (query: string, regulationCodes?: string[]) => Promise<SearchResponse>
|
||||
searchResults: Ref<SearchResponse | null>
|
||||
|
||||
// Chat
|
||||
ask: (question: string, context?: string) => Promise<AssistantResponse>
|
||||
chatHistory: Ref<ChatMessage[]>
|
||||
clearChat: () => void
|
||||
isTyping: Ref<boolean>
|
||||
|
||||
// Documents
|
||||
documents: ComputedRef<LegalDocument[]>
|
||||
availableRegulations: ComputedRef<string[]>
|
||||
|
||||
// Loading state
|
||||
isLoading: Ref<boolean>
|
||||
error: Ref<Error | null>
|
||||
}
|
||||
|
||||
export function useRAG(): UseRAGReturn {
|
||||
const store = useComplianceStore()
|
||||
const { state, rag } = store
|
||||
|
||||
const isLoading = ref(false)
|
||||
const isTyping = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
const searchResults = ref<SearchResponse | null>(null)
|
||||
const chatHistory = ref<ChatMessage[]>([])
|
||||
|
||||
// Search
|
||||
const search = async (query: string, regulationCodes?: string[]): Promise<SearchResponse> => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const results = await rag.search(query, regulationCodes)
|
||||
searchResults.value = results
|
||||
return results
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error(String(err))
|
||||
throw err
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Chat
|
||||
const ask = async (question: string, context?: string): Promise<AssistantResponse> => {
|
||||
isLoading.value = true
|
||||
isTyping.value = true
|
||||
error.value = null
|
||||
|
||||
// Add user message to history
|
||||
chatHistory.value.push({
|
||||
id: `msg_${Date.now()}`,
|
||||
role: 'user',
|
||||
content: question,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await rag.ask(question, context)
|
||||
|
||||
// Add assistant response to history
|
||||
chatHistory.value.push({
|
||||
id: `msg_${Date.now()}`,
|
||||
role: 'assistant',
|
||||
content: response.answer,
|
||||
timestamp: new Date().toISOString(),
|
||||
citations: response.citations,
|
||||
})
|
||||
|
||||
return response
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error(String(err))
|
||||
|
||||
// Add error message to history
|
||||
chatHistory.value.push({
|
||||
id: `msg_${Date.now()}`,
|
||||
role: 'assistant',
|
||||
content: 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.',
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
|
||||
throw err
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
isTyping.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const clearChat = (): void => {
|
||||
chatHistory.value = []
|
||||
rag.clearHistory()
|
||||
}
|
||||
|
||||
// Documents
|
||||
const documents = computed(() => state.legalDocuments)
|
||||
|
||||
const availableRegulations = computed(() => {
|
||||
const codes = new Set<string>()
|
||||
state.legalDocuments.forEach(doc => {
|
||||
if (doc.regulationCode) {
|
||||
codes.add(doc.regulationCode)
|
||||
}
|
||||
})
|
||||
return Array.from(codes).sort()
|
||||
})
|
||||
|
||||
return {
|
||||
search,
|
||||
searchResults,
|
||||
ask,
|
||||
chatHistory,
|
||||
clearChat,
|
||||
isTyping,
|
||||
documents,
|
||||
availableRegulations,
|
||||
isLoading,
|
||||
error,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Security composable for SBOM and security scanning
|
||||
*/
|
||||
|
||||
import { computed, type ComputedRef, type Ref, ref } from 'vue'
|
||||
import { useComplianceStore } from '../plugin'
|
||||
import type {
|
||||
SBOM,
|
||||
SBOMComponent,
|
||||
SecurityIssue,
|
||||
Vulnerability,
|
||||
SecurityScanResult,
|
||||
} from '@breakpilot/compliance-sdk-types'
|
||||
|
||||
export interface UseSecurityReturn {
|
||||
// SBOM
|
||||
sbom: ComputedRef<SBOM | null>
|
||||
components: ComputedRef<SBOMComponent[]>
|
||||
componentsByCategory: ComputedRef<Record<string, SBOMComponent[]>>
|
||||
vulnerableComponents: ComputedRef<SBOMComponent[]>
|
||||
generateSBOM: (source?: string) => Promise<SBOM>
|
||||
exportSBOM: (format: 'cyclonedx' | 'spdx') => Promise<Blob>
|
||||
|
||||
// Security Issues
|
||||
securityIssues: ComputedRef<SecurityIssue[]>
|
||||
criticalIssues: ComputedRef<SecurityIssue[]>
|
||||
openIssues: ComputedRef<SecurityIssue[]>
|
||||
issuesBySeverity: ComputedRef<Record<string, SecurityIssue[]>>
|
||||
|
||||
// Scanning
|
||||
scan: (options?: ScanOptions) => Promise<SecurityScanResult>
|
||||
lastScanResult: Ref<SecurityScanResult | null>
|
||||
isScanning: Ref<boolean>
|
||||
|
||||
// Vulnerabilities
|
||||
vulnerabilities: ComputedRef<Vulnerability[]>
|
||||
getVulnerabilitiesForComponent: (componentId: string) => Vulnerability[]
|
||||
|
||||
// Loading state
|
||||
isLoading: Ref<boolean>
|
||||
error: Ref<Error | null>
|
||||
}
|
||||
|
||||
export interface ScanOptions {
|
||||
tools?: string[]
|
||||
targetPath?: string
|
||||
excludePaths?: string[]
|
||||
}
|
||||
|
||||
export function useSecurity(): UseSecurityReturn {
|
||||
const store = useComplianceStore()
|
||||
const { state, security } = store
|
||||
|
||||
const isLoading = ref(false)
|
||||
const isScanning = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
const lastScanResult = ref<SecurityScanResult | null>(null)
|
||||
|
||||
// SBOM
|
||||
const sbom = computed(() => state.sbom)
|
||||
|
||||
const components = computed(() => state.sbom?.components || [])
|
||||
|
||||
const componentsByCategory = computed(() => {
|
||||
const comps = state.sbom?.components || []
|
||||
return comps.reduce(
|
||||
(acc, comp) => {
|
||||
const cat = comp.category || 'other'
|
||||
if (!acc[cat]) acc[cat] = []
|
||||
acc[cat].push(comp)
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, SBOMComponent[]>
|
||||
)
|
||||
})
|
||||
|
||||
const vulnerableComponents = computed(() => {
|
||||
return components.value.filter(c => c.vulnerabilities && c.vulnerabilities.length > 0)
|
||||
})
|
||||
|
||||
const generateSBOM = async (source?: string): Promise<SBOM> => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
return await security.generateSBOM(source)
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error(String(err))
|
||||
throw err
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const exportSBOM = async (format: 'cyclonedx' | 'spdx'): Promise<Blob> => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
return await security.exportSBOM(format)
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error(String(err))
|
||||
throw err
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Security Issues
|
||||
const securityIssues = computed(() => state.securityIssues)
|
||||
|
||||
const criticalIssues = computed(() =>
|
||||
state.securityIssues.filter(i => i.severity === 'CRITICAL' || i.severity === 'HIGH')
|
||||
)
|
||||
|
||||
const openIssues = computed(() =>
|
||||
state.securityIssues.filter(i => i.status === 'OPEN' || i.status === 'IN_PROGRESS')
|
||||
)
|
||||
|
||||
const issuesBySeverity = computed(() => {
|
||||
return state.securityIssues.reduce(
|
||||
(acc, issue) => {
|
||||
if (!acc[issue.severity]) acc[issue.severity] = []
|
||||
acc[issue.severity].push(issue)
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, SecurityIssue[]>
|
||||
)
|
||||
})
|
||||
|
||||
// Scanning
|
||||
const scan = async (options?: ScanOptions): Promise<SecurityScanResult> => {
|
||||
isScanning.value = true
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const result = await security.scan(options)
|
||||
lastScanResult.value = result
|
||||
return result
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error(String(err))
|
||||
throw err
|
||||
} finally {
|
||||
isScanning.value = false
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Vulnerabilities
|
||||
const vulnerabilities = computed(() => {
|
||||
const vulns: Vulnerability[] = []
|
||||
components.value.forEach(comp => {
|
||||
if (comp.vulnerabilities) {
|
||||
vulns.push(...comp.vulnerabilities)
|
||||
}
|
||||
})
|
||||
return vulns
|
||||
})
|
||||
|
||||
const getVulnerabilitiesForComponent = (componentId: string): Vulnerability[] => {
|
||||
const comp = components.value.find(c => c.name === componentId)
|
||||
return comp?.vulnerabilities || []
|
||||
}
|
||||
|
||||
return {
|
||||
sbom,
|
||||
components,
|
||||
componentsByCategory,
|
||||
vulnerableComponents,
|
||||
generateSBOM,
|
||||
exportSBOM,
|
||||
securityIssues,
|
||||
criticalIssues,
|
||||
openIssues,
|
||||
issuesBySeverity,
|
||||
scan,
|
||||
lastScanResult,
|
||||
isScanning,
|
||||
vulnerabilities,
|
||||
getVulnerabilitiesForComponent,
|
||||
isLoading,
|
||||
error,
|
||||
}
|
||||
}
|
||||
64
breakpilot-compliance-sdk/packages/vue/src/index.ts
Normal file
64
breakpilot-compliance-sdk/packages/vue/src/index.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @breakpilot/compliance-sdk-vue
|
||||
*
|
||||
* Vue 3 integration for BreakPilot Compliance SDK
|
||||
*
|
||||
* Usage:
|
||||
* import { createApp } from 'vue'
|
||||
* import { CompliancePlugin, useCompliance } from '@breakpilot/compliance-sdk-vue'
|
||||
*
|
||||
* const app = createApp(App)
|
||||
* app.use(CompliancePlugin, {
|
||||
* apiEndpoint: 'https://compliance.example.com/api/v1',
|
||||
* apiKey: 'pk_live_xxx',
|
||||
* tenantId: 'tenant_xxx'
|
||||
* })
|
||||
*/
|
||||
|
||||
// Plugin
|
||||
export {
|
||||
CompliancePlugin,
|
||||
useComplianceStore,
|
||||
COMPLIANCE_KEY,
|
||||
type CompliancePluginOptions,
|
||||
type ComplianceStore,
|
||||
} from './plugin'
|
||||
|
||||
// Composables
|
||||
export {
|
||||
useCompliance,
|
||||
useDSGVO,
|
||||
useRAG,
|
||||
useControls,
|
||||
useSecurity,
|
||||
type UseComplianceReturn,
|
||||
type UseDSGVOReturn,
|
||||
type UseRAGReturn,
|
||||
type UseControlsReturn,
|
||||
type UseSecurityReturn,
|
||||
type ScanOptions,
|
||||
} from './composables'
|
||||
|
||||
// Re-export types
|
||||
export type {
|
||||
SDKState,
|
||||
SDKAction,
|
||||
SDKStep,
|
||||
Risk,
|
||||
Control,
|
||||
Evidence,
|
||||
DSRRequest,
|
||||
ConsentRecord,
|
||||
ProcessingActivity,
|
||||
TOM,
|
||||
DSFA,
|
||||
RetentionPolicy,
|
||||
Obligation,
|
||||
SBOM,
|
||||
SBOMComponent,
|
||||
SecurityIssue,
|
||||
Vulnerability,
|
||||
SearchResponse,
|
||||
AssistantResponse,
|
||||
ChatMessage,
|
||||
} from '@breakpilot/compliance-sdk-types'
|
||||
164
breakpilot-compliance-sdk/packages/vue/src/plugin.ts
Normal file
164
breakpilot-compliance-sdk/packages/vue/src/plugin.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* BreakPilot Compliance SDK - Vue 3 Plugin
|
||||
*
|
||||
* Usage:
|
||||
* import { createApp } from 'vue'
|
||||
* import { CompliancePlugin } from '@breakpilot/compliance-sdk-vue'
|
||||
*
|
||||
* const app = createApp(App)
|
||||
* app.use(CompliancePlugin, {
|
||||
* apiEndpoint: 'https://compliance.example.com/api/v1',
|
||||
* apiKey: 'pk_live_xxx',
|
||||
* tenantId: 'tenant_xxx'
|
||||
* })
|
||||
*/
|
||||
|
||||
import { type App, reactive, inject, type InjectionKey, readonly } from 'vue'
|
||||
import {
|
||||
ComplianceClient,
|
||||
sdkReducer,
|
||||
DSGVOModule,
|
||||
ComplianceModule,
|
||||
RAGModule,
|
||||
SecurityModule,
|
||||
StateSyncManager,
|
||||
} from '@breakpilot/compliance-sdk-core'
|
||||
import type { SDKState, SDKAction } from '@breakpilot/compliance-sdk-types'
|
||||
import { createInitialState } from '@breakpilot/compliance-sdk-types'
|
||||
|
||||
// ============================================================================
|
||||
// Types
|
||||
// ============================================================================
|
||||
|
||||
export interface CompliancePluginOptions {
|
||||
apiEndpoint: string
|
||||
apiKey: string
|
||||
tenantId?: string
|
||||
autoSync?: boolean
|
||||
syncInterval?: number
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
export interface ComplianceStore {
|
||||
state: SDKState
|
||||
dispatch: (action: SDKAction) => void
|
||||
client: ComplianceClient
|
||||
dsgvo: DSGVOModule
|
||||
compliance: ComplianceModule
|
||||
rag: RAGModule
|
||||
security: SecurityModule
|
||||
syncManager: StateSyncManager
|
||||
isReady: boolean
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Injection Key
|
||||
// ============================================================================
|
||||
|
||||
export const COMPLIANCE_KEY: InjectionKey<ComplianceStore> = Symbol('compliance')
|
||||
|
||||
// ============================================================================
|
||||
// Plugin
|
||||
// ============================================================================
|
||||
|
||||
export const CompliancePlugin = {
|
||||
install(app: App, options: CompliancePluginOptions): void {
|
||||
// Create client
|
||||
const client = new ComplianceClient({
|
||||
apiEndpoint: options.apiEndpoint,
|
||||
apiKey: options.apiKey,
|
||||
tenantId: options.tenantId,
|
||||
})
|
||||
|
||||
// Create reactive state
|
||||
const state = reactive<SDKState>(createInitialState())
|
||||
|
||||
// Create dispatch function
|
||||
const dispatch = (action: SDKAction): void => {
|
||||
const newState = sdkReducer(state, action)
|
||||
Object.assign(state, newState)
|
||||
}
|
||||
|
||||
// Create modules
|
||||
const dsgvo = new DSGVOModule(state, dispatch, client)
|
||||
const compliance = new ComplianceModule(state, dispatch, client)
|
||||
const rag = new RAGModule(state, dispatch, client)
|
||||
const security = new SecurityModule(state, dispatch, client)
|
||||
|
||||
// Create sync manager
|
||||
const syncManager = new StateSyncManager({
|
||||
client,
|
||||
syncInterval: options.syncInterval || 30000,
|
||||
onStateLoaded: loadedState => {
|
||||
Object.assign(state, loadedState)
|
||||
},
|
||||
onSyncError: error => {
|
||||
console.error('[ComplianceSDK] Sync error:', error)
|
||||
store.error = error
|
||||
},
|
||||
})
|
||||
|
||||
// Create store
|
||||
const store = reactive<ComplianceStore>({
|
||||
state: state as SDKState,
|
||||
dispatch,
|
||||
client,
|
||||
dsgvo,
|
||||
compliance,
|
||||
rag,
|
||||
security,
|
||||
syncManager,
|
||||
isReady: false,
|
||||
error: null,
|
||||
})
|
||||
|
||||
// Initialize
|
||||
const initialize = async (): Promise<void> => {
|
||||
try {
|
||||
// Load state from server
|
||||
const savedState = await client.getState()
|
||||
if (savedState) {
|
||||
Object.assign(state, savedState.state)
|
||||
}
|
||||
|
||||
// Start sync if enabled
|
||||
if (options.autoSync !== false) {
|
||||
syncManager.start()
|
||||
}
|
||||
|
||||
store.isReady = true
|
||||
|
||||
if (options.debug) {
|
||||
console.log('[ComplianceSDK] Initialized:', state)
|
||||
}
|
||||
} catch (error) {
|
||||
store.error = error instanceof Error ? error : new Error(String(error))
|
||||
console.error('[ComplianceSDK] Initialization failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Start initialization
|
||||
initialize()
|
||||
|
||||
// Provide store
|
||||
app.provide(COMPLIANCE_KEY, store)
|
||||
|
||||
// Also make available as global property
|
||||
app.config.globalProperties.$compliance = store
|
||||
},
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Injection Helper
|
||||
// ============================================================================
|
||||
|
||||
export function useComplianceStore(): ComplianceStore {
|
||||
const store = inject(COMPLIANCE_KEY)
|
||||
if (!store) {
|
||||
throw new Error(
|
||||
'[ComplianceSDK] No store found. Did you forget to install the CompliancePlugin?'
|
||||
)
|
||||
}
|
||||
return store
|
||||
}
|
||||
Reference in New Issue
Block a user