Free

Laisser Claude déployer en production

Les erreurs de déploiement n'ont pas de symptômes. Quatre garde-fous — vaults séparés, scripts EDITOR, relecture de vérification, bascule runtime par env — pour utiliser Claude sans que tout brûle.


La grande différence entre déployer et écrire du code : le déploiement est à une seule balle, à enjeux élevés, et pénible à revenir en arrière. Écris une ligne cassée, un test l'attrape. Écris une ligne de credentials cassée, tu ne le découvres qu'au premier vrai paiement — les utilisateurs ont été débités, l'argent n'est pas arrivé sur ton compte, les logs ne sont que des 400.

J'ai récemment fait passer how2claude du dev local à la prod avec Claude : compte Stripe live, wallet x402 mainnet, Google OAuth, Kamal secrets. Claude ne sait pas quelles valeurs sont de test et lesquelles sont réelles. Il ne sait pas que sk_live_ vs sk_test_ est une différence d'une lettre aux conséquences apocalyptiques. Les garde-fous, c'est toi qui les poses.

Garde-fou #1 : Fichiers de credentials séparés pour dev et prod

Rails arrive par défaut avec config/credentials.yml.enc, déchiffré par config/master.key. Si tu utilises ce défaut, tu as perdu.

Si tu mets sk_live_xxx dans ce fichier puis que tu lances les tests localement, ton code de test utilise le Stripe de production. Chaque run de test débite une carte réelle.

Scinde en deux :
- config/credentials.yml.enc + config/master.key : dev/test, contient sk_test_xxx
- config/credentials/production.yml.enc + config/credentials/production.key : prod, contient sk_live_xxx

Les deux .key dans .gitignore, les deux .enc committés. production.key ne vit que sur la machine de déploiement.

Ensuite les secrets Kamal doivent pointer vers le bon fichier :

 # .kamal/secrets
-RAILS_MASTER_KEY=$(cat config/master.key)
+RAILS_MASTER_KEY=$(cat config/credentials/production.key)

Dans le conteneur, RAILS_MASTER_KEY pointe maintenant vers la clé de production, et ce qui est déchiffré ce sont les credentials de production. J'ai regardé Claude écrire cette ligne — le template Kamal par défaut est config/master.key (celui de dev), ce qui déploie silencieusement la clé Stripe de dev en production.

Garde-fou #2 : Utilise un script EDITOR, pas du copier-coller

bin/rails credentials:edit --environment production ouvre un éditeur interactif. Claude ne peut pas piloter un éditeur interactif. Tu ne veux pas non plus coller à la main une douzaine de secrets (une faute de frappe et tout casse).

Utilise ce pattern :

EDITOR="ruby script/set_prod_webhook_secret.rb" \
  bin/rails credentials:edit --environment production
rm script/set_prod_webhook_secret.rb

script/set_prod_webhook_secret.rb ressemble à ça :

# ARGV[0] est le chemin du fichier YAML temporaire déchiffré
file = ARGV[0]
require "yaml"
data = YAML.load_file(file) || {}
data["stripe"] ||= {}
data["stripe"]["webhook_secret"] = "whsec_GHWObNAKFh2HPOlJpbGmlYfIiKz1C8EY"
File.write(file, data.to_yaml)

Rails écrit le YAML déchiffré dans un fichier temporaire, appelle ton « EDITOR » avec ce chemin en argument, puis ré-encrypte à la sortie. Ton « EDITOR » n'est qu'un script Ruby qui modifie chirurgicalement une clé et enregistre.

Pourquoi c'est bien :
- Précis : ne touche que stripe.webhook_secret, rien d'autre.
- Idempotent : le lancer deux fois équivaut à le lancer une fois.
- Auditable : le script est le diff. Claude l'écrit, tu jettes un œil, tu sais exactement ce qui va changer.
- Disparaît à la suppression : après rm, pas de credential en clair sur disque, pas de paste de whsec_... dans l'historique du shell.

Un script par credential : set_stripe_live_key.rb, set_webhook_secret.rb, set_price_ids.rb, set_wallet_address.rb. rm chacun juste après.

