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,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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user