Evita la "sessione scaduta" e i deploy che restano invisibili all'utente. - api.js: refresh PROATTIVO dell'access token ~2 min prima della scadenza (scheduleTokenRefresh su exp del JWT, riprogrammato ad ogni setTokens) + ensureFreshToken() per rinnovo immediato al ritorno sulla scheda. Con refresh a 7gg l'utente resta loggato senza mai vedere il login. - common.js: watch versione (poll version.json ogni 5 min + su visibilitychange) → banner "È disponibile una nuova versione — Aggiorna" (reload) quando cambia; nudge service worker (registration.update); su visibilitychange chiama anche api.ensureFreshToken(). Nessun hard-refresh manuale. - Cache-buster api/common ?v=20260729b. version 1.25.12. Solo frontend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
218 lines
17 KiB
HTML
218 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="it">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
<title>Modello Organizzativo SGSI (ISO 27001) · NIS2 Agile</title>
|
||
<!-- UI V3: Inter self-host + design system v3.css. Self-host only, nessun CDN esterno. -->
|
||
<link rel="stylesheet" href="/vendor/inter/inter.css?v=20260627">
|
||
<link rel="stylesheet" href="/css/v3.css?v=20260627">
|
||
<style>
|
||
/* Stili specifici della pagina SGSI non coperti da v3.css (nessun CDN). */
|
||
.text-muted { color: var(--muted); }
|
||
.sr-only { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
|
||
/* Base .btn usata dai bottoni generati via JS (es. "btn btn-sm btn-outline") */
|
||
.btn { display:inline-flex; align-items:center; justify-content:center; gap:7px; font:inherit; font-weight:600; font-size:12.5px; border-radius:8px; padding:8px 13px; border:1px solid transparent; cursor:pointer; line-height:1.4; text-decoration:none; }
|
||
.btn .icon, .btn .ic { width:15px; height:15px; }
|
||
.isms-intro { background:#EAF1FA; border-left:4px solid var(--c-blue); padding:14px 18px; border-radius:10px; margin-bottom:18px; font-size:.92rem; line-height:1.6; color:var(--ink); }
|
||
.isms-steps { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:20px; }
|
||
.isms-step { flex:1 1 140px; min-width:120px; padding:11px 12px; border:1.5px solid var(--line); border-radius:11px; background:#fff; cursor:pointer; font-size:.82rem; text-align:center; transition:border-color .12s,background .12s; }
|
||
.isms-step:hover { border-color:#9FBEDD; }
|
||
.isms-step.active { border-color:var(--c-blue); background:#EAF1FA; font-weight:700; }
|
||
.isms-step.done { border-color:var(--c-green); }
|
||
.isms-step .num { display:inline-block; width:22px; height:22px; line-height:22px; border-radius:50%; background:#EEF2F7; font-weight:700; margin-bottom:4px; }
|
||
.isms-step.done .num { background:var(--c-green); color:#fff; }
|
||
.isms-panel { display:none; }
|
||
.isms-panel.active { display:block; }
|
||
.isms-panel h3 { margin:0 0 12px; font-size:17px; font-weight:800; }
|
||
.isms-panel h4 { margin:16px 0 8px; font-size:14px; font-weight:700; }
|
||
.isms-disclaimer { font-size:.8rem; color:#92400e; background:#FBF1E2; border:1px solid #fde68a; border-radius:8px; padding:10px 12px; margin:12px 0; }
|
||
.raci-row { display:flex; gap:8px; align-items:center; flex-wrap:wrap; padding:8px 0; border-bottom:1px solid var(--line); }
|
||
.raci-row input, .raci-row select { padding:8px 10px; border:1px solid var(--line); border-radius:8px; font:inherit; font-size:.85rem; color:var(--ink); }
|
||
.soa-std { border:1px solid var(--line); border-radius:11px; margin-bottom:14px; overflow:hidden; }
|
||
.soa-std-head { background:#F5F8FC; padding:12px 16px; cursor:pointer; display:flex; justify-content:space-between; align-items:center; }
|
||
.soa-std-body { padding:6px 14px 14px; display:none; }
|
||
.soa-std.open .soa-std-body { display:block; }
|
||
.soa-theme { font-size:.78rem; font-weight:700; text-transform:uppercase; color:var(--muted); margin:14px 0 6px; letter-spacing:.04em; }
|
||
.soa-ctrl { padding:12px 0; border-top:1px solid var(--line); }
|
||
.soa-ctrl-head { display:flex; gap:10px; align-items:flex-start; justify-content:space-between; flex-wrap:wrap; }
|
||
.soa-code { display:inline-block; background:#E7F0FB; color:#1F5FA8; font-weight:700; font-size:.72rem; padding:2px 8px; border-radius:6px; margin-right:6px; }
|
||
.soa-derived { background:#E6F4EC; color:#1E7A4E; font-size:.68rem; padding:1px 6px; border-radius:5px; }
|
||
.soa-opts { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
|
||
.soa-opt { min-height:34px; padding:5px 10px; border:1.5px solid var(--line); border-radius:18px; background:#fff; cursor:pointer; font:inherit; font-size:.8rem; font-weight:600; color:var(--ink); }
|
||
.soa-opt.sel-implemented,.soa-opt.sel-verified { background:var(--c-green); color:#fff; border-color:var(--c-green); }
|
||
.soa-opt.sel-in_progress { background:var(--c-amber); color:#fff; border-color:var(--c-amber); }
|
||
.soa-opt.sel-not_started { background:#9ca3af; color:#fff; border-color:#9ca3af; }
|
||
.soa-justif { width:100%; margin-top:8px; padding:8px; border:1px solid var(--line); border-radius:8px; font:inherit; font-size:.84rem; min-height:46px; color:var(--ink); }
|
||
.isms-field { margin-bottom:14px; }
|
||
.isms-field label { display:block; font-weight:600; font-size:.88rem; margin-bottom:4px; }
|
||
.isms-field textarea, .isms-field input { width:100%; padding:9px; border:1px solid var(--line); border-radius:8px; font:inherit; font-size:.9rem; color:var(--ink); }
|
||
.isms-flags label { display:block; padding:8px 0; font-size:.9rem; }
|
||
.ck-item { display:flex; justify-content:space-between; padding:8px 0; border-bottom:1px solid var(--line); font-size:.9rem; }
|
||
.ck-yes { color:var(--c-green); font-weight:700; } .ck-no { color:#9ca3af; }
|
||
.savehint { font-size:.78rem; color:var(--muted); min-height:16px; }
|
||
</style>
|
||
<!-- PWA:start -->
|
||
<link rel="manifest" href="/manifest.webmanifest">
|
||
<meta name="theme-color" content="#0066CC">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
|
||
<meta name="application-name" content="NIS2 Agile">
|
||
<script src="/js/pwa.js?v=20260614" defer></script>
|
||
<!-- PWA:end -->
|
||
</head>
|
||
<body>
|
||
<!-- Chrome V3 (appbar + mega-menu) iniettata da topnav-v3.js in questo host -->
|
||
<div id="topnav"></div>
|
||
|
||
<main class="wrap">
|
||
<nav class="crumb" aria-label="breadcrumb">
|
||
<i data-lucide="home" class="ic"></i><a href="dashboard.html">Home</a>
|
||
<i data-lucide="chevron-right" class="ic"></i><span>SGSI (ISO 27001)</span>
|
||
</nav>
|
||
<div class="page-head">
|
||
<div>
|
||
<h1 data-i18n="isms.title">Modello Organizzativo SGSI (ISO 27001)</h1>
|
||
<p class="sub">Procedura guidata ISO/IEC 27001:2022 — clausole 4–10 + Statement of Applicability</p>
|
||
</div>
|
||
<div class="content-header-actions" style="display:flex; align-items:center; gap:12px; flex-wrap:wrap;">
|
||
<span class="savehint" id="isms-savehint" role="status" aria-live="polite"></span>
|
||
<button class="btn-ghost" id="nis2-isms-btn-export" onclick="ismsExportView()" data-i18n="isms.export">
|
||
<i data-lucide="file-text" class="ic"></i>
|
||
<span>Esporta SGSI</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<section class="card card-pad">
|
||
<div class="isms-intro" id="nis2-isms-intro">
|
||
<strong data-i18n="isms.intro.title">Costruisci il tuo Sistema di Gestione della Sicurezza delle Informazioni.</strong>
|
||
<span data-i18n="isms.intro.body">Procedura guidata ISO/IEC 27001:2022 (clausole 4-10 + Statement of Applicability). Lo Statement of Applicability viene pre-popolato dalle tue risposte alla Gap Analysis NIS2. Attiva le estensioni cloud ISO 27017/27018 dove pertinenti.</span>
|
||
</div>
|
||
<div class="isms-disclaimer" id="nis2-isms-disclaimer" data-i18n="isms.disclaimer">Strumento di supporto e pre-audit: non costituisce una certificazione ISO 27001 né un parere professionale vincolante. Gli obblighi normativi in Italia derivano da NIS2 / D.Lgs. 138/2024 / Determinazioni ACN; ISO 27001/27017/27018 sono best practice.</div>
|
||
|
||
<div class="isms-steps" id="isms-steps"></div>
|
||
|
||
<!-- STEP 1 - Contesto & Ambito (cl.4) -->
|
||
<div class="isms-panel" id="panel-0">
|
||
<div class="card card-pad">
|
||
<h3 data-i18n="isms.s1.title">1. Contesto e Ambito (cl. 4)</h3>
|
||
<div class="isms-field"><label for="f-scope" data-i18n="isms.s1.scope">Ambito del SGSI (scope statement)</label><textarea id="f-scope" rows="3" placeholder="Es. Tutti i sistemi e processi a supporto dei servizi ICT erogati dalla sede di..."></textarea></div>
|
||
<div class="isms-field"><label for="f-ctx-int" data-i18n="isms.s1.ctx_int">Contesto interno</label><textarea id="f-ctx-int" rows="2"></textarea></div>
|
||
<div class="isms-field"><label for="f-ctx-ext" data-i18n="isms.s1.ctx_ext">Contesto esterno</label><textarea id="f-ctx-ext" rows="2"></textarea></div>
|
||
<div class="isms-field"><label for="f-parties" data-i18n="isms.s1.parties">Parti interessate (una per riga)</label><textarea id="f-parties" rows="3" placeholder="Clienti Autorità (ACN/CSIRT) Fornitori ICT"></textarea></div>
|
||
<div class="isms-field"><label for="f-boundaries" data-i18n="isms.s1.boundaries">Confini del SGSI</label><textarea id="f-boundaries" rows="2"></textarea></div>
|
||
<div class="isms-field"><label for="f-exclusions" data-i18n="isms.s1.exclusions">Esclusioni motivate</label><textarea id="f-exclusions" rows="2"></textarea></div>
|
||
<div class="isms-flags">
|
||
<strong data-i18n="isms.s1.cloud">Estensioni cloud (attivano i controlli condizionali nel SoA)</strong>
|
||
<label><input type="checkbox" id="f-uses-cloud"> <span data-i18n="isms.s1.uses_cloud">Usiamo servizi cloud pubblici (Microsoft 365, AWS, Google...) → ISO 27017</span></label>
|
||
<label><input type="checkbox" id="f-cloud-provider"> <span data-i18n="isms.s1.cloud_provider">Siamo fornitori di servizi cloud → ISO 27017 (lato provider)</span></label>
|
||
<label><input type="checkbox" id="f-pii-cloud"> <span data-i18n="isms.s1.pii_cloud">Trattiamo dati personali (PII) in cloud pubblico come responsabili → ISO 27018</span></label>
|
||
</div>
|
||
<button class="btn-primary" id="nis2-isms-btn-save-step1" onclick="saveStep1()" data-i18n="isms.save_next">Salva e continua</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 2 - Leadership (cl.5) -->
|
||
<div class="isms-panel" id="panel-1">
|
||
<div class="card card-pad">
|
||
<h3 data-i18n="isms.s2.title">2. Leadership: ruoli e responsabilità (cl. 5)</h3>
|
||
<p class="text-muted" data-i18n="isms.s2.hint">Definisci i ruoli del SGSI con la matrice RACI (Responsible, Accountable, Consulted, Informed).</p>
|
||
<div id="roles-list"></div>
|
||
<div class="raci-row" style="border-top:2px solid var(--line); margin-top:10px;">
|
||
<input id="r-name" placeholder="Ruolo (es. CISO)" aria-label="Ruolo" style="flex:1 1 160px;">
|
||
<input id="r-resp" placeholder="Responsabilità" aria-label="Responsabilità" style="flex:2 1 220px;">
|
||
<select id="r-raci" aria-label="RACI"><option value="">RACI</option><option>R</option><option>A</option><option>C</option><option>I</option></select>
|
||
<button class="btn-primary btn-sm" id="nis2-isms-btn-add-role" onclick="addRole()" data-i18n="isms.s2.add">Aggiungi ruolo</button>
|
||
</div>
|
||
<button class="btn-ghost" id="nis2-isms-btn-next-step2" style="margin-top:14px;" onclick="goStep(2)" data-i18n="isms.next">Continua</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 3 - Risk (cl.6) -->
|
||
<div class="isms-panel" id="panel-2">
|
||
<div class="card card-pad">
|
||
<h3 data-i18n="isms.s3.title">3. Risk: metodologia e obiettivi (cl. 6)</h3>
|
||
<div class="isms-field"><label for="f-method" data-i18n="isms.s3.method">Metodologia di risk assessment</label><textarea id="f-method" rows="3" placeholder="Es. ISO 27005 / NIST SP 800-30; scala probabilità×impatto 5×5 (già usata nel modulo Rischi)."></textarea></div>
|
||
<div class="isms-field"><label for="f-objectives" data-i18n="isms.s3.objectives">Obiettivi del SGSI (uno per riga)</label><textarea id="f-objectives" rows="3"></textarea></div>
|
||
<p class="text-muted" data-i18n="isms.s3.link">Il registro dei rischi vive nel modulo <a href="risks.html">Rischi</a>: questo passo ne dichiara la metodologia.</p>
|
||
<button class="btn-primary" id="nis2-isms-btn-save-step3" onclick="saveStep3()" data-i18n="isms.save_next">Salva e continua</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 4 - SoA -->
|
||
<div class="isms-panel" id="panel-3">
|
||
<div class="card card-pad">
|
||
<h3 data-i18n="isms.s4.title">4. Statement of Applicability</h3>
|
||
<p class="text-muted" data-i18n="isms.s4.hint">I controlli sono pre-popolati dalle risposte NIS2 dove esiste corrispondenza (badge "da NIS2"). Conferma applicabilità, stato e motivazione per ciascuno.</p>
|
||
<div style="margin:10px 0;">
|
||
<button class="btn-ghost btn-sm" id="nis2-isms-btn-derive-soa" onclick="deriveSoa()" data-i18n="isms.s4.derive">Ri-deriva dal NIS2</button>
|
||
<span id="soa-stats" class="text-muted" style="margin-left:12px; font-size:.85rem;"></span>
|
||
</div>
|
||
<div id="soa-groups"></div>
|
||
<button class="btn-ghost" id="nis2-isms-btn-next-step4" style="margin-top:14px;" onclick="goStep(4)" data-i18n="isms.next">Continua</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 5 - Documented information (cl.7-8) -->
|
||
<div class="isms-panel" id="panel-4">
|
||
<div class="card card-pad">
|
||
<h3 data-i18n="isms.s5.title">5. Documented Information (cl. 7-8)</h3>
|
||
<div class="raci-row" style="border:none;">
|
||
<label for="d-type" class="sr-only">Tipo di documento</label>
|
||
<select id="d-type" style="flex:1 1 200px;" aria-label="Tipo di documento">
|
||
<option value="policy_sgsi">Policy SGSI</option>
|
||
<option value="dichiarazione_applicabilita">Dichiarazione di Applicabilità</option>
|
||
<option value="politica_controllo_accessi">Politica controllo accessi</option>
|
||
<option value="procedura_incident">Procedura gestione incidenti</option>
|
||
<option value="procedura_continuita">Procedura continuità operativa</option>
|
||
<option value="politica_fornitori">Politica sicurezza fornitori</option>
|
||
</select>
|
||
<button class="btn-primary btn-sm" onclick="aiGenDoc()" id="btn-aigen" data-i18n="isms.s5.aigen">Genera bozza con AI</button>
|
||
</div>
|
||
<div class="savehint" id="aigen-hint" role="status" aria-live="polite"></div>
|
||
<div id="docs-list" style="margin-top:14px;"></div>
|
||
<button class="btn-ghost" id="nis2-isms-btn-next-step5" style="margin-top:14px;" onclick="goStep(5)" data-i18n="isms.next">Continua</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 6 - Monitoring & Readiness (cl.9-10) -->
|
||
<div class="isms-panel" id="panel-5">
|
||
<div class="card card-pad">
|
||
<h3 data-i18n="isms.s6.title">6. Monitoraggio e Miglioramento (cl. 9-10)</h3>
|
||
<p class="text-muted" data-i18n="isms.s6.hint">Gli audit interni e le non conformità si gestiscono nei moduli esistenti: <a href="reports.html">Audit & Report</a> e NCR/CAPA.</p>
|
||
<h4 data-i18n="isms.s6.readiness">Completamento del SGSI</h4>
|
||
<div style="text-align:center; margin:14px 0;">
|
||
<div style="font-size:2.6rem; font-weight:800; color:var(--c-blue);" id="readiness-pct">0%</div>
|
||
</div>
|
||
<div id="readiness-checklist"></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Scripts V3: api.js → common.js (helper+FAB reali) → Lucide self-host →
|
||
topnav-v3.js (chrome, ridefinisce loadSidebar) → i18n → help → isms.js.
|
||
isms.js si auto-inizializza su DOMContentLoaded (checkAuth/I18n/loadSidebar/Help/render). -->
|
||
<script src="/js/api.js?v=20260729b"></script>
|
||
<script src="/js/common.js?v=20260729b"></script>
|
||
<script src="/vendor/lucide/lucide.min.js"></script>
|
||
<script src="/js/topnav-v3.js?v=20260729"></script>
|
||
<script src="/js/i18n.js?v=20260729"></script>
|
||
<script src="/js/help.js?v=20260729b"></script>
|
||
<script src="/js/isms.js?v=20260627v3"></script>
|
||
<script>
|
||
// Icone Lucide della chrome + crumb/page-head statici. L'init dati e il wiring
|
||
// (renderSteps/loadModel/goStep) restano in isms.js (suo DOMContentLoaded).
|
||
document.addEventListener('DOMContentLoaded', function(){
|
||
if (window.lucide && lucide.createIcons) { try { lucide.createIcons(); } catch (e) {} }
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|