This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/app/(admin)/infrastructure/sbom/page.tsx
BreakPilot Dev f09e24d52c refactor(admin-v2): Consolidate compliance/DSGVO pages into SDK pipeline
Remove duplicate compliance and DSGVO admin pages that have been superseded
by the unified SDK pipeline. Update navigation, sidebar, roles, and module
registry to reflect the new structure. Add DSFA corpus API proxy and
source-policy components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 23:26:05 +01:00

913 lines
61 KiB
TypeScript

'use client'
/**
* SBOM (Software Bill of Materials) Admin Page
*
* Migriert von /admin/sbom (website) nach /infrastructure/sbom (admin-v2)
*
* Displays:
* - All infrastructure components (Docker services)
* - Python/Go dependencies
* - Node.js packages
* - License information
* - Version tracking
*/
import { useState, useEffect } from 'react'
import Link from 'next/link'
import { PagePurpose } from '@/components/common/PagePurpose'
import { DevOpsPipelineSidebarResponsive } from '@/components/infrastructure/DevOpsPipelineSidebar'
interface Component {
type: string
name: string
version: string
purl?: string
licenses?: { license: { id: string } }[]
category?: string
port?: string
description?: string
license?: string
sourceUrl?: string
}
interface SBOMData {
bomFormat?: string
specVersion?: string
version?: number
metadata?: {
timestamp?: string
tools?: { vendor: string; name: string; version: string }[]
component?: { type: string; name: string; version: string }
}
components?: Component[]
}
type CategoryType = 'all' | 'infrastructure' | 'security-tools' | 'python' | 'go' | 'nodejs' | 'unity' | 'csharp'
type InfoTabType = 'audit' | 'documentation'
// Infrastructure components from docker-compose.yml and project analysis
const INFRASTRUCTURE_COMPONENTS: Component[] = [
// ===== DATABASES =====
{ type: 'service', name: 'PostgreSQL', version: '16-alpine', category: 'database', port: '5432', description: 'Hauptdatenbank', license: 'PostgreSQL', sourceUrl: 'https://github.com/postgres/postgres' },
{ type: 'service', name: 'Synapse PostgreSQL', version: '16-alpine', category: 'database', port: '-', description: 'Matrix Datenbank', license: 'PostgreSQL', sourceUrl: 'https://github.com/postgres/postgres' },
{ type: 'service', name: 'ERPNext MariaDB', version: '10.6', category: 'database', port: '-', description: 'ERPNext Datenbank', license: 'GPL-2.0', sourceUrl: 'https://github.com/MariaDB/server' },
{ type: 'service', name: 'MongoDB', version: '7.0', category: 'database', port: '27017', description: 'LibreChat Datenbank', license: 'SSPL-1.0', sourceUrl: 'https://github.com/mongodb/mongo' },
// ===== CACHE & QUEUE =====
{ type: 'service', name: 'Valkey', version: '8-alpine', category: 'cache', port: '6379', description: 'In-Memory Cache & Sessions (Redis OSS Fork)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/valkey-io/valkey' },
{ type: 'service', name: 'ERPNext Valkey Queue', version: 'alpine', category: 'cache', port: '-', description: 'Job Queue', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/valkey-io/valkey' },
{ type: 'service', name: 'ERPNext Valkey Cache', version: 'alpine', category: 'cache', port: '-', description: 'Cache Layer', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/valkey-io/valkey' },
// ===== SEARCH ENGINES =====
{ type: 'service', name: 'Qdrant', version: '1.7.4', category: 'search', port: '6333', description: 'Vector Database (RAG/Embeddings)', license: 'Apache-2.0', sourceUrl: 'https://github.com/qdrant/qdrant' },
{ type: 'service', name: 'OpenSearch', version: '2.x', category: 'search', port: '9200', description: 'Volltext-Suche (Elasticsearch Fork)', license: 'Apache-2.0', sourceUrl: 'https://github.com/opensearch-project/OpenSearch' },
{ type: 'service', name: 'Meilisearch', version: 'latest', category: 'search', port: '7700', description: 'Instant Search Engine', license: 'MIT', sourceUrl: 'https://github.com/meilisearch/meilisearch' },
// ===== OBJECT STORAGE =====
{ type: 'service', name: 'MinIO', version: 'latest', category: 'storage', port: '9000/9001', description: 'S3-kompatibel Object Storage', license: 'AGPL-3.0', sourceUrl: 'https://github.com/minio/minio' },
{ type: 'service', name: 'IPFS (Kubo)', version: '0.24', category: 'storage', port: '5001', description: 'Dezentrales Speichersystem', license: 'MIT/Apache-2.0', sourceUrl: 'https://github.com/ipfs/kubo' },
{ type: 'service', name: 'DSMS Gateway', version: '1.0', category: 'storage', port: '8082', description: 'IPFS REST API', license: 'Proprietary', sourceUrl: '-' },
// ===== SECURITY =====
{ type: 'service', name: 'HashiCorp Vault', version: '1.15', category: 'security', port: '8200', description: 'Secrets Management', license: 'BUSL-1.1', sourceUrl: 'https://github.com/hashicorp/vault' },
{ type: 'service', name: 'Keycloak', version: '23.0', category: 'security', port: '8180', description: 'Identity Provider (SSO/OIDC)', license: 'Apache-2.0', sourceUrl: 'https://github.com/keycloak/keycloak' },
{ type: 'service', name: 'NetBird', version: '0.64.5', category: 'security', port: '-', description: 'Zero-Trust Mesh VPN (WireGuard-basiert)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/netbirdio/netbird' },
// ===== COMMUNICATION =====
{ type: 'service', name: 'Matrix Synapse', version: 'latest', category: 'communication', port: '8008', description: 'E2EE Messenger Server', license: 'AGPL-3.0', sourceUrl: 'https://github.com/element-hq/synapse' },
{ type: 'service', name: 'Jitsi Web', version: 'stable-9823', category: 'communication', port: '8443', description: 'Videokonferenz UI', license: 'Apache-2.0', sourceUrl: 'https://github.com/jitsi/jitsi-meet' },
{ type: 'service', name: 'Jitsi Prosody (XMPP)', version: 'stable-9823', category: 'communication', port: '-', description: 'XMPP Server', license: 'MIT', sourceUrl: 'https://github.com/bjc/prosody' },
{ type: 'service', name: 'Jitsi Jicofo', version: 'stable-9823', category: 'communication', port: '-', description: 'Conference Focus Component', license: 'Apache-2.0', sourceUrl: 'https://github.com/jitsi/jicofo' },
{ type: 'service', name: 'Jitsi JVB', version: 'stable-9823', category: 'communication', port: '10000/udp', description: 'Videobridge (WebRTC SFU)', license: 'Apache-2.0', sourceUrl: 'https://github.com/jitsi/jitsi-videobridge' },
{ type: 'service', name: 'Jibri', version: 'stable-9823', category: 'communication', port: '-', description: 'Recording & Streaming Service', license: 'Apache-2.0', sourceUrl: 'https://github.com/jitsi/jibri' },
// ===== APPLICATION SERVICES (Python) =====
{ type: 'service', name: 'Python Backend (FastAPI)', version: '3.12', category: 'application', port: '8000', description: 'Haupt-Backend API, Studio & Alerts Agent', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Klausur Service', version: '1.0', category: 'application', port: '8086', description: 'Abitur-Klausurkorrektur (BYOEH)', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Compliance Module', version: '2.0', category: 'application', port: '8000', description: 'GRC Framework (19 Regulations, 558 Requirements, AI)', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Transcription Worker', version: '1.0', category: 'application', port: '-', description: 'Whisper + pyannote Transkription', license: 'Proprietary', sourceUrl: '-' },
// ===== APPLICATION SERVICES (Go) =====
{ type: 'service', name: 'Go Consent Service', version: '1.21', category: 'application', port: '8081', description: 'DSGVO Consent Management', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Go School Service', version: '1.21', category: 'application', port: '8084', description: 'Klausuren, Noten, Zeugnisse', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Go Billing Service', version: '1.21', category: 'application', port: '8083', description: 'Stripe Billing Integration', license: 'Proprietary', sourceUrl: '-' },
// ===== APPLICATION SERVICES (Node.js) =====
{ type: 'service', name: 'Next.js Admin Frontend', version: '15.1', category: 'application', port: '3000', description: 'Admin Dashboard (React)', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'H5P Content Service', version: 'latest', category: 'application', port: '8085', description: 'Interaktive Inhalte', license: 'MIT', sourceUrl: 'https://github.com/h5p/h5p-server' },
{ type: 'service', name: 'Policy Vault (NestJS)', version: '1.0', category: 'application', port: '3001', description: 'Richtlinien-Verwaltung API', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Policy Vault (Angular)', version: '17', category: 'application', port: '4200', description: 'Richtlinien-Verwaltung UI', license: 'Proprietary', sourceUrl: '-' },
// ===== APPLICATION SERVICES (Vue) =====
{ type: 'service', name: 'Creator Studio (Vue 3)', version: '3.4', category: 'application', port: '-', description: 'Content Creation UI', license: 'Proprietary', sourceUrl: '-' },
// ===== AI/LLM SERVICES =====
{ type: 'service', name: 'LibreChat', version: 'latest', category: 'ai', port: '3080', description: 'Multi-LLM Chat Interface', license: 'MIT', sourceUrl: 'https://github.com/danny-avila/LibreChat' },
{ type: 'service', name: 'RAGFlow', version: 'latest', category: 'ai', port: '9380', description: 'RAG Pipeline Service', license: 'Apache-2.0', sourceUrl: 'https://github.com/infiniflow/ragflow' },
// ===== ERP =====
{ type: 'service', name: 'ERPNext', version: 'v15', category: 'erp', port: '8090', description: 'Open Source ERP System', license: 'GPL-3.0', sourceUrl: 'https://github.com/frappe/erpnext' },
// ===== CI/CD & VERSION CONTROL =====
{ type: 'service', name: 'Woodpecker CI', version: '2.x', category: 'cicd', port: '8082', description: 'Self-hosted CI/CD Pipeline (Drone Fork)', license: 'Apache-2.0', sourceUrl: 'https://github.com/woodpecker-ci/woodpecker' },
{ type: 'service', name: 'Gitea', version: '1.21', category: 'cicd', port: '3003', description: 'Self-hosted Git Service', license: 'MIT', sourceUrl: 'https://github.com/go-gitea/gitea' },
{ type: 'service', name: 'Dokploy', version: '0.26.7', category: 'cicd', port: '3000', description: 'Self-hosted PaaS (Vercel/Heroku Alternative)', license: 'Apache-2.0', sourceUrl: 'https://github.com/Dokploy/dokploy' },
// ===== DEVELOPMENT =====
{ type: 'service', name: 'Mailpit', version: 'latest', category: 'development', port: '8025/1025', description: 'E-Mail Testing (SMTP Catch-All)', license: 'MIT', sourceUrl: 'https://github.com/axllent/mailpit' },
// ===== GAME (Breakpilot Drive) =====
{ type: 'service', name: 'Breakpilot Drive (Unity WebGL)', version: '6000.0', category: 'game', port: '3001', description: 'Lernspiel fuer Schueler (Klasse 2-6)', license: 'Proprietary', sourceUrl: '-' },
// ===== VOICE SERVICE =====
{ type: 'service', name: 'Voice Service (FastAPI)', version: '1.0', category: 'voice', port: '8091', description: 'Voice-First Interface mit PersonaPlex-7B & TaskOrchestrator', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'PersonaPlex-7B (NVIDIA)', version: '7B', category: 'voice', port: '8998', description: 'Full-Duplex Speech-to-Speech (Produktion)', license: 'MIT/NVIDIA Open Model', sourceUrl: 'https://developer.nvidia.com' },
{ type: 'service', name: 'TaskOrchestrator', version: '1.0', category: 'voice', port: '-', description: 'Agent-Orchestrierung mit Task State Machine', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'Mimi Audio Codec', version: '1.0', category: 'voice', port: '-', description: 'Audio Streaming (24kHz, 80ms Frames)', license: 'MIT', sourceUrl: '-' },
// ===== BQAS (Quality Assurance) =====
{ type: 'service', name: 'BQAS Local Scheduler', version: '1.0', category: 'qa', port: '-', description: 'Lokale GitHub Actions Alternative (launchd)', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'BQAS LLM Judge', version: '1.0', category: 'qa', port: '-', description: 'Qwen2.5-32B basierte Test-Bewertung', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'BQAS RAG Judge', version: '1.0', category: 'qa', port: '-', description: 'RAG/Korrektur Evaluierung', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'BQAS Notifier', version: '1.0', category: 'qa', port: '-', description: 'Desktop/Slack/Email Benachrichtigungen', license: 'Proprietary', sourceUrl: '-' },
{ type: 'service', name: 'BQAS Regression Tracker', version: '1.0', category: 'qa', port: '-', description: 'Score-Historie und Regression-Erkennung', license: 'Proprietary', sourceUrl: '-' },
]
// Security Tools discovered in project
const SECURITY_TOOLS: Component[] = [
{ type: 'tool', name: 'Trivy', version: 'latest', category: 'security-tool', description: 'Container Vulnerability Scanner', license: 'Apache-2.0', sourceUrl: 'https://github.com/aquasecurity/trivy' },
{ type: 'tool', name: 'Grype', version: 'latest', category: 'security-tool', description: 'SBOM Vulnerability Scanner', license: 'Apache-2.0', sourceUrl: 'https://github.com/anchore/grype' },
{ type: 'tool', name: 'Syft', version: 'latest', category: 'security-tool', description: 'SBOM Generator', license: 'Apache-2.0', sourceUrl: 'https://github.com/anchore/syft' },
{ type: 'tool', name: 'Gitleaks', version: 'latest', category: 'security-tool', description: 'Secrets Detection in Git', license: 'MIT', sourceUrl: 'https://github.com/gitleaks/gitleaks' },
{ type: 'tool', name: 'TruffleHog', version: '3.x', category: 'security-tool', description: 'Secrets Scanner (Regex/Entropy)', license: 'AGPL-3.0', sourceUrl: 'https://github.com/trufflesecurity/trufflehog' },
{ type: 'tool', name: 'Semgrep', version: 'latest', category: 'security-tool', description: 'SAST - Static Analysis', license: 'LGPL-2.1', sourceUrl: 'https://github.com/semgrep/semgrep' },
{ type: 'tool', name: 'Bandit', version: 'latest', category: 'security-tool', description: 'Python Security Linter', license: 'Apache-2.0', sourceUrl: 'https://github.com/PyCQA/bandit' },
{ type: 'tool', name: 'Gosec', version: 'latest', category: 'security-tool', description: 'Go Security Scanner', license: 'Apache-2.0', sourceUrl: 'https://github.com/securego/gosec' },
{ type: 'tool', name: 'govulncheck', version: 'latest', category: 'security-tool', description: 'Go Vulnerability Check', license: 'BSD-3-Clause', sourceUrl: 'https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck' },
{ type: 'tool', name: 'golangci-lint', version: 'latest', category: 'security-tool', description: 'Go Linter (Security Rules)', license: 'GPL-3.0', sourceUrl: 'https://github.com/golangci/golangci-lint' },
{ type: 'tool', name: 'npm audit', version: 'built-in', category: 'security-tool', description: 'Node.js Vulnerability Check', license: 'Artistic-2.0', sourceUrl: 'https://docs.npmjs.com/cli/commands/npm-audit' },
{ type: 'tool', name: 'pip-audit', version: 'latest', category: 'security-tool', description: 'Python Dependency Audit', license: 'Apache-2.0', sourceUrl: 'https://github.com/pypa/pip-audit' },
{ type: 'tool', name: 'safety', version: 'latest', category: 'security-tool', description: 'Python Safety Check', license: 'MIT', sourceUrl: 'https://github.com/pyupio/safety' },
{ type: 'tool', name: 'CodeQL', version: 'latest', category: 'security-tool', description: 'GitHub Security Analysis', license: 'MIT', sourceUrl: 'https://github.com/github/codeql' },
]
// Key Python packages (from requirements.txt)
const PYTHON_PACKAGES: Component[] = [
{ type: 'library', name: 'FastAPI', version: '0.109+', category: 'python', description: 'Web Framework', license: 'MIT', sourceUrl: 'https://github.com/tiangolo/fastapi' },
{ type: 'library', name: 'Uvicorn', version: '0.38+', category: 'python', description: 'ASGI Server', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/encode/uvicorn' },
{ type: 'library', name: 'Starlette', version: '0.49+', category: 'python', description: 'ASGI Framework (FastAPI Basis)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/encode/starlette' },
{ type: 'library', name: 'Pydantic', version: '2.x', category: 'python', description: 'Data Validation', license: 'MIT', sourceUrl: 'https://github.com/pydantic/pydantic' },
{ type: 'library', name: 'SQLAlchemy', version: '2.x', category: 'python', description: 'ORM', license: 'MIT', sourceUrl: 'https://github.com/sqlalchemy/sqlalchemy' },
{ type: 'library', name: 'Alembic', version: '1.14+', category: 'python', description: 'DB Migrations (Classroom, Feedback Tables)', license: 'MIT', sourceUrl: 'https://github.com/sqlalchemy/alembic' },
{ type: 'library', name: 'psycopg2-binary', version: '2.9+', category: 'python', description: 'PostgreSQL Driver', license: 'LGPL-3.0', sourceUrl: 'https://github.com/psycopg/psycopg2' },
{ type: 'library', name: 'httpx', version: 'latest', category: 'python', description: 'Async HTTP Client', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/encode/httpx' },
{ type: 'library', name: 'PyJWT', version: 'latest', category: 'python', description: 'JWT Handling', license: 'MIT', sourceUrl: 'https://github.com/jpadilla/pyjwt' },
{ type: 'library', name: 'hvac', version: 'latest', category: 'python', description: 'Vault Client', license: 'Apache-2.0', sourceUrl: 'https://github.com/hvac/hvac' },
{ type: 'library', name: 'python-multipart', version: 'latest', category: 'python', description: 'File Uploads', license: 'Apache-2.0', sourceUrl: 'https://github.com/andrew-d/python-multipart' },
{ type: 'library', name: 'aiofiles', version: 'latest', category: 'python', description: 'Async File I/O', license: 'Apache-2.0', sourceUrl: 'https://github.com/Tinche/aiofiles' },
{ type: 'library', name: 'openai', version: 'latest', category: 'python', description: 'OpenAI SDK', license: 'MIT', sourceUrl: 'https://github.com/openai/openai-python' },
{ type: 'library', name: 'anthropic', version: 'latest', category: 'python', description: 'Anthropic Claude SDK', license: 'MIT', sourceUrl: 'https://github.com/anthropics/anthropic-sdk-python' },
{ type: 'library', name: 'langchain', version: 'latest', category: 'python', description: 'LLM Framework', license: 'MIT', sourceUrl: 'https://github.com/langchain-ai/langchain' },
{ type: 'library', name: 'aioimaplib', version: 'latest', category: 'python', description: 'Async IMAP Client (Unified Inbox)', license: 'MIT', sourceUrl: 'https://github.com/bamthomas/aioimaplib' },
{ type: 'library', name: 'aiosmtplib', version: 'latest', category: 'python', description: 'Async SMTP Client (Mail Sending)', license: 'MIT', sourceUrl: 'https://github.com/cole/aiosmtplib' },
{ type: 'library', name: 'email-validator', version: 'latest', category: 'python', description: 'Email Validation', license: 'CC0-1.0', sourceUrl: 'https://github.com/JoshData/python-email-validator' },
{ type: 'library', name: 'cryptography', version: 'latest', category: 'python', description: 'Encryption (Mail Credentials)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/pyca/cryptography' },
{ type: 'library', name: 'asyncpg', version: 'latest', category: 'python', description: 'Async PostgreSQL Driver', license: 'Apache-2.0', sourceUrl: 'https://github.com/MagicStack/asyncpg' },
{ type: 'library', name: 'python-dateutil', version: 'latest', category: 'python', description: 'Date Parsing (Deadline Extraction)', license: 'Apache-2.0', sourceUrl: 'https://github.com/dateutil/dateutil' },
{ type: 'library', name: 'faster-whisper', version: '1.0+', category: 'python', description: 'CTranslate2 Whisper (GPU-optimiert)', license: 'MIT', sourceUrl: 'https://github.com/SYSTRAN/faster-whisper' },
{ type: 'library', name: 'pyannote.audio', version: '3.x', category: 'python', description: 'Speaker Diarization', license: 'MIT', sourceUrl: 'https://github.com/pyannote/pyannote-audio' },
{ type: 'library', name: 'rq', version: '1.x', category: 'python', description: 'Redis Queue (Task Processing)', license: 'BSD-2-Clause', sourceUrl: 'https://github.com/rq/rq' },
{ type: 'library', name: 'ffmpeg-python', version: '0.2+', category: 'python', description: 'FFmpeg Python Bindings', license: 'Apache-2.0', sourceUrl: 'https://github.com/kkroening/ffmpeg-python' },
{ type: 'library', name: 'webvtt-py', version: '0.4+', category: 'python', description: 'WebVTT Subtitle Export', license: 'MIT', sourceUrl: 'https://github.com/glut23/webvtt-py' },
{ type: 'library', name: 'minio', version: '7.x', category: 'python', description: 'MinIO S3 Client', license: 'Apache-2.0', sourceUrl: 'https://github.com/minio/minio-py' },
{ type: 'library', name: 'structlog', version: '24.x', category: 'python', description: 'Structured Logging', license: 'Apache-2.0', sourceUrl: 'https://github.com/hynek/structlog' },
{ type: 'library', name: 'feedparser', version: '6.x', category: 'python', description: 'RSS/Atom Feed Parser (Alerts Agent)', license: 'BSD-2-Clause', sourceUrl: 'https://github.com/kurtmckee/feedparser' },
{ type: 'library', name: 'APScheduler', version: '3.x', category: 'python', description: 'AsyncIO Job Scheduler (Alerts Agent)', license: 'MIT', sourceUrl: 'https://github.com/agronholm/apscheduler' },
{ type: 'library', name: 'beautifulsoup4', version: '4.x', category: 'python', description: 'HTML Parser (Email Parsing, Compliance Scraper)', license: 'MIT', sourceUrl: 'https://code.launchpad.net/beautifulsoup' },
{ type: 'library', name: 'lxml', version: '5.x', category: 'python', description: 'XML/HTML Parser (EUR-Lex Scraping)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/lxml/lxml' },
{ type: 'library', name: 'PyMuPDF', version: '1.24+', category: 'python', description: 'PDF Parser (BSI-TR Extraction)', license: 'AGPL-3.0', sourceUrl: 'https://github.com/pymupdf/PyMuPDF' },
{ type: 'library', name: 'pdfplumber', version: '0.11+', category: 'python', description: 'PDF Table Extraction (Compliance Docs)', license: 'MIT', sourceUrl: 'https://github.com/jsvine/pdfplumber' },
{ type: 'library', name: 'websockets', version: '14.x', category: 'python', description: 'WebSocket Support (Voice Streaming)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/python-websockets/websockets' },
{ type: 'library', name: 'soundfile', version: '0.13+', category: 'python', description: 'Audio File Processing (Voice Service)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/bastibe/python-soundfile' },
{ type: 'library', name: 'scipy', version: '1.14+', category: 'python', description: 'Signal Processing (Audio)', license: 'BSD-3-Clause', sourceUrl: 'https://github.com/scipy/scipy' },
{ type: 'library', name: 'redis', version: '5.x', category: 'python', description: 'Valkey/Redis Client (Voice Sessions)', license: 'MIT', sourceUrl: 'https://github.com/redis/redis-py' },
{ type: 'library', name: 'pydantic-settings', version: '2.x', category: 'python', description: 'Settings Management (Voice Config)', license: 'MIT', sourceUrl: 'https://github.com/pydantic/pydantic-settings' },
]
// Key Go modules (from go.mod files)
const GO_MODULES: Component[] = [
{ type: 'library', name: 'gin-gonic/gin', version: '1.9+', category: 'go', description: 'Web Framework', license: 'MIT', sourceUrl: 'https://github.com/gin-gonic/gin' },
{ type: 'library', name: 'gorm.io/gorm', version: '1.25+', category: 'go', description: 'ORM', license: 'MIT', sourceUrl: 'https://github.com/go-gorm/gorm' },
{ type: 'library', name: 'golang-jwt/jwt', version: 'v5', category: 'go', description: 'JWT Library', license: 'MIT', sourceUrl: 'https://github.com/golang-jwt/jwt' },
{ type: 'library', name: 'stripe/stripe-go', version: 'v76', category: 'go', description: 'Stripe SDK', license: 'MIT', sourceUrl: 'https://github.com/stripe/stripe-go' },
{ type: 'library', name: 'spf13/viper', version: 'latest', category: 'go', description: 'Configuration', license: 'MIT', sourceUrl: 'https://github.com/spf13/viper' },
{ type: 'library', name: 'uber-go/zap', version: 'latest', category: 'go', description: 'Structured Logging', license: 'MIT', sourceUrl: 'https://github.com/uber-go/zap' },
{ type: 'library', name: 'swaggo/swag', version: 'latest', category: 'go', description: 'Swagger Docs', license: 'MIT', sourceUrl: 'https://github.com/swaggo/swag' },
]
// Key Node.js packages (from package.json files)
const NODE_PACKAGES: Component[] = [
{ type: 'library', name: 'Next.js', version: '15.1', category: 'nodejs', description: 'React Framework', license: 'MIT', sourceUrl: 'https://github.com/vercel/next.js' },
{ type: 'library', name: 'React', version: '19', category: 'nodejs', description: 'UI Library', license: 'MIT', sourceUrl: 'https://github.com/facebook/react' },
{ type: 'library', name: 'Vue.js', version: '3.4', category: 'nodejs', description: 'UI Framework (Creator Studio)', license: 'MIT', sourceUrl: 'https://github.com/vuejs/core' },
{ type: 'library', name: 'Angular', version: '17', category: 'nodejs', description: 'UI Framework (Policy Vault)', license: 'MIT', sourceUrl: 'https://github.com/angular/angular' },
{ type: 'library', name: 'NestJS', version: '10', category: 'nodejs', description: 'Node.js Framework', license: 'MIT', sourceUrl: 'https://github.com/nestjs/nest' },
{ type: 'library', name: 'TypeScript', version: '5.x', category: 'nodejs', description: 'Type System', license: 'Apache-2.0', sourceUrl: 'https://github.com/microsoft/TypeScript' },
{ type: 'library', name: 'Tailwind CSS', version: '3.4', category: 'nodejs', description: 'Utility CSS', license: 'MIT', sourceUrl: 'https://github.com/tailwindlabs/tailwindcss' },
{ type: 'library', name: 'Prisma', version: '5.x', category: 'nodejs', description: 'ORM (Policy Vault)', license: 'Apache-2.0', sourceUrl: 'https://github.com/prisma/prisma' },
{ type: 'library', name: 'Material Design Icons', version: 'latest', category: 'nodejs', description: 'Icon-System (Companion UI, Studio)', license: 'Apache-2.0', sourceUrl: 'https://github.com/google/material-design-icons' },
{ type: 'library', name: 'Recharts', version: '2.12', category: 'nodejs', description: 'React Charts (Compliance Dashboard)', license: 'MIT', sourceUrl: 'https://github.com/recharts/recharts' },
{ type: 'library', name: 'React Flow', version: '11.x', category: 'nodejs', description: 'Node-basierte Flow-Diagramme (Screen Flow)', license: 'MIT', sourceUrl: 'https://github.com/xyflow/xyflow' },
{ type: 'library', name: 'Playwright', version: '1.50', category: 'nodejs', description: 'E2E Testing Framework (SDK Tests)', license: 'Apache-2.0', sourceUrl: 'https://github.com/microsoft/playwright' },
{ type: 'library', name: 'Vitest', version: '4.x', category: 'nodejs', description: 'Unit Testing Framework', license: 'MIT', sourceUrl: 'https://github.com/vitest-dev/vitest' },
{ type: 'library', name: 'jsPDF', version: '4.x', category: 'nodejs', description: 'PDF Generation (SDK Export)', license: 'MIT', sourceUrl: 'https://github.com/parallax/jsPDF' },
{ type: 'library', name: 'JSZip', version: '3.x', category: 'nodejs', description: 'ZIP File Creation (SDK Export)', license: 'MIT/GPL-3.0', sourceUrl: 'https://github.com/Stuk/jszip' },
{ type: 'library', name: 'Lucide React', version: '0.468', category: 'nodejs', description: 'Icon Library', license: 'ISC', sourceUrl: 'https://github.com/lucide-icons/lucide' },
]
// Unity packages (Breakpilot Drive game engine)
const UNITY_PACKAGES: Component[] = [
{ type: 'library', name: 'Unity Engine', version: '6000.0 (Unity 6)', category: 'unity', description: 'Game Engine', license: 'Unity EULA', sourceUrl: 'https://unity.com' },
{ type: 'library', name: 'Universal Render Pipeline (URP)', version: '17.x', category: 'unity', description: 'Render Pipeline', license: 'Unity Companion', sourceUrl: 'https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@17.0' },
{ type: 'library', name: 'TextMeshPro', version: '3.2', category: 'unity', description: 'Advanced Text Rendering', license: 'Unity Companion', sourceUrl: 'https://docs.unity3d.com/Packages/com.unity.textmeshpro@3.2' },
{ type: 'library', name: 'Unity Mathematics', version: '1.3', category: 'unity', description: 'Math Library (SIMD)', license: 'Unity Companion', sourceUrl: 'https://docs.unity3d.com/Packages/com.unity.mathematics@1.3' },
{ type: 'library', name: 'Newtonsoft.Json (Unity)', version: '3.2', category: 'unity', description: 'JSON Serialization', license: 'MIT', sourceUrl: 'https://docs.unity3d.com/Packages/com.unity.nuget.newtonsoft-json@3.2' },
{ type: 'library', name: 'Unity UI', version: '2.0', category: 'unity', description: 'UI System', license: 'Unity Companion', sourceUrl: 'https://docs.unity3d.com/Packages/com.unity.ugui@2.0' },
{ type: 'library', name: 'Unity Input System', version: '1.8', category: 'unity', description: 'New Input System', license: 'Unity Companion', sourceUrl: 'https://docs.unity3d.com/Packages/com.unity.inputsystem@1.8' },
]
// C# dependencies (Breakpilot Drive)
const CSHARP_PACKAGES: Component[] = [
{ type: 'library', name: '.NET Standard', version: '2.1', category: 'csharp', description: 'Runtime', license: 'MIT', sourceUrl: 'https://github.com/dotnet/standard' },
{ type: 'library', name: 'UnityWebRequest', version: 'built-in', category: 'csharp', description: 'HTTP Client', license: 'Unity Companion', sourceUrl: '-' },
{ type: 'library', name: 'System.Text.Json', version: 'built-in', category: 'csharp', description: 'JSON Parsing', license: 'MIT', sourceUrl: 'https://github.com/dotnet/runtime' },
]
export default function SBOMPage() {
const [sbomData, setSbomData] = useState<SBOMData | null>(null)
const [loading, setLoading] = useState(true)
const [activeCategory, setActiveCategory] = useState<CategoryType>('all')
const [searchTerm, setSearchTerm] = useState('')
const [activeInfoTab, setActiveInfoTab] = useState<InfoTabType>('audit')
const [showFullDocs, setShowFullDocs] = useState(false)
useEffect(() => {
loadSBOM()
}, [])
const loadSBOM = async () => {
setLoading(true)
try {
const res = await fetch('/api/v1/security/sbom')
if (res.ok) {
const data = await res.json()
setSbomData(data)
}
} catch (error) {
console.error('Failed to load SBOM:', error)
} finally {
setLoading(false)
}
}
const getAllComponents = (): Component[] => {
const infraComponents = INFRASTRUCTURE_COMPONENTS.map(c => ({
...c,
category: c.category || 'infrastructure'
}))
const securityToolsComponents = SECURITY_TOOLS.map(c => ({
...c,
category: c.category || 'security-tool'
}))
const pythonComponents = PYTHON_PACKAGES.map(c => ({
...c,
category: 'python'
}))
const goComponents = GO_MODULES.map(c => ({
...c,
category: 'go'
}))
const nodeComponents = NODE_PACKAGES.map(c => ({
...c,
category: 'nodejs'
}))
const unityComponents = UNITY_PACKAGES.map(c => ({
...c,
category: 'unity'
}))
const csharpComponents = CSHARP_PACKAGES.map(c => ({
...c,
category: 'csharp'
}))
// Add dynamic SBOM data from backend if available
const dynamicPython = (sbomData?.components || []).map(c => ({
...c,
category: 'python'
}))
return [...infraComponents, ...securityToolsComponents, ...pythonComponents, ...goComponents, ...nodeComponents, ...unityComponents, ...csharpComponents, ...dynamicPython]
}
const getFilteredComponents = () => {
let components = getAllComponents()
if (activeCategory !== 'all') {
if (activeCategory === 'infrastructure') {
components = INFRASTRUCTURE_COMPONENTS
} else if (activeCategory === 'security-tools') {
components = SECURITY_TOOLS
} else if (activeCategory === 'python') {
components = [...PYTHON_PACKAGES, ...(sbomData?.components || [])]
} else if (activeCategory === 'go') {
components = GO_MODULES
} else if (activeCategory === 'nodejs') {
components = NODE_PACKAGES
} else if (activeCategory === 'unity') {
components = UNITY_PACKAGES
} else if (activeCategory === 'csharp') {
components = CSHARP_PACKAGES
}
}
if (searchTerm) {
components = components.filter(c =>
c.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
c.version.toLowerCase().includes(searchTerm.toLowerCase()) ||
(c.description?.toLowerCase().includes(searchTerm.toLowerCase()))
)
}
return components
}
const getCategoryColor = (category?: string) => {
switch (category) {
case 'database': return 'bg-blue-100 text-blue-800'
case 'security': return 'bg-purple-100 text-purple-800'
case 'security-tool': return 'bg-red-100 text-red-800'
case 'application': return 'bg-green-100 text-green-800'
case 'communication': return 'bg-yellow-100 text-yellow-800'
case 'storage': return 'bg-orange-100 text-orange-800'
case 'search': return 'bg-pink-100 text-pink-800'
case 'erp': return 'bg-indigo-100 text-indigo-800'
case 'cache': return 'bg-cyan-100 text-cyan-800'
case 'ai': return 'bg-violet-100 text-violet-800'
case 'development': return 'bg-gray-100 text-gray-800'
case 'cicd': return 'bg-orange-100 text-orange-800'
case 'python': return 'bg-emerald-100 text-emerald-800'
case 'go': return 'bg-sky-100 text-sky-800'
case 'nodejs': return 'bg-lime-100 text-lime-800'
case 'unity': return 'bg-amber-100 text-amber-800'
case 'csharp': return 'bg-fuchsia-100 text-fuchsia-800'
case 'game': return 'bg-rose-100 text-rose-800'
case 'voice': return 'bg-teal-100 text-teal-800'
case 'qa': return 'bg-blue-100 text-blue-800'
default: return 'bg-slate-100 text-slate-800'
}
}
const getLicenseColor = (license?: string) => {
if (!license) return 'bg-gray-100 text-gray-600'
if (license.includes('MIT')) return 'bg-green-100 text-green-700'
if (license.includes('Apache')) return 'bg-blue-100 text-blue-700'
if (license.includes('BSD')) return 'bg-cyan-100 text-cyan-700'
if (license.includes('GPL') || license.includes('LGPL')) return 'bg-orange-100 text-orange-700'
return 'bg-gray-100 text-gray-600'
}
const stats = {
totalInfra: INFRASTRUCTURE_COMPONENTS.length,
totalSecurityTools: SECURITY_TOOLS.length,
totalPython: PYTHON_PACKAGES.length + (sbomData?.components?.length || 0),
totalGo: GO_MODULES.length,
totalNode: NODE_PACKAGES.length,
totalUnity: UNITY_PACKAGES.length,
totalCsharp: CSHARP_PACKAGES.length,
totalAll: INFRASTRUCTURE_COMPONENTS.length + SECURITY_TOOLS.length + PYTHON_PACKAGES.length + GO_MODULES.length + NODE_PACKAGES.length + UNITY_PACKAGES.length + CSHARP_PACKAGES.length + (sbomData?.components?.length || 0),
databases: INFRASTRUCTURE_COMPONENTS.filter(c => c.category === 'database').length,
services: INFRASTRUCTURE_COMPONENTS.filter(c => c.category === 'application').length,
communication: INFRASTRUCTURE_COMPONENTS.filter(c => c.category === 'communication').length,
game: INFRASTRUCTURE_COMPONENTS.filter(c => c.category === 'game').length,
}
const categories = [
{ id: 'all', name: 'Alle', count: stats.totalAll },
{ id: 'infrastructure', name: 'Infrastruktur', count: stats.totalInfra },
{ id: 'security-tools', name: 'Security Tools', count: stats.totalSecurityTools },
{ id: 'python', name: 'Python', count: stats.totalPython },
{ id: 'go', name: 'Go', count: stats.totalGo },
{ id: 'nodejs', name: 'Node.js', count: stats.totalNode },
{ id: 'unity', name: 'Unity', count: stats.totalUnity },
{ id: 'csharp', name: 'C#', count: stats.totalCsharp },
]
const filteredComponents = getFilteredComponents()
return (
<div>
<PagePurpose
title="SBOM"
purpose="Software Bill of Materials - Alle Komponenten & Abhaengigkeiten der Breakpilot-Plattform. Wichtig fuer Supply-Chain-Security, Compliance-Audits und Lizenz-Pruefung."
audience={['DevOps', 'Compliance', 'Security', 'Auditoren']}
gdprArticles={['Art. 32 (Sicherheit der Verarbeitung)']}
architecture={{
services: ['Syft (SBOM Generator)', 'Trivy (CVE Scanner)'],
databases: ['CycloneDX JSON'],
}}
relatedPages={[
{ name: 'Security', href: '/infrastructure/security', description: 'DevSecOps Dashboard' },
{ name: 'Controls', href: '/sdk/controls', description: 'Security Controls' },
]}
collapsible={true}
defaultCollapsed={true}
/>
{/* DevOps Pipeline Sidebar */}
<DevOpsPipelineSidebarResponsive currentTool="sbom" />
{/* Wizard Link */}
<div className="mb-6 flex justify-end">
<Link
href="/infrastructure/sbom/wizard"
className="flex items-center gap-2 px-4 py-2 rounded-lg font-medium bg-purple-100 text-purple-700 border border-purple-200 hover:bg-purple-200 transition-colors"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
Lern-Wizard
</Link>
</div>
{/* Stats Cards */}
<div className="grid grid-cols-2 md:grid-cols-5 lg:grid-cols-10 gap-4 mb-6">
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-slate-800">{stats.totalAll}</div>
<div className="text-sm text-slate-500">Komponenten Total</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-purple-600">{stats.totalInfra}</div>
<div className="text-sm text-slate-500">Docker Services</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-red-600">{stats.totalSecurityTools}</div>
<div className="text-sm text-slate-500">Security Tools</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-emerald-600">{stats.totalPython}</div>
<div className="text-sm text-slate-500">Python</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-sky-600">{stats.totalGo}</div>
<div className="text-sm text-slate-500">Go</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-lime-600">{stats.totalNode}</div>
<div className="text-sm text-slate-500">Node.js</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-amber-600">{stats.totalUnity}</div>
<div className="text-sm text-slate-500">Unity</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-fuchsia-600">{stats.totalCsharp}</div>
<div className="text-sm text-slate-500">C#</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-blue-600">{stats.databases}</div>
<div className="text-sm text-slate-500">Datenbanken</div>
</div>
<div className="bg-white rounded-lg shadow p-4">
<div className="text-3xl font-bold text-rose-600">{stats.game}</div>
<div className="text-sm text-slate-500">Game</div>
</div>
</div>
{/* Filters */}
<div className="bg-white rounded-lg shadow p-4 mb-6">
<div className="flex flex-col md:flex-row gap-4 items-center justify-between">
{/* Category Tabs */}
<div className="flex flex-wrap gap-2">
{categories.map((cat) => (
<button
key={cat.id}
onClick={() => setActiveCategory(cat.id as CategoryType)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
activeCategory === cat.id
? 'bg-orange-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
{cat.name} ({cat.count})
</button>
))}
</div>
{/* Search */}
<div className="relative w-full md:w-64">
<input
type="text"
placeholder="Suchen..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-transparent"
/>
<svg className="absolute left-3 top-2.5 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
</div>
</div>
{/* SBOM Metadata */}
{sbomData?.metadata && (
<div className="bg-slate-50 rounded-lg p-4 mb-6 text-sm">
<div className="flex flex-wrap gap-6">
<div>
<span className="text-slate-500">Format:</span>
<span className="ml-2 font-medium">{sbomData.bomFormat} {sbomData.specVersion}</span>
</div>
<div>
<span className="text-slate-500">Generiert:</span>
<span className="ml-2 font-medium">
{sbomData.metadata.timestamp ? new Date(sbomData.metadata.timestamp).toLocaleString('de-DE') : '-'}
</span>
</div>
<div>
<span className="text-slate-500">Anwendung:</span>
<span className="ml-2 font-medium">
{sbomData.metadata.component?.name} v{sbomData.metadata.component?.version}
</span>
</div>
</div>
</div>
)}
{/* Components Table */}
{loading ? (
<div className="flex items-center justify-center py-12">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-orange-600"></div>
<span className="ml-3 text-gray-600">Lade SBOM...</span>
</div>
) : (
<div className="bg-white rounded-lg shadow overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Komponente</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Version</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kategorie</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider min-w-[300px]">Verwendungszweck</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Port</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lizenz</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{filteredComponents.map((component, idx) => {
// Get license from either the new license field or the old licenses array
const licenseId = component.license || component.licenses?.[0]?.license?.id
return (
<tr key={idx} className="hover:bg-gray-50">
<td className="px-4 py-4">
<div className="text-sm font-medium text-gray-900">{component.name}</div>
</td>
<td className="px-4 py-4 whitespace-nowrap">
<span className="text-sm font-mono text-gray-900">{component.version}</span>
</td>
<td className="px-4 py-4 whitespace-nowrap">
<span className={`px-2 py-1 text-xs font-medium rounded ${getCategoryColor(component.category)}`}>
{component.category || component.type}
</span>
</td>
<td className="px-4 py-4">
{component.description ? (
<div className="text-sm text-gray-600 leading-relaxed">{component.description}</div>
) : (
<span className="text-sm text-gray-400 italic">Keine Beschreibung</span>
)}
</td>
<td className="px-4 py-4 whitespace-nowrap">
{component.port ? (
<span className="text-sm font-mono text-gray-600">{component.port}</span>
) : (
<span className="text-sm text-gray-400">-</span>
)}
</td>
<td className="px-4 py-4 whitespace-nowrap">
{licenseId ? (
<span className={`px-2 py-1 text-xs font-medium rounded ${getLicenseColor(licenseId)}`}>
{licenseId}
</span>
) : (
<span className="text-sm text-gray-400">-</span>
)}
</td>
<td className="px-4 py-4 whitespace-nowrap">
{component.sourceUrl && component.sourceUrl !== '-' ? (
<a
href={component.sourceUrl}
target="_blank"
rel="noopener noreferrer"
className="text-orange-600 hover:text-orange-800 text-sm flex items-center gap-1"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
GitHub
</a>
) : (
<span className="text-sm text-gray-400">-</span>
)}
</td>
</tr>
)
})}
</tbody>
</table>
{filteredComponents.length === 0 && (
<div className="p-8 text-center text-gray-500">
Keine Komponenten gefunden.
</div>
)}
</div>
)}
{/* Export Button */}
<div className="mt-6 flex justify-end">
<button
onClick={() => {
const data = JSON.stringify({
...sbomData,
infrastructure: INFRASTRUCTURE_COMPONENTS
}, null, 2)
const blob = new Blob([data], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `breakpilot-sbom-${new Date().toISOString().split('T')[0]}.json`
a.click()
}}
className="px-4 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition-colors flex items-center gap-2"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
SBOM exportieren (JSON)
</button>
</div>
{/* Info Tabs Section */}
<div className="mt-8">
<div className="bg-white rounded-lg shadow">
{/* Tab Headers */}
<div className="border-b border-gray-200">
<nav className="flex -mb-px">
<button
onClick={() => setActiveInfoTab('audit')}
className={`px-6 py-4 text-sm font-medium border-b-2 transition-colors ${
activeInfoTab === 'audit'
? 'border-orange-500 text-orange-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
<span className="flex items-center gap-2">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Audit
</span>
</button>
<button
onClick={() => setActiveInfoTab('documentation')}
className={`px-6 py-4 text-sm font-medium border-b-2 transition-colors ${
activeInfoTab === 'documentation'
? 'border-orange-500 text-orange-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
<span className="flex items-center gap-2">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Dokumentation
</span>
</button>
</nav>
</div>
{/* Tab Content */}
<div className="p-6">
{/* Audit Tab */}
{activeInfoTab === 'audit' && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* SBOM Status */}
<div className="bg-slate-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-slate-800 mb-4 flex items-center gap-2">
<svg className="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
SBOM Status
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Letzte Generierung</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">CI/CD</span>
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Format</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">CycloneDX 1.5</span>
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Komponenten</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">Alle erfasst</span>
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Transitive Deps</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">Inkludiert</span>
</span>
</div>
</div>
</div>
{/* License Compliance */}
<div className="bg-slate-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-slate-800 mb-4 flex items-center gap-2">
<svg className="w-5 h-5 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 6l3 1m0 0l-3 9a5.002 5.002 0 006.001 0M6 7l3 9M6 7l6-2m6 2l3-1m-3 1l-3 9a5.002 5.002 0 006.001 0M18 7l3 9m-3-9l-6-2m0-2v2m0 16V5m0 16H9m3 0h3" />
</svg>
License Compliance
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Erlaubte Lizenzen</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">MIT, Apache, BSD</span>
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Copyleft (GPL)</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">0</span>
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Unbekannte Lizenzen</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
<span className="text-sm font-medium">0</span>
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-600">Kommerzielle</span>
<span className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-yellow-500"></span>
<span className="text-sm font-medium">Review erforderlich</span>
</span>
</div>
</div>
</div>
</div>
)}
{/* Documentation Tab */}
{activeInfoTab === 'documentation' && (
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold text-slate-800">SBOM Dokumentation</h3>
<button
onClick={() => setShowFullDocs(!showFullDocs)}
className="px-4 py-2 bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 transition-colors flex items-center gap-2"
>
<svg className={`w-4 h-4 transition-transform ${showFullDocs ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
{showFullDocs ? 'Weniger anzeigen' : 'Vollstaendige Dokumentation'}
</button>
</div>
{!showFullDocs ? (
<div className="prose prose-slate max-w-none">
<p className="text-slate-600">
Das SBOM-Modul generiert und analysiert die vollstaendige Komponentenliste aller Software-Abhaengigkeiten.
Es dient der Compliance, Sicherheit und Supply-Chain-Transparenz.
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
<div className="bg-blue-50 p-4 rounded-lg">
<h4 className="font-medium text-blue-800 mb-2">Generator</h4>
<p className="text-sm text-blue-600">Syft (Primary), Trivy (Validation)</p>
</div>
<div className="bg-purple-50 p-4 rounded-lg">
<h4 className="font-medium text-purple-800 mb-2">Format</h4>
<p className="text-sm text-purple-600">CycloneDX 1.5, SPDX</p>
</div>
<div className="bg-green-50 p-4 rounded-lg">
<h4 className="font-medium text-green-800 mb-2">Retention</h4>
<p className="text-sm text-green-600">5 Jahre (Compliance)</p>
</div>
</div>
</div>
) : (
<div className="prose prose-slate max-w-none bg-slate-50 p-6 rounded-lg overflow-auto max-h-[600px]">
<h2>Software Bill of Materials (SBOM)</h2>
<h3>1. Uebersicht</h3>
<p>Das SBOM-Modul generiert und analysiert die vollstaendige Komponentenliste aller Software-Abhaengigkeiten. Es dient der Compliance, Sicherheit und Supply-Chain-Transparenz.</p>
<h3>2. SBOM-Generierung</h3>
<pre className="bg-slate-800 text-slate-100 p-4 rounded-lg overflow-x-auto text-sm">
{`Source Code
v
┌───────────────────────────────────────────────────────────────┐
│ SBOM Generators │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Syft │ │ Trivy │ │ Native Tooling │ │
│ │ (Primary) │ │ (Validation)│ │ (npm, go mod, pip) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
└─────────┼────────────────┼────────────────────┼───────────────┘
│ │ │
└────────────────┴────────────────────┘
v
┌────────────────┐
│ CycloneDX │
│ Format │
└────────────────┘`}
</pre>
<h3>3. Erfasste Komponenten</h3>
<table className="min-w-full">
<thead>
<tr>
<th className="text-left">Typ</th>
<th className="text-left">Quelle</th>
<th className="text-left">Beispiele</th>
</tr>
</thead>
<tbody>
<tr><td>npm packages</td><td>package-lock.json</td><td>react, next, tailwindcss</td></tr>
<tr><td>Go modules</td><td>go.sum</td><td>gin, gorm, jwt-go</td></tr>
<tr><td>Python packages</td><td>requirements.txt</td><td>fastapi, pydantic, httpx</td></tr>
<tr><td>Container Images</td><td>Dockerfile</td><td>node:20-alpine, postgres:16</td></tr>
<tr><td>OS Packages</td><td>apk, apt</td><td>openssl, libpq</td></tr>
</tbody>
</table>
<h3>4. License Compliance</h3>
<table className="min-w-full">
<thead>
<tr>
<th className="text-left">Kategorie</th>
<th className="text-left">Lizenzen</th>
<th className="text-left">Status</th>
</tr>
</thead>
<tbody>
<tr><td>Permissive (erlaubt)</td><td>MIT, Apache 2.0, BSD, ISC</td><td className="text-green-600">OK</td></tr>
<tr><td>Weak Copyleft</td><td>LGPL, MPL</td><td className="text-yellow-600">Review</td></tr>
<tr><td>Strong Copyleft</td><td>GPL, AGPL</td><td className="text-red-600">Nicht erlaubt</td></tr>
<tr><td>Proprietaer</td><td>Commercial</td><td className="text-yellow-600">Genehmigung</td></tr>
</tbody>
</table>
<h3>5. Aufbewahrung & Compliance</h3>
<ul>
<li><strong>Retention:</strong> 5 Jahre (Compliance)</li>
<li><strong>Format:</strong> JSON + PDF Report</li>
<li><strong>Signierung:</strong> Digital signiert</li>
<li><strong>Audit:</strong> Jederzeit abrufbar</li>
</ul>
</div>
)}
</div>
)}
</div>
</div>
</div>
</div>
)
}