-- 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);