From cf23be9c7771c77376f6ad8cb0f160157287bbe7 Mon Sep 17 00:00:00 2001 From: DevEnv nis2-agile Date: Tue, 23 Jun 2026 22:43:43 +0200 Subject: [PATCH] [FEAT] Inventario Rilevanza NIS2: significato opzioni combo + dettaglio punteggio per criterio (ticket #431, #432) - AssetScoringService::GRID: aggiunto campo 'desc' a tutte le 35 opzioni dei 6 criteri (significato operativo, additivo) - assets.html: ogni combo mostra il significato dell'opzione selezionata + nuovo box 'Dettaglio punteggio per criterio' (live, anche alla riapertura di una valutazione salvata) Co-Authored-By: Claude Opus 4.8 --- application/services/AssetScoringService.php | 68 ++++++++++---------- public/assets.html | 30 +++++++-- public/version.json | 2 +- 3 files changed, 60 insertions(+), 40 deletions(-) diff --git a/application/services/AssetScoringService.php b/application/services/AssetScoringService.php index 9797771..2d94bb4 100644 --- a/application/services/AssetScoringService.php +++ b/application/services/AssetScoringService.php @@ -33,12 +33,12 @@ class AssetScoringService 'max' => 25, 'help' => 'Quanto il sistema e essenziale per l\'erogazione dei servizi core business.', 'options' => [ - 'critical' => ['label' => 'Critico', 'points' => 25], - 'very_high' => ['label' => 'Molto Alto', 'points' => 20], - 'high' => ['label' => 'Alto', 'points' => 15], - 'medium' => ['label' => 'Medio', 'points' => 10], - 'low' => ['label' => 'Basso', 'points' => 5], - 'negligible' => ['label' => 'Trascurabile', 'points' => 0], + 'critical' => ['label' => 'Critico', 'points' => 25, 'desc' => 'Sistema indispensabile: un suo fermo blocca subito i servizi core dell\'organizzazione.'], + 'very_high' => ['label' => 'Molto Alto', 'points' => 20, 'desc' => 'Sistema primario: un fermo degrada gravemente i servizi core, con alternative molto limitate.'], + 'high' => ['label' => 'Alto', 'points' => 15, 'desc' => 'Sistema importante: il fermo rallenta i servizi core ma esistono alternative parziali.'], + 'medium' => ['label' => 'Medio', 'points' => 10, 'desc' => 'Sistema di supporto: il fermo ha impatto contenuto e gestibile sui servizi core.'], + 'low' => ['label' => 'Basso', 'points' => 5, 'desc' => 'Sistema accessorio: il fermo incide poco sull\'operativita.'], + 'negligible' => ['label' => 'Trascurabile', 'points' => 0, 'desc' => 'Sistema non essenziale: nessun impatto pratico sui servizi core.'], ], ], 'c2_disruption_impact' => [ @@ -46,12 +46,12 @@ class AssetScoringService 'max' => 25, 'help' => 'Conseguenze di un\'interruzione in termini di durata e utenti impattati.', 'options' => [ - 'gt24h_gt70' => ['label' => '>24h + >70% utenti', 'points' => 25], - 'h8_24_50_70' => ['label' => '8-24h + 50-70% utenti', 'points' => 20], - 'h4_8_30_50' => ['label' => '4-8h + 30-50% utenti', 'points' => 15], - 'h1_4_10_30' => ['label' => '1-4h + 10-30% utenti', 'points' => 10], - 'lt1h_lt10' => ['label' => '<1h + <10% utenti', 'points' => 5], - 'none' => ['label' => 'Nessun impatto', 'points' => 0], + 'gt24h_gt70' => ['label' => '>24h + >70% utenti', 'points' => 25, 'desc' => 'Interruzione oltre 24 ore che coinvolge piu del 70% degli utenti.'], + 'h8_24_50_70' => ['label' => '8-24h + 50-70% utenti', 'points' => 20, 'desc' => 'Interruzione da 8 a 24 ore, dal 50 al 70% degli utenti coinvolti.'], + 'h4_8_30_50' => ['label' => '4-8h + 30-50% utenti', 'points' => 15, 'desc' => 'Interruzione da 4 a 8 ore, dal 30 al 50% degli utenti coinvolti.'], + 'h1_4_10_30' => ['label' => '1-4h + 10-30% utenti', 'points' => 10, 'desc' => 'Interruzione da 1 a 4 ore, dal 10 al 30% degli utenti coinvolti.'], + 'lt1h_lt10' => ['label' => '<1h + <10% utenti', 'points' => 5, 'desc' => 'Interruzione sotto 1 ora, meno del 10% degli utenti coinvolti.'], + 'none' => ['label' => 'Nessun impatto', 'points' => 0, 'desc' => 'Nessun impatto operativo apprezzabile in caso di interruzione.'], ], ], 'c3_data_processed' => [ @@ -59,11 +59,11 @@ class AssetScoringService 'max' => 20, 'help' => 'Sensibilita e criticita dei dati gestiti dal sistema.', 'options' => [ - 'gdpr_art9' => ['label' => 'Dati Sensibili Art.9 GDPR', 'points' => 20], - 'personal_large' => ['label' => 'Dati Personali larga scala', 'points' => 15], - 'personal_fin' => ['label' => 'Dati Personali + Finanziari', 'points' => 10], - 'confidential' => ['label' => 'Dati Aziendali Riservati', 'points' => 5], - 'public' => ['label' => 'Dati Pubblici', 'points' => 0], + 'gdpr_art9' => ['label' => 'Dati Sensibili Art.9 GDPR', 'points' => 20, 'desc' => 'Categorie particolari di dati personali (salute, biometrici, ecc.) ai sensi dell\'Art.9 GDPR.'], + 'personal_large' => ['label' => 'Dati Personali larga scala', 'points' => 15, 'desc' => 'Dati personali comuni trattati su larga scala.'], + 'personal_fin' => ['label' => 'Dati Personali + Finanziari', 'points' => 10, 'desc' => 'Dati personali insieme a dati finanziari o di pagamento.'], + 'confidential' => ['label' => 'Dati Aziendali Riservati', 'points' => 5, 'desc' => 'Dati aziendali riservati non personali (know-how, contratti).'], + 'public' => ['label' => 'Dati Pubblici', 'points' => 0, 'desc' => 'Solo dati pubblici o gia liberamente divulgabili.'], ], ], 'c4_dependencies' => [ @@ -71,12 +71,12 @@ class AssetScoringService 'max' => 15, 'help' => 'Quanti altri sistemi critici dipendono da questo sistema.', 'options' => [ - 'ge5_critical' => ['label' => '>=5 sistemi critici', 'points' => 15], - 'n3_4_critical' => ['label' => '3-4 sistemi critici', 'points' => 12], - 'n2_critical' => ['label' => '2 sistemi critici', 'points' => 9], - 'n1_critical' => ['label' => '1 sistema critico', 'points' => 6], - 'noncritical' => ['label' => '1-2 sistemi non critici', 'points' => 3], - 'none' => ['label' => 'Nessuna dipendenza', 'points' => 0], + 'ge5_critical' => ['label' => '>=5 sistemi critici', 'points' => 15, 'desc' => 'Da questo sistema dipendono 5 o piu sistemi critici.'], + 'n3_4_critical' => ['label' => '3-4 sistemi critici', 'points' => 12, 'desc' => 'Da questo sistema dipendono 3 o 4 sistemi critici.'], + 'n2_critical' => ['label' => '2 sistemi critici', 'points' => 9, 'desc' => 'Da questo sistema dipendono 2 sistemi critici.'], + 'n1_critical' => ['label' => '1 sistema critico', 'points' => 6, 'desc' => 'Da questo sistema dipende 1 sistema critico.'], + 'noncritical' => ['label' => '1-2 sistemi non critici', 'points' => 3, 'desc' => 'Dipendono solo 1-2 sistemi non critici.'], + 'none' => ['label' => 'Nessuna dipendenza', 'points' => 0, 'desc' => 'Nessun altro sistema dipende da questo.'], ], ], 'c5_exposure' => [ @@ -84,12 +84,12 @@ class AssetScoringService 'max' => 10, 'help' => 'Superficie di attacco ed esposizione del sistema.', 'options' => [ - 'internet_no_mfa' => ['label' => 'Internet pubblico senza MFA', 'points' => 10], - 'internet_mfa' => ['label' => 'Internet con MFA', 'points' => 8], - 'partner_net' => ['label' => 'Reti partner/fornitori', 'points' => 6], - 'intranet' => ['label' => 'Rete aziendale intranet', 'points' => 4], - 'mgmt_isolated' => ['label' => 'Rete gestione isolata', 'points' => 2], - 'air_gapped' => ['label' => 'Completamente isolato', 'points' => 0], + 'internet_no_mfa' => ['label' => 'Internet pubblico senza MFA', 'points' => 10, 'desc' => 'Esposto su Internet pubblico senza autenticazione a piu fattori.'], + 'internet_mfa' => ['label' => 'Internet con MFA', 'points' => 8, 'desc' => 'Esposto su Internet ma protetto da autenticazione a piu fattori.'], + 'partner_net' => ['label' => 'Reti partner/fornitori', 'points' => 6, 'desc' => 'Raggiungibile dalle reti di partner o fornitori.'], + 'intranet' => ['label' => 'Rete aziendale intranet', 'points' => 4, 'desc' => 'Raggiungibile solo dalla rete aziendale interna.'], + 'mgmt_isolated' => ['label' => 'Rete gestione isolata', 'points' => 2, 'desc' => 'Accessibile solo da una rete di gestione isolata.'], + 'air_gapped' => ['label' => 'Completamente isolato', 'points' => 0, 'desc' => 'Completamente isolato, senza connettivita di rete.'], ], ], 'c6_regulatory' => [ @@ -97,11 +97,11 @@ class AssetScoringService 'max' => 5, 'help' => 'Se il sistema e soggetto a obblighi normativi o contrattuali specifici.', 'options' => [ - 'nis2_required' => ['label' => 'Richiesto da NIS2', 'points' => 5], - 'mandatory_cert' => ['label' => 'Certificazioni obbligatorie', 'points' => 4], - 'strict_sla' => ['label' => 'Obblighi SLA stringenti', 'points' => 3], - 'external_audit' => ['label' => 'Audit esterni regolari', 'points' => 2], - 'none' => ['label' => 'Nessun obbligo', 'points' => 0], + 'nis2_required' => ['label' => 'Richiesto da NIS2', 'points' => 5, 'desc' => 'Sistema che rientra negli obblighi NIS2 dell\'organizzazione.'], + 'mandatory_cert' => ['label' => 'Certificazioni obbligatorie', 'points' => 4, 'desc' => 'Soggetto a certificazioni obbligatorie (es. ISO o settoriali).'], + 'strict_sla' => ['label' => 'Obblighi SLA stringenti', 'points' => 3, 'desc' => 'Vincolato a SLA contrattuali stringenti.'], + 'external_audit' => ['label' => 'Audit esterni regolari', 'points' => 2, 'desc' => 'Sottoposto regolarmente ad audit esterni.'], + 'none' => ['label' => 'Nessun obbligo', 'points' => 0, 'desc' => 'Nessun obbligo normativo o contrattuale specifico.'], ], ], ]; diff --git a/public/assets.html b/public/assets.html index 1522bf9..3bcf825 100644 --- a/public/assets.html +++ b/public/assets.html @@ -634,16 +634,18 @@ const sel = (pv != null) ? (typeof pv === 'object' ? (pv.value || '') : pv) : ''; let opts = ``; for (const [ov, od] of Object.entries(def.options)) { - opts += ``; + opts += ``; } body += `
${def.help}
- + +
`; } body += `
- Totale: 0/100 — —
`; + Totale: 0/100 — — +
`; showModal(`Valuta Rilevanza NIS2 — ${escapeHtml(a.name)}`, body, { size: 'lg', @@ -658,9 +660,23 @@ function updateScorePreview() { let total = 0, complete = true; + let rows = ''; document.querySelectorAll('.score-criterion').forEach(s => { - if (!s.value) { complete = false; return; } - total += parseInt(s.selectedOptions[0].dataset.pts || '0', 10); + const meaningEl = document.getElementById('meaning-' + s.dataset.key); + if (!s.value) { + complete = false; + if (meaningEl) meaningEl.textContent = ''; + return; + } + const opt = s.selectedOptions[0]; + const pts = parseInt(opt.dataset.pts || '0', 10); + total += pts; + // #432: mostra il significato dell'opzione selezionata sotto la combo + if (meaningEl) meaningEl.textContent = opt.dataset.desc || ''; + // #431: dettaglio per criterio del punteggio raggiunto + rows += `
+ ${escapeHtml(s.dataset.critLabel)}: ${escapeHtml(opt.dataset.lbl || '')} + ${pts}/${s.dataset.max}
`; }); let cls = total >= 80 ? 'critico' : total >= 60 ? 'alto' : total >= 40 ? 'medio' : total >= 20 ? 'basso' : 'trascurabile'; const color = relevanceClassColors[cls]; @@ -668,6 +684,10 @@ const clsEl = document.getElementById('score-class'); clsEl.textContent = complete ? `${cls.charAt(0).toUpperCase() + cls.slice(1)}${total >= 40 ? ' — Rilevante NIS2 ✓' : ''}` : '(completa tutti i criteri)'; clsEl.style.color = complete ? color : 'var(--gray-400)'; + const bdEl = document.getElementById('score-breakdown'); + if (bdEl) bdEl.innerHTML = rows + ? `
Dettaglio punteggio per criterio
${rows}` + : ''; } async function submitScoring(id) { diff --git a/public/version.json b/public/version.json index ff7c24b..d49682d 100644 --- a/public/version.json +++ b/public/version.json @@ -1 +1 @@ -{"version": "1.24.9", "build": "2026-06-23-v1.24.9", "date": "2026-06-23", "changelog": "Assistente ARIA — Ora ARIA conosce la barra laterale REALE dell'app e, quando ti spiega dove cliccare, usa i nomi esatti delle voci di menu (es. «sezione Operativo > Inventario») senza piu' inventare moduli o «fasi» inesistenti. Inoltre riceve la pagina da cui stai scrivendo, cosi' da darti indicazioni piu' pertinenti al punto in cui ti trovi. Risolto ticket #424."} +{"version": "1.24.10", "build": "2026-06-23-v1.24.10", "date": "2026-06-23", "changelog": "Valuta Rilevanza NIS2 (Inventario) — Ogni voce delle tendine ora mostra anche il suo SIGNIFICATO: scegliendo un'opzione compare sotto la combo una breve spiegazione di cosa indica (es. cosa vuol dire «Critico» per la Criticita Operativa). In piu' la finestra mostra il «Dettaglio punteggio per criterio»: vedi quanti punti hai ottenuto da ciascuna voce e come si compone il totale, anche riaprendo una valutazione gia' salvata. Risolti ticket #431 e #432."}