# AUDIT COMPLET: veza-backend-api Broken Pipe & Fichier .env Manquant dans Incus

**Date**: 2025-01-27  
**Problème**: veza-backend-api broken pipe. can't find .env file inside the dedicated incus container for the incus deploy  
**Priorité**: P0 - CRITIQUE (bloque le déploiement)

---

## 1. RÉSUMÉ EXÉCUTIF

### 1.1 Problème Principal
Le service `veza-backend-api` déployé dans un conteneur Incus rencontre deux problèmes critiques:
1. **Broken Pipe Error**: Erreurs de "broken pipe" lors de l'écriture des logs
2. **Fichier .env Manquant**: L'application ne trouve pas le fichier `.env` dans le conteneur

### 1.2 Impact
- ❌ Le service ne démarre pas correctement
- ❌ Les logs ne sont pas capturés par systemd/journald
- ❌ L'application ne peut pas charger les variables d'environnement
- ❌ Le déploiement Incus échoue silencieusement

---

## 2. ANALYSE DÉTAILLÉE

### 2.1 Architecture Actuelle du Déploiement

#### 2.1.1 Fichiers de Configuration
```
config/incus/env/backend-api.env          # Source (sur l'hôte)
  ↓ (copié via incus file push)
/etc/veza/backend-api.env                 # Destination (dans le conteneur)
```

#### 2.1.2 Service Systemd
```ini
[Service]
WorkingDirectory=/opt/veza/backend-api
ExecStart=/opt/veza/backend-api/start-backend-api.sh
EnvironmentFile=/etc/veza/backend-api.env
StandardOutput=journal
StandardError=journal
```

#### 2.1.3 Script Wrapper
```bash
#!/bin/bash
# start-backend-api.sh
source /etc/veza/backend-api.env
exec /usr/local/bin/veza-backend-api
```

#### 2.1.4 Application Go
```go
// main.go
_ = godotenv.Load()  // Cherche .env dans le working directory

// config.NewConfig()
LoadEnvFiles(env)    // Cherche .env.{env} et .env dans le working directory
```

### 2.2 Problèmes Identifiés

#### 2.2.1 Problème #1: Incohérence des Chemins de Fichiers .env

**Symptôme**: L'application Go cherche un fichier `.env` dans `/opt/veza/backend-api/` mais le fichier est à `/etc/veza/backend-api.env`

**Cause Racine**:
- Le script de déploiement copie le fichier à `/etc/veza/backend-api.env`
- Systemd charge les variables via `EnvironmentFile=/etc/veza/backend-api.env`
- Le wrapper script charge les variables via `source /etc/veza/backend-api.env`
- **MAIS** l'application Go fait `godotenv.Load()` qui cherche `.env` dans le working directory (`/opt/veza/backend-api/`)
- L'application Go fait aussi `LoadEnvFiles(env)` qui cherche `.env.production` et `.env` dans le working directory

