[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:
co-authored by
Claude Opus 4.8
parent
a7a21faa82
commit
5c545ea3d0
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/BaseController.php';
|
||||
require_once __DIR__ . '/../services/AssetScoringService.php';
|
||||
|
||||
class AssetController extends BaseController
|
||||
{
|
||||
@@ -29,6 +30,10 @@ class AssetController extends BaseController
|
||||
$where .= ' AND status = ?';
|
||||
$params[] = $this->getParam('status');
|
||||
}
|
||||
if ($this->hasParam('nis2_relevant')) {
|
||||
$where .= ' AND is_nis2_relevant = ?';
|
||||
$params[] = $this->getParam('nis2_relevant') ? 1 : 0;
|
||||
}
|
||||
|
||||
$total = Database::count('assets', $where, $params);
|
||||
$assets = Database::fetchAll(
|
||||
@@ -157,4 +162,116 @@ class AssetController extends BaseController
|
||||
|
||||
$this->jsonSuccess(['nodes' => $nodes, 'edges' => $edges]);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/assets/scoringGrid
|
||||
* Ritorna la griglia ufficiale di valutazione rilevanza NIS2 (GV.OC-04)
|
||||
* per costruire la UI di scoring lato client.
|
||||
*/
|
||||
public function scoringGrid(): void
|
||||
{
|
||||
$this->requireOrgAccess();
|
||||
$this->jsonSuccess([
|
||||
'grid' => AssetScoringService::GRID,
|
||||
'threshold' => AssetScoringService::RELEVANCE_THRESHOLD,
|
||||
'classes' => [
|
||||
['key' => 'critico', 'min' => 80, 'max' => 100, 'label' => 'Critico - Priorita Massima'],
|
||||
['key' => 'alto', 'min' => 60, 'max' => 79, 'label' => 'Alto - Priorita Alta'],
|
||||
['key' => 'medio', 'min' => 40, 'max' => 59, 'label' => 'Medio - Rilevante'],
|
||||
['key' => 'basso', 'min' => 20, 'max' => 39, 'label' => 'Basso - Monitoraggio'],
|
||||
['key' => 'trascurabile', 'min' => 0, 'max' => 19, 'label' => 'Trascurabile'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/assets/{id}/score
|
||||
* Calcola e salva la rilevanza NIS2 dell'asset a partire dalle selezioni
|
||||
* sui 6 criteri. Body: { criteria: { c1_operational_criticality: 'critical', ... } }
|
||||
*/
|
||||
public function score(int $id): void
|
||||
{
|
||||
$this->requireOrgRole(['org_admin', 'compliance_manager']);
|
||||
|
||||
$asset = Database::fetchOne(
|
||||
'SELECT id FROM assets WHERE id = ? AND organization_id = ?',
|
||||
[$id, $this->getCurrentOrgId()]
|
||||
);
|
||||
if (!$asset) {
|
||||
$this->jsonError('Asset non trovato', 404, 'ASSET_NOT_FOUND');
|
||||
}
|
||||
|
||||
$criteria = $this->getParam('criteria');
|
||||
if (!is_array($criteria)) {
|
||||
$this->jsonError('Campo "criteria" mancante o non valido', 422, 'INVALID_CRITERIA');
|
||||
}
|
||||
|
||||
try {
|
||||
$result = AssetScoringService::calculate($criteria);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$this->jsonError($e->getMessage(), 422, 'INVALID_CRITERIA');
|
||||
return;
|
||||
}
|
||||
|
||||
Database::update('assets', [
|
||||
'relevance_score' => $result['score'],
|
||||
'relevance_criteria' => json_encode($result['breakdown'], JSON_UNESCAPED_UNICODE),
|
||||
'relevance_class' => $result['class'],
|
||||
'is_nis2_relevant' => $result['is_relevant'] ? 1 : 0,
|
||||
'criticality' => $result['criticality'],
|
||||
'relevance_assessed_at' => date('Y-m-d H:i:s'),
|
||||
'relevance_assessed_by' => $this->getCurrentUserId(),
|
||||
], 'id = ? AND organization_id = ?', [$id, $this->getCurrentOrgId()]);
|
||||
|
||||
$this->logAudit('asset_scored', 'asset', $id, [
|
||||
'score' => $result['score'],
|
||||
'class' => $result['class'],
|
||||
]);
|
||||
|
||||
$this->jsonSuccess([
|
||||
'score' => $result['score'],
|
||||
'class' => $result['class'],
|
||||
'is_nis2_relevant' => $result['is_relevant'],
|
||||
'breakdown' => $result['breakdown'],
|
||||
'required_measures'=> AssetScoringService::requiredMeasures($result['class']),
|
||||
], 'Rilevanza NIS2 calcolata');
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/assets/relevantSystems
|
||||
* Elenco dei sistemi classificati rilevanti NIS2 (score >= 40), ordinati
|
||||
* per punteggio. Alimenta il registro formale "Sistemi Rilevanti" (GV.OC-04).
|
||||
*/
|
||||
public function relevantSystems(): void
|
||||
{
|
||||
$this->requireOrgAccess();
|
||||
|
||||
$rows = Database::fetchAll(
|
||||
"SELECT a.id, a.name, a.asset_type, a.category, a.ip_address, a.location,
|
||||
a.relevance_score, a.relevance_class, a.relevance_criteria,
|
||||
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",
|
||||
[$this->getCurrentOrgId()]
|
||||
);
|
||||
|
||||
$stats = ['critico' => 0, 'alto' => 0, 'medio' => 0];
|
||||
foreach ($rows as &$r) {
|
||||
$r['relevance_criteria'] = json_decode($r['relevance_criteria'] ?? 'null', true);
|
||||
$r['required_measures'] = AssetScoringService::requiredMeasures($r['relevance_class'] ?? '');
|
||||
if (isset($stats[$r['relevance_class']])) {
|
||||
$stats[$r['relevance_class']]++;
|
||||
}
|
||||
}
|
||||
unset($r);
|
||||
|
||||
$this->jsonSuccess([
|
||||
'systems' => $rows,
|
||||
'count' => count($rows),
|
||||
'by_class' => $stats,
|
||||
'threshold' => AssetScoringService::RELEVANCE_THRESHOLD,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user