cc80e59e5e
Migration 121: compliance_cra_vulnerabilities table with full lifecycle tracking
- Status state machine: reported → triaged → patched → disclosed (+ withdrawn)
- CRA Art. 14(2) deadlines tracked: reported_to_enisa_at (24h), detailed_report_at (72h)
- CVE-ID, severity, CVSS, affected_components (JSONB), embargo_until
Backend endpoints in cra_routes.py:
- POST /vulnerabilities — create with validation (severity, CVSS range)
- GET /vulnerabilities — list with deadline-breach summary (24h/72h counters)
- PATCH /vulnerabilities/{id} — update fields + auto-set lifecycle timestamps
- DELETE /vulnerabilities/{id} — soft-delete (withdrawn)
- GET /monitoring — combined view: CRA deadlines + vuln summary + post-market checklist
Frontend:
- /vuln page: intake form, vuln cards with 24h/72h-countdown buttons,
status-transition flow with auto-timestamps
- /monitoring page: CRA deadlines (11.06.26 / 11.09.26 / 11.12.27), breach banner
if 24h/72h obligations missed, post-market checklist with deep-links
- Dashboard: +2 buttons (Vulns, Monitoring)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
56 lines
2.3 KiB
SQL
56 lines
2.3 KiB
SQL
-- Migration 121: CRA Vulnerability Disclosure + Lifecycle
|
|
-- Tracks vulnerabilities reported against a CRA project + CRA-mandated deadlines:
|
|
-- - 24h: Early warning to ENISA / national CSIRT (CRA Art. 14(2)(a))
|
|
-- - 72h: Detailed report (CRA Art. 14(2)(b))
|
|
-- - Patch -> Disclosure (typically with embargo)
|
|
--
|
|
-- Status state machine (whitelist):
|
|
-- reported -> triaged -> patched -> disclosed
|
|
-- (or withdrawn at any time)
|
|
|
|
CREATE TABLE IF NOT EXISTS compliance_cra_vulnerabilities (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
cra_project_id UUID NOT NULL,
|
|
tenant_id VARCHAR(255) NOT NULL,
|
|
|
|
-- Identification
|
|
cve_id VARCHAR(50), -- CVE-YYYY-NNNN (optional)
|
|
title VARCHAR(500) NOT NULL,
|
|
description TEXT DEFAULT '',
|
|
severity VARCHAR(20), -- LOW | MEDIUM | HIGH | CRITICAL
|
|
cvss_score NUMERIC(3,1), -- 0.0 - 10.0
|
|
|
|
-- Affected components (e.g. ["lodash@4.17.20", "axios@0.21.0"])
|
|
affected_components JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
|
|
-- Reporter
|
|
reporter_source VARCHAR(50) DEFAULT 'internal', -- internal | external | researcher | scanner
|
|
reporter_contact VARCHAR(500),
|
|
|
|
-- Lifecycle timestamps
|
|
discovered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
triaged_at TIMESTAMPTZ,
|
|
patched_at TIMESTAMPTZ,
|
|
disclosed_at TIMESTAMPTZ,
|
|
embargo_until TIMESTAMPTZ,
|
|
|
|
-- CRA-Mandated reports (Art. 14(2))
|
|
reported_to_enisa_at TIMESTAMPTZ, -- 24h deadline
|
|
detailed_report_at TIMESTAMPTZ, -- 72h deadline
|
|
|
|
-- Status (whitelist)
|
|
status VARCHAR(30) NOT NULL DEFAULT 'reported',
|
|
|
|
-- Free-text notes (triage rationale, decision log)
|
|
notes TEXT DEFAULT '',
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_cra_vuln_project ON compliance_cra_vulnerabilities(cra_project_id);
|
|
CREATE INDEX IF NOT EXISTS idx_cra_vuln_tenant ON compliance_cra_vulnerabilities(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_cra_vuln_status ON compliance_cra_vulnerabilities(cra_project_id, status);
|
|
CREATE INDEX IF NOT EXISTS idx_cra_vuln_cve ON compliance_cra_vulnerabilities(cve_id) WHERE cve_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_cra_vuln_discovered ON compliance_cra_vulnerabilities(cra_project_id, discovered_at DESC);
|