""" BreakPilot Developer Admin Frontend Ein separates Admin-Frontend fuer Entwickler mit DevSecOps Dashboard, SBOM-Viewer, Security-Scans und anderen Entwickler-Tools. URL: /dev-admin """ from fastapi import APIRouter from fastapi.responses import HTMLResponse # Import der Security Module from .modules.security import SecurityModule router = APIRouter() def get_dev_admin_css() -> str: """CSS fuer das Developer Admin Frontend.""" return """ /* ========================================== DEVELOPER ADMIN - CSS VARIABLES ========================================== */ :root { /* Primary Colors - Entwickler Blau */ --da-primary: #3b82f6; --da-primary-hover: #2563eb; --da-primary-soft: rgba(59, 130, 246, 0.1); /* Background */ --da-bg: #0f172a; --da-surface: #1e293b; --da-surface-elevated: #334155; /* Borders */ --da-border: #475569; --da-border-subtle: rgba(255, 255, 255, 0.1); /* Text */ --da-text: #e5e7eb; --da-text-muted: #9ca3af; /* Status Colors */ --da-danger: #ef4444; --da-warning: #f59e0b; --da-success: #22c55e; --da-info: #3b82f6; /* Sidebar */ --sidebar-width: 260px; } /* Light Theme */ [data-theme="light"] { --da-bg: #f8fafc; --da-surface: #ffffff; --da-surface-elevated: #f1f5f9; --da-border: #e2e8f0; --da-border-subtle: rgba(0, 0, 0, 0.1); --da-text: #1e293b; --da-text-muted: #64748b; } /* ========================================== RESET & BASE ========================================== */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'JetBrains Mono', 'SF Mono', 'Monaco', monospace; background: var(--da-bg); color: var(--da-text); min-height: 100vh; line-height: 1.5; } /* ========================================== LAYOUT ========================================== */ .dev-admin-root { display: flex; min-height: 100vh; } /* Sidebar */ .dev-admin-sidebar { width: var(--sidebar-width); background: var(--da-surface); border-right: 1px solid var(--da-border); position: fixed; top: 0; left: 0; height: 100vh; overflow-y: auto; z-index: 100; } .dev-admin-sidebar-header { padding: 20px; border-bottom: 1px solid var(--da-border); } .dev-admin-brand { display: flex; align-items: center; gap: 12px; } .dev-admin-logo { width: 40px; height: 40px; background: linear-gradient(135deg, #3b82f6, #8b5cf6); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 20px; } .dev-admin-title { font-size: 16px; font-weight: 700; color: var(--da-text); } .dev-admin-subtitle { font-size: 11px; color: var(--da-text-muted); } /* Sidebar Navigation */ .dev-admin-nav { padding: 16px 12px; } .dev-admin-nav-section { margin-bottom: 24px; } .dev-admin-nav-label { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: var(--da-text-muted); padding: 0 8px; margin-bottom: 8px; } .dev-admin-nav-item { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; color: var(--da-text-muted); cursor: pointer; transition: all 0.2s ease; font-size: 13px; } .dev-admin-nav-item:hover { background: var(--da-surface-elevated); color: var(--da-text); } .dev-admin-nav-item.active { background: var(--da-primary-soft); color: var(--da-primary); } .dev-admin-nav-icon { font-size: 18px; width: 24px; text-align: center; } .dev-admin-nav-badge { margin-left: auto; padding: 2px 8px; font-size: 10px; border-radius: 10px; background: var(--da-primary-soft); color: var(--da-primary); } /* Main Content */ .dev-admin-main { flex: 1; margin-left: var(--sidebar-width); padding: 24px; min-height: 100vh; } /* Header */ .dev-admin-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid var(--da-border); } .dev-admin-header h1 { font-size: 24px; font-weight: 600; } .dev-admin-header-actions { display: flex; gap: 12px; align-items: center; } /* Theme Toggle */ .theme-toggle-dev { width: 40px; height: 40px; border-radius: 8px; border: 1px solid var(--da-border); background: var(--da-surface); color: var(--da-text); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; transition: all 0.2s ease; } .theme-toggle-dev:hover { background: var(--da-surface-elevated); border-color: var(--da-primary); } /* Panels */ .dev-admin-panel { display: none; } .dev-admin-panel.active { display: block; } /* Back Link */ .dev-admin-back { display: flex; align-items: center; gap: 8px; color: var(--da-text-muted); text-decoration: none; font-size: 13px; padding: 8px 12px; margin: 16px 12px; border-radius: 8px; transition: all 0.2s ease; } .dev-admin-back:hover { background: var(--da-surface-elevated); color: var(--da-text); } /* ========================================== LOGS STYLES ========================================== */ .log-controls { display: flex; gap: 12px; align-items: center; } .log-controls select { padding: 8px 12px; border-radius: 6px; border: 1px solid var(--da-border); background: var(--da-surface); color: var(--da-text); font-size: 13px; } .logs-list { font-family: 'JetBrains Mono', monospace; font-size: 12px; max-height: 500px; overflow-y: auto; } .log-entry { display: flex; gap: 12px; padding: 8px 12px; border-bottom: 1px solid var(--da-border-subtle); align-items: baseline; } .log-entry:hover { background: var(--da-surface-elevated); } .log-time { color: var(--da-text-muted); min-width: 80px; } .log-level { padding: 2px 8px; border-radius: 4px; font-size: 10px; font-weight: 600; min-width: 60px; text-align: center; } .log-error .log-level { background: rgba(239, 68, 68, 0.2); color: #ef4444; } .log-warning .log-level { background: rgba(245, 158, 11, 0.2); color: #f59e0b; } .log-info .log-level { background: rgba(59, 130, 246, 0.2); color: #3b82f6; } .log-debug .log-level { background: rgba(156, 163, 175, 0.2); color: #9ca3af; } .log-service { color: var(--da-primary); min-width: 120px; } .log-message { color: var(--da-text); flex: 1; } /* ========================================== METRICS STYLES ========================================== */ .metrics-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; } .metric-card { background: var(--da-surface-elevated); border-radius: 12px; padding: 20px; position: relative; } .metric-name { font-size: 12px; color: var(--da-text-muted); margin-bottom: 8px; } .metric-value { font-size: 28px; font-weight: 700; color: var(--da-text); } .metric-unit { font-size: 14px; font-weight: 400; color: var(--da-text-muted); } .metric-trend { position: absolute; top: 16px; right: 16px; font-size: 16px; } .trend-up { color: #22c55e; } .trend-down { color: #ef4444; } .trend-stable { color: var(--da-text-muted); } /* ========================================== CONTAINERS STYLES ========================================== */ .containers-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; } .container-card { background: var(--da-surface-elevated); border-radius: 12px; padding: 16px; border-left: 4px solid var(--da-success); } .container-card.status-unhealthy { border-left-color: var(--da-danger); } .container-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } .container-name { font-weight: 600; font-size: 14px; color: var(--da-text); } .container-status { font-size: 12px; color: var(--da-success); } .status-unhealthy .container-status { color: var(--da-danger); } .container-stats { display: flex; gap: 16px; } .container-stats .stat { flex: 1; text-align: center; } .container-stats .stat-label { display: block; font-size: 10px; color: var(--da-text-muted); text-transform: uppercase; margin-bottom: 4px; } .container-stats .stat-value { font-size: 14px; font-weight: 600; color: var(--da-text); } /* ========================================== SERVICES STYLES ========================================== */ .services-list { display: flex; flex-direction: column; gap: 12px; } .service-row { display: grid; grid-template-columns: 200px 1fr 100px; gap: 16px; align-items: center; padding: 16px; background: var(--da-surface-elevated); border-radius: 8px; border-left: 4px solid var(--da-success); } .service-row.status-unhealthy { border-left-color: var(--da-danger); } .service-info { display: flex; align-items: center; gap: 12px; } .service-status { font-size: 16px; } .status-healthy .service-status { color: var(--da-success); } .status-unhealthy .service-status { color: var(--da-danger); } .service-name { font-weight: 600; color: var(--da-text); } .service-url { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--da-text-muted); } .service-response { font-weight: 600; text-align: right; } .response-fast { color: var(--da-success); } .response-medium { color: var(--da-warning); } .response-slow { color: var(--da-danger); } /* ========================================== SBOM EXTRAS ========================================== */ .stat-card { background: var(--da-surface-elevated); border-radius: 8px; padding: 16px; text-align: center; } .stat-card .stat-value { font-size: 24px; font-weight: 700; color: var(--da-primary); } .stat-card .stat-label { font-size: 11px; color: var(--da-text-muted); text-transform: uppercase; margin-top: 4px; } .license-badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; background: var(--da-primary-soft); color: var(--da-primary); } """ def get_dev_admin_html() -> str: """HTML-Struktur fuer das Developer Admin Frontend.""" return """ BreakPilot Developer Admin

