[FEAT] ISO-readiness: Audit interni (§9.2) + Riesame Direzione (§9.3) + Calendario scadenze (mig.055-056, v1.22.0)

Rilascio unico (3 moduli) costruito in flotta parallela + verifica avversariale.

MODULO A — Audit interni (ISO 27001 §9.2, mig.055): internal_audits + internal_audit_items;
codice AUD-NNN; checklist pre-popolata (clausole 4-10 + Annex A applicabili dal SoA);
esiti per riga; apertura non conformità collegata a NCR/CAPA (source polimorfico);
report HTML stampabile. InternalAuditController + internal-audits.html.

MODULO B — Riesame di Direzione (ISO 27001 §9.3, mig.056): management_reviews +
management_review_decisions; codice RD-AAAA-NN; INPUT aggregati automaticamente dai
moduli (gather: NC/CAPA, audit interni, rischi+trattamenti, KPI/score, obiettivi, formazione,
stakeholder, normative, scadenze), congelati nello snapshot all'approvazione; decisioni;
verbale stampabile. ManagementReviewController + management-review.html.

MODULO C — Calendario unico scadenze: aggregatore SOLA LETTURA (nessuna migrazione) di tutte
le scadenze (incidenti/policy/rischi/NC-CAPA/formazione/stakeholder/audit/riesame/review_schedule),
griglia mensile + lista + filtri + deep-link. CalendarController + calendario.html.

Integrazione: router (3 controller+actionMap), api.js, sidebar V2+legacy, help.js (3 sezioni),
i18n (IT+EN), review_schedule ENUM += internal_audit. v1.22.0 + sw cache + cache-buster 20260630.

Verifica flotta (28 agenti, 4 dim + avversariale): 9 finding confermati, TUTTI corretti —
MAJOR gatherRisks (risk_treatments.organization_id inesistente → JOIN risks); nextCode numerico
(no dup >99/anno); footer report audit con etichetta "ISO buona prassi, non obbligo"; help 24→25
clausole; ARIA tab/calendario; focus modali; tasti su celle calendario; rimossi helper api morti.

