Files
nis2-agile/application/cli/build_nuova_agile_p1.php
DevEnv nis2-agileandClaude Opus 4.8 1c2eced7a4 [CLIENT] Nuova Agile Technology srl (org 996003) — build completo SGSI/NIS2
Provisioning idempotente di un'azienda cliente cloud-only (Aruba/Hetzner/AI, no server in sede, PC portatili):
- Fase 1: org + classificazione NIS2 (important, sub_threshold_candidate/preliminary) + 3 membri esistenti collegati + organigramma 8 ruoli
- Fase 2: 12 asset (NIS2-rilevanti) + 4 fornitori + 10 rischi + gap analysis (80 risposte, 45%)
- Fase 3: ISMS model + SoA 111 controlli (27001/27017/27018) + 31 documenti (Manuale/10 politiche/13 procedure/7 istruzioni)
- Fase 4: 15 piani di controllo periodici + 5 corsi formazione
Documenti AI-redatti con regole fonti-certe (D.Lgs.138/2024 art.23/24/25; 24h/72h/1 mese). Sorgenti in _docs_na/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 10:19:23 +02:00

104 lines
6.9 KiB
PHP

<?php
/**
* build_nuova_agile_p1.php — FASE 1: fondazione "Nuova Agile Technology srl"
* Org + classificazione NIS2 (important) + membership utenti esistenti + organigramma (org_roles).
* IDEMPOTENTE (rilanciabile). READ creds da config app (TLS).
* Uso: docker exec nis2-app php /var/www/nis2-agile/application/cli/build_nuova_agile_p1.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 ex(PDO $p, string $sql, array $a = []): void { $s=$p->prepare($sql); $s->execute($a); }
function one(PDO $p, string $sql, array $a = []) { $s=$p->prepare($sql); $s->execute($a); return $s->fetch(PDO::FETCH_ASSOC); }
$NOW = '2026-06-20 10:30:00';
/* ---- 1) Organization (idempotente per name) -------------------------------- */
$ORG_NAME = 'Nuova Agile Technology srl';
$org = one($pdo, "SELECT id FROM organizations WHERE name = ?", [$ORG_NAME]);
$mission = "Software house italiana che sviluppa e fornisce soluzioni applicative ai propri clienti con due modelli: "
. "(a) prodotti in licenza d'uso installati sui server dei clienti (on-premise presso il cliente); "
. "(b) servizi SaaS erogati in cloud. Infrastruttura interamente cloud (Aruba, Hetzner) e piattaforme AI; "
. "nessun server gestito in sede; postazioni di lavoro su PC portatili. "
. "Organico: 9 dipendenti, 2 collaboratori esterni con P.IVA, Presidente Silvia Garretto.";
if (!$org) {
ex($pdo, "INSERT INTO organizations
(name, sector, entity_type, voluntary_compliance, employee_count, annual_turnover_eur,
country, city, website, contact_email, subscription_plan, is_active,
is_autonomous, size_independent_category, has_code_of_ethics, designation_basis,
self_assessment_status, mission, created_at, updated_at)
VALUES (?, 'digital_infra', 'important', 0, 9, NULL,
'IT', NULL, NULL, 'presidenza@agile.software', 'enterprise', 1,
1, 'none', 0, 'sub_threshold_candidate',
'preliminary', ?, ?, ?)",
[$ORG_NAME, $mission, $NOW, $NOW]);
$orgId = (int)$pdo->lastInsertId();
echo "ORG creata id=$orgId\n";
} else {
$orgId = (int)$org['id'];
ex($pdo, "UPDATE organizations SET sector='digital_infra', entity_type='important', voluntary_compliance=0,
employee_count=9, country='IT', subscription_plan='enterprise', is_active=1, is_autonomous=1,
size_independent_category='none', has_code_of_ethics=0, designation_basis='sub_threshold_candidate',
self_assessment_status='preliminary', mission=?, updated_at=? WHERE id=?",
[$mission, $NOW, $orgId]);
echo "ORG esistente id=$orgId (aggiornata)\n";
}
/* ---- 2) Membership utenti ESISTENTI (no duplicati) -------------------------- */
// Silvia Garretto=103 (Presidente), Massimo Tagliavini=326 (Resp. SGSI), Simon Fattori=330 (org_admin/IT)
$members = [
[103, 'board_member', 1], // Presidente / Alta Direzione (primary)
[326, 'compliance_manager', 0], // Responsabile SGSI
[330, 'org_admin', 0], // Amministratore piattaforma / IT security
];
foreach ($members as [$uid, $role, $primary]) {
$u = one($pdo, "SELECT id, full_name FROM users WHERE id=?", [$uid]);
if (!$u) { echo " ! utente $uid inesistente, salto\n"; continue; }
$ex = one($pdo, "SELECT id FROM user_organizations WHERE user_id=? AND organization_id=?", [$uid, $orgId]);
if (!$ex) {
ex($pdo, "INSERT INTO user_organizations (user_id, organization_id, role, is_primary, joined_at) VALUES (?,?,?,?,?)",
[$uid, $orgId, $role, $primary, $NOW]);
echo " membership +{$u['full_name']} ($role)\n";
} else {
ex($pdo, "UPDATE user_organizations SET role=?, is_primary=? WHERE id=?", [$role, $primary, $ex['id']]);
echo " membership ~{$u['full_name']} ($role)\n";
}
}
/* ---- 3) Organigramma (org_roles) ------------------------------------------- */
// key, role_name, parent_key, holder_user_id, is_governance_body, description, sort
$roles = [
['cda', 'Consiglio di Amministrazione / Presidenza', null, 103, 1, 'Alta Direzione: definisce indirizzo strategico, approva la Politica SGSI e gli obiettivi, assegna risorse, riesame della direzione (ISO 27001 cl.5/9.3). Presidente: Silvia Garretto.', 1],
['dg', 'Direzione Generale', 'cda', 103, 1, 'Conduzione operativa dell\'azienda; sponsor del Sistema di Gestione; garantisce la leadership e l\'impegno (ISO 27001 cl.5.1).', 2],
['rsgsi','Responsabile del Sistema di Gestione (RSGSI)','dg', 326, 0, 'Responsabile SGSI/ISMS: mantiene il sistema, coordina valutazione rischi, audit interni, SoA, formazione, gestione NC/azioni correttive. Riferisce alla Direzione.', 3],
['itsec','Responsabile IT e Sicurezza Tecnica', 'dg', 330, 0, 'Gestione infrastruttura cloud (Aruba, Hetzner), piattaforme AI, sicurezza tecnica, gestione accessi/MFA, backup, patch, monitoraggio, gestione incidenti tecnici.', 4],
['dpo', 'Referente Protezione Dati (DPO/Privacy)', 'dg', null, 0, 'Presidio GDPR e ISO 27018 (dati personali nel cloud), DPIA, gestione richieste interessati. Ruolo coperto da consulente esterno (da nominare).', 5],
['dev', 'Team Sviluppo Software / SaaS', 'itsec', null, 0, 'Sviluppo prodotti in licenza e piattaforma SaaS; secure SDLC, gestione vulnerabilità applicative, code review. Composto da dipendenti.', 6],
['ops', 'Erogazione SaaS & Supporto Clienti', 'itsec', null, 0, 'Esercizio dei servizi SaaS, supporto ai clienti, gestione delle installazioni on-premise presso i clienti.', 7],
['ext', 'Collaboratori esterni (P.IVA)', 'dg', null, 0, '2 collaboratori esterni/interni con partita IVA: prestazioni specialistiche sotto accordo contrattuale con clausole di riservatezza e sicurezza (ISO 27001 A.5.19/A.6.6).', 8],
];
$idByKey = [];
foreach ($roles as [$key,$name,$pkey,$holder,$gov,$desc,$sort]) {
$exr = one($pdo, "SELECT id FROM org_roles WHERE organization_id=? AND role_name=?", [$orgId, $name]);
if (!$exr) {
ex($pdo, "INSERT INTO org_roles (organization_id, role_name, parent_role_id, holder_user_id, is_governance_body, description, sort_order, created_by, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?)",
[$orgId, $name, null, $holder, $gov, $desc, $sort, 103, $NOW, $NOW]);
$rid = (int)$pdo->lastInsertId();
echo " role + $name\n";
} else {
$rid = (int)$exr['id'];
ex($pdo, "UPDATE org_roles SET holder_user_id=?, is_governance_body=?, description=?, sort_order=?, updated_at=? WHERE id=?",
[$holder, $gov, $desc, $sort, $NOW, $rid]);
echo " role ~ $name\n";
}
$idByKey[$key] = $rid;
}
// seconda passata: parent linking
foreach ($roles as [$key,$name,$pkey]) {
if ($pkey && isset($idByKey[$pkey])) ex($pdo, "UPDATE org_roles SET parent_role_id=? WHERE id=?", [$idByKey[$pkey], $idByKey[$key]]);
}
echo "ORGANIGRAMMA: ".count($idByKey)." ruoli\n";
echo "\nFASE 1 OK — org_id=$orgId\n";