'use client' /** * Security Dashboard Admin Page * * DevSecOps Dashboard with: * - Security scan results (Gitleaks, Semgrep, Bandit, Trivy, Grype) * - Vulnerability findings with severity levels * - Scan history and statistics * - Manual scan triggers */ import { useState, useEffect } from 'react' import AdminLayout from '@/components/admin/AdminLayout' interface Finding { id: string tool: string severity: string title: string message?: string file?: string line?: number found_at: string } interface SeveritySummary { critical: number high: number medium: number low: number info: number total: number } interface ToolStatus { name: string installed: boolean version?: string last_run?: string last_findings: number } interface HistoryItem { timestamp: string title: string description: string status: string } interface Metric { name: string value: number unit: string trend?: string } interface Container { name: string status: string health: string cpu_percent: number memory_mb: number uptime: string } type TabType = 'overview' | 'findings' | 'scans' | 'monitoring' export default function SecurityPage() { const [activeTab, setActiveTab] = useState('overview') const [summary, setSummary] = useState(null) const [findings, setFindings] = useState([]) const [tools, setTools] = useState([]) const [history, setHistory] = useState([]) const [metrics, setMetrics] = useState([]) const [containers, setContainers] = useState([]) const [loading, setLoading] = useState(true) const [scanLoading, setScanLoading] = useState(false) const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000' useEffect(() => { loadData() }, []) const loadData = async () => { setLoading(true) try { const [summaryRes, findingsRes, toolsRes, historyRes, metricsRes, containersRes] = await Promise.all([ fetch(`${BACKEND_URL}/api/v1/security/summary`), fetch(`${BACKEND_URL}/api/v1/security/findings`), fetch(`${BACKEND_URL}/api/v1/security/tools`), fetch(`${BACKEND_URL}/api/v1/security/history`), fetch(`${BACKEND_URL}/api/v1/security/monitoring/metrics`), fetch(`${BACKEND_URL}/api/v1/security/monitoring/containers`), ]) if (summaryRes.ok) setSummary(await summaryRes.json()) if (findingsRes.ok) setFindings(await findingsRes.json()) if (toolsRes.ok) setTools(await toolsRes.json()) if (historyRes.ok) setHistory(await historyRes.json()) if (metricsRes.ok) setMetrics(await metricsRes.json()) if (containersRes.ok) setContainers(await containersRes.json()) } catch (error) { console.error('Failed to load security data:', error) } finally { setLoading(false) } } const runScan = async (scanType: string) => { setScanLoading(true) try { const res = await fetch(`${BACKEND_URL}/api/v1/security/scan/${scanType}`, { method: 'POST', }) if (res.ok) { // Reload data after a short delay setTimeout(loadData, 2000) } } catch (error) { console.error('Scan failed:', error) } finally { setScanLoading(false) } } const getSeverityColor = (severity: string) => { switch (severity.toUpperCase()) { case 'CRITICAL': return 'bg-purple-100 text-purple-800 border-purple-200' case 'HIGH': return 'bg-red-100 text-red-800 border-red-200' case 'MEDIUM': return 'bg-yellow-100 text-yellow-800 border-yellow-200' case 'LOW': return 'bg-blue-100 text-blue-800 border-blue-200' default: return 'bg-gray-100 text-gray-800 border-gray-200' } } const getStatusColor = (status: string) => { switch (status) { case 'success': return 'text-green-600' case 'warning': return 'text-yellow-600' case 'error': return 'text-red-600' default: return 'text-gray-600' } } const tabs = [ { id: 'overview', name: 'Übersicht', icon: 'πŸ“Š' }, { id: 'findings', name: 'Findings', icon: 'πŸ”' }, { id: 'scans', name: 'Scans', icon: 'πŸ›‘οΈ' }, { id: 'monitoring', name: 'Monitoring', icon: 'πŸ“ˆ' }, ] return ( {/* Tab Navigation */}
{loading ? (
Lade Sicherheitsdaten...
) : ( <> {/* Overview Tab */} {activeTab === 'overview' && (
{/* Severity Summary Cards */}
{summary?.critical || 0}
Critical
{summary?.high || 0}
High
{summary?.medium || 0}
Medium
{summary?.low || 0}
Low
{summary?.total || 0}
Total
{/* Tools Status */}

DevSecOps Tools

{tools.map((tool) => (
{tool.name}
{tool.version &&
{tool.version}
}
))}
{/* Recent History */}

Letzte Scans

{history.slice(0, 5).map((item, idx) => (
{item.title}
{item.description}
{new Date(item.timestamp).toLocaleString('de-DE')}
))}
)} {/* Findings Tab */} {activeTab === 'findings' && (

Security Findings ({findings.length})

{findings.length === 0 ? (
Keine Findings vorhanden. Starten Sie einen Scan.
) : ( findings.map((finding, idx) => (
{finding.severity}
{finding.title}
{finding.message}
Tool: {finding.tool} {finding.file && File: {finding.file}} {finding.line && Line: {finding.line}}
)) )}
)} {/* Scans Tab */} {activeTab === 'scans' && (

Scan starten

{[ { type: 'secrets', name: 'Secrets', icon: 'πŸ”‘', desc: 'Gitleaks' }, { type: 'sast', name: 'SAST', icon: 'πŸ”¬', desc: 'Semgrep, Bandit' }, { type: 'deps', name: 'Dependencies', icon: 'πŸ“¦', desc: 'Trivy, Grype' }, { type: 'containers', name: 'Container', icon: '🐳', desc: 'Trivy Image' }, { type: 'sbom', name: 'SBOM', icon: 'πŸ“‹', desc: 'Syft' }, { type: 'all', name: 'Full Scan', icon: 'πŸ›‘οΈ', desc: 'Alle Tools' }, ].map((scan) => ( ))}
{scanLoading && (
Scan lΓ€uft...
)}
{/* Scan History */}

Scan Historie

{history.map((item, idx) => (
{item.title}
{item.description}
{new Date(item.timestamp).toLocaleString('de-DE')}
))}
)} {/* Monitoring Tab */} {activeTab === 'monitoring' && (
{/* Metrics */}

System Metriken

{metrics.map((metric, idx) => (
{metric.value}{metric.unit && {metric.unit}}
{metric.name}
{metric.trend && (
{metric.trend === 'up' ? '↑' : metric.trend === 'down' ? '↓' : 'β†’'} {metric.trend}
)}
))}
{/* Containers */}

Container Status

{containers.map((container, idx) => (
{container.name.replace('breakpilot-pwa-', '')}
{container.status}
CPU: {container.cpu_percent}%
RAM: {container.memory_mb}MB
{container.uptime}
))}
)} )} {/* Refresh Button */}
) }