[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
+55 -5
View File
@@ -28,6 +28,32 @@ class AIService
}
}
/**
* Blocco "fonti certe" da iniettare nei system prompt.
* Elenca le fonti normative autoritative e impone di citarle, vietando
* riferimenti inventati. (Richiesta utente 2026-05-29 - grounding su fonti certe.)
*/
private function authoritativeSourcesBlock(): string
{
static $sources = null;
if ($sources === null) {
$sources = @include __DIR__ . '/../config/nis2_sources.php';
if (!is_array($sources)) $sources = [];
}
if (empty($sources)) return '';
$lines = [];
foreach ($sources as $s) {
$lines[] = '- ' . $s['citation'] . ' — ' . $s['authority'];
}
return "\n## FONTI NORMATIVE CERTE (cita SEMPRE quella pertinente)\n"
. implode("\n", $lines)
. "\n\nREGOLE SULLE FONTI (vincolanti):\n"
. "1. Ogni affermazione normativa DEVE essere ancorata a una di queste fonti, citata esplicitamente (es. \"ai sensi dell'art. 23 della Direttiva (UE) 2022/2555\" o \"Determinazione ACN n. 164179/2025, Allegato 3\").\n"
. "2. NON inventare numeri di articolo, determine, allegati o date: se non sei certo, dichiaralo e invita a verificare la fonte ufficiale.\n"
. "3. Preferisci sempre il riferimento normativo italiano (D.Lgs. 138/2024 + Determine ACN) per gli obblighi operativi, e la Direttiva UE per i principi.\n";
}
/**
* Analizza risultati gap analysis e genera raccomandazioni
*/
@@ -162,8 +188,23 @@ PROMPT;
*/
public function classifyIncident(string $title, string $description, array $organization): array
{
$entityType = $organization['entity_type'] ?? 'important';
// Allegato 3 (soggetti essenziali) vs Allegato 4 (soggetti importanti):
// gli importanti NON hanno l'obbligo sugli incidenti ricorrenti (IS-4).
$isEssential = ($entityType === 'essential');
$allowedIs = $isEssential ? 'IS-1|IS-2|IS-3|IS-4' : 'IS-1|IS-2|IS-3';
$allegato = $isEssential ? 'Allegato 3 (soggetti essenziali)' : 'Allegato 4 (soggetti importanti)';
$sourcesBlock = $this->authoritativeSourcesBlock();
$prompt = <<<PROMPT
Sei un analista di incident response. Classifica il seguente incidente di sicurezza secondo i criteri NIS2.
Sei un analista di incident response NIS2. Classifica il seguente incidente secondo il quadro normativo italiano.
## Quadro normativo di riferimento (cita la fonte pertinente in ogni campo motivazionale)
- Obbligo di notifica: art. 23 D.Lgs. 138/2024 e Direttiva (UE) 2022/2555.
- Classificazione incidenti significativi e tempistiche: Determinazione ACN n. 164179/2025, {$allegato}.
- Tempistiche: preallarme entro 24h, notifica completa entro 72h, relazione finale entro 1 mese dalla conoscenza dell'incidente significativo.
- Tipologie significative applicabili a questo soggetto ({$entityType}): {$allowedIs}.
{$sourcesBlock}
## Incidente
- Titolo: {$title}
@@ -171,21 +212,23 @@ Sei un analista di incident response. Classifica il seguente incidente di sicure
## Organizzazione
- Settore: {$organization['sector']}
- Tipo entità: {$organization['entity_type']}
- Tipo entità: {$entityType}
Rispondi in formato JSON:
{
"classification": "cyber_attack|data_breach|system_failure|human_error|natural_disaster|supply_chain|other",
"nis2_incident_type": "{$allowedIs}|none",
"severity": "low|medium|high|critical",
"is_significant": true/false,
"significance_reason": "Motivo se significativo secondo NIS2",
"significance_reason": "Motivo con citazione esplicita della fonte (es. Determina ACN 164179/2025, {$allegato})",
"requires_csirt_notification": true/false,
"notification_basis": "Riferimento normativo dell'obbligo (es. art. 23 D.Lgs. 138/2024)",
"suggested_actions": ["Azione immediata 1", "Azione immediata 2"],
"potential_impact": "Descrizione impatto potenziale",
"iocs_to_check": ["Indicatore 1", "Indicatore 2"]
}
Rispondi SOLO con il JSON.
Non inventare riferimenti: usa solo le fonti elencate sopra. Rispondi SOLO con il JSON.
PROMPT;
$response = $this->callAPI($prompt);
@@ -219,6 +262,12 @@ Rispondi sempre in italiano, in modo professionale, preciso e conciso.
Non includere dati identificativi dell'organizzazione nelle risposte.
SYSTEM;
// Grounding su fonti certe: applicato solo al prompt di default
// (i system prompt espliciti gestiscono le fonti per conto proprio).
if ($systemPrompt === null) {
$system .= "\n" . $this->authoritativeSourcesBlock();
}
$body = [
'model' => $this->model,
'max_tokens' => $this->maxTokens,
@@ -602,7 +651,8 @@ PROMPT;
}
$systemPrompt = "Sei un esperto consulente di cybersecurity NIS2 (EU 2022/2555) e D.Lgs. 138/2024.\n"
. "Rispondi in modo preciso e cita le fonti del contesto quando rilevanti.\n";
. "Rispondi in modo preciso e cita le fonti del contesto quando rilevanti.\n"
. $this->authoritativeSourcesBlock();
if (!empty($contextBlock)) {
$systemPrompt .= "\n## Contesto documentale (knowledge base)\n" . $contextBlock
. "\n\nQuando rispondi, cita esplicitamente i numeri tra parentesi quadre [1], [2], ... che corrispondono ai documenti del contesto.";