8f21650d74
CI / detect-changes (push) Successful in 16s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 15s
CI / validate-canonical-controls (push) Successful in 13s
CI / loc-budget (push) Successful in 25s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 3m9s
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 31s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
- /sdk/dokumente: Kundensicht nur auf veroeffentlichte Rechtsdokumente (Ansehen + Download); Proxy mit Allow-List nur /public — Templates/Drafts/ Generator bleiben unerreichbar. - /sdk/cra-meldewesen: CRA Art. 14 Meldewesen (24h/72h/14d-Kaskade) mit Fristen-Tracking + ENISA-SRP-Export-Entwurf (kein Live-API). Backend: cra_meldewesen (pure, getestet) + cra_incident_store (schema-neutral ueber compliance_cra_documents) + /api/v1/cra/incidents (additiv, contract-safe). - Screening (Self-Scan) aus dem Frontend genommen: Flow-Stepper-Eintrag ausgeblendet (visibleWhen), Dashboard-Kachel + Import-Button entfernt. Repo-Scanning laeuft extern im Compliance-Scanner; Backend-Router bleibt vorerst gemountet (Contract-Stabilitaet). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
67 lines
3.4 KiB
TypeScript
67 lines
3.4 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { Meta } from '../_hooks/useMeldewesen'
|
|
|
|
const KIND_LABEL: Record<string, string> = {
|
|
exploited_vulnerability: 'Aktiv ausgenutzte Schwachstelle',
|
|
severe_incident: 'Schwerwiegender Sicherheitsvorfall',
|
|
}
|
|
const SEV_LABEL: Record<string, string> = {
|
|
critical: 'kritisch', high: 'hoch', medium: 'mittel', low: 'niedrig',
|
|
}
|
|
|
|
export function NewIncidentForm({ meta, onCreate, onCancel }: {
|
|
meta: Meta | null
|
|
onCreate: (body: Record<string, unknown>) => Promise<boolean>
|
|
onCancel: () => void
|
|
}) {
|
|
const [f, setF] = useState<Record<string, string>>({
|
|
summary: '', product_name: '', product_version: '', manufacturer: '',
|
|
kind: 'exploited_vulnerability', severity: 'high', contact: '', impact: '',
|
|
})
|
|
const [busy, setBusy] = useState(false)
|
|
const set = (k: string, v: string) => setF((p) => ({ ...p, [k]: v }))
|
|
const field = 'w-full text-sm rounded border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 p-2'
|
|
|
|
const submit = async () => {
|
|
setBusy(true)
|
|
try { if (await onCreate(f)) onCancel() } finally { setBusy(false) }
|
|
}
|
|
|
|
return (
|
|
<div className="rounded-xl border border-indigo-200 dark:border-indigo-800 bg-indigo-50/40 dark:bg-indigo-900/20 p-4 space-y-3">
|
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100">Neue CRA-Meldung erfassen</h3>
|
|
<p className="text-xs text-gray-600 dark:text-gray-300">
|
|
Die 24h/72h/14-Tage-Fristen laufen ab dem Zeitpunkt, an dem Sie Kenntnis erlangt haben.
|
|
</p>
|
|
<input className={field} placeholder="Kurzbeschreibung des Vorfalls *"
|
|
value={f.summary} onChange={(e) => set('summary', e.target.value)} />
|
|
<div className="grid grid-cols-2 gap-2">
|
|
<input className={field} placeholder="Produkt" value={f.product_name} onChange={(e) => set('product_name', e.target.value)} />
|
|
<input className={field} placeholder="Version" value={f.product_version} onChange={(e) => set('product_version', e.target.value)} />
|
|
<input className={field} placeholder="Hersteller" value={f.manufacturer} onChange={(e) => set('manufacturer', e.target.value)} />
|
|
<input className={field} placeholder="Kontakt (PSIRT-E-Mail)" value={f.contact} onChange={(e) => set('contact', e.target.value)} />
|
|
<select className={field} value={f.kind} onChange={(e) => set('kind', e.target.value)}>
|
|
{(meta?.kinds || ['exploited_vulnerability', 'severe_incident']).map((k) => (
|
|
<option key={k} value={k}>{KIND_LABEL[k] || k}</option>
|
|
))}
|
|
</select>
|
|
<select className={field} value={f.severity} onChange={(e) => set('severity', e.target.value)}>
|
|
{(meta?.severities || ['low', 'medium', 'high', 'critical']).map((s) => (
|
|
<option key={s} value={s}>{SEV_LABEL[s] || s}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<textarea className={field} rows={2} placeholder="Auswirkung (kurz)" value={f.impact} onChange={(e) => set('impact', e.target.value)} />
|
|
<div className="flex items-center gap-2">
|
|
<button onClick={submit} disabled={busy || f.summary.trim().length < 3}
|
|
className="rounded bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white text-sm px-4 py-2">
|
|
{busy ? 'Lege an …' : 'Meldung anlegen'}
|
|
</button>
|
|
<button onClick={onCancel} className="text-sm text-gray-500 hover:underline">Abbrechen</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|