You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
🚧 Draft — à instruire. Description courte volontairement : le périmètre, les critères
d'acceptation et le découpage en tâches restent à écrire avant de démarrer.
De quoi il s'agit
Aujourd'hui, terraform plan et terraform apply se lancent à la main, depuis un poste, contre
la prod. Cette issue instruit leur passage en CI — non pas pour retirer l'humain de la boucle, mais
pour garantir que le plan appliqué est exactement celui qui a été relu.
L'automatisation n'est pas un acquis : la décision actuelle est délibérée, pas un oubli. infra/README.md (qui arrive avec #30) la formule ainsi, en renvoyant à #12 :
Pas de sandbox GCP (décision figée de l'issue #12) : plan est le seul filet avant un apply
qui touche directement la prod. Toujours relire un plan avant d'applyer.
Toute proposition ici doit donc dire ce qu'elle fait de ce filet, pas seulement comment elle
câble le workflow.
Ce qui existe
Le job terraform de ci.yml fait fmt, validate, tflint, terraform test, checkov. Il ne
fait ni plan ni apply, et il en est structurellement incapable : terraform init -backend=false (jamais de connexion au bucket pick-a-book-tfstate) et mock_provider pour les
tests, hermétique par construction. Le repo n'a par ailleurs ni secret, ni variable, ni environment
GitHub — aucun chemin d'authentification vers GCP.
Pourquoi un apply automatique et non gardé serait dangereux
Ce n'est pas théorique : c'est ce qui se serait produit au merge de #28, relevé en appliquant
l'infrastructure pour de vrai le 2026-08-20.
Le plan comportait 2 destructions — bucket et Artifact Registry recréés pour la bascule europe-west3 → europe-west1. Sans relecture, personne n'aurait vérifié qu'ils étaient vides.
Il aurait échoué en plein milieu : un destroy et un create visaient le même service account
GCP (pick-a-book-api@…), sous deux adresses Terraform différentes après renommage de module.
Terraform n'a aucune dépendance entre ces deux adresses ; selon l'ordre, soit le create échoue en 409 alreadyExists, soit le destroy supprime le SA d'abord — et GCP retient l'identifiant d'un
SA supprimé pendant ~30 jours, ce qui aurait bloqué la recréation. C'est un terraform state mv
manuel qui l'a évité, opération qu'aucun workflow ne peut décider seul.
L'apply a en outre remonté deux erreurs qu'il fallait savoir distinguer : un 404 IAM sur le
bucket (course de propagation GCS, transitoire, réglée au second apply) et un secret DATABASE_URL sans version (réel, bloquant, résolu hors Terraform). Un pipeline qui traite les
deux de la même façon se trompe une fois sur deux.
La conclusion à instruire n'est donc pas « faut-il automatiser », mais où placer l'approbation
humaine pour qu'elle porte sur le plan et non sur le diff de code.
À instruire
Forme du garde-fou.plan sur PR posté en commentaire, apply sur push main derrière un
GitHub environment avec reviewer requis ? Et l'apply consomme-t-il un fichier de plan
sauvegardé issu du plan relu (terraform plan -out), seule façon de garantir l'équivalence ?
Authentification. Workload Identity Federation plutôt qu'une clé de SA en secret longue durée.
À provisionner dans infra/ (pool, provider, bindings) — donc décision structurante, ADR avant ou
avec le code. Prérequis partagé avec ci(cd): pipeline de build et de déploiement d'image — Artifact Registry puis Cloud Run #32 : instruire les deux ensemble évitera de le faire deux
fois, en gardant deux identités distinctes (le déploiement d'image n'a pas besoin d'écrire l'état
Terraform).
Droits séparés plan / apply. Le plan a besoin d'un accès lecture à l'état et aux ressources,
l'apply d'un accès écriture. Deux identités, ou une seule ?
Verrouillage d'état. Retirer le -backend=false expose au concurrent apply : le backend gcs
gère le lock, à confirmer et à tester (que se passe-t-il si deux runs se chevauchent ?).
Comportement en cas de dérive. Le workflow doit échouer bruyamment plutôt que tenter d'être
malin : un plan qui contient un destroy inattendu, ou qui exige un state mv, se traite à la
main. Quel signal, et quelle procédure manuelle documentée ?
Périmètre. Un seul environnement (envs/prod) aujourd'hui. Le workflow doit-il déjà être écrit
pour en accueillir d'autres, ou rester délibérément mono-env ?
Constat annexe : le job terraform ne bloque pas les merges
Relevé le 2026-08-21, en marge de cette issue mais du même sujet — les garde-fous de la CI infra.
main est bien protégée, par le ruleset « Protect main » (id=20000430, actif : deletion, non_fast_forward, pull_request, required_status_checks). Mais la liste des contextes requis
contient check, et rien d'autre. Le job terraform — fmt, validate, tflint, terraform test, checkov — n'y figure pas.
Observé concrètement : #34 a été mergée par l'auto-merge pendant que le job terraform tournait
encore. Il est passé, mais rien ne le garantissait. Or #30, #31 et #34 sont trois PR
d'infrastructure d'affilée dont la seule validation réelle n'a jamais conditionné le merge.
Ajouter terraform aux contextes requis est un réglage GitHub, pas un changement de code — mais il
appartient au même sujet que cette issue : jusqu'où la CI doit-elle bloquer sur l'infrastructure.
À trancher avec le reste plutôt qu'à la volée.
Hors périmètre
Le build et le déploiement d'image applicative — c'est ci(cd): pipeline de build et de déploiement d'image — Artifact Registry puis Cloud Run #32. Profil de risque différent :
déployer une image se retire par update-traffic sur une révision précédente, appliquer de
l'infrastructure peut détruire une ressource. Les deux issues ne partagent que le prérequis
d'authentification.
De quoi il s'agit
Aujourd'hui,
terraform planetterraform applyse lancent à la main, depuis un poste, contrela prod. Cette issue instruit leur passage en CI — non pas pour retirer l'humain de la boucle, mais
pour garantir que le plan appliqué est exactement celui qui a été relu.
L'automatisation n'est pas un acquis : la décision actuelle est délibérée, pas un oubli.
infra/README.md(qui arrive avec #30) la formule ainsi, en renvoyant à #12 :Toute proposition ici doit donc dire ce qu'elle fait de ce filet, pas seulement comment elle
câble le workflow.
Ce qui existe
Le job
terraformdeci.ymlfaitfmt,validate,tflint,terraform test,checkov. Il nefait ni
planniapply, et il en est structurellement incapable :terraform init -backend=false(jamais de connexion au bucketpick-a-book-tfstate) etmock_providerpour lestests, hermétique par construction. Le repo n'a par ailleurs ni secret, ni variable, ni environment
GitHub — aucun chemin d'authentification vers GCP.
Pourquoi un apply automatique et non gardé serait dangereux
Ce n'est pas théorique : c'est ce qui se serait produit au merge de #28, relevé en appliquant
l'infrastructure pour de vrai le 2026-08-20.
europe-west3 → europe-west1. Sans relecture, personne n'aurait vérifié qu'ils étaient vides.destroyet uncreatevisaient le même service accountGCP (
pick-a-book-api@…), sous deux adresses Terraform différentes après renommage de module.Terraform n'a aucune dépendance entre ces deux adresses ; selon l'ordre, soit le
createéchoue en409 alreadyExists, soit ledestroysupprime le SA d'abord — et GCP retient l'identifiant d'unSA supprimé pendant ~30 jours, ce qui aurait bloqué la recréation. C'est un
terraform state mvmanuel qui l'a évité, opération qu'aucun workflow ne peut décider seul.
bucket (course de propagation GCS, transitoire, réglée au second apply) et un secret
DATABASE_URLsans version (réel, bloquant, résolu hors Terraform). Un pipeline qui traite lesdeux de la même façon se trompe une fois sur deux.
La conclusion à instruire n'est donc pas « faut-il automatiser », mais où placer l'approbation
humaine pour qu'elle porte sur le plan et non sur le diff de code.
À instruire
plansur PR posté en commentaire,applysurpush mainderrière unGitHub
environmentavec reviewer requis ? Et l'apply consomme-t-il un fichier de plansauvegardé issu du plan relu (
terraform plan -out), seule façon de garantir l'équivalence ?À provisionner dans
infra/(pool, provider, bindings) — donc décision structurante, ADR avant ouavec le code. Prérequis partagé avec ci(cd): pipeline de build et de déploiement d'image — Artifact Registry puis Cloud Run #32 : instruire les deux ensemble évitera de le faire deux
fois, en gardant deux identités distinctes (le déploiement d'image n'a pas besoin d'écrire l'état
Terraform).
plan/apply. Le plan a besoin d'un accès lecture à l'état et aux ressources,l'apply d'un accès écriture. Deux identités, ou une seule ?
-backend=falseexpose au concurrent apply : le backendgcsgère le lock, à confirmer et à tester (que se passe-t-il si deux runs se chevauchent ?).
malin : un plan qui contient un
destroyinattendu, ou qui exige unstate mv, se traite à lamain. Quel signal, et quelle procédure manuelle documentée ?
envs/prod) aujourd'hui. Le workflow doit-il déjà être écritpour en accueillir d'autres, ou rester délibérément mono-env ?
Constat annexe : le job
terraformne bloque pas les mergesRelevé le 2026-08-21, en marge de cette issue mais du même sujet — les garde-fous de la CI infra.
mainest bien protégée, par le ruleset « Protect main » (id=20000430, actif :deletion,non_fast_forward,pull_request,required_status_checks). Mais la liste des contextes requiscontient
check, et rien d'autre. Le jobterraform—fmt,validate,tflint,terraform test,checkov— n'y figure pas.Observé concrètement : #34 a été mergée par l'auto-merge pendant que le job
terraformtournaitencore. Il est passé, mais rien ne le garantissait. Or #30, #31 et #34 sont trois PR
d'infrastructure d'affilée dont la seule validation réelle n'a jamais conditionné le merge.
Ajouter
terraformaux contextes requis est un réglage GitHub, pas un changement de code — mais ilappartient au même sujet que cette issue : jusqu'où la CI doit-elle bloquer sur l'infrastructure.
À trancher avec le reste plutôt qu'à la volée.
Hors périmètre
déployer une image se retire par
update-trafficsur une révision précédente, appliquer del'infrastructure peut détruire une ressource. Les deux issues ne partagent que le prérequis
d'authentification.
environnement de répétition est nécessaire, ça relève d'un ADR distinct, pas de cette issue.
🤖 Generated with Claude Code