[FIX] ri-review guida: 2 fix guida + 2 fix prodotto UI orfane
cap-5: sei->quattro modalita + chiosa adeguatezza-ruolo sotto GV.RR-04 (non GV.PO-01) cap-7: nomi bottoni allineati alla UI (Invia Report Finale 30gg) assets.html: bottone Importa (openImportModal era orfana) reports.html: tab Requisiti ACN (loadAcnRequirements -> endpoint esistente, 87/116 per entity_type) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
33790427df
commit
7a23789b0f
@ -264,6 +264,7 @@
|
|||||||
<h2 data-i18n="assets.title">Inventario Asset</h2>
|
<h2 data-i18n="assets.title">Inventario Asset</h2>
|
||||||
<div class="content-header-actions">
|
<div class="content-header-actions">
|
||||||
<span class="text-muted" style="font-size:0.8rem; margin-right:8px;">Art. 21.2.i NIS2</span>
|
<span class="text-muted" style="font-size:0.8rem; margin-right:8px;">Art. 21.2.i NIS2</span>
|
||||||
|
<button class="btn btn-secondary" onclick="openImportModal()" title="Importa asset da CSV/CMDB">Importa</button>
|
||||||
<button class="btn btn-primary" onclick="showCreateAssetModal()">+ Nuovo Asset</button>
|
<button class="btn btn-primary" onclick="showCreateAssetModal()">+ Nuovo Asset</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -425,7 +425,7 @@
|
|||||||
<h3>Come si fa nella piattaforma</h3>
|
<h3>Come si fa nella piattaforma</h3>
|
||||||
<ol class="step-list">
|
<ol class="step-list">
|
||||||
<li>Vai su <strong>Gap Analysis</strong> e clicca "Nuovo Assessment".</li>
|
<li>Vai su <strong>Gap Analysis</strong> e clicca "Nuovo Assessment".</li>
|
||||||
<li>Rispondi alle 80 domande (sei modalità: implementato / parziale / non implementato / non applicabile).</li>
|
<li>Rispondi alle 80 domande (quattro modalità: implementato / parziale / non implementato / non applicabile).</li>
|
||||||
<li>Per ogni risposta, indica il <strong>livello di maturità</strong> (0–5).</li>
|
<li>Per ogni risposta, indica il <strong>livello di maturità</strong> (0–5).</li>
|
||||||
<li>Salva: puoi continuare in più sessioni.</li>
|
<li>Salva: puoi continuare in più sessioni.</li>
|
||||||
<li>Quando finisci, clicca <strong>"Analisi AI"</strong> per ricevere raccomandazioni prioritarie.</li>
|
<li>Quando finisci, clicca <strong>"Analisi AI"</strong> per ricevere raccomandazioni prioritarie.</li>
|
||||||
@ -449,9 +449,10 @@
|
|||||||
<div class="example-box">
|
<div class="example-box">
|
||||||
<strong>Esempio (requisiti di governance).</strong> <code>GV.RR-04</code> richiede che la cybersicurezza
|
<strong>Esempio (requisiti di governance).</strong> <code>GV.RR-04</code> richiede che la cybersicurezza
|
||||||
sia integrata nella gestione delle risorse umane: chi accede ai sistemi (utenti e amministratori) deve
|
sia integrata nella gestione delle risorse umane: chi accede ai sistemi (utenti e amministratori) deve
|
||||||
avere <strong>competenze e affidabilità adeguate al ruolo</strong>, valutate e documentate.
|
avere <strong>competenze e affidabilità adeguate al ruolo</strong>, valutate e documentate — è il
|
||||||
|
"controllo di adeguatezza al ruolo" delle figure chiave dell'organigramma.
|
||||||
<code>GV.PO-01</code> richiede una <strong>policy di gestione del rischio cyber</strong> formalizzata,
|
<code>GV.PO-01</code> richiede una <strong>policy di gestione del rischio cyber</strong> formalizzata,
|
||||||
comunicata e applicata. È il "controllo di adeguatezza al ruolo" delle figure chiave dell'organigramma.
|
comunicata e applicata.
|
||||||
</div>
|
</div>
|
||||||
<div class="callout-tip">
|
<div class="callout-tip">
|
||||||
<strong>Come si collega alla piattaforma.</strong> Le <strong>80 domande</strong> della Gap Analysis
|
<strong>Come si collega alla piattaforma.</strong> Le <strong>80 domande</strong> della Gap Analysis
|
||||||
@ -612,8 +613,8 @@
|
|||||||
<li>Vai su <strong>Incidenti</strong> e clicca "+ Nuovo Incidente".</li>
|
<li>Vai su <strong>Incidenti</strong> e clicca "+ Nuovo Incidente".</li>
|
||||||
<li>Compila titolo, classificazione, severità, ora di rilevazione.</li>
|
<li>Compila titolo, classificazione, severità, ora di rilevazione.</li>
|
||||||
<li>Il sistema calcola automaticamente le 3 scadenze (24h / 72h / 1 mese).</li>
|
<li>Il sistema calcola automaticamente le 3 scadenze (24h / 72h / 1 mese).</li>
|
||||||
<li>Quando arriva il momento, usa i bottoni <strong>"Invia Early Warning"</strong>,
|
<li>Quando arriva il momento, usa i bottoni <strong>"Invia Early Warning (24h)"</strong>,
|
||||||
<strong>"Invia Notifica"</strong> e <strong>"Invia Final Report"</strong>: le email partono verso
|
<strong>"Invia Notifica (72h)"</strong> e <strong>"Invia Report Finale (30gg)"</strong>: le email partono verso
|
||||||
l'indirizzo CSIRT configurato.</li>
|
l'indirizzo CSIRT configurato.</li>
|
||||||
<li>Aggiorna lo stato dell'incidente (analisi → contenimento → eradicazione → recovery → chiuso).</li>
|
<li>Aggiorna lo stato dell'incidente (analisi → contenimento → eradicazione → recovery → chiuso).</li>
|
||||||
<li>Compila root cause e lezioni apprese alla chiusura.</li>
|
<li>Compila root cause e lezioni apprese alla chiusura.</li>
|
||||||
|
|||||||
@ -360,6 +360,7 @@
|
|||||||
<button onclick="switchTab('audit', this)">Audit Log</button>
|
<button onclick="switchTab('audit', this)">Audit Log</button>
|
||||||
<button onclick="switchTab('iso', this)">ISO 27001</button>
|
<button onclick="switchTab('iso', this)">ISO 27001</button>
|
||||||
<button onclick="switchTab('monitoring', this)" data-i18n="audit.monitoring_tab">Monitoraggio Continuo</button>
|
<button onclick="switchTab('monitoring', this)" data-i18n="audit.monitoring_tab">Monitoraggio Continuo</button>
|
||||||
|
<button onclick="switchTab('acn', this)">Requisiti ACN</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tab: Report Compliance -->
|
<!-- Tab: Report Compliance -->
|
||||||
@ -412,6 +413,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-panel" id="tab-acn">
|
||||||
|
<div id="acn-container">
|
||||||
|
<div class="loading-state">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<p>Caricamento requisiti ACN...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@ -479,6 +489,61 @@
|
|||||||
if (tabId === 'audit') { auditPage = 1; loadAuditLogs(); }
|
if (tabId === 'audit') { auditPage = 1; loadAuditLogs(); }
|
||||||
if (tabId === 'iso') loadIsoMapping();
|
if (tabId === 'iso') loadIsoMapping();
|
||||||
if (tabId === 'monitoring') loadMonitoring();
|
if (tabId === 'monitoring') loadMonitoring();
|
||||||
|
if (tabId === 'acn') loadAcnRequirements();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Requisiti ACN (specifiche di base, Determina 164179/2025) ──────────
|
||||||
|
const ACN_ST = {
|
||||||
|
not_started: ['Da iniziare', '#9ca3af'],
|
||||||
|
in_progress: ['In corso', '#eab308'],
|
||||||
|
implemented: ['Implementato', '#22c55e'],
|
||||||
|
not_applicable:['Non applicabile', '#64748b']
|
||||||
|
};
|
||||||
|
async function loadAcnRequirements() {
|
||||||
|
const c = document.getElementById('acn-container');
|
||||||
|
if (!c) return;
|
||||||
|
c.innerHTML = '<div class="loading-state"><div class="spinner"></div><p>Caricamento...</p></div>';
|
||||||
|
let res;
|
||||||
|
try { res = await api.getAcnRequirements(); }
|
||||||
|
catch (e) { c.innerHTML = '<p style="color:#ef4444;padding:16px;">Errore di connessione</p>'; return; }
|
||||||
|
if (!res.success) { c.innerHTML = '<p style="color:#ef4444;padding:16px;">' + escapeHtml(res.message || 'Errore') + '</p>'; return; }
|
||||||
|
const d = res.data;
|
||||||
|
const s = d.summary || {};
|
||||||
|
const cards = ['implemented','in_progress','not_started','not_applicable'].map(k =>
|
||||||
|
`<div style="border-left:4px solid ${ACN_ST[k][1]};padding:8px 14px;background:var(--gray-50,#f8fafc);border-radius:6px;min-width:110px;">
|
||||||
|
<div style="font-size:1.4rem;font-weight:700;">${s[k]||0}</div><div style="font-size:.75rem;color:#64748b;">${ACN_ST[k][0]}</div></div>`).join('');
|
||||||
|
const groups = {};
|
||||||
|
(d.requirements||[]).forEach(r => { (groups[r.function_name] = groups[r.function_name] || []).push(r); });
|
||||||
|
let body = '';
|
||||||
|
Object.keys(groups).forEach(fn => {
|
||||||
|
const reqs = groups[fn];
|
||||||
|
body += `<h3 style="margin:18px 0 8px;">${escapeHtml(fn)} <span style="font-weight:400;color:#64748b;font-size:.85rem;">(${reqs.length})</span></h3>`;
|
||||||
|
body += '<table class="data-table" style="width:100%;"><thead><tr><th style="width:90px;">Sottocat.</th><th>Requisito</th><th style="width:175px;">Stato</th></tr></thead><tbody>';
|
||||||
|
reqs.forEach(r => {
|
||||||
|
const st = ACN_ST[r.status] || ACN_ST.not_started;
|
||||||
|
const opts = Object.keys(ACN_ST).map(k => `<option value="${k}"${k===r.status?' selected':''}>${ACN_ST[k][0]}</option>`).join('');
|
||||||
|
body += `<tr>
|
||||||
|
<td><code title="${escapeHtml(r.subcategory_text||'')}">${escapeHtml(r.subcategory)}</code></td>
|
||||||
|
<td>${escapeHtml(r.requirement)}</td>
|
||||||
|
<td><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${st[1]};margin-right:6px;"></span>
|
||||||
|
<select onchange="updateAcn(${r.id}, this.value)" style="padding:4px;border:1px solid #cbd5e1;border-radius:5px;">${opts}</select></td></tr>`;
|
||||||
|
});
|
||||||
|
body += '</tbody></table>';
|
||||||
|
});
|
||||||
|
c.innerHTML = `
|
||||||
|
<p style="font-size:.85rem;color:#475569;margin-bottom:12px;">
|
||||||
|
Requisiti operativi <strong>specifiche di base ACN</strong> (Determina 164179/2025, Framework Nazionale 2025)
|
||||||
|
per questa organizzazione (<strong>${escapeHtml(d.entity)}</strong>: ${d.total} requisiti).
|
||||||
|
Compliance: <strong>${d.compliance_percent}%</strong>. <em>${escapeHtml(d.source||'')}</em></p>
|
||||||
|
<div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px;">${cards}</div>
|
||||||
|
${body}`;
|
||||||
|
}
|
||||||
|
async function updateAcn(id, status) {
|
||||||
|
try {
|
||||||
|
const res = await api.updateAcnRequirement(id, status, null);
|
||||||
|
if (res.success) { if (typeof showNotification==='function') showNotification('Stato aggiornato', 'success'); loadAcnRequirements(); }
|
||||||
|
else if (typeof showNotification==='function') showNotification(res.message || 'Errore', 'error');
|
||||||
|
} catch (e) { if (typeof showNotification==='function') showNotification('Errore di connessione', 'error'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Continuous Control Monitoring (P1) ───────────────────────
|
// ── Continuous Control Monitoring (P1) ───────────────────────
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user