Smoke prod OK (calendario 18 eventi, audit AUD-001 25 item + report + audit→NCR + audit→calendario,
riesame gather/decisione/approve/report, gatherRisks ora available); org 151 ripulita. Additivo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-17 07:48:49 +02:00
co-authored by Claude Opus 4.8
parent 18a4a0b509
commit 79ca72fba9
54 changed files with 3774 additions and 148 deletions
+38
View File
@@ -221,6 +221,7 @@ class NIS2API {
// ═══════════════════════════════════════════════════════════════════
orgRolesList() { return this._acn(this.get('/org-roles/list')); }
orgRolesAssignableUsers() { return this._acn(this.get('/org-roles/assignable-users')); }
orgMembers() { return this._acn(this.get('/organizations/' + (this.orgId || '') + '/members')); }
orgRoleGet(id) { return this._acn(this.get(`/org-roles/${id}`)); }
orgRoleCreate(data) { return this._acn(this.post('/org-roles/create', data || {})); }
orgRoleUpdate(id, data) { return this._acn(this.put(`/org-roles/${id}`, data)); }
@@ -333,6 +334,43 @@ class NIS2API {
stkActAddComment(id, d) { return this._acn(this.post(`/stakeholder-activities/${id}/comments`, d || {})); }
stkActAttachments(id) { return this._acn(this.get(`/stakeholder-activities/${id}/attachments`)); }
// ── Audit interni (Modulo A — ISO 27001 §9.2) ──
intAuditList() { return this._acn(this.get('/internal-audits/list')); }
intAuditGet(id) { return this._acn(this.get(`/internal-audits/${id}`)); }
intAuditCreate(data) { return this._acn(this.post('/internal-audits/create', data || {})); }
intAuditUpdate(id, data) { return this._acn(this.put(`/internal-audits/${id}`, data)); }
intAuditDelete(id) { return this._acn(this.del(`/internal-audits/${id}`)); }
intAuditAddItem(data) { return this._acn(this.post('/internal-audits/items', data || {})); }
intAuditUpdateItem(itemId, data) { return this._acn(this.put(`/internal-audits/items/${itemId}`, data)); }
intAuditRaiseNcr(id, data) { return this._acn(this.post(`/internal-audits/${id}/raise-ncr`, data || {})); }
// ── Riesame di Direzione (ISO 27001 §9.3, Modulo B) ──
mgmtReviewList() { return this._acn(this.get('/management-reviews/list')); }
mgmtReviewGet(id) { return this._acn(this.get(`/management-reviews/${id}`)); }
mgmtReviewCreate(data) { return this._acn(this.post('/management-reviews/create', data || {})); }
mgmtReviewUpdate(id, data) { return this._acn(this.put(`/management-reviews/${id}`, data || {})); }
mgmtReviewGather() { return this._acn(this.get('/management-reviews/gather')); }
mgmtReviewAddDecision(id, data) { return this._acn(this.post(`/management-reviews/${id}/decisions`, data || {})); }
mgmtReviewUpdateDecision(subId, data) { return this._acn(this.put(`/management-reviews/decisions/${subId}`, data || {})); }
mgmtReviewApprove(id) { return this._acn(this.post(`/management-reviews/${id}/approve`, {})); }
// ── Calendario unico scadenze (Modulo C) — aggregatore sola lettura ──
calendarEvents(params) {
const qs = new URLSearchParams();
if (params && params.from) qs.set('from', params.from);
if (params && params.to) qs.set('to', params.to);
if (params && params.types) qs.set('types', Array.isArray(params.types) ? params.types.join(',') : params.types);
const q = qs.toString();
return this._acn(this.get('/calendar/events' + (q ? '?' + q : '')));
}
calendarSummary(params) {
const qs = new URLSearchParams();
if (params && params.from) qs.set('from', params.from);
if (params && params.to) qs.set('to', params.to);
const q = qs.toString();
return this._acn(this.get('/calendar/summary' + (q ? '?' + q : '')));
}
// ═══════════════════════════════════════════════════════════════════
// Dashboard
// ═══════════════════════════════════════════════════════════════════
+3
View File
@@ -62,6 +62,7 @@
label: 'Principale', i18nKey: 'nav.main',
items: [
{ name: 'Dashboard', href: 'dashboard.html', icon: iconGrid(), i18nKey: 'nav.dashboard' },
{ name: 'Calendario', href: 'calendario.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.calendar' },
{ name: 'Compliance Journey', href: 'workflow.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"/></svg>' },
{ name: 'Gap Analysis', href: 'assessment.html', icon: iconClipboardCheck(), i18nKey: 'nav.gap_analysis' },
{ name: 'Misure e Requisiti', href: 'misure-requisiti.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h8a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/></svg>', i18nKey: 'nav.framework' },
@@ -90,6 +91,8 @@
items: [
{ name: 'Formazione', href: 'training.html', icon: iconAcademicCap(), i18nKey: 'nav.training' },
{ name: 'Inventario', href: 'assets.html', icon: iconServer(), i18nKey: 'nav.assets' },
{ name: 'Audit interni', href: 'internal-audits.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm5.707 6.707a1 1 0 00-1.414-1.414L7 10.586l-.293-.293a1 1 0 00-1.414 1.414l1 1a1 1 0 001.414 0l2-2zM10 13a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.internal_audits' },
{ name: 'Riesame di Direzione', href: 'management-review.html', icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>`, i18nKey: 'nav.management_review' },
{ name: 'Audit & Report', href: 'reports.html', icon: iconChartBar(), i18nKey: 'nav.audit' }
]
},
+3
View File
@@ -186,6 +186,7 @@ function loadSidebar() {
label: 'Principale', i18nKey: 'nav.main',
items: [
{ name: 'Dashboard', href: 'dashboard.html', icon: iconGrid(), i18nKey: 'nav.dashboard' },
{ name: 'Calendario', href: 'calendario.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.calendar' },
{ name: 'Compliance Journey', href: 'workflow.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"/></svg>` },
{ name: 'Gap Analysis', href: 'assessment.html', icon: iconClipboardCheck(), i18nKey: 'nav.gap_analysis' },
{ name: 'Misure e Requisiti', href: 'misure-requisiti.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h8a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.framework' },
@@ -216,6 +217,8 @@ function loadSidebar() {
items: [
{ name: 'Formazione', href: 'training.html', icon: iconAcademicCap(), i18nKey: 'nav.training' },
{ name: 'Inventario', href: 'assets.html', icon: iconServer(), i18nKey: 'nav.assets' },
{ name: 'Audit interni', href: 'internal-audits.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm5.707 6.707a1 1 0 00-1.414-1.414L7 10.586l-.293-.293a1 1 0 00-1.414 1.414l1 1a1 1 0 001.414 0l2-2zM10 13a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.internal_audits' },
{ name: 'Riesame di Direzione', href: 'management-review.html', icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>`, i18nKey: 'nav.management_review' },
{ name: 'Audit & Report',href: 'reports.html', icon: iconChartBar(), i18nKey: 'nav.audit' },
]
},
+120
View File
@@ -400,6 +400,120 @@ const HelpSystem = (function () {
'NOTA: gli obblighi normativi in Italia derivano dal D.Lgs. 138/2024; la matrice e i framework NIST CSF/ACN sono strumenti di supporto, non un parere legale.'
]
},
'internal-audits': {
title: 'Guida - Audit interni',
intro: 'Il modulo Audit interni gestisce il ciclo degli audit del SGSI previsto dalla clausola 9.2 della ISO/IEC 27001: programmi gli audit, conduci la checklist (clausole 4-10 ISO 27001 + controlli Annex A applicabili dal tuo SoA), registri gli esiti riga per riga, apri una non conformità sui punti non conformi e generi il report stampabile. È uno strumento di supporto organizzativo, non un parere legale.',
sections: [
{
heading: 'Programma audit',
items: [
'Crea un <strong>audit</strong> indicando titolo, ambito (scope), criteri (es. "ISO/IEC 27001:2022 cl.4-10 + Annex A"), data pianificata, data di esecuzione e auditor capo (un utente dell\'organizzazione oppure un ruolo dell\'organigramma).',
'Il sistema assegna automaticamente un <strong>codice progressivo</strong> (AUD-001, AUD-002, …) per organizzazione.',
'La <strong>data pianificata</strong> compare automaticamente nel <strong>calendario NIS2</strong> (Scadenziario).'
]
},
{
heading: 'Checklist di conduzione',
items: [
'Alla creazione la checklist viene <strong>pre-popolata</strong>: le <strong>clausole 4-10</strong> della ISO 27001 e i <strong>controlli Annex A</strong> marcati come applicabili nel tuo <strong>SoA</strong> (Modello SGSI). Parti già con la checklist, non da foglio bianco.',
'Per ogni voce scegli l\'<strong>esito</strong> (Da verificare, Conforme, Non conforme, Osservazione, Opportunità, Non applicabile) e annoti note/evidenze; il salvataggio è immediato.',
'Puoi aggiungere <strong>voci custom</strong> non previste dalle clausole o dall\'Annex A.'
]
},
{
heading: 'Non conformità e report',
items: [
'Sulle voci marcate <strong>Non conforme</strong> puoi premere <strong>Apri NC</strong>: il sistema crea una non conformità collegata (sorgente "audit") che confluisce nel modulo <strong>NCR/CAPA</strong>, dove ne gestisci root cause e azioni correttive.',
'Il pulsante <strong>Report</strong> apre un verbale di audit <strong>stampabile</strong> (HTML) con metadati, sintesi degli esiti, checklist completa e conclusioni: usa "Stampa / Salva PDF" del browser.'
]
},
{
heading: 'Riferimenti normativi',
items: [
'<strong>ISO/IEC 27001:2022 §9.2</strong>: l\'organizzazione conduce audit interni a intervalli pianificati per verificare che il SGSI sia conforme ai requisiti e attuato efficacemente.',
'<strong>NIST CSF 2.0 / GV.PO-02</strong>: la politica di sicurezza e i programmi di gestione sono rivisti e migliorati nel tempo (buona prassi anche per NIS2).',
'Le <strong>azioni</strong> correttive/preventive si gestiscono nel modulo NCR/CAPA.'
]
}
],
references: [
'ISO/IEC 27001:2022 - Clausola 9.2 Audit interni',
'ISO/IEC 27001:2022 - Clausole 4-10 e Annex A (controlli del SoA)',
'NIST CSF 2.0 / GV.PO-02 - Revisione e miglioramento del programma di sicurezza',
'Gli audit interni e il riesame periodico sono buona prassi di governance; gli obblighi normativi in Italia derivano dal D.Lgs. 138/2024.',
'NOTA: strumento di supporto organizzativo, non un parere legale.'
]
},
'management-review': {
title: 'Guida - Riesame di Direzione (ISO 27001 §9.3)',
intro: 'Il Riesame di Direzione e il momento in cui la direzione valuta periodicamente l\'idoneita, l\'adeguatezza e l\'efficacia del Sistema di Gestione della Sicurezza delle Informazioni (SGSI). Il modulo produce il VERBALE con gli elementi in ingresso (aggregati automaticamente dai moduli esistenti) e in uscita (le decisioni). E\' uno strumento di SUPPORTO e PRE-AUDIT: non sostituisce l\'auditor ne costituisce una certificazione.',
sections: [
{
heading: 'Come si compila un verbale',
items: [
'<strong>1. Crea il riesame</strong>: indica data, periodo di riferimento (es. "2026 H1"), presidente e partecipanti. Il codice RD-AAAA-NN viene generato automaticamente.',
'<strong>2. Aggrega i dati</strong>: il pulsante "Aggrega dati" raccoglie gli elementi in ingresso §9.3.2 da tutta la piattaforma (non conformita, audit interni, rischi, SoA, obiettivi, formazione, stakeholder, normativa, scadenze).',
'<strong>3. Rivedi e completa</strong>: gli input aggregati sono una proposta da rivedere; aggiungi le conclusioni della direzione.',
'<strong>4. Registra le decisioni</strong>: ogni decisione (elemento in uscita §9.3.3) ha un responsabile (ruolo dell\'organigramma), una scadenza e uno stato. Puo essere collegata a un\'azione CAPA.',
'<strong>5. Approva e congela</strong>: l\'approvazione (riservata all\'org_admin) salva uno snapshot immutabile degli input al momento del verbale e blocca ogni ulteriore modifica.'
]
},
{
heading: 'Elementi in ingresso aggregati automaticamente',
items: [
'Le sezioni vengono lette in modo difensivo: se un modulo non e ancora attivo (es. Audit interni) o non ha dati, la sezione mostra "dato non disponibile" senza bloccare le altre.',
'Tutti i dati sono filtrati per la tua organizzazione e fotografati nello snapshot al momento dell\'approvazione, cosi il verbale resta coerente nel tempo.',
'Dal verbale puoi aprire la versione stampabile (pulsante "Verbale") da archiviare o presentare in audit.'
]
}
],
references: [
'ISO/IEC 27001:2022 §9.3 - Riesame di direzione (elementi in ingresso 9.3.2 / in uscita 9.3.3)',
'D.Lgs. 138/2024 art. 23 - Obblighi di governance degli organi di amministrazione e direttivi (NIS2 GV.PO-02)',
'NOTA: ISO e best practice non vincolante; gli obblighi italiani derivano da NIS2 / D.Lgs. 138/2024 / Determinazioni ACN.'
]
},
'calendario': {
title: 'Guida - Calendario scadenze',
intro: 'Il Calendario raccoglie in un unico posto ogni scadenza del sistema: incidenti Art.23, revisioni di policy e controlli, trattamenti di rischio, non conformita e azioni correttive, formazione, attivita stakeholder, scadenziario delle revisioni periodiche, audit interni e decisioni del riesame di direzione. E\' un aggregatore in SOLA LETTURA, sempre coerente con i moduli sorgente: ogni scadenza viene calcolata in tempo reale e rimanda direttamente all\'elemento che la genera. E\' uno strumento di supporto operativo, non un parere legale.',
sections: [
{
heading: 'Le viste',
items: [
'<strong>Griglia mensile</strong>: ogni giorno mostra dei pallini colorati, uno per scadenza. Il colore indica il tipo, mentre la navigazione &lsaquo; / &rsaquo; sposta il mese e "Oggi" torna al mese corrente. Clic su un giorno apre l\'elenco delle sue scadenze.',
'<strong>Lista</strong>: tutte le scadenze ordinate per data, con quelle <strong>in ritardo</strong> in cima. Clic sul nome apre l\'elemento sorgente (incidente, policy, rischio, ...).'
]
},
{
heading: 'Stato delle scadenze',
items: [
'<strong>In ritardo</strong> (rosso): la data e\' gia\' passata e la scadenza non risulta assolta.',
'<strong>In scadenza</strong> (arancione): mancano 14 giorni o meno.',
'<strong>Futura</strong> (blu): oltre 14 giorni.',
'<strong>Assolta</strong> (verde): la scadenza e\' stata chiusa/completata nel modulo di origine.'
]
},
{
heading: 'Filtri',
items: [
'Puoi filtrare per <strong>tipo</strong> (incidenti, policy, rischi, controlli, NC/CAPA, formazione, stakeholder, revisioni, audit interni, riesame) e per <strong>stato</strong>, combinando le due dimensioni.',
'I conteggi in alto (in ritardo / in scadenza / future / assolte) danno il colpo d\'occhio complessivo sul periodo caricato.'
]
},
{
heading: 'Da dove arrivano le scadenze',
items: [
'Il calendario non duplica i dati: legge le scadenze direttamente dai moduli. Per modificarne una, apri l\'elemento dal link e aggiornala nel suo modulo (es. la data di revisione di una policy si cambia in Policy).',
'Le scadenze dei moduli Audit interni e Riesame di direzione compaiono automaticamente non appena quei moduli sono attivi.'
]
}
],
references: [
'ISO/IEC 27001:2022, cl. 9.1 (monitoraggio e misurazione) e 9.3 (riesame di direzione) - buona prassi',
'NIST CSF 2.0 / GV.PO-02, GV.SC-07, DE.CM (best practice) - revisione periodica e monitoraggio continuo',
'NOTA: il calendario e\' uno strumento di supporto al monitoraggio delle scadenze; gli obblighi normativi derivano da NIS2 (Dir. UE 2022/2555) e dal D.Lgs. 138/2024.'
]
},
'stakeholder-activities': {
title: 'Guida - Attività stakeholder',
intro: 'Le attività verso gli stakeholder ti permettono di inviare questionari (da compilare o per firma di avvenuta lettura) e pianificare azioni, collegandoli alle procedure e alle misure/requisiti, con data e scadenza sul calendario NIS2. Strumento di supporto organizzativo, non un parere legale.',
@@ -1283,6 +1397,12 @@ const HelpSystem = (function () {
'stakeholders.html': 'stakeholders',
'stakeholders': 'stakeholders',
'stakeholder-activities.html': 'stakeholder-activities',
'internal-audits.html': 'internal-audits',
'internal-audits': 'internal-audits',
'management-review.html': 'management-review',
'management-review': 'management-review',
'calendario.html': 'calendario',
'calendario': 'calendario',
'stakeholder-activities': 'stakeholder-activities',
'risks.html': 'risks',
'risks': 'risks',
+6
View File
@@ -76,6 +76,12 @@ const I18n = (function () {
'rev.title': { it: 'Scadenziario', en: 'Review Schedule' },
'stk.title': { it: 'Stakeholder', en: 'Stakeholders' },
'sact.title': { it: 'Attività stakeholder', en: 'Stakeholder activities' },
'nav.calendar': { it: 'Calendario', en: 'Calendar' },
'cal.title': { it: 'Calendario scadenze', en: 'Deadlines calendar' },
'nav.internal_audits': { it: 'Audit interni', en: 'Internal audits' },
'iaud.title': { it: 'Audit interni', en: 'Internal audits' },
'nav.management_review': { it: 'Riesame di Direzione', en: 'Management Review' },
'mreview.title': { it: 'Riesame di Direzione', en: 'Management Review' },
'nav.risks': { it: 'Rischi', en: 'Risks' },
'nav.incidents': { it: 'Incidenti', en: 'Incidents' },
'nav.policies': { it: 'Policy', en: 'Policies' },