**Impact**:
- Si les variables sont déjà chargées par systemd/wrapper, `godotenv.Load()` échoue silencieusement (pas d'erreur si fichier absent)
- Si les variables ne sont PAS chargées par systemd/wrapper, l'application ne trouve pas le fichier `.env` et échoue

**Preuve**:
```go
// veza-backend-api/cmd/api/main.go:50
_ = godotenv.Load()  // Cherche .env dans le répertoire courant

// veza-backend-api/internal/config/env_loader.go:24
_ = godotenv.Load()  // Cherche .env dans le répertoire courant
```

#### 2.2.2 Problème #2: Broken Pipe Error

**Symptôme**: Erreurs "broken pipe" lors de l'écriture des logs

**Cause Racine**:
- Systemd/journald peut fermer le pipe stdout/stderr si le service démarre trop vite
- Le wrapper script peut écrire sur stdout/stderr avant que systemd ne soit prêt
- L'application Go peut essayer d'écrire sur stdout/stderr après que journald ait fermé le pipe

**Impact**:
- Les logs ne sont pas capturés correctement
- L'application peut crasher si les erreurs de broken pipe ne sont pas gérées

**Preuve**:
- Le code Go a déjà des mécanismes pour gérer les broken pipe (dans `logging/logger.go`)
- Mais le wrapper script et les premières lignes de `main.go` peuvent écrire sur stdout/stderr avant que le logger ne soit initialisé

#### 2.2.3 Problème #3: Vérification Insuffisante du Fichier .env

**Symptôme**: Le script de déploiement vérifie que le fichier existe mais ne vérifie pas qu'il est accessible par l'application

**Cause Racine**:
- Le script `deploy-service-native.sh` vérifie que le fichier existe (`test -f`)
- Le script vérifie que le fichier est lisible (`test -r`)
- **MAIS** le script ne vérifie pas que le fichier est accessible depuis le working directory de l'application
- Le script ne crée pas de lien symbolique ou copie vers le working directory

**Impact**:
- L'application Go ne peut pas charger le fichier `.env` même si les variables sont chargées par systemd

#### 2.2.4 Problème #4: Ordre de Chargement des Variables d'Environnement

**Symptôme**: Les variables peuvent être chargées dans le mauvais ordre

**Ordre Actuel**:
1. Systemd charge `/etc/veza/backend-api.env` (via `EnvironmentFile`)
2. Wrapper script charge `/etc/veza/backend-api.env` (via `source`)
3. Application Go charge `.env` dans working directory (via `godotenv.Load()`)
4. Application Go charge `.env.{env}` et `.env` (via `LoadEnvFiles()`)

**Problème**:
- Si le fichier `.env` n'existe pas dans le working directory, `godotenv.Load()` échoue silencieusement
- Si les variables ne sont pas chargées par systemd/wrapper, l'application échoue

---

## 3. CAUSES RACINES

### 3.1 Cause Racine #1: Architecture Incohérente
- **Problème**: Mélange de deux approches (systemd EnvironmentFile + godotenv.Load())
- **Solution**: Choisir une seule approche et l'appliquer de manière cohérente

### 3.2 Cause Racine #2: Broken Pipe Non Géré au Démarrage
- **Problème**: Écriture sur stdout/stderr avant que journald ne soit prêt
- **Solution**: Rediriger stdout/stderr vers journald dès le début ou utiliser un logger qui gère les broken pipe

### 3.3 Cause Racine #3: Vérification Incomplète
- **Problème**: Le script de déploiement ne vérifie pas que l'application peut accéder au fichier .env
- **Solution**: Créer un fichier `.env` dans le working directory ou modifier l'application pour chercher le fichier au bon endroit

### 3.4 Cause Racine #4: Documentation Manquante
- **Problème**: Pas de documentation claire sur où le fichier .env doit être et comment il est chargé
- **Solution**: Documenter clairement l'architecture de chargement des variables d'environnement

---

## 4. SCÉNARIOS D'ÉCHEC

### 4.1 Scénario 1: Fichier .env Non Copié
```
1. Script de déploiement échoue silencieusement lors de la copie
2. Fichier /etc/veza/backend-api.env n'existe pas
3. Systemd ne charge pas les variables (mais ne signale pas d'erreur si EnvironmentFile est optionnel)
4. Wrapper script échoue avec "No such file or directory"
5. Application ne démarre pas
```

### 4.2 Scénario 2: Fichier .env Non Lisible
```
1. Fichier copié mais permissions incorrectes
2. Systemd peut charger les variables (root)
3. Wrapper script peut charger les variables (root)
4. Application Go cherche .env dans working directory (n'existe pas)
5. Application démarre mais avec variables manquantes
```

### 4.3 Scénario 3: Broken Pipe au Démarrage
```
1. Systemd démarre le service
2. Wrapper script écrit sur stdout/stderr
3. Journald n'est pas encore prêt → broken pipe
4. Application Go essaie d'écrire sur stdout/stderr → broken pipe
5. Application crash ou logs perdus
```

### 4.4 Scénario 4: Variables Non Chargées
```
1. Fichier .env copié correctement
2. Systemd charge les variables
3. Wrapper script charge les variables
4. Application Go cherche .env dans working directory (n'existe pas)
5. Si variables critiques manquantes → application échoue
```

---

## 5. POINTS DE VÉRIFICATION

### 5.1 Vérifications à Effectuer

#### 5.1.1 Dans le Conteneur
```bash
# Vérifier que le fichier existe
incus exec veza-backend-api -- test -f /etc/veza/backend-api.env && echo "OK" || echo "FAIL"

# Vérifier les permissions
incus exec veza-backend-api -- ls -la /etc/veza/backend-api.env

# Vérifier le contenu
incus exec veza-backend-api -- cat /etc/veza/backend-api.env

# Vérifier que systemd peut le charger
incus exec veza-backend-api -- systemctl show veza-backend-api --property=EnvironmentFiles

# Vérifier le working directory
incus exec veza-backend-api -- pwd
incus exec veza-backend-api -- ls -la /opt/veza/backend-api/

# Vérifier les variables d'environnement chargées
incus exec veza-backend-api -- systemctl show veza-backend-api --property=Environment
```

#### 5.1.2 Logs Systemd
```bash
# Vérifier les logs du service
incus exec veza-backend-api -- journalctl -u veza-backend-api -n 50

# Vérifier les erreurs
incus exec veza-backend-api -- journalctl -u veza-backend-api -p err

# Vérifier les broken pipe
incus exec veza-backend-api -- journalctl -u veza-backend-api | grep -i "broken pipe"
```

#### 5.1.3 Status du Service
```bash
# Vérifier le status
incus exec veza-backend-api -- systemctl status veza-backend-api

# Vérifier si le service est actif
incus exec veza-backend-api -- systemctl is-active veza-backend-api

# Vérifier les erreurs de démarrage
incus exec veza-backend-api -- systemctl status veza-backend-api | grep -i error
```

---

## 6. SOLUTIONS PROPOSÉES

### 6.1 Solution 1: Créer un Fichier .env dans le Working Directory (RECOMMANDÉ)

**Avantages**:
- Compatible avec l'application Go existante
- Pas de modification du code Go
- Simple à implémenter

**Inconvénients**:
- Duplication du fichier (mais acceptable pour la cohérence)

**Implémentation**:
1. Modifier `deploy-service-native.sh` pour copier aussi le fichier vers `/opt/veza/backend-api/.env`
2. Vérifier que le fichier est créé et lisible

### 6.2 Solution 2: Modifier l'Application Go pour Chercher le Fichier au Bon Endroit

**Avantages**:
- Pas de duplication
- Architecture plus propre

**Inconvénients**:
- Modification du code Go
- Plus complexe à maintenir

**Implémentation**:
1. Modifier `env_loader.go` pour chercher le fichier à `/etc/veza/backend-api.env` en premier
2. Fallback vers `.env` dans le working directory

### 6.3 Solution 3: Utiliser Uniquement Systemd EnvironmentFile

**Avantages**:
- Architecture simple
- Pas de duplication
- Variables chargées avant le démarrage de l'application

**Inconvénients**:
- Nécessite de supprimer `godotenv.Load()` du code Go
- Peut casser le développement local

**Implémentation**:
1. Supprimer `godotenv.Load()` de `main.go`
2. Supprimer `LoadEnvFiles()` de `config.NewConfig()`
3. S'assurer que systemd charge toutes les variables nécessaires

### 6.4 Solution 4: Gérer les Broken Pipe au Démarrage

**Avantages**:
- Résout le problème des broken pipe
- Améliore la robustesse

**Implémentation**:
1. Rediriger stdout/stderr vers journald dès le début du wrapper script
2. S'assurer que le logger Go gère les broken pipe (déjà fait)
3. Éviter d'écrire sur stdout/stderr avant que le logger ne soit initialisé

---

## 7. RECOMMANDATION FINALE

**Solution Recommandée**: Combinaison de Solution 1 + Solution 4

1. **Créer un fichier `.env` dans le working directory** pour compatibilité avec l'application Go
2. **Gérer les broken pipe** en redirigeant stdout/stderr vers journald dès le début
3. **Améliorer les vérifications** dans le script de déploiement
4. **Documenter** l'architecture de chargement des variables d'environnement

**Raison**:
- Compatible avec l'application Go existante
- Résout les deux problèmes (broken pipe + fichier .env)
- Minimal impact sur le code existant
- Facile à maintenir

---

## 8. RISQUES ET MITIGATION

### 8.1 Risque 1: Duplication du Fichier .env
**Mitigation**: Le fichier est petit et la duplication est acceptable pour la cohérence

### 8.2 Risque 2: Modification du Script de Déploiement
**Mitigation**: Tester le script sur un conteneur de test avant production

### 8.3 Risque 3: Régression sur le Développement Local
**Mitigation**: S'assurer que les modifications n'affectent pas le développement local

---

## 9. TESTS DE VALIDATION

### 9.1 Tests à Effectuer

1. **Test 1: Déploiement Complet**
   ```bash
   ./config/incus/deploy-service-native.sh backend-api
   ./config/incus/verify-deployment.sh
   ```

2. **Test 2: Vérification du Fichier .env**
   ```bash
   incus exec veza-backend-api -- test -f /etc/veza/backend-api.env
   incus exec veza-backend-api -- test -f /opt/veza/backend-api/.env
   ```

3. **Test 3: Vérification des Variables**
   ```bash
   incus exec veza-backend-api -- env | grep DATABASE_URL
   incus exec veza-backend-api -- env | grep JWT_SECRET
   ```

4. **Test 4: Vérification des Logs**
   ```bash
   incus exec veza-backend-api -- journalctl -u veza-backend-api -n 20
   incus exec veza-backend-api -- journalctl -u veza-backend-api | grep -i "broken pipe"
   ```

5. **Test 5: Test de Santé**
   ```bash
   incus exec veza-backend-api -- curl -f http://localhost:8080/health
   ```

---

## 10. RÉFÉRENCES

### 10.1 Fichiers Concernés
- `config/incus/deploy-service-native.sh` (lignes 315-358)
- `config/incus/systemd/veza-backend-api.service`
- `config/incus/scripts/start-backend-api.sh`
- `veza-backend-api/cmd/api/main.go` (ligne 50)
- `veza-backend-api/internal/config/env_loader.go`
- `veza-backend-api/internal/config/config.go` (ligne 210)

### 10.2 Documentation
- Systemd EnvironmentFile: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#EnvironmentFile=
- godotenv: https://github.com/joho/godotenv
- Incus file push: https://linuxcontainers.org/incus/docs/main/instances/#file-management

---

**Fin de l'Audit**
