[FIX] Epic C / C1 — correzioni post-verifica flotta (1 major + 5 minor)

Flotta di verifica (14 agenti): sicurezza pulita, fedeltà del dato perfetta (codifica
Simon intatta, 0 scostamenti). Corretti i 6 finding confermati:
- MAJOR: PolicyController::ensureFrameworkProcedures ora in transazione + SELECT...FOR UPDATE
  sulla riga org -> no procedure duplicate su fallimento parziale (rollback) o richieste concorrenti.
- MINOR: importer idempotente committato application/cli/seed_framework.php (DDL + upsert da
  nis2_framework_seed.json) -> re-seed riproducibile/versionato (verificato 2 run = 0 duplicati).
- MINOR: allineato '92 requisiti' importanti (dato autoritativo Simon) in help.js + nis2_sources.php
  (era 87, contraddizione interna); coerente '24 requisiti aggiuntivi essenziali' (116-92).
- MINOR (UI): troncamento anteprima valutazione sul RAW prima di esc() (no entita HTML spezzate).
- MINOR (UI a11y/AGID): modale valutazione con focus iniziale, ripristino focus, focus-trap.
Cache-buster ?v=20260623, version 1.18.2, SW nis2-shell-v1.18.2.
NB residuo da verificare: data esatta Determinazione 333017/2025 (mese senza giorno) in nis2_sources.php.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-16 18:40:31 +02:00
co-authored by Claude Opus 4.8
parent 1f2d48df7c
commit 45e6c3599c
41 changed files with 278 additions and 130 deletions
+11 -3
View File
@@ -67,12 +67,18 @@ class PolicyController extends BaseController
if (!empty($this->isDemo)) { return; }
$orgId = $this->getCurrentOrgId();
if (!$orgId) { return; }
$pdo = Database::getInstance();
try {
// Transazione + lock di riga: serializza richieste concorrenti (niente doppio
// seed) e, in caso di fallimento parziale, il rollback annulla gli insert già
// fatti (niente procedure duplicate alla ri-prova). Il flag si scrive nello
// stesso commit degli insert.
$pdo->beginTransaction();
$org = Database::fetchOne(
'SELECT framework_procedures_seeded_at FROM organizations WHERE id = ?',
'SELECT framework_procedures_seeded_at FROM organizations WHERE id = ? FOR UPDATE',
[$orgId]
);
if (!$org || $org['framework_procedures_seeded_at'] !== null) { return; }
if (!$org || $org['framework_procedures_seeded_at'] !== null) { $pdo->commit(); return; }
$procs = Database::fetchAll(
"SELECT p.proc_code, p.proc_descr,
@@ -85,7 +91,7 @@ class PolicyController extends BaseController
FROM cfg_nis2_requisiti q3 WHERE q3.proc_code = p.proc_code) AS misure
FROM cfg_nis2_procedure p ORDER BY p.proc_code"
);
if (!$procs) { return; } // framework non ancora seedato: riprova al prossimo accesso
if (!$procs) { $pdo->commit(); return; } // framework non ancora seedato: riprova al prossimo accesso
foreach ($procs as $p) {
$cat = self::PROC_NIST_CATEGORY[$p['nist_code'] ?? ''] ?? 'information_security';
@@ -107,7 +113,9 @@ class PolicyController extends BaseController
'UPDATE organizations SET framework_procedures_seeded_at = NOW() WHERE id = ?',
[$orgId]
);
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) { $pdo->rollBack(); }
error_log('[PolicyController] seed procedure default fallito (org ' . $orgId . '): ' . $e->getMessage());
}
}