nis2-agile/docs/integration/lg231-nis2-integration.md
DevEnv nis2-agile 5ecdce7d47 [INTEG] Pagina integrazioni esterne + spec lg231↔NIS2
- public/integrazioniext.html: pagina pubblica con 4 tab (Services API,
  Guida lg231, Webhook, Quick Start) — link in sidebar
- docs/integration/lg231-nis2-integration.md: spec tecnica completa
  per agente Claude lg231 (provider-config, Nis2Client, widget, escalation OdV)
- common.js: voce sidebar → integrazioniext.html

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 14:43:59 +01:00

11 KiB

Integrazione lg231 Agile ↔ NIS2 Agile

Documento per l'agente Claude di lg231. Leggi questo file prima di implementare qualsiasi integrazione con NIS2 Agile.


Perché integrare

lg231 gestisce compliance D.Lgs. 231/2001 (reati societari, OdV, MOG). NIS2 Agile gestisce compliance Direttiva NIS2 (cybersecurity, incidenti, rischi IT).

I due mondi si sovrappongono su tre punti critici:

Evento NIS2 Rilevanza 231
Incidente cybersecurity (Art.23 NIS2) Reato presupposto 231 art.24-bis (criminalità informatica)
Fornitore IT ad alto rischio Rischio 231: complicità in reati informatici via supply chain
Policy sicurezza non approvata Gap nel MOG (Modello Organizzativo e di Gestione)
Score compliance NIS2 basso Indicatore per l'OdV di carenza nei controlli
Whistleblowing sicurezza Potenziale escalation verso OdV 231

Architettura dell'integrazione

