[FEAT] Integrazione analisi docs/nis2 v1.7.0 — scoring asset, tassonomia incidenti, PIR, NIST CSF, fonti certe
Fase 1 - Asset Relevance Scoring NIS2 (GV.OC-04): metodologia 0-100 a 6 criteri, AssetScoringService + endpoint scoringGrid/score/relevantSystems + UI assets.html + registro stampabile. Fase 2 - Tassonomia incidenti Determina ACN 164179/2025: IS-1..4 + regime essenziale/importante (Allegati 3/4). Fase 3 - Post-Incident Review (5-Whys) + metriche TTD/TTC/TTR + timestamp di fase. Fase 4 - Mapping NIST CSF 2.0 (43 controlli) reference-only. Fonti certe: registry config/nis2_sources.php + grounding AI (vieta riferimenti inventati) + citazioni help.js + ingest PDF normativi nella KB RAG (scripts/ingest-nis2-sources.php). Migrazioni 020/021/022 (additive idempotenti). Fix VectorService IP Qdrant (drift .5->.3). Analisi concorrenza Evix (docs/EVIX_ANALISI_CONCORRENZA.html, gap-driven). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a7a21faa82
commit
5c545ea3d0
@@ -0,0 +1,66 @@
|
||||
-- ============================================================================
|
||||
-- Migration 020 - Asset Relevance Scoring (NIS2 GV.OC-04)
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Aggiunge la metodologia di scoring rilevanza NIS2 (0-100, 6 criteri pesati)
|
||||
-- alla tabella assets. Adattata dai mockup docs/nis2/assets.html +
|
||||
-- doc-relevant-systems.html (Determina/metodologia CdA, soglia >=40 rilevante).
|
||||
--
|
||||
-- Criteri: C1 Criticita Operativa (0-25), C2 Impatto Interruzione (0-25),
|
||||
-- C3 Dati Trattati (0-20), C4 Dipendenze (0-15),
|
||||
-- C5 Esposizione (0-10), C6 Obblighi Normativi (0-5).
|
||||
-- Classificazione: >=80 critico | 60-79 alto | 40-59 medio | 20-39 basso | <20 trascurabile
|
||||
-- Rilevanza NIS2: score >= 40.
|
||||
--
|
||||
-- IMPORTANTE (vedi CLAUDE.md / memoria): MySQL 8 Ubuntu NON supporta
|
||||
-- "ADD COLUMN IF NOT EXISTS". Questo script usa una stored procedure idempotente
|
||||
-- che verifica information_schema prima di ogni ALTER. Rilanciabile senza danni.
|
||||
-- Eseguire con: mysql -h localhost nis2_agile_db -e "source docs/sql/020_asset_relevance.sql"
|
||||
-- ============================================================================
|
||||
|
||||
DELIMITER //
|
||||
|
||||
DROP PROCEDURE IF EXISTS _mig020_add_col //
|
||||
CREATE PROCEDURE _mig020_add_col(IN col VARCHAR(64), IN ddl TEXT)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'assets' AND COLUMN_NAME = col
|
||||
) THEN
|
||||
SET @sql = CONCAT('ALTER TABLE assets ADD COLUMN ', ddl);
|
||||
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;
|
||||
END IF;
|
||||
END //
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
CALL _mig020_add_col('relevance_score', "relevance_score TINYINT UNSIGNED NULL COMMENT 'Punteggio rilevanza NIS2 0-100'");
|
||||
CALL _mig020_add_col('relevance_criteria', "relevance_criteria JSON NULL COMMENT 'Dettaglio punteggi C1-C6 per audit'");
|
||||
CALL _mig020_add_col('relevance_class', "relevance_class ENUM('critico','alto','medio','basso','trascurabile') NULL");
|
||||
CALL _mig020_add_col('is_nis2_relevant', "is_nis2_relevant TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 se score >= 40'");
|
||||
CALL _mig020_add_col('relevance_assessed_at', "relevance_assessed_at DATETIME NULL");
|
||||
CALL _mig020_add_col('relevance_assessed_by', "relevance_assessed_by INT NULL");
|
||||
|
||||
DROP PROCEDURE IF EXISTS _mig020_add_col;
|
||||
|
||||
-- Indice per filtri "sistemi rilevanti" (idempotente via check)
|
||||
DELIMITER //
|
||||
DROP PROCEDURE IF EXISTS _mig020_add_idx //
|
||||
CREATE PROCEDURE _mig020_add_idx()
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'assets' AND INDEX_NAME = 'idx_relevance'
|
||||
) THEN
|
||||
ALTER TABLE assets ADD INDEX idx_relevance (is_nis2_relevant, relevance_score);
|
||||
END IF;
|
||||
END //
|
||||
DELIMITER ;
|
||||
CALL _mig020_add_idx();
|
||||
DROP PROCEDURE IF EXISTS _mig020_add_idx;
|
||||
|
||||
-- ROLLBACK (manuale):
|
||||
-- ALTER TABLE assets
|
||||
-- DROP COLUMN relevance_score, DROP COLUMN relevance_criteria,
|
||||
-- DROP COLUMN relevance_class, DROP COLUMN is_nis2_relevant,
|
||||
-- DROP COLUMN relevance_assessed_at, DROP COLUMN relevance_assessed_by,
|
||||
-- DROP INDEX idx_relevance;
|
||||
@@ -0,0 +1,36 @@
|
||||
-- ============================================================================
|
||||
-- Migration 021 - Tassonomia Incidenti NIS2 (Determina ACN 164179/2025)
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Aggiunge alla tabella incidents:
|
||||
-- - nis2_incident_type: tipologia incidente significativo IS-1/IS-2/IS-3/IS-4
|
||||
-- (Determinazione ACN n. 164179 del 14/04/2025, Allegati 3 e 4).
|
||||
-- - entity_obligation: regime di obblighi applicabile (essential=Allegato 3,
|
||||
-- important=Allegato 4). I soggetti importanti NON sono tenuti all'IS-4
|
||||
-- (incidenti ricorrenti).
|
||||
--
|
||||
-- Fonte: D.Lgs. 138/2024 art. 23 + Determina ACN 164179/2025.
|
||||
-- Idempotente via information_schema. Rilanciabile.
|
||||
-- mysql -h localhost nis2_agile_db -e "source docs/sql/021_incident_nis2_taxonomy.sql"
|
||||
-- ============================================================================
|
||||
|
||||
DELIMITER //
|
||||
DROP PROCEDURE IF EXISTS _mig021_add_col //
|
||||
CREATE PROCEDURE _mig021_add_col(IN col VARCHAR(64), IN ddl TEXT)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'incidents' AND COLUMN_NAME = col
|
||||
) THEN
|
||||
SET @sql = CONCAT('ALTER TABLE incidents ADD COLUMN ', ddl);
|
||||
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;
|
||||
END IF;
|
||||
END //
|
||||
DELIMITER ;
|
||||
|
||||
CALL _mig021_add_col('nis2_incident_type', "nis2_incident_type ENUM('IS-1','IS-2','IS-3','IS-4') NULL COMMENT 'Tipologia incidente significativo - Determina ACN 164179/2025'");
|
||||
CALL _mig021_add_col('entity_obligation', "entity_obligation ENUM('essential','important') NULL COMMENT 'Regime obblighi: essential=Allegato 3, important=Allegato 4'");
|
||||
|
||||
DROP PROCEDURE IF EXISTS _mig021_add_col;
|
||||
|
||||
-- ROLLBACK:
|
||||
-- ALTER TABLE incidents DROP COLUMN nis2_incident_type, DROP COLUMN entity_obligation;
|
||||
@@ -0,0 +1,73 @@
|
||||
-- ============================================================================
|
||||
-- Migration 022 - Metriche Incidente (TTD/TTC/TTR) + Post-Incident Review
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- 1) Timestamp di fase su incidents per calcolare le metriche:
|
||||
-- triaged_at, contained_at, eradicated_at, recovered_at.
|
||||
-- (la tabella aveva solo detected_at e closed_at)
|
||||
-- TTD = triaged_at - detected_at (Time to Detect/triage)
|
||||
-- TTC = contained_at - detected_at (Time to Contain)
|
||||
-- TTR = recovered_at - detected_at (Time to Recover)
|
||||
-- 2) Tabella incident_pir: Post-Incident Review strutturato (RC.CO-03 / NIST CSF),
|
||||
-- con Root Cause Analysis 5-Whys, metriche, costo stimato, lesson learned.
|
||||
--
|
||||
-- Idempotente. mysql -h localhost nis2_agile_db -e "source docs/sql/022_incident_metrics_pir.sql"
|
||||
-- ============================================================================
|
||||
|
||||
DELIMITER //
|
||||
DROP PROCEDURE IF EXISTS _mig022_add_col //
|
||||
CREATE PROCEDURE _mig022_add_col(IN col VARCHAR(64), IN ddl TEXT)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'incidents' AND COLUMN_NAME = col
|
||||
) THEN
|
||||
SET @sql = CONCAT('ALTER TABLE incidents ADD COLUMN ', ddl);
|
||||
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;
|
||||
END IF;
|
||||
END //
|
||||
DELIMITER ;
|
||||
|
||||
CALL _mig022_add_col('triaged_at', "triaged_at DATETIME NULL COMMENT 'Inizio triage'");
|
||||
CALL _mig022_add_col('contained_at', "contained_at DATETIME NULL COMMENT 'Incidente contenuto'");
|
||||
CALL _mig022_add_col('eradicated_at', "eradicated_at DATETIME NULL COMMENT 'Minaccia eradicata'");
|
||||
CALL _mig022_add_col('recovered_at', "recovered_at DATETIME NULL COMMENT 'Servizi ripristinati'");
|
||||
|
||||
DROP PROCEDURE IF EXISTS _mig022_add_col;
|
||||
|
||||
-- Post-Incident Review (1:1 con incident)
|
||||
CREATE TABLE IF NOT EXISTS incident_pir (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
incident_id INT NOT NULL,
|
||||
organization_id INT NOT NULL,
|
||||
-- Root Cause Analysis - 5 Whys
|
||||
problem_statement TEXT,
|
||||
why_1 TEXT, why_2 TEXT, why_3 TEXT, why_4 TEXT, why_5 TEXT,
|
||||
root_cause TEXT,
|
||||
-- Metriche (snapshot al momento della review, in minuti)
|
||||
ttd_minutes INT NULL,
|
||||
ttc_minutes INT NULL,
|
||||
ttr_minutes INT NULL,
|
||||
downtime_minutes INT NULL,
|
||||
affected_users INT NULL,
|
||||
estimated_cost_eur DECIMAL(12,2) NULL,
|
||||
notification_compliance TINYINT(1) NULL COMMENT '1 se notifiche entro le tempistiche NIS2',
|
||||
-- Lesson learned & azioni di miglioramento
|
||||
what_went_well TEXT,
|
||||
what_to_improve TEXT,
|
||||
improvement_actions JSON NULL COMMENT 'lista azioni {desc, owner, due_date, status}',
|
||||
participants TEXT,
|
||||
reviewed_by INT NULL,
|
||||
reviewed_at DATETIME NULL,
|
||||
status ENUM('draft','completed') DEFAULT 'draft',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_incident (incident_id),
|
||||
INDEX idx_org (organization_id),
|
||||
CONSTRAINT fk_pir_incident FOREIGN KEY (incident_id) REFERENCES incidents(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_pir_org FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ROLLBACK:
|
||||
-- DROP TABLE IF EXISTS incident_pir;
|
||||
-- ALTER TABLE incidents DROP COLUMN triaged_at, DROP COLUMN contained_at,
|
||||
-- DROP COLUMN eradicated_at, DROP COLUMN recovered_at;
|
||||
Reference in New Issue
Block a user