-- ============================================================================ -- Migration 026 - Risk quantitativo FAIR + KRI (P2) -- ---------------------------------------------------------------------------- -- Affianca al risk register qualitativo (likelihood/impact 1-5) l'analisi -- quantitativa FAIR (Factor Analysis of Information Risk) in valore economico: -- - parametri FAIR su risks (TEF, vulnerability, loss magnitude PERT min/ml/max) -- - ale_min / ale_ml / ale_max / ale_mean: Annualized Loss Expectancy (EUR) -- calcolati via Monte Carlo e persistiti. -- - tabella kri: Key Risk Indicators con soglie e valori correnti. -- -- Idempotente. Rilanciabile. -- mysql -h localhost nis2_agile_db -e "source docs/sql/026_risk_quantitative.sql" -- ============================================================================ DELIMITER // DROP PROCEDURE IF EXISTS _mig026_col // CREATE PROCEDURE _mig026_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='risks' AND COLUMN_NAME=col) THEN SET @sql = CONCAT('ALTER TABLE risks ADD COLUMN ', ddl); PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st; END IF; END // DELIMITER ; -- Parametri FAIR (input) CALL _mig026_col('fair_tef_min', "fair_tef_min DECIMAL(10,2) NULL COMMENT 'Threat Event Frequency min (eventi/anno)'"); CALL _mig026_col('fair_tef_ml', "fair_tef_ml DECIMAL(10,2) NULL COMMENT 'Threat Event Frequency most likely (eventi/anno)'"); CALL _mig026_col('fair_tef_max', "fair_tef_max DECIMAL(10,2) NULL COMMENT 'Threat Event Frequency max (eventi/anno)'"); CALL _mig026_col('fair_vuln', "fair_vuln DECIMAL(5,4) NULL COMMENT 'Vulnerability: prob. che una minaccia diventi perdita (0-1)'"); CALL _mig026_col('fair_lm_min', "fair_lm_min DECIMAL(14,2) NULL COMMENT 'Loss Magnitude min (EUR per evento)'"); CALL _mig026_col('fair_lm_ml', "fair_lm_ml DECIMAL(14,2) NULL COMMENT 'Loss Magnitude most likely (EUR per evento)'"); CALL _mig026_col('fair_lm_max', "fair_lm_max DECIMAL(14,2) NULL COMMENT 'Loss Magnitude max (EUR per evento)'"); -- Risultati FAIR (output ALE in EUR) CALL _mig026_col('ale_min', "ale_min DECIMAL(16,2) NULL COMMENT 'Annualized Loss Expectancy - percentile basso (P10)'"); CALL _mig026_col('ale_ml', "ale_ml DECIMAL(16,2) NULL COMMENT 'Annualized Loss Expectancy - mediana (P50)'"); CALL _mig026_col('ale_max', "ale_max DECIMAL(16,2) NULL COMMENT 'Annualized Loss Expectancy - percentile alto (P90)'"); CALL _mig026_col('ale_mean', "ale_mean DECIMAL(16,2) NULL COMMENT 'Annualized Loss Expectancy - media simulazione'"); CALL _mig026_col('fair_computed_at',"fair_computed_at DATETIME NULL COMMENT 'Ultimo calcolo FAIR'"); DROP PROCEDURE IF EXISTS _mig026_col; -- Key Risk Indicators CREATE TABLE IF NOT EXISTS kri ( id INT NOT NULL AUTO_INCREMENT, organization_id INT NOT NULL, name VARCHAR(160) NOT NULL, description VARCHAR(255) NULL, category ENUM('cyber','operational','compliance','supply_chain','physical','human') NOT NULL DEFAULT 'cyber', unit VARCHAR(40) NULL COMMENT 'Unita di misura (%, count, EUR, giorni)', current_value DECIMAL(16,4) NULL, target_value DECIMAL(16,4) NULL COMMENT 'Valore obiettivo/atteso', threshold_warning DECIMAL(16,4) NULL COMMENT 'Soglia ambra', threshold_critical DECIMAL(16,4) NULL COMMENT 'Soglia rossa', direction ENUM('higher_worse','lower_worse') NOT NULL DEFAULT 'higher_worse' COMMENT 'Se valori alti=peggio o bassi=peggio', status ENUM('green','amber','red','unknown') NOT NULL DEFAULT 'unknown', linked_risk_id INT NULL, measured_at DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_kri_org (organization_id), KEY idx_kri_risk (linked_risk_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Key Risk Indicators con soglie e stato semaforo'; -- ROLLBACK: -- DROP TABLE IF EXISTS kri; -- ALTER TABLE risks DROP COLUMN fair_tef_min, DROP COLUMN fair_tef_ml, DROP COLUMN fair_tef_max, -- DROP COLUMN fair_vuln, DROP COLUMN fair_lm_min, DROP COLUMN fair_lm_ml, DROP COLUMN fair_lm_max, -- DROP COLUMN ale_min, DROP COLUMN ale_ml, DROP COLUMN ale_max, DROP COLUMN ale_mean, DROP COLUMN fair_computed_at;