Files
netconfig/MEMORY.md
T
2026-05-22 13:55:01 +02:00

315 lines
12 KiB
Markdown

---
# 🧠 MEMORY.md
```markdown
# 🧠 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:
1. Salvare configurazioni di apparati di rete (es. switch) nel database MySQL
2. Tenere traccia delle variazioni della configurazione (versioning)
3. Implementare massive actions (azioni di massa)
4. Gestire i profili come già integrato in GLPI (ACL native)
5. Permettere l'esportazione in file di testo del contenuto salvato (solo per utenti con diritti)
6. Lanciare il comando per recuperare la configurazione dall'apparato di rete
7. Valutare l'utilizzo di un agent GLPI remoto per eseguire il recupero configurazione
8. 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_content` cifrato con `Glpi\Toolbox\Encryption::encrypt()`
- **Chiave**: Derivata da `crypt_key` in `GLPI_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
```php
// Pattern confermato per tutti i metodi sensibili
if (!\PluginNetconfig\Config::canView()) {
http_response_code(403);
exit('Access denied');
}
```
### Redaction Export
```php
// 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)
```php
// 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
1. **Installazione plugin**: Verificare creazione tabella e registrazione hook
2. **Diritti profilo**: Assegnare READ a utente test, verificare accesso a tab Config History
3. **Agent simulation**: Invio JSON via curl, verificare risposta e record in DB
4. **Export flow**: Login utente con diritti, click export, verificare download e redaction
5. **Diff visual**: Salvare due versioni diverse, verificare rendering HTML differenze
### Test di Sicurezza
```bash
# 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)
```json
{
"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
```txt
# 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
```bash
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)
```mermaid
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)
```mermaid
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)
```mermaid
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
1. **Composer in ambienti non-standard**: Il warning `installed.json not found` è innocuo se `composer install` completa con successo. Non bloccare l'installazione per questo.
2. **Hash vs Timestamp per versioning**: Confrontare hash SHA256 è più affidabile dei timestamp (orologi non sincronizzati, config identiche con timestamp diversi).
3. **Cifratura nativa GLPI**: Usare `Glpi\Toolbox\Encryption` evita di gestire chiavi separatamente e garantisce compatibilità con backup/restore GLPI.
4. **Diff on-demand**: Calcolare il diff solo per l'ultima configurazione (non per tutto lo storico) migliora le performance con config grandi.
5. **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 `|escape('js')` in Twig |
| 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)](https://git.azienda.it/glpi-plugins/netconfig)
- [Documentazione GLPI 11 Developer](https://glpi-developer-documentation.readthedocs.io/en/11.0/)
- [Netmiko Platform Support](https://github.com/ktbyers/netmiko/blob/develop/PLATFORMS.md)
- [GLPI API Postman Collection](https://github.com/glpi-project/glpi/blob/11.0/apirest.md)
- [Checklist Sicurezza Plugin GLPI](https://github.com/glpi-project/glpi/blob/11.0/DEV/SECURITY.md)
---
> 📌 **Nota Operativa**: Questo documento va aggiornato ad ogni modifica architetturale significativa.
> **Ultima revisione**: 2026-05-22 | **Prossima review pianificata**: 2026-08-22
```
---