Security Dashboard

{security_content}

📜 Software Bill of Materials (SBOM)

Vollstaendige Liste aller Abhaengigkeiten und deren Versionen.

Lade SBOM-Daten...

🔍 Security Scans ausfuehren

📄 Application Logs

Lade Logs...

📈 System Metrics

Lade Metriken...

📦 Container Status

Lade Container-Status...

⚙ Service Health

Lade Service-Status...
""" def get_dev_admin_js() -> str: """JavaScript fuer das Developer Admin Frontend.""" return """ // ========================================== // DEVELOPER ADMIN - JAVASCRIPT // ========================================== const panelTitles = { 'security': 'Security Dashboard', 'sbom': 'SBOM Viewer', 'scans': 'Security Scans', 'logs': 'Application Logs', 'metrics': 'System Metrics', 'containers': 'Container Status', 'services': 'Service Health' }; function switchPanel(panelId) { // Alle Panels ausblenden document.querySelectorAll('.dev-admin-panel').forEach(panel => { panel.classList.remove('active'); }); // Alle Nav-Items deaktivieren document.querySelectorAll('.dev-admin-nav-item').forEach(item => { item.classList.remove('active'); }); // Gewaehltes Panel anzeigen const panel = document.getElementById('panel-' + panelId); if (panel) { panel.classList.add('active'); } // Nav-Item aktivieren const navItem = document.querySelector('[data-panel="' + panelId + '"]'); if (navItem) { navItem.classList.add('active'); } // Titel aktualisieren document.getElementById('panel-title').textContent = panelTitles[panelId] || 'Developer Admin'; // Panel-spezifische Initialisierung if (panelId === 'security' && typeof SecurityDashboard !== 'undefined') { SecurityDashboard.init(); } else if (panelId === 'sbom') { loadSBOM(); } else if (panelId === 'logs') { loadLogs(); } else if (panelId === 'metrics') { loadMetrics(); } else if (panelId === 'containers') { loadContainers(); } else if (panelId === 'services') { loadServices(); } } function toggleTheme() { const html = document.documentElement; const currentTheme = html.getAttribute('data-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; html.setAttribute('data-theme', newTheme); localStorage.setItem('dev-admin-theme', newTheme); } function loadSBOM() { const container = document.getElementById('sbom-content'); container.innerHTML = '
Lade SBOM-Daten...
'; // Nutze /demo/sbom - gibt Mock-Daten wenn keine echten verfuegbar fetch('/api/v1/security/demo/sbom') .then(res => res.json()) .then(data => { if (data.components && data.components.length > 0) { let html = '
'; html += '
' + data.components.length + '
Komponenten
'; // Lizenzen zaehlen const licenses = {}; data.components.forEach(c => { const lic = c.licenses?.[0]?.license?.id || 'Unknown'; licenses[lic] = (licenses[lic] || 0) + 1; }); html += '
' + Object.keys(licenses).length + '
Lizenzen
'; html += '
' + (data.metadata?.component?.version || '-') + '
App Version
'; html += '
' + (data.specVersion || '-') + '
SBOM Spec
'; html += '
'; html += ''; html += ''; html += ''; data.components.slice(0, 100).forEach(comp => { const license = comp.licenses?.[0]?.license?.id || '-'; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; }); html += '
NameVersionTypLizenzPURL
' + (comp.name || '-') + '' + (comp.version || '-') + '' + (comp.type || '-') + '' + license + '' + (comp.purl || '-') + '
'; if (data.components.length > 100) { html += '

