From ae7bb072d79caea99f3de006810d62acfa2fc39c Mon Sep 17 00:00:00 2001 From: DevEnv nis2-agile Date: Thu, 11 Jun 2026 18:19:54 +0200 Subject: [PATCH] [DOCS] Manuale d'uso COMPLETO v1.14.0: accesso/registrazione/onboarding passo-passo + 18 moduli dall'help reale Riscrittura completa: istruzioni concrete (login, registrazione 3 step, onboarding 4 step con campi reali, navigazione), per ogni modulo "cosa trovi e come si usa" estratto dall'help contestuale del prodotto (help.js), FAQ, glossario. Rimosse le interruzioni di pagina che lasciavano pagine vuote. Generatore self-contained (estrae i contenuti da public/js/help.js via node). Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/MANUALE_UTENTE_NIS2_AGILE.docx | Bin 11910 -> 26747 bytes scripts/genera-manuale-utente.py | 531 ++++++++++++---------------- 2 files changed, 222 insertions(+), 309 deletions(-) diff --git a/docs/MANUALE_UTENTE_NIS2_AGILE.docx b/docs/MANUALE_UTENTE_NIS2_AGILE.docx index bb9bffa1c563bd79b189b1fd947ba8af9cd03d31..e85df079d9c8aaca9084659628136d7cd1efa309 100644 GIT binary patch delta 25180 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

