Free

Віддаємо продакшен-деплой Claude

Помилки деплою без симптомів. Чотири огорожі — розділені vault'и, EDITOR-скрипти, перевірка зворотним читанням, рантайм-фліп за env — щоб використовувати Claude, не спаливши все.


Головна відмінність деплою від написання коду: деплой — один постріл, високі ставки, відкат болючий. Напишеш зламаний рядок коду — один прогін тестів його ловить. Напишеш зламаний рядок credentials — дізнаєшся лише при першому реальному платежі: користувачі списали з картки, гроші не дійшли до твого рахунку, логи — суцільні 400.

Нещодавно перевів how2claude з локального dev'у в продакшен разом із Claude: Stripe live-акаунт, x402 mainnet гаманець, Google OAuth, Kamal secrets. Claude не знає, які значення тестові, а які справжні. Не знає, що sk_live_ vs sk_test_ — різниця в одну літеру з апокаліптичними наслідками. Огорожі ставиш ти.

Огорожа #1: окремі credentials-файли для dev і prod

Rails за замовчуванням використовує config/credentials.yml.enc, розшифровується через config/master.key. Якщо використовуєш цей дефолт — ти програв.

Якщо покласти sk_live_xxx у цей файл і прогнати тести локально, твій тестовий код звертається до продакшен Stripe. Кожен прогін списує з реальної картки.

Розділяй на два:
- config/credentials.yml.enc + config/master.key: dev/test, тримає sk_test_xxx
- config/credentials/production.yml.enc + config/credentials/production.key: prod, тримає sk_live_xxx

Обидва .key в .gitignore, обидва .enc закомічені. production.key живе лише на деплой-машині.

Далі Kamal secrets має вказувати на правильний файл:

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

Усередині контейнера RAILS_MASTER_KEY тепер указує на продакшен-ключ, а розшифровуються продакшен-credentials. Я спостерігав, як Claude пише цей рядок — дефолтний шаблон Kamal — config/master.key (dev'овий), який мовчки деплоїть dev Stripe key у продакшен.

Огорожа #2: використовуй EDITOR-скрипт, не копіпасту

bin/rails credentials:edit --environment production відкриває інтерактивний редактор. Claude інтерактивний редактор не веде. Ти теж не хочеш вручну вставляти десяток секретів (одна опечатка все ламає).

Використовуй цей патерн:

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 виглядає так:

# ARGV[0] — шлях до тимчасового розшифрованого YAML-файлу
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 пише розшифрований YAML у тимчасовий файл, викликає твій «EDITOR» із цим шляхом як аргумент, на виході шифрує назад. Твій «EDITOR» — просто Ruby-скрипт, який хірургічно змінює один ключ і зберігає.

Чому добре:
- Точно: чіпає лише stripe.webhook_secret, нічого більше.
- Ідемпотентно: прогнати двічі — як прогнати один раз.
- Аудитовано: скрипт і є diff. Claude пише, ти глянув — і точно знаєш, що він змінить.
- Зникає після видалення: після rm немає plaintext credential'а на диску, немає вставки whsec_... в історії шелу.

По скрипту на credential: set_stripe_live_key.rb, set_webhook_secret.rb, set_price_ids.rb, set_wallet_address.rb. Кожен одразу rm.

Огорожа #3: верифікуй зворотним читанням через Rails runner

Написав — не вір, що написав правильно. Прочитай назад:

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
"

Головне — перевірки префіксу і довжини, а не просто роздрукувати значення.

  • Stripe live secret завжди починається з sk_live_. Якщо назад читається sk_test_, Claude поклав test key у prod-файл — цей баг ти не знайдеш до першого реального платежу.
  • Webhook secrets завжди з префіксом whsec_. Правильний формат чи ні — видно одразу.
  • EVM-адреси завжди 42 символи, 0x.... Неправильна довжина — значить, залетів сторонній символ.

Додавання перевірок префіксу блокує більшість опечаток, пропущених полів і переплутаних середовищ.

Огорожа #4: перемикайся в рантаймі за env, а не руками при деплої

Спокусливо подумати: «перед деплоєм переключу network на mainnet». Такий перемикач тримається на людській пам'яті. Рано чи пізно обпечешся.

Вкарбуй правило в 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

Той самий код, testnet (sepolia) в dev, mainnet (base) в prod. При деплої нічого міняти не треба. Claude не може «забути перемкнути», бо перемикати — не його робота.

Той самий прийом для basescan_tx_url, видимості Plan (dev-only плани не рендеряться в prod), вибору Stripe price ID тощо. Усе, що відрізняється між dev і prod, перевертай через Rails.env. Не покладайся на те, що згадаєш при деплої.

Останній крок: пройди реальний флоу сам

Навіть із чотирма огорожами перший клік платежу справжніми грошима — за тобою.

У попередній статті Налагоджуємо тихі баги з Claude я розповів про перший клік x402-платежу в проді: invalid_string at payTo у консолі. 43-й символ адреси гаманця — знак питання повної ширини, що залетів із китайського IME. Перевірки префіксу його не ловили (0x на місці), тести не ловили (тести не стріляють реальними транзакціями), лише реальний клік витяг його назовні.

Огорожі деплою — не для Claude. Вони для тебе — автоматизуй те, що можна автоматизувати (префікси, довжини, env-перевороти), щоб збережена увага йшла на реальні взаємодії, які автоматизація не покриває.


Повний флоу деплою з Claude:

  1. Розділи dev- і prod-credentials на окремі .enc + .key файли.
  2. Для кожного значення, яке треба встановити, пиши одноразовий Ruby-скрипт, підсовуй через EDITOR=script, одразу видаляй.
  3. Після кожного запису читай назад через Rails runner, перевіряй префікси й довжини.
  4. Усі dev/prod відмінності перевертай через Rails.env, не при деплої.
  5. Кнопку зі справжніми грошима перший раз тисни сам.

Деплой — це не «писати код із вищими ставками». Деплой — це «писати код, де ніхто не каже тобі, що ти неправий». Огорожі існують, щоб перетворити «ніхто не каже» на «ти знаєш за 15 секунд».