'; html += 'Zeige 100 von ' + data.components.length + ' Komponenten

'; } container.innerHTML = html; } else { container.innerHTML = '

Keine SBOM-Daten verfuegbar. Fuehren Sie "syft" aus.

'; } }) .catch(err => { container.innerHTML = '

Fehler beim Laden: ' + err.message + '

'; }); } async function runScan(scanType) { const resultsDiv = document.getElementById('scan-results'); resultsDiv.innerHTML = '
Starte ' + scanType + ' Scan...
'; try { const response = await fetch('/api/v1/security/scan/' + scanType, { method: 'POST' }); const data = await response.json(); if (response.ok) { resultsDiv.innerHTML = '
' + '✔ Scan gestartet: ' + data.scan_type + '
Status: ' + data.status + '
Message: ' + (data.message || 'Scan laeuft im Hintergrund') + '
'; } else { resultsDiv.innerHTML = '
' + '✘ Fehler: ' + (data.detail || 'Unbekannter Fehler') + '
'; } } catch (err) { resultsDiv.innerHTML = '
' + '✘ Netzwerkfehler: ' + err.message + '
'; } } // =================== // LOGS VIEWER // =================== function loadLogs() { const container = document.getElementById('logs-content'); const serviceFilter = document.getElementById('log-service-filter')?.value || ''; const levelFilter = document.getElementById('log-level-filter')?.value || ''; let url = '/api/v1/security/monitoring/logs?limit=50'; if (serviceFilter) url += '&service=' + serviceFilter; if (levelFilter) url += '&level=' + levelFilter; container.innerHTML = '
Lade Logs...
'; fetch(url) .then(res => res.json()) .then(logs => { if (logs.length === 0) { container.innerHTML = '