M5Lt`SiI9Kt3pMGyQ1WD_@~UrG}oxI+O3Cin&h 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 DBCS>` diff --git a/scripts/genera-manuale-utente.py b/scripts/genera-manuale-utente.py index 6a3cc05..1de7d03 100644 --- a/scripts/genera-manuale-utente.py +++ b/scripts/genera-manuale-utente.py @@ -1,287 +1,228 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Genera il Manuale d'uso di NIS2 Agile in .docx usando solo stdlib (zipfile+XML).""" -import zipfile, re, datetime +"""Manuale d'uso COMPLETO di NIS2 Agile (.docx, solo stdlib). Contenuti moduli da help.js reale.""" +import zipfile, re, json, html as _html, subprocess, os from xml.sax.saxutils import escape -OUT = "/projects/nis2-agile/docs/MANUALE_UTENTE_NIS2_AGILE.docx" - -# ───────────────────────────────────────────────────────────────────────── -# CONTENUTO DEL MANUALE (DSL: lista di blocchi) -# ('title', titolo, sottotitolo, riga_meta) -# ('h1'|'h2'|'h3', testo) | ('p', testo) | ('note', testo) -# ('ul', [voci]) | ('ol', [voci]) -# ('table', [intestazioni], [[riga],...]) -# ('pb',) page break -# Nel testo: **grassetto** supportato. -# ───────────────────────────────────────────────────────────────────────── +BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # repo root +OUT = os.path.join(BASE, "docs", "MANUALE_UTENTE_NIS2_AGILE.docx") +HELP_JSON = "/tmp/help.json" +# Auto-estrae i contenuti dall'help reale del prodotto (public/js/help.js) via node. +_node = ('const fs=require("fs");let s=fs.readFileSync(process.argv[1],"utf8");' + 'const a=s.indexOf("var _helpContent");const start=s.indexOf("{",a);' + 'const end=s.indexOf("var _pageMap");let obj=s.slice(start,s.lastIndexOf("}",end)+1);' + 'fs.writeFileSync(process.argv[2],JSON.stringify(eval("("+obj+")")));') +subprocess.run(["node","-e",_node, os.path.join(BASE,"public","js","help.js"), HELP_JSON], check=True) +HELP = json.load(open(HELP_JSON, encoding="utf-8")) DATE = "11 giugno 2026" + C = [] def add(*b): C.append(b) -add('title', "NIS2 Agile", "Manuale d'uso del prodotto", - "Versione piattaforma 1.14.0 · Aggiornato all'%s" % DATE) +def html2mk(s): + """Converte l'HTML dell'help nel markup interno (**bold**) + testo pulito.""" + s = re.sub(r'|', '**', s) + s = re.sub(r'<[^>]+>', '', s) # rimuovi altri tag (span/em/...) + s = _html.unescape(s) # < ≥   ... + s = s.replace(' ', ' ') + s = re.sub(r'\s+', ' ', s).strip() + # bilancia eventuali ** dispari + if s.count('**') % 2: s += '**' + return s -# ===== INDICE (statico, i numeri di pagina non sono calcolati) ===== -add('h1', "Indice dei contenuti") -for n in ["1. Introduzione","2. Primi passi (accesso, registrazione, onboarding)", - "3. Dashboard","4. Gap Analysis NIS2 (Art. 21)","5. Gap Analysis ACN (Determinazione 164179/2025)", - "6. Modello Organizzativo SGSI (ISO 27001/27017/27018)","7. Gestione dei Rischi", - "8. Gestione degli Incidenti (Art. 23)","9. Policy e procedure","10. Supply Chain (fornitori)", - "11. Formazione","12. Asset","13. Audit & Report","14. Whistleblowing (Art. 32)", - "15. Aggiornamenti normativi","16. Knowledge Base e Assistente AI","17. Segnalazioni (feedback)", - "18. Impostazioni","19. Amministrazione","20. Integrazioni e API","21. Glossario","22. Riferimenti normativi"]: - add('p', n) +def module_chapter(num, title, topic_key, lead=None): + t = HELP.get(topic_key, {}) + add('h1', f"{num}. {title}") + if lead: add('p', lead) + if t.get('intro'): add('p', html2mk(t['intro'])) + for sec in t.get('sections', []): + add('h3', html2mk(sec.get('heading',''))) + items = [html2mk(x) for x in sec.get('items', [])] + if items: add('ul', items) + refs = [html2mk(x) for x in t.get('references', [])] + if refs: + add('h3', "Riferimenti normativi") + add('ul', refs) + +# ══════════════════ COPERTINA ══════════════════ +add('title', "NIS2 Agile", "Manuale d'uso del prodotto", + f"Guida operativa completa · Versione piattaforma 1.14.0 · {DATE}") +add('p', "Questo manuale spiega passo dopo passo come accedere alla piattaforma, registrarsi, completare l'onboarding aziendale e utilizzare ogni modulo. Per ogni schermata trovi cosa contiene, a cosa serve e come operare.") add('pb') -# ===== 1. INTRODUZIONE ===== +# ══════════════════ INDICE ══════════════════ +add('h1', "Indice") +toc = ["1. Introduzione","2. Requisiti e accesso alla piattaforma","3. Registrazione di un nuovo utente", + "4. Onboarding: configurazione dell'azienda","5. Come muoversi nell'interfaccia","6. Dashboard", + "7. Gap Analysis NIS2 (Art. 21)","8. Gap Analysis ACN (Determinazione 164179/2025)", + "9. Modello Organizzativo SGSI (ISO 27001/27017/27018)","10. Gestione dei Rischi", + "11. Gestione degli Incidenti (Art. 23)","12. Policy e procedure","13. Supply Chain (fornitori)", + "14. Formazione","15. Asset","16. Audit & Report","17. Whistleblowing (Art. 32)", + "18. Aggiornamenti normativi","19. Knowledge Base","20. Compliance Journey","21. Segnalazioni (feedback)", + "22. Impostazioni","23. Gestione delle aziende (consulenti)","24. Domande frequenti (FAQ)", + "25. Glossario","26. Riferimenti normativi"] +for x in toc: add('p', x) +add('note', "I nomi delle voci e l'aspetto delle schermate possono variare leggermente con gli aggiornamenti. In ogni pagina è disponibile il pulsante di aiuto contestuale (icona ?) con la guida e i riferimenti normativi.") + +# ══════════════════ 1. INTRODUZIONE ══════════════════ add('h1', "1. Introduzione") -add('h2', "1.1 Che cos'è NIS2 Agile") -add('p', "NIS2 Agile è una piattaforma SaaS multi-tenant che supporta le aziende nel percorso di conformità alla **Direttiva (UE) 2022/2555 (NIS2)** e al suo recepimento italiano (**D.Lgs. 138/2024**), comprese le **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale (Claude) per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.") -add('p', "Dalla versione 1.14.0 la piattaforma include anche un modulo guidato per la costruzione del **Modello Organizzativo SGSI secondo ISO/IEC 27001:2022**, con estensioni cloud ISO/IEC 27017:2015 e 27018:2019.") -add('h2', "1.2 A chi è rivolto") -add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2 con risorse limitate;", - "**Grandi imprese / Enterprise** con processi di compliance strutturati;", - "**Consulenti e CISO** che gestiscono più organizzazioni clienti tramite uno studio (consulting firm)."]) -add('h2', "1.3 Quadro normativo di riferimento") -add('table', ["Fonte","Ruolo"], - [["Direttiva (UE) 2022/2555 (NIS2)","Principi e obblighi europei di cibersicurezza"], - ["D.Lgs. 138/2024","Recepimento italiano della NIS2 (obblighi operativi)"], - ["Determinazione ACN 164179/2025","Misure di sicurezza di base, classificazione e notifica incidenti (Allegati)"], - ["ISO/IEC 27001:2022","Requisiti del Sistema di Gestione della Sicurezza delle Informazioni (best practice)"], - ["ISO/IEC 27017:2015 / 27018:2019","Controlli per servizi cloud / protezione PII in cloud (best practice)"]]) -add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante, e non rilascia certificazioni ISO. Le valutazioni proposte (perimetro, applicabilità, significatività) vanno confermate con il referente compliance/legale dell'organizzazione.") +add('p', "**NIS2 Agile** è una piattaforma web (SaaS) che accompagna le aziende nella conformità alla **Direttiva (UE) 2022/2555 (NIS2)**, al suo recepimento italiano (**D.Lgs. 138/2024**) e alle **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.") +add('p', "Dalla versione 1.14.0 include anche il **Modello Organizzativo SGSI** secondo **ISO/IEC 27001:2022**, con estensioni cloud ISO 27017/27018.") +add('h3', "A chi è rivolto") +add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2;", + "**Grandi imprese** con processi di compliance strutturati;", + "**Consulenti e CISO** che seguono più aziende clienti tramite uno studio."]) +add('h3', "Come è organizzato il lavoro nella piattaforma") +add('p', "Il percorso tipico è: **(1)** accedi o registrati → **(2)** completa l'onboarding dell'azienda (che ne determina la classificazione NIS2) → **(3)** esegui la Gap Analysis NIS2 → **(4)** approfondisci con la Gap Analysis ACN e costruisci il Modello SGSI → **(5)** gestisci rischi, incidenti, policy, fornitori, formazione e audit nel tempo.") +add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante e non rilascia certificazioni ISO. Le valutazioni proposte vanno confermate con il referente compliance/legale dell'organizzazione.") -# ===== 2. PRIMI PASSI ===== -add('pb'); add('h1', "2. Primi passi") -add('h2', "2.1 Accesso e indirizzo") -add('p', "La piattaforma è raggiungibile all'indirizzo **https://nis2.agile.software/**. L'accesso avviene con email e password (autenticazione JWT). Se la tua organizzazione usa il Single Sign-On centralizzato (AgileHub), le credenziali sono condivise tra i prodotti della suite.") -add('h2', "2.2 Registrazione") -add('ol', ["Apri la pagina di **Registrazione** e inserisci i dati richiesti (email, password conforme alla policy di sicurezza).", - "Al termine vieni indirizzato automaticamente alla procedura di **onboarding** aziendale.", - "Se possiedi un **invito/licenza** (token `inv_...`) fornito da un partner, inseriscilo per attivare l'organizzazione pre-configurata."]) -add('h2', "2.3 Recupero password") -add('p', "Dalla pagina di login usa **Password dimenticata** per ricevere un link di reset via email. Il cambio password effettuato da AgileHub si propaga automaticamente entro pochi minuti grazie al sync SSO.") -add('h2', "2.4 Onboarding dell'organizzazione") -add('p', "Il wizard di onboarding crea l'organizzazione e ne determina la classificazione NIS2. Si articola in quattro passi:") -add('ol', ["**Dati azienda** — inserimento manuale oppure precompilazione tramite **Partita IVA** (lookup automatico) o caricamento della **visura camerale** (estrazione AI dei dati).", - "**Verifica e completamento** — settore (ATECO → settore NIS2), numero dipendenti, fatturato, sede, contatti.", - "**Profilo utente** — nome, ruolo, telefono.", - "**Classificazione NIS2** — la piattaforma propone se il soggetto è **essenziale**, **importante** o **non applicabile** in base a settore e dimensione; è possibile aderire volontariamente."]) -add('note', "La classificazione (essenziale/importante) determina il perimetro applicabile in più moduli, in particolare la Gap Analysis ACN e gli obblighi sugli incidenti. Puoi rivederla in Impostazioni › Classificazione NIS2.") -add('h2', "2.5 Ruoli e permessi") -add('table', ["Ruolo","Descrizione"], - [["super_admin","Amministratore di piattaforma (accesso a tutte le organizzazioni)"], - ["org_admin","Amministratore dell'organizzazione"], - ["compliance_manager","Responsabile compliance: gestisce assessment, rischi, policy, SGSI"], - ["board_member","Organo direttivo: visione e approvazioni"], - ["auditor","Revisore: lettura e compilazione evidenze/controlli"], - ["employee","Dipendente: formazione, segnalazioni"], - ["consultant","Consulente di studio che opera su più organizzazioni clienti"]]) -add('h2', "2.6 Multi-organizzazione, lingua e aiuto") -add('ul', ["Chi appartiene a più organizzazioni (es. consulenti) può **cambiare contesto** dall'intestazione/menu.", - "L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).", - "Ogni pagina dispone di **Aiuto contestuale** (icona ?) con guida e riferimenti normativi certi."]) +# ══════════════════ 2. ACCESSO ══════════════════ +add('h1', "2. Requisiti e accesso alla piattaforma") +add('h3', "Requisiti") +add('ul', ["Un browser web aggiornato (Chrome, Edge, Firefox o Safari);", + "una connessione a Internet;", + "le credenziali di accesso (email e password) oppure un invito ricevuto dal proprio studio/partner."]) +add('h3', "Indirizzo della piattaforma") +add('p', "Apri il browser e vai su **https://nis2.agile.software/**. Si apre la pagina di accesso.") +add('h3', "Come accedere (login)") +add('ol', ["Nel campo **Indirizzo Email** inserisci l'email con cui sei registrato (es. nome@azienda.it).", + "Nel campo **Password** inserisci la tua password. Puoi usare l'icona a forma di occhio per mostrarla/nasconderla.", + "Premi **Accedi**.", + "Se le credenziali sono corrette: se hai già un'azienda configurata vieni portato alla **Dashboard**, altrimenti alla procedura di **Onboarding**."]) +add('p', "In caso di errore compare un messaggio in rosso sotto il titolo. Verifica email e password e riprova.") +add('h3', "Password dimenticata") +add('ol', ["Dalla pagina di accesso scegli **Password dimenticata**.", + "Inserisci l'email dell'account: riceverai un messaggio con un link per impostare una nuova password.", + "Apri il link, scegli la nuova password (rispettando i requisiti di sicurezza) e conferma."]) +add('note', "Se la tua azienda usa il Single Sign-On della suite (AgileHub), la password è condivisa tra i prodotti: un cambio password si propaga automaticamente entro pochi minuti.") +add('h3', "Disconnessione e sessioni") +add('p', "Per uscire usa la voce **Esci/Logout** nel menu utente. Dalle Impostazioni puoi vedere i **dispositivi collegati** (sessioni attive) e revocarli singolarmente o tutti.") -# ===== 3. DASHBOARD ===== -add('pb'); add('h1', "3. Dashboard") -add('p', "La Dashboard è la pagina iniziale dopo l'accesso e offre una visione d'insieme dello stato di conformità.") -add('ul', ["**Avanzamento implementazione misure Art. 21 NIS2** — indicatore complessivo (gauge);", - "**Scadenze imminenti** — adempimenti e revisioni in arrivo da più moduli;", - "**Attività recenti** — ultime azioni tracciate;", - "**Heatmap dei rischi** — distribuzione dei rischi su probabilità × impatto;", - "**Benchmark settoriale** (anonimizzato) — confronto con il proprio settore;", - "**Compliance Journey** — percorso guidato che indica i prossimi passi consigliati."]) +# ══════════════════ 3. REGISTRAZIONE ══════════════════ +add('h1', "3. Registrazione di un nuovo utente") +add('p', "Se non hai un account, dalla pagina di accesso scegli **Registrati**. La registrazione è una procedura guidata in tre passi, con un indicatore di avanzamento in alto.") +add('h3', "Passo 1 — Ruolo e (eventuale) codice invito") +add('p', "Scegli il **ruolo** con cui ti registri, selezionando una delle schede disponibili:") +add('table', ["Scheda ruolo","Quando sceglierlo"], + [["Responsabile compliance","Gestisci direttamente assessment, rischi, policy e SGSI dell'azienda"], + ["Amministratore organizzazione","Amministri l'azienda, gli utenti e le impostazioni"], + ["Consulente","Segui più aziende clienti per conto di uno studio"], + ["Auditor","Esegui verifiche e compili evidenze/controlli (lettura prevalente)"], + ["Membro del board","Organo direttivo: visione e approvazioni"]]) +add('p', "Se hai ricevuto un **Codice Invito** da un partner o dal tuo studio (formato `inv_...`), inseriscilo nell'apposito campo: il sistema lo verifica e mostra l'azienda/piano associati. Premi **Avanti** per proseguire.") +add('h3', "Passo 2 — Dati personali e password") +add('ul', ["**Nome** e **Cognome** (es. Mario Rossi);", + "**Email** (sarà il tuo identificativo di accesso);", + "eventuale **Partita IVA** dell'azienda (verificata in tempo reale, dove richiesto);", + "**Password** (minimo 8 caratteri): un indicatore mostra la robustezza della password mentre la digiti;", + "**Conferma password**: ripeti la stessa password."]) +add('h3', "Passo 3 — Conferma e avvio") +add('p', "Rivedi i dati, accetta le condizioni e completa la registrazione. Al termine vieni indirizzato automaticamente all'**Onboarding** per configurare l'azienda (se non sei entrato tramite un invito che la pre-configura).") -# ===== 4. GAP ANALYSIS NIS2 ===== -add('pb'); add('h1', "4. Gap Analysis NIS2 (Art. 21)") -add('p', "Analisi di **primo livello** sulle 10 categorie di misure dell'Art. 21.2 NIS2, basata su un questionario di 80 domande (10 categorie), ciascuna collegata anche al controllo ISO 27001 corrispondente.") -add('h2', "4.1 Come si svolge") -add('ol', ["Crea un nuovo assessment: la piattaforma pre-popola tutte le domande.", - "Per ogni domanda indica lo stato: **Attuato**, **Parziale**, **Non attuato**, **Non applicabile**. Le risposte si salvano automaticamente.", - "Completa l'assessment per ottenere un **punteggio** per categoria e complessivo.", - "Avvia l'**analisi AI** per ricevere sintesi esecutiva, priorità, quick win e una roadmap di conformità."]) -add('note', "Le risposte della Gap Analysis NIS2 alimentano automaticamente il Modello SGSI (capitolo 6): il loro stato pre-popola lo Statement of Applicability ISO 27001.") +# ══════════════════ 4. ONBOARDING ══════════════════ +add('h1', "4. Onboarding: configurazione dell'azienda") +add('p', "L'onboarding crea l'organizzazione e ne stabilisce la **classificazione NIS2** (essenziale, importante o non applicabile), che determina gli obblighi e il perimetro applicabile negli altri moduli. È una procedura guidata con uno **stepper** in alto che mostra i passi.") +add('h3', "Passo 1 — Inserisci la Partita IVA") +add('p', "Nella prima schermata (\"Inserisci la Partita IVA dell'azienda\") digiti la **Partita IVA** (es. 12345678901) e premi il pulsante di ricerca: la piattaforma tenta di **recuperare automaticamente** i dati aziendali. In alternativa puoi caricare la **visura camerale** (i dati vengono estratti dall'AI) oppure proseguire e inserire tutto manualmente. Premi **Continua**.") +add('h3', "Passo 2 — Verifica e completa i dati aziendali") +add('p', "Nella schermata \"Verifica e Completa i Dati Aziendali\" un banner indica la fonte dei dati (visura, lookup P.IVA o inserimento manuale). Controlla e completa i campi:") +add('ul', ["**Ragione sociale** (es. Acme S.r.l.);", + "**Partita IVA** e **Codice Fiscale**;", + "**Indirizzo**, **Città**, **Sito web**;", + "**Email aziendale** e **Telefono aziendale**;", + "**Settore** — scegli dall'elenco il settore NIS2 (es. Energia, Trasporti, Sanità, Infrastrutture digitali, ecc.): è determinante per la classificazione;", + "**Numero di dipendenti** e **fatturato** annuo, usati per stabilire la dimensione dell'impresa."]) +add('h3', "Passo 3 — Il tuo profilo") +add('p', "Inserisci i dati del tuo profilo utente: **nome completo**, **ruolo** in azienda e **telefono** di contatto.") +add('h3', "Passo 4 — Classificazione NIS2") +add('p', "In base a settore e dimensione, la piattaforma **propone la classificazione**: soggetto **essenziale**, **importante** oppure **non applicabile**. Se non rientri obbligatoriamente ma vuoi adeguarti, puoi indicare l'**adesione volontaria**. Conferma per completare l'onboarding e accedere alla Dashboard.") +add('note', "Puoi rivedere o aggiornare la classificazione in qualsiasi momento da Impostazioni › Classificazione NIS2. La classificazione filtra automaticamente, ad esempio, i requisiti applicabili nella Gap Analysis ACN e gli obblighi sugli incidenti.") -# ===== 5. GAP ANALYSIS ACN ===== -add('pb'); add('h1', "5. Gap Analysis ACN (Determinazione 164179/2025)") -add('p', "Analisi di **secondo livello** sulle misure e i requisiti puntuali stabiliti dall'ACN, articolati secondo il **Framework Nazionale** (funzioni Governo GV, Identificazione ID, Protezione PR, Rilevamento DE, Risposta RS, Ripristino RC).") -add('table', ["Classificazione","Perimetro applicabile"], - [["Soggetto IMPORTANTE (Allegato 1)","37 misure / 87 requisiti"], - ["Soggetto ESSENZIALE (Allegato 2)","43 misure / 116 requisiti"]]) -add('ul', ["Il perimetro è filtrato automaticamente in base alla classificazione NIS2 dell'organizzazione;", - "scoring per funzione del Framework Nazionale e punteggio complessivo;", - "**piano d'azione** dei requisiti non conformi e **analisi AI** ancorata ai 203 requisiti ACN reali (nessun riferimento inventato);", - "**Catalogo requisiti** consultabile in sola lettura."]) +# ══════════════════ 5. NAVIGAZIONE ══════════════════ +add('h1', "5. Come muoversi nell'interfaccia") +add('p', "Dopo l'accesso l'interfaccia è composta da una **barra laterale** (sidebar) a sinistra con il menu, e dall'**area principale** a destra che mostra la pagina selezionata. In alto a destra di ogni pagina trovi il pulsante di **aiuto contestuale (?)** e le azioni della pagina.") +add('h3', "Le sezioni del menu") +add('table', ["Sezione","Voci"], + [["Principale","Dashboard, Compliance Journey, Gap Analysis (NIS2), Gap Analysis ACN, Modello SGSI (ISO 27001)"], + ["Gestione","Rischi, Incidenti, Policy, Supply Chain, Segnalazioni (whistleblowing), Normative, AI Cross-Analysis, Knowledge Base"], + ["Operativo","Formazione, Asset, Audit & Report"], + ["Sistema","Guida all'uso, Impostazioni, Architettura, Simulazione Demo, Integrazioni Esterne"]]) +add('h3', "Lingua e aiuto") +add('ul', ["L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).", + "Il pulsante **?** in ogni pagina apre la guida contestuale con spiegazioni e riferimenti normativi.", + "Chi appartiene a più aziende (consulenti) può **cambiare organizzazione** dal menu."]) -# ===== 6. MODELLO SGSI ISO 27001 (NUOVO) ===== -add('pb'); add('h1', "6. Modello Organizzativo SGSI (ISO 27001/27017/27018)") -add('p', "Procedura guidata per costruire il **Sistema di Gestione della Sicurezza delle Informazioni (SGSI / ISMS)** secondo **ISO/IEC 27001:2022** (clausole 4–10) e il relativo **Statement of Applicability (SoA)** sui 93 controlli dell'Annex A. È uno strumento di supporto e pre-audit, non una certificazione.") -add('h2', "6.1 Il wizard in 6 passi") -add('table', ["Passo","Clausola ISO 27001","Contenuto"], - [["1. Contesto e Ambito","cl. 4","Scope del SGSI, contesto interno/esterno, parti interessate, confini, esclusioni motivate, attivazione estensioni cloud"], - ["2. Leadership","cl. 5","Ruoli e responsabilità con matrice RACI (Responsible, Accountable, Consulted, Informed)"], - ["3. Risk","cl. 6","Metodologia di risk assessment e obiettivi del SGSI (il registro rischi resta nel modulo Rischi)"], - ["4. Statement of Applicability","cl. 6.1.3","Applicabilità, stato e motivazione dei 93 controlli Annex A + estensioni cloud"], - ["5. Documented Information","cl. 7–8","Policy e procedure, con bozze generabili dall'AI"], - ["6. Monitoraggio e Miglioramento","cl. 9–10","Audit interni e non conformità (moduli Audit & Report e NCR/CAPA); checklist di completamento"]]) -add('h2', "6.2 SoA pre-popolato dalla Gap Analysis NIS2") -add('p', "Ogni domanda della Gap Analysis NIS2 è collegata a un controllo ISO 27001 (es. A.5.1). Per questo lo Statement of Applicability viene **pre-compilato** a partire dalle risposte NIS2 già date: i controlli con corrispondenza riportano il badge **\"da NIS2\"** e uno stato proposto (Attuato = 100%, Parziale = 50%, Non attuato = 0%). I controlli non coperti dal NIS2 (es. parte dei controlli fisici A.7) restano da compilare manualmente.") -add('note', "Il pulsante \"Ri-deriva dal NIS2\" aggiunge soltanto i controlli mancanti e non sovrascrive le modifiche manuali già inserite.") -add('h2', "6.3 Estensioni cloud (condizionali)") -add('ul', ["**ISO/IEC 27017:2015** — attivala se usi servizi cloud pubblici o sei un fornitore cloud: aggiunge 7 controlli cloud (CLD.*) al SoA;", - "**ISO/IEC 27018:2019** — attivala se tratti dati personali (PII) in cloud pubblico come responsabile: aggiunge i controlli privacy (PII.*), sinergici con il GDPR.", - "Le sezioni cloud/PII compaiono nel SoA **solo** se attivi i relativi flag nel passo 1."]) -add('h2', "6.4 Documenti e generazione AI") -add('p', "Nel passo 5 puoi generare bozze di policy e procedure (Policy SGSI, Dichiarazione di Applicabilità, controllo accessi, gestione incidenti, continuità, sicurezza fornitori). Le bozze sono prodotte dall'AI con ancoraggio alle fonti certe e richiedono **revisione umana** prima dell'approvazione.") -add('h2', "6.5 Esportazione") -add('p', "Il pulsante **Esporta SGSI** apre una versione stampabile del modello (ambito, metodologia, SoA con stato dei controlli), utile come evidenza in vista di un audit.") +# ══════════════════ 6..23 MODULI (da help.js) ══════════════════ +module_chapter(6, "Dashboard", "dashboard") +module_chapter(7, "Gap Analysis NIS2 (Art. 21)", "assessment", + "Apri la voce **Gap Analysis** dal menu. È l'analisi di primo livello sulle 10 categorie di misure dell'Art. 21 NIS2.") +module_chapter(8, "Gap Analysis ACN (Determinazione 164179/2025)", "acn", + "Apri la voce **Gap Analysis ACN**. È l'analisi di secondo livello sui requisiti puntuali ACN.") +module_chapter(9, "Modello Organizzativo SGSI (ISO 27001/27017/27018)", "isms", + "Apri la voce **Modello SGSI (ISO 27001)**. Una procedura guidata in 6 passi costruisce il Sistema di Gestione della Sicurezza delle Informazioni; lo Statement of Applicability è pre-popolato dalle risposte della Gap Analysis NIS2.") +module_chapter(10, "Gestione dei Rischi", "risks", "Apri la voce **Rischi**.") +module_chapter(11, "Gestione degli Incidenti (Art. 23)", "incidents", "Apri la voce **Incidenti**.") +module_chapter(12, "Policy e procedure", "policies", "Apri la voce **Policy**.") +module_chapter(13, "Supply Chain (fornitori)", "supply-chain", "Apri la voce **Supply Chain**.") +module_chapter(14, "Formazione", "training", "Apri la voce **Formazione**.") +module_chapter(15, "Asset", "assets", "Apri la voce **Asset**.") +module_chapter(16, "Audit & Report", "reports", "Apri la voce **Audit & Report**.") +module_chapter(17, "Whistleblowing (Art. 32)", "whistleblowing", "Apri la voce **Segnalazioni**.") +module_chapter(18, "Aggiornamenti normativi", "normative", "Apri la voce **Normative**.") +module_chapter(19, "Knowledge Base", "kb", "Apri la voce **Knowledge Base**.") +module_chapter(20, "Compliance Journey", "workflow", "Apri la voce **Compliance Journey**: un percorso guidato che indica i prossimi passi consigliati.") +module_chapter(21, "Segnalazioni (feedback)", "feedback", + "Usa lo strumento di feedback per segnalare problemi o suggerimenti: ogni segnalazione cattura automaticamente versione e superficie del prodotto.") +module_chapter(22, "Impostazioni", "settings", "Apri la voce **Impostazioni**.") +module_chapter(23, "Gestione delle aziende (consulenti)", "companies", + "Disponibile per i consulenti: consente di gestire più aziende clienti da un unico accesso.") -# ===== 7. RISCHI ===== -add('pb'); add('h1', "7. Gestione dei Rischi") -add('p', "Registro dei rischi con matrice **Probabilità × Impatto 5×5** e supporto AI, conforme all'Art. 21 NIS2 e alla metodologia ISO 27005.") -add('ul', ["Creazione del rischio con scala probabilità/impatto (dettagli ISO 27005);", - "**Piani di trattamento** (mitigare, accettare, trasferire, evitare) e stato di avanzamento;", - "**Suggerimento AI** dei rischi per settore e asset (dati anonimizzati);", - "Funzioni avanzate: registro quantitativo **FAIR** (calcolo ALE Monte Carlo) e dashboard **KRI**."]) +# ══════════════════ 24. FAQ ══════════════════ +add('h1', "24. Domande frequenti (FAQ)") +add('h3', "Non riesco ad accedere") +add('p', "Verifica email e password; usa **Password dimenticata** per reimpostarla. Se usi il SSO della suite, accedi con le credenziali centralizzate.") +add('h3', "Ho sbagliato la classificazione NIS2") +add('p', "Puoi correggerla in **Impostazioni › Classificazione NIS2**: il perimetro dei moduli (es. Gap Analysis ACN) si aggiorna di conseguenza.") +add('h3', "Lo Statement of Applicability del Modello SGSI è quasi vuoto") +add('p', "Viene pre-popolato dalle risposte della **Gap Analysis NIS2**: completa prima quell'assessment, poi usa **Ri-deriva dal NIS2** nel SoA. I controlli senza corrispondenza NIS2 (es. alcuni controlli fisici) vanno compilati manualmente.") +add('h3', "Le email non vengono inviate") +add('p', "Negli ambienti dimostrativi l'invio email può essere disattivato per sicurezza. In produzione le notifiche (CSIRT, formazione, inviti) vengono inviate regolarmente.") +add('h3', "Le bozze generate dall'AI sono definitive?") +add('p', "No: sono **bozze** da rivedere e approvare. Riportano sempre un avviso e citano le fonti normative.") -# ===== 8. INCIDENTI ===== -add('pb'); add('h1', "8. Gestione degli Incidenti (Art. 23)") -add('p', "Gestione del ciclo di vita degli incidenti significativi e degli obblighi di notifica al CSIRT secondo l'Art. 23 e la Determinazione ACN 164179/2025.") -add('h2', "8.1 Tempistiche di notifica") -add('table', ["Adempimento","Termine"], - [["Pre-allarme (early warning)","entro 24 ore dalla conoscenza"], - ["Notifica completa","entro 72 ore dalla conoscenza"], - ["Relazione finale","entro 1 mese dalla notifica delle 72 ore"]]) -add('h2', "8.2 Funzioni") -add('ul', ["**Albero decisionale** per valutare la significatività (utenti ≥ 500, durata > 4h, cross-border, attacco cyber, danni > €100k);", - "**timeline** dell'incidente e metriche (triage, contenimento, eradicazione, ripristino);", - "invio di **early warning, notifica e relazione finale** al CSIRT;", - "**classificazione AI** (tipo IS-1..IS-4, severità) con citazione della fonte (Allegato 3 = importanti, Allegato 4 = essenziali);", - "**PIR** (Post-Incident Review) per l'apprendimento."]) - -# ===== 9. POLICY ===== -add('pb'); add('h1', "9. Policy e procedure") -add('ul', ["Creazione di policy da **template** o **generazione AI** (bozze marcate da revisionare);", - "flusso di **approvazione** e **versioning** con confronto delle versioni (diff);", - "**attestazione** di presa visione da parte del personale e relativo tracciamento."]) -add('note', "Le bozze generate dall'AI riportano un banner di avviso: vanno riviste e approvate da un responsabile prima della pubblicazione.") - -# ===== 10. SUPPLY CHAIN ===== -add('pb'); add('h1', "10. Supply Chain (fornitori)") -add('p', "Gestione della sicurezza della catena di approvvigionamento (Art. 21.2.d).") -add('ul', ["Anagrafica fornitori, categorie e **import** massivo;", - "**questionari** configurabili (categorie, template, domande) inviati ai fornitori;", - "**portale fornitore** dedicato con accesso separato via OTP/magic-link (autosalvataggio risposte);", - "**campagne** di valutazione e cruscotto del rischio fornitori (risk overview)."]) - -# ===== 11. FORMAZIONE ===== -add('pb'); add('h1', "11. Formazione") -add('p', "Gestione della formazione e dell'igiene informatica (Art. 21.2.g) e degli obblighi formativi per gli organi direttivi (Art. 20).") -add('ul', ["Catalogo **corsi** e **assegnazioni** al personale;", - "monitoraggio della **compliance formativa** e dei corsi obbligatori non completati."]) - -# ===== 12. ASSET ===== -add('pb'); add('h1', "12. Asset") -add('p', "Inventario degli asset informativi e delle dipendenze.") -add('ul', ["Anagrafica asset e **import** (CMDB/cloud);", - "**scoring di rilevanza NIS2** (0–100, criterio GV.OC-04) e classificazione dei sistemi rilevanti;", - "**mappa delle dipendenze** tra asset."]) - -# ===== 13. AUDIT & REPORT ===== -add('pb'); add('h1', "13. Audit & Report") -add('ul', ["Gestione dei **controlli di conformità** (framework NIS2 / ISO 27001) con stato ed evidenze;", - "caricamento **evidenze** e registro dei **log di audit**;", - "**mappature**: NIS2 ↔ ISO 27001 e NIST CSF 2.0; **registro dei sistemi rilevanti** (GV.OC-04);", - "**report esecutivo** stampabile ed **export CSV**;", - "**catena di integrità (hash chain SHA-256)**: ogni voce del log è concatenata alla precedente; verifica integrità ed **export certificato**."]) - -# ===== 14. WHISTLEBLOWING ===== -add('pb'); add('h1', "14. Whistleblowing (Art. 32)") -add('p', "Canale per le segnalazioni, anche anonime.") -add('ul', ["Invio segnalazione (anche **anonima**, con codice di tracciamento);", - "assegnazione, gestione e chiusura della segnalazione;", - "consultazione anonima dello stato tramite codice di tracciamento."]) - -# ===== 15. NORMATIVE ===== -add('pb'); add('h1', "15. Aggiornamenti normativi") -add('ul', ["Feed degli aggiornamenti **NIS2 / ACN / DORA**;", - "presa visione (**ACK**) tracciata per ciascun aggiornamento;", - "elenco aggiornamenti **in attesa** di presa visione e statistiche."]) - -# ===== 16. KB & AI ===== -add('pb'); add('h1', "16. Knowledge Base e Assistente AI") -add('h2', "16.1 Knowledge Base (RAG)") -add('p', "La Knowledge Base alimenta le risposte dell'AI tramite ricerca semantica (RAG). Prevede tre livelli di visibilità:") -add('table', ["Livello","Chi possiede","Chi vede"], - [["SYSTEM","Fornitore della piattaforma","Tutti gli utenti"], - ["FIRM","Studio di consulenza","Collaboratori dello studio + organizzazioni condivise"], - ["ORG","Singola organizzazione","Solo gli utenti di quella organizzazione"]]) -add('ul', ["Caricamento documenti (testo) con scelta dello scope;", - "ricerca semantica e cancellazione documenti;", - "le fonti normative certe (NIS2, D.Lgs. 138/2024, Determinazioni ACN) e i cataloghi **ISO 27001/27002/27017/27018** sono già indicizzati a livello SYSTEM."]) -add('h2', "16.2 Assistente AI") -add('p', "L'assistente risponde alle domande pescando dalla Knowledge Base e **cita sempre la fonte normativa pertinente**, senza inventare riferimenti. Le risposte sono di orientamento operativo e non sostituiscono il parere legale.") - -# ===== 17. FEEDBACK ===== -add('pb'); add('h1', "17. Segnalazioni (feedback)") -add('p', "Strumento integrato per segnalare bug o suggerimenti di UX. Le segnalazioni vengono classificate dall'AI e, una volta risolte, l'esito può essere comunicato ai membri dell'organizzazione. Ogni segnalazione cattura automaticamente la **versione del prodotto** e la **superficie** (web/mobile) per facilitare la diagnosi.") - -# ===== 18. IMPOSTAZIONI ===== -add('pb'); add('h1', "18. Impostazioni") -add('ul', ["**Organizzazione** — dati, classificazione NIS2;", - "**Profilo** — dati personali, cambio password, preferenze;", - "**Membri** — invito e gestione degli utenti e dei ruoli;", - "**Sessioni** — gestione dei dispositivi collegati (multi-device) e revoca;", - "**Branding** (white-label per studi) — personalizzazione per lo studio di consulenza."]) - -# ===== 19. AMMINISTRAZIONE ===== -add('pb'); add('h1', "19. Amministrazione") -add('p', "Area riservata al ruolo **super_admin**: gestione delle organizzazioni, degli utenti e statistiche di piattaforma.") - -# ===== 20. INTEGRAZIONI E API ===== -add('pb'); add('h1', "20. Integrazioni e API") -add('ul', ["**Services API** (autenticazione tramite API Key con scope) per integrazioni esterne, es. GRC/231: gap-analysis, misure, incidenti, formazione, scadenze e snapshot completo;", - "**Webhook** con firma HMAC-SHA256 e retry, per notifiche verso sistemi terzi;", - "**Licenze/inviti B2B** per provisioning di organizzazioni da parte di partner;", - "**SSO** centralizzato della suite AgileHub (sincronizzazione password)."]) - -# ===== 21. GLOSSARIO ===== -add('pb'); add('h1', "21. Glossario") +# ══════════════════ 25. GLOSSARIO ══════════════════ +add('h1', "25. Glossario") add('table', ["Termine","Significato"], [["NIS2","Direttiva (UE) 2022/2555 sulla cibersicurezza"], ["ACN","Agenzia per la Cybersicurezza Nazionale"], + ["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"], + ["Gap Analysis","Analisi degli scostamenti tra stato attuale e requisiti"], ["SGSI / ISMS","Sistema di Gestione della Sicurezza delle Informazioni (ISO 27001)"], ["SoA","Statement of Applicability: dichiarazione di applicabilità dei controlli"], - ["Annex A","Elenco dei 93 controlli di sicurezza di ISO/IEC 27001:2022"], + ["Annex A","I 93 controlli di sicurezza di ISO/IEC 27001:2022"], ["RACI","Matrice di responsabilità: Responsible, Accountable, Consulted, Informed"], - ["CSIRT","Computer Security Incident Response Team (autorità di notifica)"], + ["CSIRT","Squadra nazionale di risposta agli incidenti (autorità di notifica)"], + ["NCR / CAPA","Non conformità / azioni correttive e preventive"], ["PIR","Post-Incident Review (revisione post-incidente)"], - ["RAG","Retrieval-Augmented Generation: AI con recupero da knowledge base"], - ["PII","Personally Identifiable Information (dati personali)"], - ["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"]]) + ["RAG","Recupero da knowledge base a supporto delle risposte AI"], + ["PII","Dati personali (Personally Identifiable Information)"]]) -# ===== 22. RIFERIMENTI NORMATIVI ===== -add('pb'); add('h1', "22. Riferimenti normativi") +# ══════════════════ 26. RIFERIMENTI ══════════════════ +add('h1', "26. Riferimenti normativi") add('ul', ["Direttiva (UE) 2022/2555 (NIS2);", "Direttiva (UE) 2022/2557 (CER);", "D.Lgs. 4 settembre 2024, n. 138;", - "Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti, Allegati);", - "Determinazione ACN n. 333017/2025 (piattaforma ACN, designazione rappresentanti);", + "Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti);", + "Determinazione ACN n. 333017/2025;", "ISO/IEC 27001:2022, 27002:2022, 27017:2015, 27018:2019 (best practice, non vincolanti)."]) -add('note', "Questo manuale descrive le funzionalità della piattaforma NIS2 Agile alla versione 1.14.0. Le schermate e le voci di menu possono variare con gli aggiornamenti. Per l'aiuto contestuale usa l'icona ? presente in ogni pagina.") +add('note', f"Manuale d'uso di NIS2 Agile — versione piattaforma 1.14.0, aggiornato all'{DATE}. Per assistenza usa il pulsante di aiuto (?) presente in ogni pagina o la voce \"Guida all'uso\" nel menu.") -# ───────────────────────────────────────────────────────────────────────── -# EMITTER OOXML -# ───────────────────────────────────────────────────────────────────────── +# ════════════════════════════════ EMITTER OOXML ════════════════════════════════ def runs(text): - """Converte **bold** in run WordprocessingML.""" out = [] for i, part in enumerate(re.split(r'\*\*', text)): - if part == '': - continue - bold = (i % 2 == 1) - rpr = '' if bold else '' + if part == '': continue + rpr = '' if (i % 2 == 1) else '' out.append('%s%s' % (rpr, escape(part))) return ''.join(out) or '' @@ -294,62 +235,48 @@ def listitem(text, numid): '%s' % (numid, runs(text))) def cell(text, header=False): - shd = '' if header else '' - t = ('**%s**' % text) if header else text - # nelle intestazioni il testo bianco if header: + shd = '' r = '%s' % escape(text) else: - r = runs(text) - return ('%s%s' % (shd, r)) + shd = ''; r = runs(text) + return '%s%s' % (shd, r) def table(headers, rows): - borders = ('' + ''.join( - '' % s - for s in ['top','left','bottom','right','insideH','insideV']) + '') - tblpr = '%s' % borders - out = ['', tblpr] + borders = '' + ''.join(''%s + for s in ['top','left','bottom','right','insideH','insideV']) + '' + out = ['%s' % borders] out.append('' + ''.join(cell(h, True) for h in headers) + '') - for row in rows: - out.append('' + ''.join(cell(c) for c in row) + '') - out.append('') - out.append('') # spacing after table + for row in rows: out.append('' + ''.join(cell(c) for c in row) + '') + out.append('') return ''.join(out) -def title_block(t, sub, meta): - return (para(t, 'Title') + para(sub, 'Subtitle') + para(meta, 'Meta')) - body = [] for b in C: k = b[0] - if k == 'title': body.append(title_block(b[1], b[2], b[3])) - elif k == 'h1': body.append(para(b[1], 'Heading1')) - elif k == 'h2': body.append(para(b[1], 'Heading2')) - elif k == 'h3': body.append(para(b[1], 'Heading3')) + if k == 'title': body.append(para(b[1],'Title')+para(b[2],'Subtitle')+para(b[3],'Meta')) + elif k in ('h1','h2','h3'): body.append(para(b[1], {'h1':'Heading1','h2':'Heading2','h3':'Heading3'}[k])) elif k == 'p': body.append(para(b[1])) - elif k == 'note': body.append(para(b[1], 'Note')) - elif k == 'ul': body.append(''.join(listitem(x, 1) for x in b[1])) - elif k == 'ol': body.append(''.join(listitem(x, 2) for x in b[1])) + elif k == 'note': body.append(para(b[1],'Note')) + elif k == 'ul': body.append(''.join(listitem(x,1) for x in b[1])) + elif k == 'ol': body.append(''.join(listitem(x,2) for x in b[1])) elif k == 'table': body.append(table(b[1], b[2])) elif k == 'pb': body.append('') -SECT = ('' - '' - '') - +SECT = ('') document = ('' - '' - '' + ''.join(body) + SECT + '') + '' + + ''.join(body) + SECT + '') STYLES = ('' '' '' '' - '' - '' + '' + '' '' - '' - '' + '' + '' '' '' '' @@ -359,49 +286,35 @@ NUMBERING = ('' '' '' '' - '' - '' - '') + '') -CONTENT_TYPES = ('' +CT = ('' '' '' '' '' '' '' - '' - '') - + '') RELS = ('' '' '' - '' - '') - -DOC_RELS = ('' + '') +DRELS = ('' '' '' - '' - '') - + '') CORE = ('' - '' - 'Manuale d\'uso NIS2 AgileNIS2 Agile' - 'NIS2 Agile' - '2026-06-11T00:00:00Z' - '2026-06-11T00:00:00Z' - '') + '' + 'Manuale d\'uso NIS2 AgileNIS2 AgileNIS2 Agile' + '2026-06-11T00:00:00Z2026-06-11T00:00:00Z') with zipfile.ZipFile(OUT, 'w', zipfile.ZIP_DEFLATED) as z: - z.writestr('[Content_Types].xml', CONTENT_TYPES) + z.writestr('[Content_Types].xml', CT) z.writestr('_rels/.rels', RELS) z.writestr('word/document.xml', document) z.writestr('word/styles.xml', STYLES) z.writestr('word/numbering.xml', NUMBERING) - z.writestr('word/_rels/document.xml.rels', DOC_RELS) + z.writestr('word/_rels/document.xml.rels', DRELS) z.writestr('docProps/core.xml', CORE) - -print("OK ->", OUT) -print("blocchi:", len(C)) +print("OK ->", OUT, "| blocchi:", len(C))