Garde-fou #3 : Vérifie en relisant avec Rails runner

Après écriture, ne fais pas confiance à ce qu'il a bien écrit. Relis :

bin/rails runner -e production "
c = Rails.application.credentials
puts 'sk_live set: ' + c.dig(:stripe, :secret_key).to_s.start_with?('sk_live_').to_s
puts 'webhook_secret set: ' + c.dig(:stripe, :webhook_secret).to_s.start_with?('whsec_').to_s
puts 'wallet prefix: ' + c.dig(:x402, :wallet_address).to_s[0..5]
puts 'wallet len: ' + c.dig(:x402, :wallet_address).to_s.length.to_s
"

La clé, ce sont les vérifications de préfixe et de longueur, pas juste afficher les valeurs.

  • Une clé live Stripe commence toujours par sk_live_. Si tu relis sk_test_, Claude a mis la clé de test dans le fichier prod — un bug que tu ne trouveras qu'au premier vrai paiement.
  • Les webhook secrets commencent toujours par whsec_. Format correct ou non, visible d'un coup d'œil.
  • Les adresses EVM font toujours 42 caractères, 0x.... Mauvaise longueur signifie qu'un autre caractère s'est glissé.

Ajouter des vérifs de préfixe bloque l'essentiel des fautes de frappe, des champs oubliés et des environnements mélangés.

Garde-fou #4 : Bascule au runtime selon l'env, pas au déploiement à la main

C'est tentant de se dire « je change la network en mainnet avant de déployer ». Ce genre de bascule dépend de la mémoire humaine. Tôt ou tard, ça te brûle.

Grave la règle dans l'initializer :

# config/initializers/x402.rb
X402.configure do |c|
  c.wallet_address = Rails.application.credentials.dig(:x402, :wallet_address)
  c.chain = Rails.env.production? ? "base" : "base-sepolia"
end

Même code, testnet (sepolia) en dev, mainnet (base) en prod. Rien à changer au déploiement. Claude ne peut pas « oublier de basculer », parce que basculer n'est pas son boulot.

Même combine pour basescan_tx_url, la visibilité des Plans (les plans dev-only ne s'affichent pas en prod), la sélection de Stripe price ID, etc. Tout ce qui diffère entre dev et prod, bascule-le via Rails.env. Ne dépends pas de s'en souvenir au moment du déploiement.

Dernière étape : parcours le vrai flow toi-même

Avec les quatre garde-fous en place, tu dois quand même cliquer le paiement de vraie monnaie toi-même la première fois.

Dans l'article précédent Déboguer les bugs silencieux avec Claude, j'ai raconté le premier clic de paiement x402 en prod : invalid_string at payTo dans la console. Le 43ᵉ caractère de l'adresse wallet était un point d'interrogation pleine chasse qui s'était glissé depuis un IME chinois. Les vérifs de préfixe ne pouvaient pas l'attraper (le 0x était toujours là), les tests ne pouvaient pas l'attraper (les tests ne déclenchent pas de vraies transactions), seul un vrai clic l'a fait surgir.

Les garde-fous de déploiement ne sont pas pour Claude. Ils sont pour toi — automatise ce qui peut l'être (préfixes, longueurs, bascules d'env) pour que l'attention que tu économises aille sur les vraies interactions que l'automatisation ne couvre pas.


Le flow complet de Claude-déploiement :

  1. Sépare les credentials dev et prod en fichiers .enc + .key distincts.
  2. Pour chaque valeur à poser, écris un script Ruby à usage unique, nourris-le via EDITOR=script, supprime-le immédiatement.
  3. Après chaque écriture, relis avec Rails runner, en vérifiant préfixes et longueurs.
  4. Bascule toutes les différences dev/prod via Rails.env, pas au déploiement.
  5. Clique le bouton de vraie monnaie toi-même la première fois.

Le déploiement, ce n'est pas « écrire du code à plus gros enjeux ». Le déploiement, c'est « écrire du code où personne ne te dit que tu as tort ». Les garde-fous existent pour transformer « personne ne te dit » en « tu le sais en 15 secondes ».