'use client' import React, { useEffect, useState, useCallback, use, useRef } from 'react' interface SBOMItem { id: string filename: string format: string spec_version: string | null component_count: number summary: Record scan_status: string scan_summary: Record uploaded_at: string scanned_at: string | null } interface SBOMListResponse { project_id: string total: number items: SBOMItem[] } export default function SBOMPage({ params, }: { params: Promise<{ projectId: string }> }) { const { projectId } = use(params) const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [uploading, setUploading] = useState(false) const [error, setError] = useState('') const fileRef = useRef(null) const tenant = '00000000-0000-0000-0000-000000000001' const load = useCallback(async () => { try { const res = await fetch(`/api/sdk/v1/cra/projects/${projectId}/sbom`, { headers: { 'X-Tenant-ID': tenant }, }) if (!res.ok) throw new Error(await res.text()) setData(await res.json()) } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { setLoading(false) } }, [projectId]) useEffect(() => { load() }, [load]) const onUpload = async () => { const f = fileRef.current?.files?.[0] if (!f) return setUploading(true) setError('') try { const fd = new FormData() fd.append('file', f) const res = await fetch(`/api/sdk/v1/cra/projects/${projectId}/sbom`, { method: 'POST', headers: { 'X-Tenant-ID': tenant }, body: fd, }) if (!res.ok) throw new Error(await res.text()) if (fileRef.current) fileRef.current.value = '' await load() } catch (e) { setError(e instanceof Error ? e.message : 'Upload fehlgeschlagen') } finally { setUploading(false) } } if (loading) return

Laedt...

return (
← Zurueck zum Projekt

SBOM — Software Bill of Materials

CycloneDX oder SPDX hochladen. Verknuepft mit Annex-I Requirement 23 (SBOM-Pflicht).

{error && (
{error}
)}

Neue Version hochladen

Format: CycloneDX-JSON (mit bomFormat: "CycloneDX") oder SPDX-JSON (mit spdxVersion). Generieren z.B. via npx @cyclonedx/cyclonedx-npm oder cyclonedx-py.

{data && data.items.length === 0 && (
Noch kein SBOM hochgeladen.
)} {data && data.items.length > 0 && (

Versionen ({data.total})

{data.items.map(s => (
{s.filename} {s.format} {s.spec_version && ( v{s.spec_version} )}
{s.component_count} Komponenten · hochgeladen {new Date(s.uploaded_at).toLocaleString('de-DE')}
Scan: {s.scan_status}
{s.summary && Object.keys(s.summary).length > 0 && (
Summary-Details
{JSON.stringify(s.summary, null, 2)}
)}
))}
)}
Hinweis: Der osv.dev-Vulnerability-Scan wird durch ein separates Tool im Team durchgefuehrt. Diese Seite akzeptiert SBOM-Uploads und persistiert sie versioniert.
) }