L'installateur protégeait le fichier, pas l'état
Un installateur qui demande l'autorisation avant d'écraser un .env donne
l'impression d'être prudent. Il ne l'était qu'à moitié : ce qu'il faut
protéger n'est pas le fichier, c'est ce que la machine porte déjà. Quatre
défauts, dont deux qui cassent une instance en service.
Le volume, qu'il ne regardait pas
POSTGRES_PASSWORD n'est lu qu'une fois dans la vie d'une base, par initdb,
sur un répertoire vide. Ensuite Postgres garde le sien et ignore la
variable. Tirer un secret neuf devant un volume déjà peuplé ne le change
donc pas : l'application démarre, se présente avec un mot de passe que la
base ne connaît pas, et tombe sur « password authentication failed ».
Deux chemins y menaient, et aucun ne prévenait — la porte « écrire un .env
neuf », et le cas sans .env du tout, où le script n'a jamais rien demandé.
Le second est le pire : le mot de passe de la base n'est alors écrit nulle
part sur la machine.
Le volume est maintenant détecté avant toute écriture. S'il existe et qu'un
ancien fichier est là, le script propose de reprendre utilisateur, base et
mot de passe — les quatre autres secrets tournent normalement, et le
message final le dit plutôt que d'annoncer cinq tirages. S'il n'y a pas
d'ancien fichier, il s'arrête : retrouver le mot de passe, réaligner la
base ou la supprimer sont trois décisions d'exploitation, et deviner n'en
est pas une. Passer outre reste possible, avec la marche à suivre pour
réaligner la base ensuite.
Le port, qu'il ne confrontait à rien
La question « Port d'écoute » ne pose que celui de l'application. Ceux de
LiveKit, Postgres, Redis et MinIO sont écrits dans la composition, et
répondre 7881 les heurtait sans un mot — le conflit se découvrait à la
levée, sous un « address already in use » qui ne nomme pas le coupable.
Les réservations sont désormais relues dans docker/compose.yaml plutôt que
recopiées dans le script : une ligne ajoutée là-bas serait sinon ignorée
ici. Un port réservé est refusé sur place, plages comprises. Un port déjà
tenu sur la machine n'est qu'un avertissement — et le script se tait si
c'est un conteneur de ce projet, parce qu'une instance en service tient
légitimement son port et que s'en alarmer ferait crier à chaque
réinstallation. Le contrôle vaut aussi pour un .env conservé, qui n'était
relu par personne.
Les sauvegardes, que git suivait
.gitignore excluait .env, pas les .env.sauvegarde-* que ce script écrit.
Elles portent les secrets vivants de l'instance précédente, en 600 mais
parfaitement indexables : un git add -A les mettait en soute. L'en-tête du
script promettait déjà que .gitignore les excluait — c'est vrai maintenant.
Les clés FCM, qu'il ne connaissait pas
.env.example a gagné FCM_PROJET, FCM_COMPTE et FCM_CLE avec le relais
Android ; le script était resté en arrière et écrivait un .env amputé. Son
propre contrôle de dérive le signalait, ce qui est mieux que rien, mais
laissait le travail à faire à la main.
Contrôlé
Sur une copie isolée, avec un volume leurre créé puis supprimé : passe
neuve, reprise des identifiants Postgres, refus devant une base sans .env,
outrepassement, ports réservés simples et en plage, occupation par un
projet étranger et par le sien, .env conservé portant un port réservé.
sh -n valide.
Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com>