[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>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f9b2c9d6d7
commit
1c2eced7a4
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* build_nuova_agile_p2.php — FASE 2: asset inventory + fornitori + risk register + assessment.
|
||||
* Profilo: cloud-only (Aruba/Hetzner/AI), nessun server in sede, PC portatili. IDEMPOTENTE.
|
||||
*/
|
||||
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:35:00';
|
||||
|
||||
$org = one($pdo, "SELECT id FROM organizations WHERE name=?", ['Nuova Agile Technology srl']);
|
||||
if (!$org) { exit("ORG mancante: esegui prima la Fase 1\n"); }
|
||||
$orgId=(int)$org['id'];
|
||||
$ITSEC=330; $RSGSI=326;
|
||||
echo "ORG $orgId\n";
|
||||
|
||||
/* ---- ASSETS ---------------------------------------------------------------- */
|
||||
// name, asset_type, category, description, criticality, vendor, owner, relClass, relScore, nis2relevant
|
||||
$assets = [
|
||||
['Parco PC portatili aziendali','hardware','Endpoint','~12 notebook cifrati (BitLocker/FileVault) usati da dipendenti e collaboratori. Unico hardware gestito: nessun server in sede.','high','Misto (Dell/Apple/Lenovo)',$ITSEC,'alto',70,1],
|
||||
['Piattaforma SaaS (prodotto cloud)','service','Applicazione SaaS','Servizio applicativo multi-tenant erogato in cloud ai clienti. Asset primario di erogazione del servizio.','critical','Nuova Agile Technology',$ITSEC,'critico',95,1],
|
||||
['Prodotto in licenza d\'uso (on-premise clienti)','software','Prodotto software','Applicativo distribuito in licenza e installato sui server dei clienti. Manutenzione e aggiornamenti a carico nostro.','high','Nuova Agile Technology',$ITSEC,'alto',75,1],
|
||||
['Codice sorgente e repository (Git)','data','Proprieta intellettuale','Repository del codice sorgente di prodotto e SaaS, pipeline CI/CD, segreti di build. Asset critico di IP.','critical','GitHub/Gitea',$ITSEC,'critico',90,1],
|
||||
['Infrastruttura cloud Aruba','service','Cloud IaaS/Hosting','Hosting e risorse cloud presso Aruba S.p.A. (data center in Italia). Fornitore primario di infrastruttura.','critical','Aruba S.p.A.',$ITSEC,'critico',90,1],
|
||||
['Infrastruttura cloud Hetzner','service','Cloud IaaS','Server e risorse cloud presso Hetzner Online GmbH (Germania) per l\'erogazione SaaS.','critical','Hetzner Online GmbH',$ITSEC,'critico',90,1],
|
||||
['Piattaforme AI (API LLM)','service','AI / ML','Servizi di intelligenza artificiale (API LLM) usati nel prodotto/SaaS. Trattamento dati verso sub-fornitore AI.','high','Anthropic / OpenAI',$ITSEC,'alto',70,1],
|
||||
['Dati personali dei clienti (SaaS)','data','Dati personali','Dati personali trattati per conto dei clienti nella piattaforma SaaS. Ambito GDPR + ISO 27018.','critical','—',$RSGSI,'critico',95,1],
|
||||
['Identity Provider / SSO','service','IAM','Gestione identita e Single Sign-On per accesso ai sistemi interni e al SaaS (MFA obbligatoria).','high','SSO suite / IdP',$ITSEC,'alto',75,1],
|
||||
['Posta elettronica e collaboration','service','Produttivita','Email, documenti condivisi e comunicazione (Google Workspace / Microsoft 365).','medium','Google / Microsoft',$ITSEC,'medio',45,1],
|
||||
['Backup cloud e disaster recovery','service','Continuita','Backup cifrati e procedure di ripristino dei dati SaaS e di prodotto. Regola 3-2-1 su cloud.','high','Aruba / Hetzner',$ITSEC,'alto',80,1],
|
||||
['Dominio, DNS e sito web','network','Presenza online','Domini, record DNS e sito istituzionale/marketing.','medium','Registrar / Cloudflare',$ITSEC,'basso',30,1],
|
||||
];
|
||||
foreach ($assets as [$n,$t,$cat,$d,$crit,$ven,$own,$rc,$rs,$rel]) {
|
||||
$exa=one($pdo,"SELECT id FROM assets WHERE organization_id=? AND name=?",[$orgId,$n]);
|
||||
if(!$exa){
|
||||
ex($pdo,"INSERT INTO assets (organization_id,name,asset_type,category,description,criticality,owner_user_id,vendor,status,discovery_source,is_nis2_relevant,relevance_class,relevance_score,relevance_assessed_at,relevance_assessed_by,created_at,updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?, 'active','manual', ?,?,?,?,?,?,?)",
|
||||
[$orgId,$n,$t,$cat,$d,$crit,$own,$ven,$rel,$rc,$rs,$NOW,$RSGSI,$NOW,$NOW]);
|
||||
echo " asset + $n\n";
|
||||
} else echo " asset = $n\n";
|
||||
}
|
||||
|
||||
/* ---- SUPPLIERS ------------------------------------------------------------- */
|
||||
// name, service_type, service_description, criticality, risk_score, country-note, req_met
|
||||
$sup = [
|
||||
['Aruba S.p.A.','Cloud IaaS / Hosting','Fornitore primario di infrastruttura cloud e hosting (data center in Italia). Erogazione SaaS e servizi interni.','critical',45,1],
|
||||
['Hetzner Online GmbH','Cloud IaaS / Server','Fornitore di server e risorse cloud (Germania, UE) per l\'erogazione della piattaforma SaaS.','critical',40,1],
|
||||
['Anthropic PBC','Piattaforma AI (LLM API)','Sub-fornitore di servizi di intelligenza artificiale (API). Possibile trattamento di contenuti: data processing agreement e minimizzazione richiesti.','high',55,0],
|
||||
['Google Workspace (Google Ireland Ltd)','Email & Collaboration','Posta elettronica, documenti e collaborazione. Trattamento dati aziendali e di comunicazione.','medium',35,1],
|
||||
];
|
||||
$d180='2026-12-17'; $cs='2026-01-01'; $ce='2026-12-31';
|
||||
foreach ($sup as [$n,$st,$sd,$crit,$rscore,$met]) {
|
||||
$exs=one($pdo,"SELECT id FROM suppliers WHERE organization_id=? AND name=?",[$orgId,$n]);
|
||||
if(!$exs){
|
||||
ex($pdo,"INSERT INTO suppliers (organization_id,name,stakeholder_type,source,service_type,service_description,criticality,risk_score,last_assessment_date,next_assessment_date,contract_start_date,contract_expiry_date,security_requirements_met,status,created_at,updated_at)
|
||||
VALUES (?,?, 'supplier','manual', ?,?,?,?, ?,?,?,?, ?, 'active', ?,?)",
|
||||
[$orgId,$n,$st,$sd,$crit,$rscore,$NOW,$d180,$cs,$ce,$met,$NOW,$NOW]);
|
||||
echo " supplier + $n\n";
|
||||
} else echo " supplier = $n\n";
|
||||
}
|
||||
|
||||
/* ---- RISK REGISTER --------------------------------------------------------- */
|
||||
// code,title,description,category,L,I,treatment,nis2_article
|
||||
$risks=[
|
||||
['R-001','Indisponibilita del fornitore cloud primario','Outage o cessazione di Aruba/Hetzner con impatto sull\'erogazione SaaS e sui servizi.','supply_chain',3,5,'mitigate','21.2.d'],
|
||||
['R-002','Violazione dei dati personali dei clienti (SaaS)','Accesso non autorizzato o esfiltrazione di dati personali trattati nel SaaS multi-tenant.','cyber',3,5,'mitigate','21.2.a'],
|
||||
['R-003','Compromissione di credenziali / accesso non autorizzato','Phishing o furto credenziali con accesso ai sistemi cloud o al codice. Mitigato da MFA.','cyber',3,4,'mitigate','21.2.i'],
|
||||
['R-004','Furto o smarrimento di PC portatile','Perdita di un notebook con possibile esposizione dati. Mitigato da cifratura disco e MDM.','physical',3,3,'mitigate','21.2.j'],
|
||||
['R-005','Vulnerabilita nel prodotto / dipendenze software','Vulnerabilita nel codice o nelle dipendenze open source (supply chain software) sfruttabili dai clienti.','cyber',3,4,'mitigate','21.2.e'],
|
||||
['R-006','Indisponibilita prolungata del servizio SaaS','Interruzione del servizio oltre gli SLA per guasto, errore o attacco DoS.','operational',3,4,'mitigate','21.2.c'],
|
||||
['R-007','Esposizione di dati verso piattaforme AI','Invio non controllato di dati sensibili/personali alle API AI (data leakage verso sub-fornitore).','compliance',3,4,'mitigate','21.2.a'],
|
||||
['R-008','Non conformita GDPR / ISO 27018 nel cloud','Trattamento di dati personali nel cloud non conforme (DPA mancanti, trasferimenti extra-UE, retention).','compliance',2,4,'mitigate','21.2.a'],
|
||||
['R-009','Rischio da collaboratori esterni (P.IVA)','Accessi e trattamenti da parte di collaboratori esterni senza adeguati vincoli contrattuali/tecnici.','human',2,3,'mitigate','21.2.i'],
|
||||
['R-010','Ransomware su endpoint','Cifratura malevola di un endpoint con impatto su dati locali e potenziale propagazione.','cyber',3,4,'mitigate','21.2.h'],
|
||||
];
|
||||
foreach ($risks as [$rc,$t,$d,$cat,$L,$I,$tr,$art]) {
|
||||
$score=$L*$I;
|
||||
$exr=one($pdo,"SELECT id FROM risks WHERE organization_id=? AND risk_code=?",[$orgId,$rc]);
|
||||
if(!$exr){
|
||||
ex($pdo,"INSERT INTO risks (organization_id,risk_code,title,description,category,likelihood,impact,inherent_risk_score,treatment,status,owner_user_id,review_date,nis2_article,created_at,updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?, 'treating', ?, ?, ?, ?, ?)",
|
||||
[$orgId,$rc,$t,$d,$cat,$L,$I,$score,$tr,$ITSEC,'2026-12-20',$art,$NOW,$NOW]);
|
||||
echo " risk + $rc ($score)\n";
|
||||
} else echo " risk = $rc\n";
|
||||
}
|
||||
|
||||
/* ---- ASSESSMENT (gap analysis iniziale, da questionario) ------------------- */
|
||||
$qfile = __DIR__ . '/../data/nis2_questionnaire.json';
|
||||
$ass = one($pdo,"SELECT id FROM assessments WHERE organization_id=? AND title=?",[$orgId,'Gap Analysis iniziale NIS2 2026']);
|
||||
if (!$ass && is_file($qfile)) {
|
||||
$q=json_decode(file_get_contents($qfile),true);
|
||||
ex($pdo,"INSERT INTO assessments (organization_id,title,assessment_type,status,created_at,updated_at) VALUES (?,?, 'initial','in_progress',?,?)",
|
||||
[$orgId,'Gap Analysis iniziale NIS2 2026',$NOW,$NOW]);
|
||||
$aid=(int)$pdo->lastInsertId();
|
||||
// distribuzione realistica early-stage: pattern deterministico
|
||||
$pat=['not_implemented','partial','partial','implemented','not_implemented','partial','implemented','partial','not_implemented','partial'];
|
||||
$val2score=['not_implemented'=>0,'partial'=>50,'implemented'=>100];
|
||||
$val2mat=['not_implemented'=>1,'partial'=>2,'implemented'=>4];
|
||||
$i=0; $catAgg=[]; $tot=0;$cnt=0;
|
||||
foreach (($q['categories']??[]) as $c) {
|
||||
$catId=$c['id']; $iso=($c['iso27001_controls'][0]??null); $art=$c['nis2_article']??null;
|
||||
$sum=0;$n=0;
|
||||
foreach (($c['questions']??[]) as $qq) {
|
||||
$code=$qq['code']??('Q'.$i); $txt=$qq['text_it']??($qq['text_en']??$code);
|
||||
$rv=$pat[$i % count($pat)]; $i++;
|
||||
ex($pdo,"INSERT INTO assessment_responses (assessment_id,question_code,nis2_article,iso27001_control,category,question_text,response_value,maturity_level,answered_by,answered_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)",
|
||||
[$aid,$code,$art,$iso,$catId,$txt,$rv,$val2mat[$rv],$RSGSI,$NOW]);
|
||||
$sum+=$val2score[$rv]; $n++; $tot+=$val2score[$rv]; $cnt++;
|
||||
}
|
||||
if($n) $catAgg[$catId]=round($sum/$n,1);
|
||||
}
|
||||
$overall = $cnt? round($tot/$cnt,2) : 0;
|
||||
ex($pdo,"UPDATE assessments SET overall_score=?, category_scores=? WHERE id=?",[$overall,json_encode($catAgg),$aid]);
|
||||
echo " assessment + id=$aid ($cnt risposte, score $overall%)\n";
|
||||
} else echo " assessment = (gia presente o questionario assente)\n";
|
||||
|
||||
echo "\nFASE 2 OK\n";
|
||||
Reference in New Issue
Block a user