Keine Logs gefunden.

'; return; } let html = '
'; logs.forEach(log => { const levelClass = 'log-' + log.level.toLowerCase(); const time = new Date(log.timestamp).toLocaleTimeString('de-DE'); html += '
'; html += '' + time + ''; html += '' + log.level + ''; html += '[' + log.service + ']'; html += '' + log.message + ''; html += '
'; }); html += '
'; container.innerHTML = html; }) .catch(err => { container.innerHTML = '

Fehler: ' + err.message + '

'; }); } // =================== // METRICS DASHBOARD // =================== function loadMetrics() { const container = document.getElementById('metrics-content'); container.innerHTML = '
Lade Metriken...
'; fetch('/api/v1/security/monitoring/metrics') .then(res => res.json()) .then(metrics => { let html = '
'; metrics.forEach(metric => { const trendIcon = metric.trend === 'up' ? '▲' : (metric.trend === 'down' ? '▼' : '●'); const trendClass = metric.trend === 'up' ? 'trend-up' : (metric.trend === 'down' ? 'trend-down' : 'trend-stable'); html += '
'; html += '
' + metric.name + '
'; html += '
' + metric.value + ' ' + metric.unit + '
'; html += '
' + trendIcon + '
'; html += '
'; }); html += '
'; container.innerHTML = html; }) .catch(err => { container.innerHTML = '

Fehler: ' + err.message + '

'; }); } // =================== // CONTAINER STATUS // =================== function loadContainers() { const container = document.getElementById('containers-content'); container.innerHTML = '
Lade Container...
'; fetch('/api/v1/security/monitoring/containers') .then(res => res.json()) .then(containers => { let html = '
'; containers.forEach(c => { const healthClass = c.health === 'healthy' ? 'status-healthy' : 'status-unhealthy'; const statusIcon = c.health === 'healthy' ? '✔' : '✘'; html += '
'; html += '
'; html += '' + c.name + ''; html += '' + statusIcon + ' ' + c.status + ''; html += '
'; html += '
'; html += '
CPU' + c.cpu_percent + '%
'; html += '
Memory' + c.memory_mb + ' MB
'; html += '
Uptime' + c.uptime + '
'; html += '
'; html += '
'; }); html += '
'; container.innerHTML = html; }) .catch(err => { container.innerHTML = '

Fehler: ' + err.message + '

'; }); } // =================== // SERVICE HEALTH // =================== function loadServices() { const container = document.getElementById('services-content'); container.innerHTML = '
Pruefe Services...
'; fetch('/api/v1/security/monitoring/services') .then(res => res.json()) .then(services => { let html = '
'; services.forEach(svc => { const healthClass = svc.status === 'healthy' ? 'status-healthy' : 'status-unhealthy'; const statusIcon = svc.status === 'healthy' ? '✔' : '✘'; const responseClass = svc.response_time_ms < 100 ? 'response-fast' : (svc.response_time_ms < 500 ? 'response-medium' : 'response-slow'); html += '
'; html += '
'; html += '' + statusIcon + ''; html += '' + svc.name + ''; html += '
'; html += '
' + svc.url + '
'; html += '
' + svc.response_time_ms + 'ms
'; html += '
'; }); html += '
'; container.innerHTML = html; }) .catch(err => { container.innerHTML = '

Fehler: ' + err.message + '

'; }); } // Initialisierung beim Laden document.addEventListener('DOMContentLoaded', function() { // Theme aus localStorage laden const savedTheme = localStorage.getItem('dev-admin-theme'); if (savedTheme) { document.documentElement.setAttribute('data-theme', savedTheme); } // Security Dashboard initialisieren if (typeof SecurityDashboard !== 'undefined') { SecurityDashboard.init(); } }); """ @router.get("/dev-admin", response_class=HTMLResponse) def dev_admin_ui(): """ Rendert das Developer Admin Frontend. Enthaelt: - Security Dashboard (DevSecOps) - SBOM Viewer - Security Scans - Logs (geplant) - Metrics (geplant) - Container Status (geplant) - Service Health (geplant) """ # CSS zusammenfuegen all_css = get_dev_admin_css() + "\n" + SecurityModule.get_css() # Security-Modul HTML (ohne eigenen Container, wird in Panel eingebettet) security_html = SecurityModule.get_html() # JavaScript zusammenfuegen all_js = get_dev_admin_js() + "\n" + SecurityModule.get_js() # HTML Template fuellen html = get_dev_admin_html() html = html.replace("{css}", all_css) html = html.replace("{security_content}", security_html) html = html.replace("{js}", all_js) return html