# ClamAV Configuration — Veza Backend API

## Vue d'ensemble

Le backend Veza API intègre **ClamAV** pour scanner tous les fichiers uploadés avant toute persistance (base de données, système de fichiers, ou stockage S3). Cette fonctionnalité garantit qu'aucun malware ne peut être stocké sur le serveur.

**MOD-P1-001**: Le scan ClamAV est maintenant **obligatoire** et se fait **AVANT toute persistance**. Si ClamAV est indisponible, tous les uploads sont rejetés (fail-secure).

---

## Variables d'environnement

### Configuration ClamAV

```bash
# Activer/désactiver ClamAV (par défaut: true)
CLAMAV_ENABLED=true

# Adresse du daemon ClamAV (par défaut: localhost:3310)
# Format: host:port (ex: localhost:3310, 192.168.1.100:3310)
CLAMAV_ADDRESS=localhost:3310
```

### Exemples de configuration

#### Développement local
```bash
CLAMAV_ENABLED=true
CLAMAV_ADDRESS=localhost:3310
```

#### Production avec ClamAV distant
```bash
CLAMAV_ENABLED=true
CLAMAV_ADDRESS=clamav.internal:3310
```

#### Désactiver ClamAV (non recommandé en production)
```bash
CLAMAV_ENABLED=false
```

---

## Installation et démarrage de ClamAV

### Linux (Ubuntu/Debian)

```bash
# Installer ClamAV
sudo apt-get update
sudo apt-get install clamav clamav-daemon

# Démarrer le daemon
sudo systemctl start clamav-daemon
sudo systemctl enable clamav-daemon

# Mettre à jour les signatures de virus
sudo freshclam
```

### Docker

```bash
# Lancer ClamAV dans un conteneur Docker
docker run -d --name clamav \
  -p 3310:3310 \
  -v /var/lib/clamav:/var/lib/clamav \
  clamav/clamav:latest
```

### macOS (Homebrew)

```bash
# Installer ClamAV
brew install clamav

# Démarrer le daemon
brew services start clamav
```

---

## Comportement fail-secure

### Si ClamAV est activé mais indisponible

- ✅ **Le serveur démarre** (pas de blocage au démarrage)
- ❌ **Tous les uploads sont rejetés** avec HTTP 503 (Service Unavailable)
- 📝 **Message d'erreur clair** : "Virus scanning service is temporarily unavailable"

### Si un virus est détecté

- ❌ **L'upload est rejeté** avec HTTP 422 (Unprocessable Entity)
- 📝 **Message d'erreur** : "File rejected: virus detected"
- 🔒 **Le fichier n'est JAMAIS persistant** (ni DB, ni FS, ni S3)

### Si le scan échoue (timeout, erreur de connexion)

- ❌ **L'upload est rejeté** avec HTTP 503 (Service Unavailable)
- 📝 **Message d'erreur** : "Virus scan failed"
- 🔒 **Fail-secure** : en cas de doute, on rejette

---

## Tests

### Tests unitaires (sans ClamAV requis)

```bash
# Exécuter tous les tests unitaires
go test ./internal/services -run TestUploadValidator -v

# Tests spécifiques
go test ./internal/services -run TestUploadValidator_ClamAVDown_RejectsUploads -v
go test ./internal/services -run TestUploadValidator_ClamAVDisabled_AllowsUploads -v
```

### Tests d'intégration (ClamAV requis)

Les tests d'intégration nécessitent ClamAV en cours d'exécution et utilisent un build tag.

```bash
# 1. Démarrer ClamAV (voir section Installation)

# 2. Exécuter les tests d'intégration avec le tag 'clamav'
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV -v

# 3. Test spécifique avec fichier EICAR (test virus standard)
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV_EICAR_Rejected -v

# 4. Test avec fichier propre
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV_CleanFile_Accepted -v
```

### Configuration pour les tests d'intégration

Par défaut, les tests utilisent `localhost:3310`. Pour utiliser une autre adresse :

```bash
export CLAMAV_ADDRESS=192.168.1.100:3310
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV -v
```

---

## Vérification que le scan se fait AVANT la persistance

### Preuve dans le code

1. **Handler** (`internal/core/track/handler.go:117-160`):
   - Le scan ClamAV est appelé **AVANT** `trackService.UploadTrack()`
   - Si le scan échoue, la fonction retourne immédiatement (pas d'appel au service)

2. **Service** (`internal/core/track/service.go:145-216`):
   - `UploadTrack()` sauvegarde le fichier (ligne 182) et crée l'enregistrement DB (ligne 213)
   - **Ces opérations ne sont jamais appelées** si le scan échoue dans le handler

3. **Validateur** (`internal/services/upload_validator.go:124-222`):
   - `ValidateFile()` fait le scan ClamAV **avant** de retourner `result.Valid = true`
   - Si le scan détecte un virus, `result.Valid = false` et une erreur est retournée

### Ordre d'exécution garanti

```
1. Handler reçoit le fichier uploadé
2. Handler appelle ValidateFile() avec context
3. ValidateFile() fait le scan ClamAV (timeout 30s)
4. Si scan OK → ValidateFile() retourne result.Valid = true
5. Si scan OK → Handler appelle trackService.UploadTrack()
6. UploadTrack() sauvegarde le fichier et crée l'enregistrement DB
```

**Si le scan échoue à l'étape 3, les étapes 5-6 ne sont JAMAIS exécutées.**

---

## Timeouts et limites

- **Timeout de scan** : 30 secondes maximum
- **Gestion du contexte** : Utilise `context.WithTimeout()` pour éviter les blocages
- **Logs structurés** : Tous les scans sont loggés avec `zap.Logger`

---

## Codes HTTP retournés

| Situation | Code HTTP | Message |
|-----------|-----------|---------|
| ClamAV indisponible (enabled mais down) | 503 | "Virus scanning service is temporarily unavailable" |
| Virus détecté | 422 | "File rejected: virus detected" |
| Erreur de scan (timeout, connexion) | 503 | "Virus scan failed" |
| Fichier propre | 201 | Upload réussi |

---

## Dépannage

### Le serveur démarre mais les uploads sont rejetés

**Symptôme** : HTTP 503 avec message "Virus scanning service is temporarily unavailable"

**Causes possibles** :
1. ClamAV n'est pas démarré : `sudo systemctl status clamav-daemon`
2. Mauvaise adresse : Vérifier `CLAMAV_ADDRESS`
3. Firewall bloque le port 3310

**Solution** :
```bash
# Vérifier que ClamAV écoute
sudo netstat -tlnp | grep 3310

# Tester la connexion
telnet localhost 3310

# Redémarrer ClamAV
sudo systemctl restart clamav-daemon
```

### Les tests d'intégration échouent

**Symptôme** : `go test -tags=clamav` échoue avec erreur de connexion

**Solution** :
1. Vérifier que ClamAV est démarré
2. Vérifier la variable `CLAMAV_ADDRESS` si ClamAV est sur une autre machine
3. Vérifier les logs : `sudo journalctl -u clamav-daemon -f`

---

## Références

- [ClamAV Documentation](https://docs.clamav.net/)
- [go-clamd Library](https://github.com/dutchcoders/go-clamd)
- [EICAR Test File](https://en.wikipedia.org/wiki/EICAR_test_file)
