[FEAT] Rischi #500 opzione B: matrice dai rischi-requisito (probabilità×impatto)
Ogni rischio derivato da un requisito puo' ora essere valutato con Probabilita' e Impatto (1-5) e compare nella matrice 5x5. - DB: mig 066 (org_requisito_state += likelihood/impact) + runner idempotente. - Backend: FrameworkController::setState accetta likelihood/impact; RiskController ::derivedList ritorna likelihood/impact/score. Applicata su prod + reload. - Frontend risks.html: colonne Probabilita'/Impatto/Rischio(P×I) + tasto "Valuta" (modale, riservato a super_admin/org_admin/compliance_manager); matrice calcolata client-side dai rischi derivati valutati (esclusi i non_applicabile, caveat nis2-expert) + rischi custom. Framing normativo invariato. - help.js/i18n aggiornati; version 1.25.7; buster help/i18n ?v=20260727b. 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
f1156a81bb
commit
f6d2076684
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* migrate_066_requisito_risk_scoring.php — Ticket #500 (opzione B, matrice).
|
||||
* org_requisito_state += likelihood TINYINT NULL, impact TINYINT NULL (scala 1-5).
|
||||
* Serve a posizionare i rischi-da-requisito (RSK-<misura>Com.N) sulla matrice 5x5.
|
||||
* Additiva e IDEMPOTENTE. Nessun dato esistente toccato (valori NULL = non ancora valutato).
|
||||
*
|
||||
* Eseguire (host): docker exec nis2-app php /var/www/nis2-agile/application/cli/migrate_066_requisito_risk_scoring.php
|
||||
*/
|
||||
if (PHP_SAPI !== 'cli') { http_response_code(403); exit("CLI only\n"); }
|
||||
require_once __DIR__ . '/../config/env.php';
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
$pdo = Database::getInstance();
|
||||
|
||||
function colExists(PDO $pdo, string $table, string $col): bool {
|
||||
$st = $pdo->prepare(
|
||||
"SELECT 1 FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?"
|
||||
);
|
||||
$st->execute([$table, $col]);
|
||||
return (bool) $st->fetchColumn();
|
||||
}
|
||||
|
||||
$adds = [
|
||||
'likelihood' => "ADD COLUMN likelihood TINYINT NULL COMMENT 'Probabilita 1-5 (rischio da non conformita del requisito)' AFTER valutazione_rischio",
|
||||
'impact' => "ADD COLUMN impact TINYINT NULL COMMENT 'Impatto 1-5' AFTER likelihood",
|
||||
];
|
||||
|
||||
foreach ($adds as $col => $clause) {
|
||||
if (colExists($pdo, 'org_requisito_state', $col)) { echo " - $col gia presente, skip\n"; continue; }
|
||||
$pdo->exec("ALTER TABLE org_requisito_state $clause");
|
||||
echo " + aggiunta colonna org_requisito_state.$col\n";
|
||||
}
|
||||
|
||||
echo "Migrazione 066 — org_requisito_state.likelihood/impact OK. Prossima mig=067.\n";
|
||||
@@ -199,21 +199,32 @@ class FrameworkController extends BaseController
|
||||
$note = array_key_exists('note', $body)
|
||||
? ($body['note'] !== '' ? (string) $body['note'] : null) : null;
|
||||
|
||||
// Probabilita/impatto 1-5 (opzione B ticket #500, matrice 5x5). null = non valutato.
|
||||
$scale = static function ($v) {
|
||||
if ($v === null || $v === '') return null;
|
||||
$n = (int) $v;
|
||||
return ($n >= 1 && $n <= 5) ? $n : null;
|
||||
};
|
||||
$likelihood = array_key_exists('likelihood', $body) ? $scale($body['likelihood']) : null;
|
||||
$impact = array_key_exists('impact', $body) ? $scale($body['impact']) : null;
|
||||
|
||||
// upsert org-scoped (UNIQUE org+requisito)
|
||||
Database::query(
|
||||
'INSERT INTO org_requisito_state
|
||||
(organization_id, requisito_id, stato, valutazione_rischio, note, updated_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
(organization_id, requisito_id, stato, valutazione_rischio, note, likelihood, impact, updated_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
stato = VALUES(stato),
|
||||
valutazione_rischio = VALUES(valutazione_rischio),
|
||||
note = VALUES(note),
|
||||
likelihood = VALUES(likelihood),
|
||||
impact = VALUES(impact),
|
||||
updated_by = VALUES(updated_by)',
|
||||
[$orgId, $reqId, $stato ?? 'da_valutare', $valutazione, $note, $this->getCurrentUserId()]
|
||||
[$orgId, $reqId, $stato ?? 'da_valutare', $valutazione, $note, $likelihood, $impact, $this->getCurrentUserId()]
|
||||
);
|
||||
|
||||
$row = Database::fetchOne(
|
||||
'SELECT requisito_id, stato, valutazione_rischio, note, updated_at
|
||||
'SELECT requisito_id, stato, valutazione_rischio, note, likelihood, impact, updated_at
|
||||
FROM org_requisito_state WHERE organization_id = ? AND requisito_id = ?',
|
||||
[$orgId, $reqId]
|
||||
);
|
||||
@@ -222,6 +233,8 @@ class FrameworkController extends BaseController
|
||||
'stato' => $row['stato'],
|
||||
'valutazione_rischio' => $row['valutazione_rischio'],
|
||||
'note' => $row['note'],
|
||||
'likelihood' => $row['likelihood'] !== null ? (int) $row['likelihood'] : null,
|
||||
'impact' => $row['impact'] !== null ? (int) $row['impact'] : null,
|
||||
'updated_at' => $row['updated_at'],
|
||||
], 'Valutazione salvata');
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class RiskController extends BaseController
|
||||
"SELECT q.id AS requisito_id, q.n, q.misura_code, q.requisito_code,
|
||||
q.requisito_descr, q.applies_important, q.applies_essential,
|
||||
m.misura_descr, m.nist_code, m.area_politica, m.ord,
|
||||
s.stato, s.valutazione_rischio, s.note
|
||||
s.stato, s.valutazione_rischio, s.note, s.likelihood, s.impact
|
||||
FROM cfg_nis2_requisiti q
|
||||
JOIN cfg_nis2_misure m ON m.misura_code = q.misura_code
|
||||
LEFT JOIN org_requisito_state s
|
||||
@@ -105,6 +105,10 @@ class RiskController extends BaseController
|
||||
'stato' => $q['stato'] ?? 'da_valutare',
|
||||
'valutazione_rischio' => $q['valutazione_rischio'] ?? null,
|
||||
'note' => $q['note'] ?? null,
|
||||
'likelihood' => isset($q['likelihood']) && $q['likelihood'] !== null ? (int) $q['likelihood'] : null,
|
||||
'impact' => isset($q['impact']) && $q['impact'] !== null ? (int) $q['impact'] : null,
|
||||
'score' => (isset($q['likelihood'], $q['impact']) && $q['likelihood'] !== null && $q['impact'] !== null)
|
||||
? (int) $q['likelihood'] * (int) $q['impact'] : null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user