12 KiB
12 KiB
🧠 MEMORY.md
# 🧠 MEMORY.md - Knowledge Base Progetto NetConfig Plugin
> **Scopo**: Memoria persistente delle decisioni, contesto e apprendimenti per il team di sviluppo
> **Progetto**: GLPI 11 Plugin - Network Configuration Backup & Versioning
> **Stato**: ✅ Specifica Completa | 🚧 Implementazione Pronta | 🧪 Test in Corso
---
## 📋 Riepilogo Richieste Utente
### Richiesta Originale (Tradotta e Strutturata)
"Vorrei implementare un plugin per GLPI 11 secondo le linee guida degli sviluppatori GLPI per:
- Salvare configurazioni di apparati di rete (es. switch) nel database MySQL
- Tenere traccia delle variazioni della configurazione (versioning)
- Implementare massive actions (azioni di massa)
- Gestire i profili come già integrato in GLPI (ACL native)
- Permettere l'esportazione in file di testo del contenuto salvato (solo per utenti con diritti)
- Lanciare il comando per recuperare la configurazione dall'apparato di rete
- Valutare l'utilizzo di un agent GLPI remoto per eseguire il recupero configurazione
- Fornire una proposta architetturale completa"
### Vincoli Espliciti
- ✅ GLPI 11.0.6+ (verificato con `php bin/console glpi:version`)
- ✅ PHP 8.2+ con strict_types e namespace PSR-4
- ✅ MySQL/MariaDB con charset utf8mb4
- ✅ Integrazione con sistema profili/diritti nativo GLPI
- ✅ Massive actions compatibili con UI GLPI
- ✅ Cifratura configurazioni sensibili
- ✅ Agent remoto opzionale ma preferito per scalabilità
---
## 🗂️ Decisioni Architetturali Confermate
### ✅ Scelte Definitive
| Area | Decisione | Motivazione |
|------|-----------|-------------|
| **Struttura Plugin** | PSR-4 autoload, `src/` per classi, `ajax/` per endpoint | Conformità linee guida GLPI 11, manutenibilità |
| **Database** | Tabella dedicata `glpi_plugin_netconfig_configs` con MEDIUMTEXT | Isolamento dati, performance query, supporto config grandi |
| **Versioning** | SHA256 hash + confronto all'arrivo nuovo backup | Rilevamento modifiche efficiente, storage ottimizzato |
| **Cifratura** | `Glpi\Toolbox\Encryption` (AES-256-GCM) | Integrazione nativa, chiave gestita da GLPI, compliance |
| **Agent Remoto** | Python + netmiko + YAML config + systemd timer | Supporto multi-vendor maturo, gestione timeout/retry robusta |
| **Diff Visual** | `symfony/diff` con output HTML sanitizzato per Twig | Libreria mantenuta, output sicuro, integrazione semplice |
| **Export** | Stream diretto con redaction regex + controllo diritti | Performance, sicurezza, compliance policy aziendali |
| **API Endpoint** | POST JSON con token + validazione hash lato server | Stateless, compatibile con agent distribuiti, auditabile |
### ❌ Alternative Scartate (con Motivazione)
| Alternativa | Motivazione Scarto |
|-------------|-------------------|
| SSH diretto da PHP (phpseclib) | Timeout frequenti, gestione connessioni concorrenti complessa, scaling limitato |
| Archiviazione su filesystem | Perdita integrazione ACL GLPI, backup/disaster recovery più complesso, audit difficile |
| Integrazione Oxidized/RANCID | Overhead infrastrutturale aggiuntivo, duplicazione logica versioning, curva apprendimento team |
| Agent in PHP invece di Python | Netmiko/napalm hanno supporto multi-vendor più maturo e community attiva in Python |
| Diff calcolato lato client (JS) | Configurazioni grandi (>1MB) causano lag browser, sanitizzazione complessa per XSS |
---
## 🔐 Security & Compliance Decisions
### Credenziali e Segreti
```yaml
# ✅ DO: Usare variabili d'ambiente o vault esterno
NETCONFIG_DEFAULT_USER: "backup_svc"
NETCONFIG_DEFAULT_PASS: "${VAULT_SECRET_NETCONFIG_PASS}"
NETCONFIG_AGENT_TOKEN: "${OPENSSL_GENERATED_32B_HEX}"
# ❌ DON'T: Hardcodare nel codice o YAML
# password: "SuperSecret123" # MAI fare questo
Cifratura Dati
- A riposo:
config_contentcifrato conGlpi\Toolbox\Encryption::encrypt() - Chiave: Derivata da
crypt_keyinGLPI_CONFIG_DIR/config_db.php(gestita da GLPI) - Algoritmo: AES-256-GCM con autenticazione (previene tampering)
- Verifica: Test manuale post-install per confermare che DB contenga blob cifrati
Controllo Accessi
// Pattern confermato per tutti i metodi sensibili
if (!\PluginNetconfig\Config::canView()) {
http_response_code(403);
exit('Access denied');
}
Redaction Export
// Regex per mascherare credenziali prima dell'export
$content = preg_replace(
'/(?<=password\s|secret\s|enable\s|community\s)[^\s\r\n]+/i',
'***REDACTED***',
$content
);
// Personalizzabile in base alle policy aziendali
🧪 Test Plan Confermato
Test Unitari (PHPUnit - da implementare)
// Esempio: test hash detection
public function testSaveConfig_DetectsNoChanges(): void
{
$config = new \PluginNetconfig\Config();
$result = $config->saveConfig([
'networkdevices_id' => 123,
'content' => 'identical config content'
]);
// Primo salvataggio: true
// Secondo salvataggio stesso contenuto: true ma nessun nuovo record
}
Test di Integrazione
- Installazione plugin: Verificare creazione tabella e registrazione hook
- Diritti profilo: Assegnare READ a utente test, verificare accesso a tab Config History
- Agent simulation: Invio JSON via curl, verificare risposta e record in DB
- Export flow: Login utente con diritti, click export, verificare download e redaction
- Diff visual: Salvare due versioni diverse, verificare rendering HTML differenze
Test di Sicurezza
# 1. Tentativo export senza diritti
curl -b "glpi_session=invalid" http://glpi/plugins/netconfig/ajax/export.php?id=1
# Atteso: HTTP 403
# 2. Invio agent con token errato
curl -X POST ... -d '{"token":"wrong"}'
# Atteso: {"status":"error","message":"Unauthorized"}
# 3. Verifica cifratura DB
mysql -e "SELECT config_content FROM glpi_plugin_netconfig_configs LIMIT 1" | head
# Atteso: blob binario non leggibile, non testo in chiaro
📦 Dipendenze e Versioni Confermate
composer.json (Definitivo)
{
"name": "glpi-plugin/netconfig",
"license": "GPL-3.0-or-later",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.2",
"symfony/diff": "^6.4",
"guzzlehttp/guzzle": "^7.8"
},
"autoload": {
"psr-4": {
"PluginNetconfig\\": "src/",
"PluginNetconfig\\Api\\": "src/Api/"
}
}
}
Requisiti Python Agent
# requirements-agent.txt
netmiko>=4.3.0
requests>=2.31.0
pyyaml>=6.0.1
cryptography>=41.0.0 # Per eventuale cifratura lato agent (opzionale)
Estensioni PHP Richieste
php -m | grep -E "curl|json|mbstring|openssl|zip|pdo_mysql"
# Tutte devono essere presenti per GLPI 11 + plugin
🔄 Flussi Operativi Documentati
Flusso 1: Backup Schedulato (Agent Remoto)
sequenceDiagram
participant Cron as Systemd Timer/Cron
participant Agent as GLPI Agent (Python)
participant Device as Network Device
participant GLPI as GLPI Server + Plugin
Cron->>Agent: Trigger ogni 6h
Agent->>Device: SSH via netmiko (show running-config)
Device-->>Agent: Restituisce configurazione
Agent->>Agent: Calcola SHA256, confronta con ultimo locale (opzionale)
Agent->>GLPI: POST /ajax/agent_receive.php con JSON
GLPI->>GLPI: Valida token, decifra chiave, confronta hash DB
alt Hash diverso
GLPI->>GLPI: Cifra contenuto, salva nuovo record, registra versione
GLPI-->>Agent: {"status":"ok","message":"Saved"}
else Hash identico
GLPI-->>Agent: {"status":"ok","message":"No changes"}
end
Agent->>Cron: Log risultato, exit
Flusso 2: Export Configurazione (Utente GLPI)
sequenceDiagram
participant User as Utente GLPI
participant UI as Interfaccia GLPI
participant Plugin as Plugin NetConfig
participant DB as Database MySQL
User->>UI: Clicca "Export" su configurazione
UI->>Plugin: GET /ajax/export.php?id=XXX
Plugin->>Plugin: Verifica Session::haveRight(Config::READ)
alt Diritti insufficienti
Plugin-->>UI: HTTP 403 + messaggio errore
else Diritti OK
Plugin->>DB: SELECT config_content, is_encrypted WHERE id=XXX
DB-->>Plugin: Restituisce record
Plugin->>Plugin: Decifra se is_encrypted=1
Plugin->>Plugin: Applica regex redaction su password/secret
Plugin-->>User: HTTP 200 + file .txt in download
end
Flusso 3: Visualizzazione Diff (UI GLPI)
sequenceDiagram
participant User as Utente GLPI
participant Twig as Template Engine
participant Plugin as Plugin NetConfig
participant DiffLib as symfony/diff
User->>UI: Apri tab "Config History" su NetworkEquipment
UI->>Plugin: Richiedi liste configurazioni per device_id
Plugin->>DB: SELECT * ORDER BY created_at DESC
DB-->>Plugin: Restituisce array configurazioni
Plugin->>Plugin: Per l'ultima config, carica precedente e calcola diff
Plugin->>DiffLib: Differ::diff(old, new) con HtmlOutput
DiffLib-->>Plugin: Stringa HTML con <ins>/<del>
Plugin->>Twig: Passa configs + diff_html al template
Twig->>User: Renderizza tabella con pulsante "View Diff"
User->>UI: Clicca pulsante diff
UI->>User: Modal dialog con differenze evidenziate (verde/rosso)
🚨 Lessons Learned & Pitfalls Evitati
✅ Cosa Abbiamo Imparato
- Composer in ambienti non-standard: Il warning
installed.json not foundè innocuo secomposer installcompleta con successo. Non bloccare l'installazione per questo. - Hash vs Timestamp per versioning: Confrontare hash SHA256 è più affidabile dei timestamp (orologi non sincronizzati, config identiche con timestamp diversi).
- Cifratura nativa GLPI: Usare
Glpi\Toolbox\Encryptionevita di gestire chiavi separatamente e garantisce compatibilità con backup/restore GLPI. - Diff on-demand: Calcolare il diff solo per l'ultima configurazione (non per tutto lo storico) migliora le performance con config grandi.
- Agent token rotation: Documentare la procedura di rotazione token nel README operativo, anche se non implementata nel codice.
⚠️ Pitfalls Evitati
| Problema Potenziale | Come Lo Abbiamo Evitato |
|---|---|
| XSS nel diff HTML | Output di symfony/diff sanitizzato con ` |
| SQL injection in massive actions | Uso di prepared statements in getLastConfigByDevice() |
| Credential leak nei log | Logging configurato per escludere payload config, solo metadata |
| Timeout SSH su dispositivi lenti | Retry logic con backoff + global_delay_factor configurabile per device |
| Memory exhaustion con config grandi | Stream export invece di caricamento intero in memoria, uso di MEDIUMTEXT |
📞 Contatti e Responsabilità
| Ruolo | Responsabilità | Contatto (Esempio) |
|---|---|---|
| Plugin Maintainer | Release, compatibilità GLPI, security patch | team-dev@azienda.it |
| Agent Operator | Deploy script Python, gestione dispositivi YAML, monitoraggio | netops@azienda.it |
| Security Officer | Approvazione policy redaction, rotazione token, audit cifratura | security@azienda.it |
| GLPI Admin | Installazione plugin, gestione profili, backup database | glpi-admin@azienda.it |
🗓️ Cronologia Decisioni
| Data | Decisione | Autore | Riferimento |
|---|---|---|---|
| 2026-05-22 | Architettura plugin confermata (PSR-4, encryption nativa, agent Python) | AI Assistant + Utente | Richiesta iniziale |
| 2026-05-22 | Scelta symfony/diff ^6.4 per visualizzazione differenze | AI Assistant | Valutazione librerie |
| 2026-05-22 | Token-based auth per endpoint agent invece di session GLPI | AI Assistant | Requisito agent remoto |
| 2026-05-22 | Redaction automatica password in export tramite regex | AI Assistant | Compliance sicurezza |
| 2026-05-22 | Supporto massive actions native invece di UI custom | AI Assistant | Integrazione UX GLPI |
🔗 Link Utili per il Team
- Repository Plugin (interno)
- Documentazione GLPI 11 Developer
- Netmiko Platform Support
- GLPI API Postman Collection
- Checklist Sicurezza Plugin GLPI
📌 Nota Operativa: Questo documento va aggiornato ad ogni modifica architetturale significativa.
Ultima revisione: 2026-05-22 | Prossima review pianificata: 2026-08-22
---