lg231 Agile                         NIS2 Agile
────────────────────────────        ────────────────────────────
company-ms                          ServicesController.php
  companies.metadata JSON    ───►   /api/services/*  (REST, X-API-Key)
  + nis2_api_key                    /api/webhooks/*  (webhook outbound)
  + nis2_org_id             ◄───    WebhookController.php
  + nis2_enabled (bool)             webhook → POST lg231-endpoint

Cosa fa lg231 (lato mittente/ricevente)

1. Aggiungere NIS2 al provider-config (company-ms)

File: services/company-ms/public/index.php

Nel metodo PATCH /companies/{id}/provider-config, aggiungere ai $allowed:

$allowed = [
    'certisource_pat',
    'certisource_pat_expires_at',
    'anthropic_api_key',
    'openai_api_key',
    // ── Nuovo provider NIS2 ──
    'nis2_api_key',     // chiave API generata in NIS2 Agile → Settings → API Keys
    'nis2_org_id',      // ID organizzazione NIS2 (intero, visibile in NIS2 dashboard URL)
    'nis2_enabled',     // bool: abilitare pull automatico dati NIS2
];

Nel metodo GET /companies/{id}/provider-config, aggiungere alla response:

$nis2Key     = $meta['nis2_api_key'] ?? null;
$nis2OrgId   = $meta['nis2_org_id'] ?? null;
$nis2Enabled = (bool) ($meta['nis2_enabled'] ?? false);

// nella response array:
'nis2_configured' => !empty($nis2Key) && !empty($nis2OrgId),
'nis2_api_key'    => $nis2Key,          // uso interno microservizi
'nis2_org_id'     => $nis2OrgId,
'nis2_enabled'    => $nis2Enabled,
'nis2_key_hint'   => !empty($nis2Key) ? 'nis2_...' . substr($nis2Key, -4) : null,

2. Nuovo servizio NIS2Client (shared-lib o risk-ms)

Creare shared/nis2-lib/src/Nis2Client.php:

class Nis2Client
{
    const BASE_URL = 'https://nis2.agile.software/api/services';

    public static function get(
        string $endpoint,
        string $apiKey,
        array  $query = [],
        int    $timeout = 10
    ): array {
        $url = self::BASE_URL . $endpoint;
        if ($query) $url .= '?' . http_build_query($query);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => $timeout,
            CURLOPT_HTTPHEADER     => [
                'X-API-Key: ' . $apiKey,
                'Accept: application/json',
                'X-Caller: lg231-agile/1.0',
            ],
        ]);
        $body = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($code !== 200 || !$body) {
            return ['success' => false, 'http_code' => $code, 'data' => null];
        }

        $decoded = json_decode($body, true);
        return ['success' => true, 'http_code' => 200, 'data' => $decoded];
    }
}

API NIS2 disponibili

Base URL: https://nis2.agile.software/api/services Auth: Header X-API-Key: {nis2_api_key} (la chiave è legata a una singola org NIS2)

Endpoint GET disponibili

Endpoint Scope richiesto Cosa restituisce
/status — (no auth) Stato piattaforma, versione
/compliance-summary read:compliance Score NIS2 (0-100) per dominio Art.21, rischi aperti, incidenti
/risks/feed read:risks Lista rischi: id, title, level (low/medium/high/critical), status, area
/incidents/feed read:incidents Incidenti: id, title, severity, status, notified_csirt, deadline_72h
/controls/status read:compliance Stato controlli Art.21 per dominio (implemented/partial/missing)
/assets/critical read:assets Asset critici con tipo, criticità, dipendenze
/suppliers/risk read:suppliers Fornitori: nome, risk_level, ultimo_assessment, is_flagged
/policies/approved read:policies Policy approvate: titolo, area, data approvazione, versione

Header risposta sempre presenti:

  • X-NIS2-API-Version: 1.0
  • X-NIS2-Org-Id: {org_id}
  • X-RateLimit-Limit: 100
  • X-RateLimit-Remaining: N

Rate limit: 100 req/ora per API key.

Esempio risposta /compliance-summary

{
  "success": true,
  "data": {
    "organization": {
      "id": 5,
      "name": "Azienda XYZ S.r.l.",
      "sector": "energia",
      "nis2_entity_type": "essential"
    },
    "compliance": {
      "overall_score": 73,
      "label": "Parziale",
      "assessment_date": "2026-03-07T10:00:00+01:00",
      "domain_scores": [
        { "domain": "Gestione del rischio", "score": 80, "status": "compliant" },
        { "domain": "Sicurezza supply chain", "score": 45, "status": "partial" },
        { "domain": "Gestione incidenti", "score": 90, "status": "compliant" }
      ]
    },
    "risks": {
      "total": 12, "open": 8, "high_critical": 3, "mitigated": 4
    },
    "incidents": {
      "total": 2, "open": 1, "significant": 1, "overdue": 0
    },
    "generated_at": "2026-03-07T13:30:00+01:00"
  }
}

Esempio risposta /incidents/feed

{
  "success": true,
  "data": {
    "incidents": [
      {
        "id": 3,
        "title": "Ransomware server produzione",
        "severity": "critical",
        "status": "open",
        "is_significant": true,
        "notified_csirt": true,
        "deadline_72h": "2026-03-09T08:00:00+01:00",
        "overdue": false,
        "created_at": "2026-03-07T08:00:00+01:00"
      }
    ],
    "total": 1,
    "filters_applied": {}
  }
}

Come creare una API Key in NIS2

  1. Login su https://nis2.agile.software con l'account dell'azienda
  2. Vai su Settings → API Keys
  3. Click "Nuova API Key" → nome: "lg231 Integration" → scope: read:all
  4. Copia la chiave (mostrata una sola volta, formato: nis2_XXXX...)
  5. In lg231: PATCH /companies/{id}/provider-config con { "nis2_api_key": "nis2_...", "nis2_org_id": 5 }

Cosa mostrare in lg231

Widget "Cybersecurity NIS2" nella company view

Chiamare GET /compliance-summary e mostrare:

  • Gauge score 0-100 con colori (verde ≥70, arancione 40-69, rosso <40)
  • Badge "Essential" / "Important" / "Volontario"
  • Numero rischi high/critical aperti
  • Numero incidenti aperti (con alert se overdue: true)
  • Link "Apri NIS2 Agile" → https://nis2.agile.software/dashboard.html

Integrazione Risk Register (risk-ms)

Quando lg231 crea un'analisi dei rischi per l'azienda, importare i rischi cyber NIS2:

// Nel risk-ms, durante la creazione di un nuovo risk assessment:
$nis2Risks = Nis2Client::get('/risks/feed', $apiKey, ['level' => 'high,critical']);
foreach (($nis2Risks['data']['risks'] ?? []) as $r) {
    // Suggerisci all'utente di includerlo nel registro 231
    // Tipo: "Rischio cyber (da NIS2 Agile): " . $r['title']
    // Categoria 231: art.24-bis (criminalità informatica)
}

Escalation Incidente → OdV (monitoring-ms)

Quando NIS2 segnala un incidente significativo (is_significant: true), creare attività OdV:

$incidents = Nis2Client::get('/incidents/feed', $apiKey, ['significant' => 1, 'status' => 'open']);
foreach (($incidents['data']['incidents'] ?? []) as $inc) {
    // Crea odv_activity in monitoring-ms:
    // type: 'cyber_incident_notifica'
    // description: 'Incidente NIS2 significativo: ' . $inc['title']
    // priority: 'high'
    // source: 'nis2_agile'
    // reference_id: $inc['id']
}

Webhook NIS2 → lg231 (facoltativo, avanzato)

NIS2 può inviare notifiche push su eventi. lg231 deve esporre un endpoint ricevente.

Endpoint lg231 da creare: POST /api/integrations/nis2-webhook Firma: header X-NIS2-Signature: sha256=HMAC_HEX

Verificare la firma:

$secret    = $company['metadata']['nis2_webhook_secret'];
$body      = file_get_contents('php://input');
$expected  = 'sha256=' . hash_hmac('sha256', $body, $secret);
$received  = $_SERVER['HTTP_X_NIS2_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) { return 401; }

Eventi ricevuti:

  • incident.created → crea alert in monitoring-ms
  • incident.deadline_warning → notifica urgente OdV
  • risk.created_high → aggiunge al risk register 231
  • compliance.score_changed → aggiorna widget score
  • supplier.risk_flagged → flagga fornitore in supply chain 231

Registrare la subscription in NIS2:

POST https://nis2.agile.software/api/webhooks/subscriptions
Authorization: Bearer {jwt}
{
  "url": "https://lg231.agile.software/api/integrations/nis2-webhook",
  "events": ["incident.created", "incident.deadline_warning", "risk.created_high"],
  "description": "lg231 Agile integration"
}

Risposta: { "secret": "whsec_...", "id": 1 } → salvare secret in companies.metadata.nis2_webhook_secret


Compatibilità tenant

NIS2 usa organization_id (singolo DB). lg231 usa company_id + tenant_id (multi-tenant).

La chiave API NIS2 è già legata a una specifica organizzazione: non serve passare org_id negli header. Salvare nis2_org_id in lg231 è opzionale (solo per riferimento UI).


Checklist implementazione lg231

  • company-ms: aggiungere nis2_api_key, nis2_org_id, nis2_enabled a provider-config
  • shared/nis2-lib/src/Nis2Client.php: client HTTP leggero
  • Widget NIS2 nella company detail view (HTML + JS)
  • risk-ms: import rischi cyber durante assessment
  • monitoring-ms: escalation incidenti significativi → OdV activity
  • (opzionale) endpoint webhook ricevente + subscription NIS2
  • Test: GET /api/services/status deve rispondere 200 senza auth

Note tecniche NIS2

  • Modello: PHP 8.4, Front Controller, no framework
  • Auth: API Key sha256-hashed in DB (api_keys table)
  • Scopes: read:all, read:compliance, read:risks, read:incidents, read:assets, read:policies
  • Tabella: api_keys (id, organization_id, name, key_prefix, key_hash, scopes JSON, is_active, expires_at, last_used_at)
  • Rate limit: 100 req/h per chiave, file-based in /tmp/nis2_ratelimit/
  • CORS: origine specifica (no wildcard) — lg231 deve fare chiamate server-to-server, NON da browser

Generato: 2026-03-07 | NIS2 Agile v1.0 | Contatto: cristiano.benassati@gmail.com