Postmortem : la base de prod vidée par une migration
Le 29 octobre 2026, une commande de migration mal ciblée a vidé la base de production de GaijinToSensei. Voici ce qui s'est passé et ce qui a changé depuis. Ce postmortem est sans reproche : on cherche ce qui a permis l'erreur, pas un coupable.
- Date
- 29 octobre 2026, 03:54 UTC
- Service
- GaijinToSensei, base PostgreSQL de production (Neon)
- Cause
prisma migrate devavec une base shadow qui pointait sur la prod- Réparation
- Point-in-time restore (PITR) de Neon
Résumé
Un agent préparait une nouvelle fonctionnalité qui ajoutait deux tables. Pour créer la migration, il a lancé prisma migrate dev. La base « shadow » de Prisma était réglée sur la base de production. La commande l'a réinitialisée : les tables de prod ont été vidées.
La base a été restaurée avec le point-in-time restore de Neon, à un instant antérieur à la commande.
Chronologie
Heures en UTC, tirées de l'historique git et du journal du jour.
- 03:54L'agent lance
prisma migrate devpour créer la migration des révisions espacées. La base shadow pointe sur la prod : elle est réinitialisée. - 03:55L'agent met son travail de côté sans l'intégrer et le signale. La chaîne d'agents est mise en pause.
- EnsuiteRestauration de la base par point-in-time restore de Neon, à un instant antérieur à 03:54.
- 05:13Correctif des pages de l'app qui plantaient quand un cookie de session pointait vers un compte absent de la base.
- 11:10La fonctionnalité est réintégrée avec une nouvelle migration, créée sans toucher à la prod, et mise en ligne.
Cause
prisma migrate dev est une commande de développement. Elle utilise une base « shadow » jetable qu'elle peut effacer. Ici, la base shadow désignait la base de production.
Rien n'empêchait un agent de lancer une commande destructive avec les accès de la prod. C'est ce manque de garde-fou qui a permis l'incident.
Impact
- La base de production était vide entre 03:54 et la fin de la restauration. Pendant ce temps, l'app ne pouvait pas servir les comptes des utilisateurs.
- Après la restauration, des sessions pointaient vers des comptes absents et faisaient planter des pages de l'app, jusqu'au correctif de 05:13.
Ce qui a aidé
- Neon garde un historique qui permet de revenir à un instant précis. La restauration n'a demandé aucune sauvegarde manuelle.
- L'agent s'est arrêté au lieu de continuer, et la chaîne a été mise en pause tout de suite.
Correctifs et règles ajoutées
- Toute commande destructive est interdite sur la base de prod : pas de
migrate dev, pas de reset, pas de suppression. - Migrations additives uniquement. Le script de mise en prod refuse une migration qui contient DROP, RENAME, TRUNCATE, DELETE, UPDATE ou ALTER COLUMN, et n'applique jamais de migration lui-même.
- La mise en prod passe par un script verrouillé : préversion, contrôles, promotion, nouveau contrôle et retour arrière automatique en cas d'échec.
- Les pages de l'app vérifient que le compte existe encore et renvoient sinon vers la connexion.
Ce que j'ai appris
- Une commande de développement avec un accès de prod, c'est une commande de prod. Les accès doivent être séparés.
- Une sauvegarde qu'on sait restaurer vite vaut plus que n'importe quelle procédure écrite.
- Quand un agent fait une erreur, la question utile est : quel garde-fou manquait ? Puis on l'ajoute dans le code, pas dans une consigne.