[FEAT] Simulazioni Demo + Audit Trail Certificato SHA-256
- 5 scenari reali: Onboarding, Ransomware Art.23, Data Breach Supply Chain, Whistleblowing SCADA, Audit Hash Chain Verification - simulate-nis2.php: 3 aziende (DataCore/MedClinic/EnerNet), 10 fasi, CLI+SSE - AuditService.php: hash chain SHA-256 stile lg231 (prev_hash+entry_hash) - Migration 010: prev_hash, entry_hash, severity, performed_by su audit_logs - AuditController: GET chain-verify + GET export-certified - reset-demo.sql: reset dati demo idempotente - public/simulate.html: web runner SSE con console dark-theme - Sidebar: link Simulazione Demo + Integrazioni Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
b23bbc55fd
commit
874eabb6fc
@@ -0,0 +1,113 @@
|
||||
-- ============================================================
|
||||
-- NIS2 Agile - Migration 010: Audit Trail Certificato SHA-256
|
||||
-- Hash chain per immutabilità certificabile (ispirato da lg231 AuditTrailService)
|
||||
-- Estende la tabella audit_logs con prev_hash, entry_hash, severity, performed_by
|
||||
-- ============================================================
|
||||
-- Eseguire su Hetzner:
|
||||
-- mysql -u nis2_agile_user -p nis2_agile_db < docs/sql/010_audit_hash_chain.sql
|
||||
|
||||
USE nis2_agile_db;
|
||||
|
||||
-- ── Aggiunta colonne (idempotente via information_schema) ──────────────────
|
||||
|
||||
-- prev_hash: hash del record precedente per la stessa organization_id
|
||||
SET @has_prev = (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'prev_hash'
|
||||
);
|
||||
SET @sql_prev = IF(@has_prev = 0,
|
||||
'ALTER TABLE audit_logs ADD COLUMN prev_hash VARCHAR(64) NULL AFTER details',
|
||||
'SELECT ''prev_hash already exists'' AS note'
|
||||
);
|
||||
PREPARE s FROM @sql_prev; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- entry_hash: SHA-256 di questo record (include prev_hash per la catena)
|
||||
SET @has_entry = (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'entry_hash'
|
||||
);
|
||||
SET @sql_entry = IF(@has_entry = 0,
|
||||
'ALTER TABLE audit_logs ADD COLUMN entry_hash VARCHAR(64) NOT NULL DEFAULT \'\' AFTER prev_hash',
|
||||
'SELECT ''entry_hash already exists'' AS note'
|
||||
);
|
||||
PREPARE s FROM @sql_entry; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- severity: criticità dell'evento per filtro dashboard
|
||||
SET @has_sev = (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'severity'
|
||||
);
|
||||
SET @sql_sev = IF(@has_sev = 0,
|
||||
"ALTER TABLE audit_logs ADD COLUMN severity ENUM('info','warning','critical') NOT NULL DEFAULT 'info' AFTER entry_hash",
|
||||
'SELECT ''severity already exists'' AS note'
|
||||
);
|
||||
PREPARE s FROM @sql_sev; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- performed_by: email/identificatore utente (denormalizzato per export certificato)
|
||||
SET @has_by = (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'performed_by'
|
||||
);
|
||||
SET @sql_by = IF(@has_by = 0,
|
||||
'ALTER TABLE audit_logs ADD COLUMN performed_by VARCHAR(255) NULL AFTER severity',
|
||||
'SELECT ''performed_by already exists'' AS note'
|
||||
);
|
||||
PREPARE s FROM @sql_by; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- ── Indici ────────────────────────────────────────────────────────────────
|
||||
-- Indice su entry_hash per verifica integrità e ricerca
|
||||
SET @has_idx_hash = (
|
||||
SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND INDEX_NAME = 'idx_entry_hash'
|
||||
);
|
||||
SET @sql_idx = IF(@has_idx_hash = 0,
|
||||
'ALTER TABLE audit_logs ADD INDEX idx_entry_hash (entry_hash)',
|
||||
'SELECT ''idx_entry_hash already exists'' AS note'
|
||||
);
|
||||
PREPARE s FROM @sql_idx; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- Indice su severity per filtro dashboard
|
||||
SET @has_idx_sev = (
|
||||
SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND INDEX_NAME = 'idx_severity'
|
||||
);
|
||||
SET @sql_isev = IF(@has_idx_sev = 0,
|
||||
'ALTER TABLE audit_logs ADD INDEX idx_severity (severity, organization_id)',
|
||||
'SELECT ''idx_severity already exists'' AS note'
|
||||
);
|
||||
PREPARE s FROM @sql_isev; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
-- ── Tabella export certificati audit ─────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS audit_exports (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
organization_id INT NOT NULL,
|
||||
exported_by INT NULL, -- user_id (NULL = sistema)
|
||||
performed_by VARCHAR(255) NULL, -- email utente
|
||||
format ENUM('json','xml','csv') NOT NULL DEFAULT 'json',
|
||||
records_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
date_from DATE NULL,
|
||||
date_to DATE NULL,
|
||||
export_hash VARCHAR(64) NOT NULL, -- SHA-256 del contenuto export
|
||||
chain_valid TINYINT(1) NOT NULL DEFAULT 1, -- integrità al momento export
|
||||
purpose VARCHAR(100) NOT NULL DEFAULT 'export_certificato',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_org (organization_id),
|
||||
INDEX idx_created (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ── Tabella violazioni integrità catena ───────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS audit_violations (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
organization_id INT NOT NULL,
|
||||
detected_by VARCHAR(255) NOT NULL DEFAULT 'system',
|
||||
broken_at_id INT NULL, -- audit_logs.id dove la catena si rompe
|
||||
chain_length INT UNSIGNED NOT NULL DEFAULT 0, -- record totali verificati
|
||||
notes TEXT NULL,
|
||||
resolved TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_org (organization_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
SELECT 'Migration 010 completata: audit_logs con hash chain SHA-256 certificato' AS result;
|
||||
@@ -0,0 +1,106 @@
|
||||
-- ============================================================
|
||||
-- NIS2 Agile — Reset Dati Demo
|
||||
-- Cancella tutti i dati generati dalla simulazione, mantenendo
|
||||
-- solo le organizzazioni seed (id <= 4) e i loro utenti.
|
||||
--
|
||||
-- Eseguire su Hetzner:
|
||||
-- ssh -i docs/credentials/hetzner_key root@135.181.149.254
|
||||
-- mysql -u nis2_agile_user -p nis2_agile_db < /var/www/nis2-agile/docs/sql/reset-demo.sql
|
||||
-- ============================================================
|
||||
|
||||
USE nis2_agile_db;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ── Dati operativi generati dalla simulazione ─────────────────────────────
|
||||
|
||||
-- Notifiche incidenti / timeline
|
||||
DELETE FROM incident_timeline WHERE organization_id > 4;
|
||||
DELETE FROM incidents WHERE organization_id > 4;
|
||||
|
||||
-- Rischi e trattamenti
|
||||
DELETE FROM risk_treatments WHERE risk_id IN (SELECT id FROM risks WHERE organization_id > 4);
|
||||
DELETE FROM risks WHERE organization_id > 4;
|
||||
|
||||
-- Assessment e risposte
|
||||
DELETE FROM assessment_responses WHERE assessment_id IN (SELECT id FROM assessments WHERE organization_id > 4);
|
||||
DELETE FROM assessments WHERE organization_id > 4;
|
||||
|
||||
-- Policy
|
||||
DELETE FROM policies WHERE organization_id > 4;
|
||||
|
||||
-- Fornitori
|
||||
DELETE FROM suppliers WHERE organization_id > 4;
|
||||
|
||||
-- Training
|
||||
DELETE FROM training_assignments WHERE course_id IN (SELECT id FROM training_courses WHERE organization_id > 4);
|
||||
DELETE FROM training_courses WHERE organization_id > 4;
|
||||
|
||||
-- Asset
|
||||
DELETE FROM assets WHERE organization_id > 4;
|
||||
|
||||
-- Controlli compliance
|
||||
DELETE FROM compliance_controls WHERE organization_id > 4;
|
||||
|
||||
-- Evidenze
|
||||
DELETE FROM evidence_files WHERE organization_id > 4;
|
||||
|
||||
-- Non conformità e CAPA
|
||||
DELETE FROM corrective_actions WHERE non_conformity_id IN (SELECT id FROM non_conformities WHERE organization_id > 4);
|
||||
DELETE FROM non_conformities WHERE organization_id > 4;
|
||||
|
||||
-- Whistleblowing
|
||||
DELETE FROM whistleblowing_timeline
|
||||
WHERE report_id IN (SELECT id FROM whistleblowing_reports WHERE organization_id > 4);
|
||||
DELETE FROM whistleblowing_reports WHERE organization_id > 4;
|
||||
|
||||
-- Normativa ACK
|
||||
DELETE FROM normative_ack WHERE organization_id > 4;
|
||||
|
||||
-- API keys e webhook
|
||||
DELETE FROM webhook_deliveries
|
||||
WHERE subscription_id IN (SELECT id FROM webhook_subscriptions WHERE organization_id > 4);
|
||||
DELETE FROM webhook_subscriptions WHERE organization_id > 4;
|
||||
DELETE FROM api_keys WHERE organization_id > 4;
|
||||
|
||||
-- Audit log (solo dati demo, non i record di sistema id <= 100)
|
||||
DELETE FROM audit_logs WHERE organization_id > 4;
|
||||
DELETE FROM audit_exports WHERE organization_id > 4;
|
||||
DELETE FROM audit_violations WHERE organization_id > 4;
|
||||
|
||||
-- AI interactions
|
||||
DELETE FROM ai_interactions WHERE organization_id > 4;
|
||||
|
||||
-- Email log
|
||||
DELETE FROM email_log WHERE organization_id > 4;
|
||||
|
||||
-- ── Membership utenti ─────────────────────────────────────────────────────
|
||||
|
||||
-- Rimuove le associazioni utente-organizzazione demo
|
||||
DELETE FROM user_organizations WHERE organization_id > 4;
|
||||
|
||||
-- Rimuove token refresh degli utenti demo
|
||||
DELETE rt FROM refresh_tokens rt
|
||||
JOIN users u ON rt.user_id = u.id
|
||||
WHERE u.email LIKE '%.demo%';
|
||||
|
||||
-- Rimuove utenti demo (email terminano con .demo)
|
||||
DELETE FROM users WHERE email LIKE '%.demo%';
|
||||
|
||||
-- ── Organizzazioni demo ───────────────────────────────────────────────────
|
||||
DELETE FROM organizations WHERE id > 4;
|
||||
|
||||
-- ── Ripristino FK ─────────────────────────────────────────────────────────
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- ── Verifica stato ────────────────────────────────────────────────────────
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM organizations) AS organizations,
|
||||
(SELECT COUNT(*) FROM users) AS users,
|
||||
(SELECT COUNT(*) FROM incidents) AS incidents,
|
||||
(SELECT COUNT(*) FROM risks) AS risks,
|
||||
(SELECT COUNT(*) FROM audit_logs) AS audit_logs,
|
||||
(SELECT COUNT(*) FROM whistleblowing_reports) AS whistleblowing
|
||||
;
|
||||
|
||||
SELECT 'Reset demo completato. Dati seed mantenuti (id <= 4).' AS stato;
|
||||
Reference in New Issue
Block a user