[FEAT] Integrazione analisi docs/nis2 v1.7.0 — scoring asset, tassonomia incidenti, PIR, NIST CSF, fonti certe

Fase 1 - Asset Relevance Scoring NIS2 (GV.OC-04): metodologia 0-100 a 6 criteri,
  AssetScoringService + endpoint scoringGrid/score/relevantSystems + UI assets.html + registro stampabile.
Fase 2 - Tassonomia incidenti Determina ACN 164179/2025: IS-1..4 + regime essenziale/importante (Allegati 3/4).
Fase 3 - Post-Incident Review (5-Whys) + metriche TTD/TTC/TTR + timestamp di fase.
Fase 4 - Mapping NIST CSF 2.0 (43 controlli) reference-only.
Fonti certe: registry config/nis2_sources.php + grounding AI (vieta riferimenti inventati) +
  citazioni help.js + ingest PDF normativi nella KB RAG (scripts/ingest-nis2-sources.php).
Migrazioni 020/021/022 (additive idempotenti). Fix VectorService IP Qdrant (drift .5->.3).
Analisi concorrenza Evix (docs/EVIX_ANALISI_CONCORRENZA.html, gap-driven).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-05-29 17:15:13 +02:00
co-authored by Claude Opus 4.8
parent a7a21faa82
commit 5c545ea3d0
41 changed files with 21078 additions and 24 deletions
+112
View File
@@ -255,6 +255,118 @@ class ReportService
* @param int $orgId ID dell'organizzazione
* @return string Documento HTML completo
*/
/**
* Registro formale "Elenco Sistemi Rilevanti NIS2" (requisito GV.OC-04).
* HTML stampabile (PDF via stampa browser). Cita le fonti normative certe.
* Adattato dal mockup docs/nis2/doc-relevant-systems.html.
*/
public function generateRelevantSystemsRegister(int $orgId): string
{
$org = Database::fetchOne('SELECT name, sector, entity_type FROM organizations WHERE id = ?', [$orgId]);
if (!$org) {
return $this->buildErrorHtml('Organizzazione non trovata');
}
$systems = Database::fetchAll(
"SELECT a.name, a.asset_type, a.category, a.ip_address, a.location,
a.relevance_score, a.relevance_class, a.relevance_assessed_at,
u.full_name AS owner_name
FROM assets a
LEFT JOIN users u ON u.id = a.owner_user_id
WHERE a.organization_id = ? AND a.is_nis2_relevant = 1
ORDER BY a.relevance_score DESC, a.name",
[$orgId]
);
$orgName = htmlspecialchars($org['name'] ?? '', ENT_QUOTES, 'UTF-8');
$entity = htmlspecialchars($org['entity_type'] ?? '', ENT_QUOTES, 'UTF-8');
$sector = htmlspecialchars($org['sector'] ?? '', ENT_QUOTES, 'UTF-8');
$date = date('d/m/Y');
$appName = defined('APP_NAME') ? APP_NAME : 'NIS2 Agile';
$appVer = defined('APP_VERSION') ? APP_VERSION : '1.0.0';
$classColors = ['critico' => '#dc2626', 'alto' => '#ea580c', 'medio' => '#ca8a04'];
$counts = ['critico' => 0, 'alto' => 0, 'medio' => 0];
$rowsHtml = '';
if (empty($systems)) {
$rowsHtml = '<tr><td colspan="7" style="text-align:center;color:#888;padding:24px;">Nessun sistema classificato come rilevante (score &ge; 40). Eseguire la valutazione di rilevanza dal modulo Inventario Asset.</td></tr>';
} else {
$n = 0;
foreach ($systems as $s) {
$n++;
$cls = $s['relevance_class'] ?? 'medio';
if (isset($counts[$cls])) $counts[$cls]++;
$color = $classColors[$cls] ?? '#6b7280';
$rowsHtml .= '<tr>'
. '<td>' . $n . '</td>'
. '<td><strong>' . htmlspecialchars($s['name'], ENT_QUOTES, 'UTF-8') . '</strong></td>'
. '<td>' . htmlspecialchars(($s['asset_type'] ?? '') . ($s['category'] ? ' / ' . $s['category'] : ''), ENT_QUOTES, 'UTF-8') . '</td>'
. '<td>' . htmlspecialchars($s['ip_address'] ?: '-', ENT_QUOTES, 'UTF-8') . '</td>'
. '<td>' . htmlspecialchars($s['owner_name'] ?: '-', ENT_QUOTES, 'UTF-8') . '</td>'
. '<td style="text-align:center;font-weight:700;">' . (int) $s['relevance_score'] . '/100</td>'
. '<td style="color:' . $color . ';font-weight:700;text-transform:uppercase;">' . htmlspecialchars($cls, ENT_QUOTES, 'UTF-8') . '</td>'
. '</tr>';
}
}
$total = count($systems);
return <<<HTML
<!DOCTYPE html>
<html lang="it"><head><meta charset="utf-8">
<title>Elenco Sistemi Rilevanti NIS2 - {$orgName}</title>
<style>
body{font-family:'Segoe UI',Arial,sans-serif;color:#1f2937;margin:40px;font-size:13px;}
.conf{background:#7f1d1d;color:#fff;text-align:center;padding:8px;font-weight:700;letter-spacing:1px;border-radius:6px;margin-bottom:18px;}
h1{font-size:22px;margin:0 0 4px;} h2{font-size:15px;border-bottom:2px solid #06b6d4;padding-bottom:4px;margin-top:28px;}
.meta{color:#6b7280;font-size:12px;margin-bottom:18px;}
table{width:100%;border-collapse:collapse;margin-top:10px;} th,td{border:1px solid #e5e7eb;padding:7px 9px;text-align:left;}
th{background:#f0f9ff;font-size:12px;} .stats{display:flex;gap:14px;margin:14px 0;}
.stat{flex:1;border:1px solid #e5e7eb;border-radius:8px;padding:10px;text-align:center;}
.stat .v{font-size:22px;font-weight:800;} .src{background:#f9fafb;border-left:4px solid #06b6d4;padding:10px 14px;font-size:11.5px;color:#374151;margin-top:24px;border-radius:0 6px 6px 0;}
.sign{margin-top:36px;display:flex;justify-content:space-between;} .sign div{width:45%;border-top:1px solid #9ca3af;padding-top:6px;font-size:12px;color:#4b5563;}
@media print{body{margin:12mm;} .noprint{display:none;}}
</style></head><body>
<div class="conf">&#9888; DOCUMENTO RISERVATO - DISTRIBUZIONE LIMITATA &#9888;</div>
<h1>{$orgName}</h1>
<h1 style="font-size:18px;color:#0e7490;">Elenco Formale dei Sistemi Rilevanti NIS2</h1>
<div class="meta">Documento ai sensi della Direttiva (UE) 2022/2555 e del D.Lgs. 138/2024 &mdash; Requisito GV.OC-04 (NIST CSF 2.0)<br>
Settore: {$sector} &nbsp;|&nbsp; Tipo soggetto: {$entity} &nbsp;|&nbsp; Data emissione: {$date} &nbsp;|&nbsp; Generato da {$appName} v{$appVer}</div>
<h2>1. Premessa e metodologia</h2>
<p>Il presente documento costituisce l'elenco formale dei sistemi informativi e di rete classificati come <strong>rilevanti</strong> ai fini della conformita alla Direttiva NIS2. La classificazione adotta una metodologia di scoring 0-100 su sei criteri (Criticita Operativa, Impatto Interruzione, Dati Trattati, Dipendenze, Esposizione, Obblighi Normativi). <strong>Soglia di rilevanza: punteggio &ge; 40.</strong> I sistemi con punteggio &ge; 80 sono considerati critici e richiedono misure di sicurezza massime e monitoraggio continuo.</p>
<div class="stats">
<div class="stat"><div class="v">{$total}</div>Sistemi rilevanti</div>
<div class="stat"><div class="v" style="color:#dc2626;">{$counts['critico']}</div>Critici (&ge;80)</div>
<div class="stat"><div class="v" style="color:#ea580c;">{$counts['alto']}</div>Alti (60-79)</div>
<div class="stat"><div class="v" style="color:#ca8a04;">{$counts['medio']}</div>Medi (40-59)</div>
</div>
<h2>2. Elenco sistemi rilevanti</h2>
<table>
<thead><tr><th>#</th><th>Sistema</th><th>Tipo/Categoria</th><th>IP</th><th>Responsabile</th><th>Punteggio</th><th>Classe</th></tr></thead>
<tbody>{$rowsHtml}</tbody>
</table>
<div class="src">
<strong>Fonti normative certe:</strong><br>
&bull; Direttiva (UE) 2022/2555 (NIS2) &mdash; Parlamento europeo e Consiglio UE<br>
&bull; D.Lgs. 4 settembre 2024, n. 138 &mdash; recepimento NIS2 (artt. 23, 24)<br>
&bull; NIST Cybersecurity Framework 2.0 &mdash; controllo GV.OC-04 (elenco sistemi rilevanti)
</div>
<div class="sign">
<div>Redatto da (CISO / Responsabile Compliance)</div>
<div>Approvato da (Organo di gestione / Direzione)</div>
</div>
<p class="noprint" style="margin-top:24px;"><button onclick="window.print()">Stampa / Salva PDF</button></p>
</body></html>
HTML;
}
public function generateExecutiveReport(int $orgId): string
{
$data = $this->generateComplianceReport($orgId);