Free

Lasciare che Claude faccia il deploy in produzione

Gli errori di deploy non hanno sintomi. Quattro guardrail — vault separati, script EDITOR, rilettura di verifica, switch runtime per env — per usare Claude senza che bruci tutto.


La grossa differenza tra fare deploy e scrivere codice: il deploy è one-shot, ad alto rischio, doloroso da revertire. Scrivi una riga di codice rotta, un test la prende. Scrivi una riga di credentials rotta, te ne accorgi solo al primo pagamento vero — gli utenti hanno già pagato, i soldi non sono arrivati sul tuo conto, i log sono solo 400.

Di recente ho portato how2claude dal dev locale alla produzione con Claude: account Stripe live, wallet x402 mainnet, Google OAuth, Kamal secrets. Claude non sa quali valori sono di test e quali sono reali. Non sa che sk_live_ vs sk_test_ è una differenza di una lettera con conseguenze apocalittiche. I guardrail li metti tu.

Guardrail #1: file di credentials separati per dev e prod

Rails di default usa config/credentials.yml.enc, decifrato da config/master.key. Se usi quel default, hai perso.

Se metti sk_live_xxx in quel file e poi fai girare i test in locale, il tuo codice di test sta usando Stripe produzione. Ogni run di test addebita una carta vera.

Separa in due:
- config/credentials.yml.enc + config/master.key: dev/test, tiene sk_test_xxx
- config/credentials/production.yml.enc + config/credentials/production.key: prod, tiene sk_live_xxx

Entrambi i .key in .gitignore, entrambi i .enc committati. production.key vive solo sulla macchina di deploy.

Poi i Kamal secrets devono puntare al file giusto:

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

Dentro il container RAILS_MASTER_KEY adesso punta alla chiave di produzione, e quello che viene decifrato sono le credentials di produzione. Ho guardato Claude scrivere questa riga — il template default di Kamal è config/master.key (quello di dev), che fa silenziosamente il deploy della chiave Stripe dev in produzione.

Guardrail #2: usa uno script EDITOR, niente copia-incolla

bin/rails credentials:edit --environment production apre un editor interattivo. Claude non può pilotare un editor interattivo. Neanche tu vuoi incollare a mano una dozzina di secret (un typo e si spacca tutto).

Usa questo 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 fatto così:

# ARGV[0] è il path del file YAML temporaneo decifrato
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 scrive lo YAML decifrato in un file temporaneo, chiama il tuo "EDITOR" passandogli quel path come argomento, e ricifra all'uscita. Il tuo "EDITOR" è solo uno script Ruby che modifica chirurgicamente una chiave e salva.

Perché funziona:
- Preciso: tocca solo stripe.webhook_secret, nient'altro.
- Idempotente: farlo girare due volte è come farlo girare una.
- Auditabile: lo script è il diff. Claude lo scrive, gli dai un'occhiata, sai esattamente cosa cambierà.
- Svanisce al delete: dopo rm non c'è credential in chiaro sul disco, né paste di whsec_... nella shell history.

Uno script per credential: set_stripe_live_key.rb, set_webhook_secret.rb, set_price_ids.rb, set_wallet_address.rb. rm ciascuno subito dopo.

Guardrail #3: verifica rileggendo con Rails runner

Dopo aver scritto, non fidarti che abbia scritto bene. Rileggi:

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 chiave sono i check di prefisso e lunghezza, non solo stampare i valori.

  • Una secret live di Stripe ha sempre il prefisso sk_live_. Se rileggi sk_test_, Claude ha messo la test key nel file prod — un bug che non troverai fino al primo pagamento vero.
  • Le webhook secret hanno sempre prefisso whsec_. Formato giusto o sbagliato, a colpo d'occhio.
  • Gli indirizzi EVM sono sempre 42 caratteri, 0x.... Lunghezza sbagliata vuol dire che un altro carattere si è infilato.

Aggiungere i check di prefisso blocca la maggior parte di typo, campi saltati e ambienti mischiati.

Guardrail #4: commuta al runtime per env, non al deploy a mano

È tentante pensare "cambio la network in mainnet prima del deploy". Quel tipo di switch dipende dalla memoria umana. Prima o poi ti brucia.

Incide la regola nell'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

Stesso codice, testnet (sepolia) in dev, mainnet (base) in prod. Niente da cambiare al deploy. Claude non può "dimenticarsi di switchare" perché switchare non è il suo lavoro.

Stessa mossa per basescan_tx_url, visibilità dei Plan (i piani dev-only non si renderizzano in prod), selezione di Stripe price ID, e così via. Qualsiasi cosa differisca tra dev e prod, ribaltala con Rails.env. Non contare sul ricordartene al deploy.

L'ultimo passaggio: cammina tu stesso il flusso vero

Con tutti e quattro i guardrail a posto, devi comunque cliccare il pagamento di soldi veri tu stesso la prima volta.

Nell'articolo precedente Debuggare i bug silenziosi con Claude, ho descritto il primo click di pagamento x402 in produzione: invalid_string at payTo in console. Il 43° carattere dell'indirizzo wallet era un punto interrogativo fullwidth infilatosi da un IME cinese. I check di prefisso non riuscivano a prenderlo (0x era sempre lì), i test non riuscivano a prenderlo (i test non sparano transazioni vere), solo un click vero l'ha fatto venire fuori.

I guardrail di deploy non sono per Claude. Sono per te — automatizza quello che si può automatizzare (prefissi, lunghezze, switch di env) così l'attenzione che risparmi va alle interazioni vere che l'automazione non copre.


Il flusso completo di Claude-deploy:

  1. Separa le credentials di dev e prod in file .enc + .key distinti.
  2. Per ogni valore da settare, scrivi uno script Ruby usa-e-getta, dallo in pasto via EDITOR=script, cancellalo subito.
  3. Dopo ogni scrittura, rileggi con Rails runner, controllando prefissi e lunghezze.
  4. Ribalta tutte le differenze dev/prod tramite Rails.env, non al deploy.
  5. Il bottone coi soldi veri, cliccalo tu la prima volta.

Il deploy non è "scrivere codice con stakes più alti". Il deploy è "scrivere codice dove nessuno ti dice che hai sbagliato". I guardrail esistono per trasformare "nessuno te lo dice" in "lo sai entro 15 secondi".