[FIX] simulate-nis2: allineamento completo a schema DB reale
- ensureUser: seed-first (1 login call invece di 2) → evita rate limit - Risk category: technical→cyber, data_breach→compliance, availability→operational, human_factor→human (enum reale: cyber,operational,compliance,supply_chain,physical,human) - Risk: rimosso status:'open' (default 'identified' nel DB) - Policy: type→category nel createPolicy, aggiunto mappa cryptography→encryption, data_protection→information_security, risk_management→vulnerability_management - Incident SIM-02/03: category→classification, valori corretti (cyber_attack/data_breach), affected_systems→affected_services, rimosso estimated_impact, status investigating→analyzing, status resolved→recovering, aggiunto detected_at (campo required) - Onboarding: org_name→name, employees_count→employee_count - Classify: aggiunti employee_count e annual_turnover_eur (required) - Supplier: risk_level→criticality, rimosso is_critical Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ef8b7a90e4
commit
9f9f967d52
@ -225,28 +225,21 @@ function ensureUser(string $firstName, string $lastName, string $email, string $
|
||||
return $S['users'][$email]['jwt'];
|
||||
}
|
||||
|
||||
// Prova login prima (utente già esistente)
|
||||
// Seed diretto nel DB prima (idempotente: ON DUPLICATE KEY UPDATE).
|
||||
// Evita il rate limit: solo 1 chiamata login invece di 2 (fail + success).
|
||||
$fullName = trim("$firstName $lastName");
|
||||
$seeded = dbSeedUser($fullName, $email, $password, $role);
|
||||
|
||||
// Login (funziona sia se utente era già nel DB sia se appena seedato)
|
||||
$loginRes = api('POST', '/auth/login', ['email' => $email, 'password' => $password]);
|
||||
if (!empty($loginRes['data']['access_token'])) {
|
||||
$jwt = $loginRes['data']['access_token'];
|
||||
$S['users'][$email] = ['jwt' => $jwt, 'id' => $loginRes['data']['user']['id'] ?? null];
|
||||
skip("Login $email (già registrato)");
|
||||
ok($seeded ? "Registrato: $firstName $lastName <$email>" : "Login: $email (già registrato)");
|
||||
return $jwt;
|
||||
}
|
||||
|
||||
// Seed diretto nel DB (evita rate limit HTTP su /auth/register)
|
||||
$fullName = trim("$firstName $lastName");
|
||||
if (dbSeedUser($fullName, $email, $password, $role)) {
|
||||
$loginRes2 = api('POST', '/auth/login', ['email' => $email, 'password' => $password]);
|
||||
if (!empty($loginRes2['data']['access_token'])) {
|
||||
$jwt = $loginRes2['data']['access_token'];
|
||||
$S['users'][$email] = ['jwt' => $jwt, 'id' => $loginRes2['data']['user']['id'] ?? null];
|
||||
ok("Registrato: $firstName $lastName <$email>");
|
||||
return $jwt;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: registrazione via API
|
||||
// Fallback: registrazione via API (se DB seed fallisce — es. ambiente dev senza accesso diretto)
|
||||
$regRes = api('POST', '/auth/register', [
|
||||
'full_name' => $fullName,
|
||||
'email' => $email,
|
||||
@ -446,12 +439,12 @@ $COMPANIES = [
|
||||
['first' => 'Marco', 'last' => 'Negri', 'email' => 'auditor@datacore-srl.demo', 'role' => 'auditor'],
|
||||
],
|
||||
'risks' => [
|
||||
['title' => 'Ransomware su infrastruttura cloud', 'category' => 'technical', 'likelihood' => 4, 'impact' => 5, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Accesso non autorizzato a sistemi di produzione', 'category' => 'technical', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Data breach clienti enterprise (API key leak)', 'category' => 'data_breach', 'likelihood' => 3, 'impact' => 4, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Vulnerabilità zero-day in dipendenze npm', 'category' => 'technical', 'likelihood' => 4, 'impact' => 3, 'nis2_article' => '21.2.e'],
|
||||
['title' => 'Ransomware su infrastruttura cloud', 'category' => 'cyber', 'likelihood' => 4, 'impact' => 5, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Accesso non autorizzato a sistemi di produzione', 'category' => 'cyber', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Data breach clienti enterprise (API key leak)', 'category' => 'compliance', 'likelihood' => 3, 'impact' => 4, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Vulnerabilità zero-day in dipendenze npm', 'category' => 'cyber', 'likelihood' => 4, 'impact' => 3, 'nis2_article' => '21.2.e'],
|
||||
['title' => 'Supply chain compromise — fornitore DevOps', 'category' => 'supply_chain', 'likelihood' => 2, 'impact' => 5, 'nis2_article' => '21.2.d'],
|
||||
['title' => 'DDoS su API gateway prod', 'category' => 'availability', 'likelihood' => 3, 'impact' => 3, 'nis2_article' => '21.2.c'],
|
||||
['title' => 'DDoS su API gateway prod', 'category' => 'operational', 'likelihood' => 3, 'impact' => 3, 'nis2_article' => '21.2.c'],
|
||||
],
|
||||
'policies' => [
|
||||
['title' => 'Politica Gestione Incidenti di Sicurezza — Art.21.2.b NIS2', 'type' => 'incident_response', 'nis2_article' => '21.2.b'],
|
||||
@ -487,11 +480,11 @@ $COMPANIES = [
|
||||
['first' => 'Dott.ssa Laura','last' => 'Moretti', 'email' => 'ciso@medclinic-spa.demo', 'role' => 'compliance_manager'],
|
||||
],
|
||||
'risks' => [
|
||||
['title' => 'Violazione dati sanitari pazienti (GDPR+NIS2)', 'category' => 'data_breach', 'likelihood' => 4, 'impact' => 5, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Fermo sistemi HIS (Hospital Information System)', 'category' => 'availability', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.c'],
|
||||
['title' => 'Violazione dati sanitari pazienti (GDPR+NIS2)', 'category' => 'compliance', 'likelihood' => 4, 'impact' => 5, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Fermo sistemi HIS (Hospital Information System)', 'category' => 'operational', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.c'],
|
||||
['title' => 'Compromissione fornitore LIS (laboratorio analisi)', 'category' => 'supply_chain', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.d'],
|
||||
['title' => 'Accesso abusivo cartelle cliniche digitali', 'category' => 'technical', 'likelihood' => 4, 'impact' => 4, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Phishing staff medico (credential harvesting)', 'category' => 'human_factor', 'likelihood' => 5, 'impact' => 3, 'nis2_article' => '21.2.g'],
|
||||
['title' => 'Accesso abusivo cartelle cliniche digitali', 'category' => 'cyber', 'likelihood' => 4, 'impact' => 4, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Phishing staff medico (credential harvesting)', 'category' => 'human', 'likelihood' => 5, 'impact' => 3, 'nis2_article' => '21.2.g'],
|
||||
],
|
||||
'policies' => [
|
||||
['title' => 'Politica Protezione Dati Sanitari — Art.21.2.b NIS2 + GDPR', 'type' => 'data_protection', 'nis2_article' => '21.2.b'],
|
||||
@ -528,13 +521,13 @@ $COMPANIES = [
|
||||
['first' => 'Anna', 'last' => 'Zanetti', 'email' => 'board@enernet-srl.demo', 'role' => 'board_member'],
|
||||
],
|
||||
'risks' => [
|
||||
['title' => 'Attacco a sistemi SCADA/OT di controllo rete elettrica', 'category' => 'technical', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Interruzione fornitura energia (blackout doloso)', 'category' => 'availability', 'likelihood' => 2, 'impact' => 5, 'nis2_article' => '21.2.c'],
|
||||
['title' => 'Accesso non autorizzato sistemi AMI (smart meter)', 'category' => 'technical', 'likelihood' => 3, 'impact' => 4, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Attacco a sistemi SCADA/OT di controllo rete elettrica', 'category' => 'cyber', 'likelihood' => 3, 'impact' => 5, 'nis2_article' => '21.2.b'],
|
||||
['title' => 'Interruzione fornitura energia (blackout doloso)', 'category' => 'operational', 'likelihood' => 2, 'impact' => 5, 'nis2_article' => '21.2.c'],
|
||||
['title' => 'Accesso non autorizzato sistemi AMI (smart meter)', 'category' => 'cyber', 'likelihood' => 3, 'impact' => 4, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Supply chain — firmware malevolo contatori', 'category' => 'supply_chain', 'likelihood' => 2, 'impact' => 5, 'nis2_article' => '21.2.d'],
|
||||
['title' => 'Insider threat — tecnico campo con accesso SCADA', 'category' => 'human_factor', 'likelihood' => 2, 'impact' => 5, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Insider threat — tecnico campo con accesso SCADA', 'category' => 'human', 'likelihood' => 2, 'impact' => 5, 'nis2_article' => '21.2.i'],
|
||||
['title' => 'Incidente climatico su infrastruttura fisica (alluvione)', 'category' => 'physical', 'likelihood' => 2, 'impact' => 4, 'nis2_article' => '21.2.c'],
|
||||
['title' => 'Vulnerabilità protocollo IEC 61850 su sottostazioni', 'category' => 'technical', 'likelihood' => 3, 'impact' => 4, 'nis2_article' => '21.2.a'],
|
||||
['title' => 'Vulnerabilità protocollo IEC 61850 su sottostazioni', 'category' => 'cyber', 'likelihood' => 3, 'impact' => 4, 'nis2_article' => '21.2.a'],
|
||||
],
|
||||
'policies' => [
|
||||
['title' => 'Politica Sicurezza Sistemi OT/SCADA — Art.21.2.a NIS2', 'type' => 'risk_management', 'nis2_article' => '21.2.a'],
|
||||
@ -663,19 +656,18 @@ foreach ($COMPANIES as $slug => $comp) {
|
||||
|
||||
// Onboarding
|
||||
completeOnboarding($jwt, $orgId, [
|
||||
'org_name' => $comp['name'],
|
||||
'vat_number' => $comp['vat_number'],
|
||||
'sector' => $comp['sector'],
|
||||
'employees_count' => $comp['employees'],
|
||||
'annual_turnover_eur' => $comp['annual_turnover'],
|
||||
'name' => $comp['name'],
|
||||
'vat_number' => $comp['vat_number'],
|
||||
'sector' => $comp['sector'],
|
||||
'employee_count' => $comp['employees'],
|
||||
'annual_turnover_eur'=> $comp['annual_turnover'],
|
||||
]);
|
||||
|
||||
// Classificazione NIS2
|
||||
classifyOrg($jwt, $orgId, [
|
||||
'nis2_type' => $comp['nis2_type'],
|
||||
'sector' => $comp['sector'],
|
||||
'is_voluntary'=> 0,
|
||||
'justification'=> "Classificazione automatica: {$comp['nis2_type']} entity — settore {$comp['sector']}",
|
||||
'sector' => $comp['sector'],
|
||||
'employee_count' => $comp['employees'],
|
||||
'annual_turnover_eur'=> $comp['annual_turnover'],
|
||||
]);
|
||||
|
||||
info(" {$comp['name']}: {$comp['employees']} dip, fatturato " . number_format($comp['annual_turnover']/1000000, 1) . "M€, settore {$comp['sector']}");
|
||||
@ -752,7 +744,6 @@ foreach ($COMPANIES as $slug => $comp) {
|
||||
'risk_level' => $level,
|
||||
'nis2_article' => $riskDef['nis2_article'],
|
||||
'description' => "Rischio identificato durante gap assessment NIS2 — {$riskDef['title']}",
|
||||
'status' => 'open',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -768,9 +759,19 @@ foreach ($COMPANIES as $slug => $comp) {
|
||||
$orgId = $S['orgs'][$slug]['id'];
|
||||
|
||||
foreach ($comp['policies'] as $polDef) {
|
||||
// Mappa type→category (enum policy: incident_response,access_control,business_continuity,
|
||||
// supply_chain,encryption,information_security,hr_security,asset_management,
|
||||
// network_security,vulnerability_management)
|
||||
$polCatMap = [
|
||||
'cryptography' => 'encryption',
|
||||
'data_protection' => 'information_security',
|
||||
'risk_management' => 'vulnerability_management',
|
||||
'supply_chain_security' => 'supply_chain',
|
||||
];
|
||||
$polCategory = $polCatMap[$polDef['type']] ?? $polDef['type'];
|
||||
$polId = createPolicy($jwt, $orgId, [
|
||||
'title' => $polDef['title'],
|
||||
'type' => $polDef['type'],
|
||||
'category' => $polCategory,
|
||||
'nis2_article' => $polDef['nis2_article'],
|
||||
'content' => "Politica aziendale in conformità Art.{$polDef['nis2_article']} Direttiva NIS2 (EU 2022/2555) e D.Lgs.138/2024. Versione 1.0 — generata da simulazione demo.",
|
||||
'status' => 'draft',
|
||||
@ -801,10 +802,8 @@ foreach ($COMPANIES as $slug => $comp) {
|
||||
$supId = createSupplier($jwt, $orgId, [
|
||||
'name' => $supDef['name'],
|
||||
'service_type' => $supDef['service_type'],
|
||||
'risk_level' => $supDef['risk_level'],
|
||||
'is_critical' => $supDef['critical'],
|
||||
'criticality' => $supDef['risk_level'],
|
||||
'nis2_relevant' => 1,
|
||||
'contract_status' => 'active',
|
||||
'contact_email' => DEMO_EMAIL,
|
||||
]);
|
||||
|
||||
@ -838,14 +837,16 @@ if (!empty($S['orgs']['datacore']['id'])) {
|
||||
$orgId = $S['orgs']['datacore']['id'];
|
||||
|
||||
$incId = createIncident($jwt, $orgId, [
|
||||
'title' => 'Attacco Ransomware — Crittografia infrastruttura cloud prod',
|
||||
'description' => 'Alle 03:42 del ' . date('Y-m-d') . ' sistemi SIEM hanno rilevato attività anomala su cluster Kubernetes prod. Analisi forense preliminare indica compromissione tramite vulnerabilità CVE-2024-XXXX in plugin WordPress del portale clienti. Ransomware "LockBit 3.0" ha crittografato 3.2TB di dati su storage condiviso. 47 clienti enterprise impattati. Downtime 18h. Riscatto richiesto: 380.000 USD in Bitcoin.',
|
||||
'severity' => 'critical',
|
||||
'category' => 'ransomware',
|
||||
'affected_systems' => json_encode(['Kubernetes cluster prod', 'NAS storage 3.2TB', 'Portale clienti', 'API Gateway']),
|
||||
'estimated_impact' => 'Dati 47 clienti enterprise inaccessibili per 18h. Potenziale esfiltrazione pre-cifratura.',
|
||||
'title' => 'Attacco Ransomware — Crittografia infrastruttura cloud prod',
|
||||
'description' => 'Alle 03:42 del ' . date('Y-m-d') . ' sistemi SIEM hanno rilevato attività anomala su cluster Kubernetes prod. Analisi forense preliminare indica compromissione tramite vulnerabilità CVE-2024-XXXX in plugin WordPress del portale clienti. Ransomware "LockBit 3.0" ha crittografato 3.2TB di dati su storage condiviso. 47 clienti enterprise impattati. Downtime 18h. Riscatto richiesto: 380.000 USD in Bitcoin.',
|
||||
'severity' => 'critical',
|
||||
'classification' => 'cyber_attack',
|
||||
'affected_services'=> 'Kubernetes cluster prod, NAS storage 3.2TB, Portale clienti, API Gateway',
|
||||
'affected_users_count' => 47,
|
||||
'malicious_action' => 1,
|
||||
'is_significant' => 1,
|
||||
'status' => 'investigating',
|
||||
'detected_at' => date('Y-m-d H:i:s', strtotime('-1 day')),
|
||||
'status' => 'analyzing',
|
||||
]);
|
||||
|
||||
if ($incId) {
|
||||
@ -870,10 +871,10 @@ if (!empty($S['orgs']['datacore']['id'])) {
|
||||
|
||||
// Aggiornamento: risoluzione
|
||||
api('PUT', "/incidents/{$incId}", [
|
||||
'status' => 'resolved',
|
||||
'resolution' => 'Sistemi ripristinati da backup verificati. Vulnerabilità patchata. MFA obbligatorio su tutti gli accessi. Piano remediation 30 giorni approvato da CISO.',
|
||||
'status' => 'recovering',
|
||||
'remediation_actions' => 'Sistemi ripristinati da backup verificati. Vulnerabilità patchata. MFA obbligatorio su tutti gli accessi. Piano remediation 30 giorni approvato da CISO.',
|
||||
], $jwt, $orgId);
|
||||
ok("Incidente risolto: sistemi ripristinati da backup");
|
||||
ok("Incidente aggiornato: recovering — sistemi ripristinati da backup");
|
||||
|
||||
// Final report 30d
|
||||
$frRes = api('POST', "/incidents/{$incId}/final-report", [
|
||||
@ -918,13 +919,16 @@ if (!empty($S['orgs']['medclinic']['id'])) {
|
||||
}
|
||||
|
||||
$incId2 = createIncident($jwt, $orgId, [
|
||||
'title' => 'Data Breach — Esfiltrazione dati pazienti via fornitore LIS',
|
||||
'description' => 'Il fornitore di sistemi LIS (Laboratorio Analisi) HealthSoft ha esposto accidentalmente un endpoint API non autenticato. Dati di 2.340 pazienti (nome, codice fiscale, referti analisi) potenzialmente esfiltrati da attore esterno. Scoperto da team IR interno tramite alert SIEM su traffico anomalo verso IP russo (185.x.x.x). Violazione GDPR Art.33+34 + NIS2 Art.23.',
|
||||
'severity' => 'critical',
|
||||
'category' => 'data_breach',
|
||||
'affected_systems' => json_encode(['LIS HealthSoft API', 'Database referti', 'Portale pazienti']),
|
||||
'title' => 'Data Breach — Esfiltrazione dati pazienti via fornitore LIS',
|
||||
'description' => 'Il fornitore di sistemi LIS (Laboratorio Analisi) HealthSoft ha esposto accidentalmente un endpoint API non autenticato. Dati di 2.340 pazienti (nome, codice fiscale, referti analisi) potenzialmente esfiltrati da attore esterno. Scoperto da team IR interno tramite alert SIEM su traffico anomalo verso IP russo (185.x.x.x). Violazione GDPR Art.33+34 + NIS2 Art.23.',
|
||||
'severity' => 'critical',
|
||||
'classification' => 'data_breach',
|
||||
'affected_services'=> 'LIS HealthSoft API, Database referti, Portale pazienti',
|
||||
'affected_users_count' => 2340,
|
||||
'cross_border_impact' => 0,
|
||||
'is_significant' => 1,
|
||||
'status' => 'investigating',
|
||||
'detected_at' => date('Y-m-d H:i:s', strtotime('-12 hours')),
|
||||
'status' => 'analyzing',
|
||||
]);
|
||||
|
||||
if ($incId2) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user