change before saturday
This commit is contained in:
@@ -0,0 +1,98 @@
|
|||||||
|
Ecco una proposta architetturale e implementativa per un plugin GLPI 11 dedicato al backup e versioning delle configurazioni di rete, strutturata secondo le linee guida ufficiali degli sviluppatori GLPI (PHP 8.2+, namespace PSR-4, Twig 3, API REST, hook moderni).
|
||||||
|
🧱 1. Architettura del Plugin
|
||||||
|
12345678910111213141516171819
|
||||||
|
🗄️ 2. Schema Database (MySQL/MariaDB)
|
||||||
|
GLPI 11 usa InnoDB con charset utf8mb4. Il plugin creerà:
|
||||||
|
sql
|
||||||
|
12345678910111213
|
||||||
|
networkdevices_id punta a glpi_networkdevices
|
||||||
|
is_encrypted indica se il contenuto è cifrato con Glpi\Toolbox\Encryption
|
||||||
|
Il versioning si ottiene confrontando config_hash all'arrivo di un nuovo backup
|
||||||
|
🔐 3. Gestione Profili e Diritti (GLPI Native)
|
||||||
|
Il plugin si integra con il sistema dei profili di GLPI senza reinventare l'ACL.
|
||||||
|
src/Config.php
|
||||||
|
php
|
||||||
|
123456789101112131415161718192021
|
||||||
|
setup.php
|
||||||
|
php
|
||||||
|
1234567891011
|
||||||
|
I diritti vengono esposti automaticamente in Amministrazione > Profili.
|
||||||
|
⚡ 4. Massive Actions
|
||||||
|
GLPI 11 supporta le massive actions tramite hook e metodi nativi.
|
||||||
|
hook.php
|
||||||
|
php
|
||||||
|
123456789
|
||||||
|
Nella classe Config:
|
||||||
|
php
|
||||||
|
1234567891011121314151617181920
|
||||||
|
🌐 5. Recupero Configurazione: Agent GLPI vs Alternative
|
||||||
|
✅ Opzione Richiesta: GLPI Agent Remoto
|
||||||
|
GLPI Agent (ex FusionInventory) supporta task personalizzate in Python/Perl.
|
||||||
|
Flusso consigliato:
|
||||||
|
Il plugin espone un endpoint API: POST /api.php/plugin/netconfig/receive
|
||||||
|
L'agent esegue un task netconfig_backup (Python con netmiko/napalm o expect)
|
||||||
|
L'agent invia JSON: {"device_id": 12, "config": "...", "checksum": "sha256..."}
|
||||||
|
GLPI valida, confronta hash, cifra se necessario, salva e registra versione
|
||||||
|
Endpoint API (src/Agent/Task/Backup.php)
|
||||||
|
php
|
||||||
|
123456789101112131415161718192021222324252627282930
|
||||||
|
⚠️ Considerazioni Critiche sull'Agent
|
||||||
|
GLPI Agent non è nativamente progettato per backup di rete. Richiede sviluppo di un modulo custom (Python) con gestione timeout, fallback, credential secure (vault/keystore).
|
||||||
|
Alternative più solide in produzione:
|
||||||
|
Oxidized + webhook verso GLPI API
|
||||||
|
RANCID/Unconfigured + cron + import CSV/API
|
||||||
|
GLPI + phpseclib3 (SSH diretto, ma sconsigliato per scaling/sicurezza)
|
||||||
|
💡 Raccomandazione: Usa l'agent per trigger e orchestrazione, ma delega il retrieval a netmiko/napalm in esecuzione sull'agent stesso. Mantieni le credenziali nel sistema di secrets dell'agent o in GLPI cifrate.
|
||||||
|
📜 6. Tracciamento Variazioni e Diff
|
||||||
|
Ogni backup viene hashato (SHA256)
|
||||||
|
Se l'hash differisce dall'ultimo, si crea nuova riga
|
||||||
|
Per visualizzare il diff: usa symfony/diff o myclabs/php-diff
|
||||||
|
Esempio integrazione Twig:
|
||||||
|
twig
|
||||||
|
12345
|
||||||
|
Nel controller:
|
||||||
|
php
|
||||||
|
12345
|
||||||
|
📥 7. Esportazione Sicura
|
||||||
|
Verifica diritti: Session::haveRight(Config::class, READ)
|
||||||
|
Stream diretto con header corretti
|
||||||
|
Rimuovi/cripta password sensibili prima dell'export (opzionale ma consigliato)
|
||||||
|
ajax/export.php
|
||||||
|
php
|
||||||
|
1234567891011121314
|
||||||
|
🛣️ 8. Roadmap di Sviluppo
|
||||||
|
Fase
|
||||||
|
Attività
|
||||||
|
Tempo Stimato
|
||||||
|
1
|
||||||
|
Scaffold plugin, setup/hook, schema DB, migration
|
||||||
|
2 gg
|
||||||
|
2
|
||||||
|
CRUD Config, integrazione menu, template Twig
|
||||||
|
3 gg
|
||||||
|
3
|
||||||
|
Diritti profili, massive actions, API endpoint
|
||||||
|
2 gg
|
||||||
|
4
|
||||||
|
Logica hash, versioning, diff HTML
|
||||||
|
2 gg
|
||||||
|
5
|
||||||
|
Export sicuro, cifratura, test unitari
|
||||||
|
2 gg
|
||||||
|
6
|
||||||
|
Modulo Agent GLPI (Python) o integrazione Oxidized
|
||||||
|
3-5 gg
|
||||||
|
7
|
||||||
|
Documentazione, package, test GLPI 11 QA
|
||||||
|
2 gg
|
||||||
|
⚠️ Note Critiche per GLPI 11
|
||||||
|
Namespace PSR-4 obbligatorio: PluginNetconfig\ mappato su src/
|
||||||
|
Cifratura: Usa Glpi\Toolbox\Encryption (AES-256-GCM) con chiave in GLPI_CONFIG_DIR/config_db.php o variabile d'ambiente
|
||||||
|
API REST: GLPI 11 richiede dichiarazione esplicita degli endpoint plugin via add_api_endpoint o routing custom
|
||||||
|
Performance: Configurazioni switch/router possono superare 500KB. Usa MEDIUMTEXT e indicizza per ricerca
|
||||||
|
Sicurezza: Non esporre endpoint /ajax/retrieve.php senza CSRF+token. Preferisci l'agent o l'API con autenticazione app token
|
||||||
|
Compatibilità: Dichiara in setup.php: $PLUGIN_HOOKS['compatible']['netconfig'] = ['glpi' => '>=11.0'];
|
||||||
|
📦 Dipendenze Composer Consigliate
|
||||||
|
json
|
||||||
|
123456789101112
|
||||||
|
|
||||||
@@ -0,0 +1,625 @@
|
|||||||
|
# 🤖 AGENTS.md
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# 🤖 AGENTS.md - Network Config Backup Plugin for GLPI 11
|
||||||
|
|
||||||
|
> **Documento di contesto per AI Agent / Assistente di sviluppo**
|
||||||
|
> **Progetto**: `glpi-plugin-netconfig`
|
||||||
|
> **Ultimo aggiornamento**: 2026-05-22
|
||||||
|
> **GLPI Target**: 11.0.6+ | **PHP**: 8.2+ | **Database**: MySQL/MariaDB
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Obiettivo del Progetto
|
||||||
|
|
||||||
|
Sviluppare un plugin GLPI 11 che permetta di:
|
||||||
|
1. **Salvare configurazioni** di apparati di rete (switch, router, firewall) nel database MySQL di GLPI
|
||||||
|
2. **Tracciare le variazioni** delle configurazioni nel tempo (versioning con hash SHA256)
|
||||||
|
3. **Visualizzare differenze** (diff) tra versioni successive
|
||||||
|
4. **Esportare configurazioni** in file di testo (con controllo diritti e redaction credenziali)
|
||||||
|
5. **Lanciare il recupero configurazioni** tramite massive actions o trigger manuali
|
||||||
|
6. **Integrare GLPI Agent remoto** per l'esecuzione distribuita del backup via SSH (netmiko/napalm)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Contesto Tecnico Chiave
|
||||||
|
|
||||||
|
### Stack Tecnologico
|
||||||
|
| Componente | Versione/Nota |
|
||||||
|
|------------|--------------|
|
||||||
|
| GLPI | 11.0.6+ (CLI: `php bin/console glpi:version`) |
|
||||||
|
| PHP | 8.2+ con strict_types, namespace PSR-4 |
|
||||||
|
| Database | MySQL/MariaDB, InnoDB, utf8mb4_unicode_ci |
|
||||||
|
| Composer | 2.7.1+ (cache Packagist OK) |
|
||||||
|
| Template Engine | Twig 3 (nativo in GLPI 11) |
|
||||||
|
| Crittografia | `Glpi\Toolbox\Encryption` (AES-256-GCM) |
|
||||||
|
| Diff Engine | `symfony/diff` ^6.4 |
|
||||||
|
| HTTP Client | `guzzlehttp/guzzle` ^7.8 (opzionale per agent PHP) |
|
||||||
|
| Agent Script | Python 3 + netmiko + requests + pyyaml |
|
||||||
|
|
||||||
|
### Architettura Plugin
|
||||||
|
```
|
||||||
|
plugins/netconfig/
|
||||||
|
├── setup.php # Hook init, versioning, diritti
|
||||||
|
├── hook.php # Install/uninstall DB
|
||||||
|
├── composer.json # Dipendenze + autoload PSR-4
|
||||||
|
├── install/mysql/install.sql # Schema tabella configs
|
||||||
|
├── src/
|
||||||
|
│ ├── Config.php # CommonDBTM: CRUD, massive actions, diff
|
||||||
|
│ ├── Agent/Receive.php # Endpoint API per agent
|
||||||
|
│ └── Api/GlpiApiClient.php # Client REST API GLPI (opzionale)
|
||||||
|
├── ajax/
|
||||||
|
│ ├── export.php # Download sicuro configurazioni
|
||||||
|
│ └── agent_receive.php # Fallback endpoint agent
|
||||||
|
├── templates/config_tab.html.twig # Vista tab GLPI con storico
|
||||||
|
└── locales/ # Traduzioni it_IT/en_GB
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flusso Dati Principale
|
||||||
|
```
|
||||||
|
[Apparato di Rete]
|
||||||
|
│
|
||||||
|
▼ (SSH via netmiko)
|
||||||
|
[GLPI Agent Python] ──(POST JSON)──► [Plugin Endpoint]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Validazione Token + Hash]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Cifratura + Salvataggio DB]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Notifica UI GLPI + Diff]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔑 Decisioni Architetturali Critiche
|
||||||
|
|
||||||
|
### ✅ Scelte Confermate
|
||||||
|
1. **Namespace PSR-4**: `PluginNetconfig\` mappato su `src/` (obbligatorio GLPI 11)
|
||||||
|
2. **Cifratura nativa**: Uso di `Glpi\Toolbox\Encryption` invece di soluzioni custom
|
||||||
|
3. **Versioning via hash**: SHA256 su contenuto config per rilevamento modifiche
|
||||||
|
4. **Massive actions native**: Integrazione con sistema GLPI invece di UI custom
|
||||||
|
5. **Agent remoto Python**: Netmiko per compatibilità multi-vendor (Cisco, HP, Juniper, etc.)
|
||||||
|
6. **Token-based auth**: `NETCONFIG_AGENT_TOKEN` per validazione richieste agent
|
||||||
|
7. **Diff lato server**: `symfony/diff` con output HTML sanitizzato per Twig
|
||||||
|
8. **Export con redaction**: Regex per mascherare password/secret prima del download
|
||||||
|
|
||||||
|
### ⚠️ Alternative Valutate e Scartate
|
||||||
|
| Alternativa | Motivo Scarto |
|
||||||
|
|-------------|--------------|
|
||||||
|
| Backup via SSH diretto da PHP (phpseclib) | Scaling problematico, timeout, gestione credenziali complessa |
|
||||||
|
| Integrazione Oxidized/RANCID via webhook | Overhead infrastrutturale, duplicazione logica versioning |
|
||||||
|
| Archiviazione config su filesystem invece di DB | Perdita integrazione con ACL/profile GLPI, backup/disaster recovery più complesso |
|
||||||
|
| Agent in PHP invece di Python | Netmiko/napalm hanno supporto multi-vendor più maturo in Python |
|
||||||
|
|
||||||
|
### 🔐 Security by Design
|
||||||
|
- **Credenziali di rete**: Mai hardcodate. Usare variabili d'ambiente o vault esterno
|
||||||
|
- **Token agente**: Generato con `openssl rand -hex 32`, rotazione periodica consigliata
|
||||||
|
- **Cifratura a riposo**: `config_content` cifrato con chiave GLPI (`crypt_key` in config_db.php)
|
||||||
|
- **Export sicuro**: Controllo `Session::haveRight()` + redaction automatica credenziali
|
||||||
|
- **API endpoint**: Validazione CSRF per chiamate browser, token per chiamate agent
|
||||||
|
- **Log sensibili**: Nessun dato di configurazione nei log di sistema
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Endpoint API del Plugin
|
||||||
|
|
||||||
|
### POST `/plugins/netconfig/ajax/agent_receive.php`
|
||||||
|
**Scopo**: Ricevere configurazioni da GLPI Agent remoto
|
||||||
|
|
||||||
|
**Request JSON**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"device_id": 123,
|
||||||
|
"config": "!\nhostname SW-TEST\n...\nend",
|
||||||
|
"token": "your_secure_agent_token",
|
||||||
|
"timestamp": "2026-05-22T10:30:00+00:00",
|
||||||
|
"agent_version": "1.0.0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response JSON**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"message": "Configuration saved and versioned"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Oppure:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"message": "No changes detected"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Codici HTTP**:
|
||||||
|
- `200`: Successo (controllare `status` nel JSON)
|
||||||
|
- `400`: Payload incompleto
|
||||||
|
- `401`: Token non valido
|
||||||
|
- `405`: Metodo HTTP non consentito
|
||||||
|
- `500`: Errore database/server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐍 Script Agent Python: Punti Chiave
|
||||||
|
|
||||||
|
### Configurazione Dispositivi (`netconfig_devices.yaml`)
|
||||||
|
```yaml
|
||||||
|
devices:
|
||||||
|
- name: "SW-Core-01"
|
||||||
|
ip: "10.0.0.1"
|
||||||
|
platform: "cisco_ios" # Mappatura netmiko
|
||||||
|
glpi_id: 123 # ID in glpi_networkdevices
|
||||||
|
username: "${NETCONFIG_DEFAULT_USER}" # Variabile d'ambiente
|
||||||
|
enable_password: "${NETCONFIG_ENABLE_PASS}"
|
||||||
|
command: "show running-config"
|
||||||
|
delay_factor: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gestione Errori Robusta
|
||||||
|
- Retry logic con backoff per timeout di rete
|
||||||
|
- Distinzione tra errori di autenticazione (no retry) e timeout (retry)
|
||||||
|
- Logging strutturato con livelli: INFO per successi, WARNING per retry, ERROR per fallimenti
|
||||||
|
|
||||||
|
### Ottimizzazioni
|
||||||
|
- Invio a GLPI solo se hash diverso dall'ultimo salvato (controllo lato client opzionale)
|
||||||
|
- Pulizia output da caratteri di controllo prima dell'invio
|
||||||
|
- Supporto per piattaforme multiple tramite mapping `device_type`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Massive Actions Supportate
|
||||||
|
|
||||||
|
| Action ID | Etichetta UI | Permesso Richiesto | Comportamento |
|
||||||
|
|-----------|-------------|-------------------|---------------|
|
||||||
|
| `PluginNetconfig\Config:BackupNow` | "Force backup now" | CREATE | Triggera recupero configurazione immediato per dispositivi selezionati |
|
||||||
|
| `PluginNetconfig\Config:ExportSelected` | "Export selected" | READ | Genera download file .txt per configurazioni selezionate |
|
||||||
|
|
||||||
|
**Implementazione**: Override di `getSpecificMassiveActions()` e `processMassiveActionsForOneItemtype()` in `Config.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗄️ Schema Database
|
||||||
|
|
||||||
|
### Tabella: `glpi_plugin_netconfig_configs`
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `glpi_plugin_netconfig_configs` (
|
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`networkdevices_id` int unsigned NOT NULL DEFAULT '0', -- FK a glpi_networkdevices
|
||||||
|
`config_content` mediumtext NOT NULL, -- Cifrato AES-256-GCM
|
||||||
|
`config_hash` char(64) NOT NULL, -- SHA256 hex
|
||||||
|
`is_encrypted` tinyint NOT NULL DEFAULT '1', -- Flag cifratura
|
||||||
|
`created_at` datetime NOT NULL, -- Timestamp salvataggio
|
||||||
|
`users_id` int unsigned NOT NULL DEFAULT '0', -- 0 = system/agent
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `networkdevices_id` (`networkdevices_id`),
|
||||||
|
KEY `created_at` (`created_at`),
|
||||||
|
KEY `config_hash` (`config_hash`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**:
|
||||||
|
- `MEDIUMTEXT` supporta config fino a ~16MB (sufficiente per switch/router enterprise)
|
||||||
|
- Indici su `networkdevices_id` e `created_at` per query efficienti dello storico
|
||||||
|
- `config_hash` indicizzato per rilevamento rapido duplicati
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Integrazione UI GLPI
|
||||||
|
|
||||||
|
### Tab Personalizzato su NetworkEquipment
|
||||||
|
- **Posizione**: Scheda aggiuntiva "Config History" nel form di `NetworkEquipment`
|
||||||
|
- **Contenuto**: Tabella con data, hash abbreviato, utente, azioni (export, diff)
|
||||||
|
- **Diff Visual**: Modal dialog con output HTML di `symfony/diff` (aggiunte in verde, rimozioni in rosso)
|
||||||
|
- **Pulsante Trigger**: "Retrieve configuration now" visibile solo a utenti con diritto CREATE
|
||||||
|
|
||||||
|
### Template Twig (`config_tab.html.twig`)
|
||||||
|
- Uso di helper GLPI: `path()`, `getUserName`, `__()` per traduzioni
|
||||||
|
- Sanitizzazione output diff con `|escape('js')` per prevenzione XSS
|
||||||
|
- Responsive design con classi Bootstrap native di GLPI 11
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Comandi Utili per Sviluppo & Debug
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verifica ambiente GLPI
|
||||||
|
php /var/www/glpi/bin/console glpi:version
|
||||||
|
php /var/www/glpi/bin/console glpi:system:status
|
||||||
|
|
||||||
|
# Installazione plugin
|
||||||
|
cd /var/www/glpi/plugins/netconfig
|
||||||
|
composer install --no-dev -o
|
||||||
|
chown -R www-data:www-data .
|
||||||
|
# Poi: UI GLPI > Configurazione > Plugin > Installa
|
||||||
|
|
||||||
|
# Test endpoint agent
|
||||||
|
curl -X POST http://localhost/glpi/plugins/netconfig/ajax/agent_receive.php \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"device_id":123,"config":"test","token":"CHANGE_ME"}'
|
||||||
|
|
||||||
|
# Log utili
|
||||||
|
tail -f /var/log/glpi/php-errors.log
|
||||||
|
tail -f /var/log/glpi_agent_netconfig.log
|
||||||
|
journalctl -u glpi-netconfig.service -f
|
||||||
|
|
||||||
|
# Verifica cifratura DB
|
||||||
|
mysql -e "SELECT config_content FROM glpi_plugin_netconfig_configs LIMIT 1" glpi_db
|
||||||
|
# Deve restituire blob cifrato, non testo in chiaro
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Troubleshooting Ricorrenti
|
||||||
|
|
||||||
|
| Sintomo | Causa Probabile | Soluzione |
|
||||||
|
|---------|----------------|-----------|
|
||||||
|
| `symfony/diff not found` | Cache Composer corrotta o minimum-stability mancante | `composer clear-cache && composer install -vvv` |
|
||||||
|
| Agent riceve 401 | Token non configurato o mismatch | Verificare `NETCONFIG_AGENT_TOKEN` in env e payload |
|
||||||
|
| Config non salvata ma nessun errore | Hash identico all'ultima versione (nessuna modifica) | Controllare log: messaggio "No changes detected" è normale |
|
||||||
|
| Diff non visualizzato | `symfony/diff` non installato o autoload non aggiornato | `composer dump-autoload -o` |
|
||||||
|
| Export scarica file vuoto | Permessi insufficienti o config cifrata senza chiave valida | Verificare `crypt_key` in `config_db.php` e diritti profilo |
|
||||||
|
| Massive action non appare | Plugin non attivato o hook non registrato | Controllare `setup.php` e stato plugin in UI GLPI |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 Roadmap Futura (Opzionale)
|
||||||
|
|
||||||
|
- [ ] Supporto per backup multipli paralleli (queue RabbitMQ/Redis)
|
||||||
|
- [ ] Integrazione con GLPI Notifications per alert su config change
|
||||||
|
- [ ] Plugin settings UI per configurare token, timeout, piattaforme supportate
|
||||||
|
- [ ] Supporto per dispositivi via API REST (non solo SSH)
|
||||||
|
- [ ] Reportistica: grafico frequenza modifiche, compliance check
|
||||||
|
- [ ] Webhook outbound per integrazione con SIEM/ITSM esterni
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Riferimenti Ufficiali
|
||||||
|
|
||||||
|
- [GLPI 11 Developer Documentation](https://glpi-developer-documentation.readthedocs.io/en/11.0/)
|
||||||
|
- [GLPI Plugin Development Guidelines](https://github.com/glpi-project/glpi/blob/11.0/DEV/PLUGIN.md)
|
||||||
|
- [Netmiko Documentation](https://ktbyers.github.io/netmiko/)
|
||||||
|
- [Symfony Diff Component](https://symfony.com/doc/current/components/diff.html)
|
||||||
|
- [GLPI REST API Reference](https://github.com/glpi-project/glpi/blob/11.0/apirest.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 💡 **Nota per l'Agent AI**: Quando assisti nello sviluppo di questo plugin, priorizza:
|
||||||
|
> 1. Conformità alle linee guida GLPI 11 (namespace, strict_types, DBConnection)
|
||||||
|
> 2. Sicurezza (cifratura, validazione input, controllo diritti)
|
||||||
|
> 3. Performance (query indicizzate, diff calcolato on-demand)
|
||||||
|
> 4. Manutenibilità (codice commentato, log chiari, configurazione esterna)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🧠 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
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ **I file `AGENTS.md` e `MEMORY.md` sono pronti per essere salvati nella root del repository del plugin**.
|
||||||
|
|
||||||
|
Entrambi i documenti:
|
||||||
|
- Sono scritti in **Markdown puro**, copiabili direttamente
|
||||||
|
- Contengono **tutto il contesto tecnico** emerso dalla nostra conversazione
|
||||||
|
- Sono strutturati per essere **utili sia a sviluppatori umani che ad AI agent**
|
||||||
|
- Includono **decisioni, motivazioni, flussi operativi e checklist di sicurezza**
|
||||||
|
|
||||||
|
Posso generare anche:
|
||||||
|
- Un `README.md` finale per gli utenti finali del plugin
|
||||||
|
- Un file `CHANGELOG.md` con versioning semantico
|
||||||
|
- Script di deploy automatizzato (Ansible/Bash)
|
||||||
|
|
||||||
|
Fammi sapere se vuoi procedere con uno di questi! 🚀
|
||||||
Reference in New Issue
Block a user