Claude Media
Claude CodeでFastlaneのリリースを自動化 — uploadはaskで止める

Claude CodeでFastlaneのリリースを自動化 — uploadはaskで止める

Fastfileの作成をClaude Codeに任せつつ、TestFlightやApp Storeへ送るlaneは権限ルールで確認を挟む。検証用laneとFastfile編集の守り方まで書きます。

Fastlaneの公開系アクションは、lane名で確認を挟む

Fastlaneは、ビルド、署名、TestFlight配信、App Storeへの提出といった手作業を、Fastfileに書いたlane(一連の処理に付けた名前)として自動化するツールです。Claude Codeに任せるなら、Fastfileを書かせてビルドまでを自走させる使い方が向いています。一方で、App Store ConnectやGoogle Playへ送るアクションは、実行した時点で外部に残ります。

整える方針は3つです。

  • ビルドと検証だけのlaneは、確認なしで走らせる
  • アップロードするlaneは、askルールで毎回確認を挟む
  • 審査提出まで進むlaneは、Claude Codeからは実行させない

ここで押さえたい点があります。Claude Codeの権限ルールが見るのは、Claudeが書いたシェルのコマンド文字列です。upload_to_app_storeがFastfileの中で呼ばれていても、ルールにはlane名しか見えません。つまり、止める単位はアクションではなくlaneです。この前提で、lane設計、権限設定、Fastfile自体の守り方を順に組みます。

iOSアプリ自体の作り方はClaude CodeでSwiftUI iOSアプリを開発する手順にあります。ここでは、アプリが手元でビルドできる状態から、リリース工程だけを扱います。

どのアクションが外部に書き込むのか

Fastlaneのアクション一覧は、カテゴリ別に分かれています。リリース関連の「Releasing your app」には、deliver(upload_to_app_storeの別名)、supply(upload_to_play_storeの別名)、upload_to_app_store、upload_to_play_store、upload_app_privacy_details_to_app_storeなどが並びます。TestFlightに送るpilotは、Betaカテゴリでupload_to_testflightの別名として載っています。

確認を挟む対象を決めるため、外へ書き込む側と読むだけの側に分けておきます。

分類アクション外部への影響
読むだけアクションapp_store_build_number、latest_testflight_build_number外部への影響App Store Connectの現在値を取得する
ローカルのみアクションbuild_app(ipaを作る)外部への影響手元にipaができる
書き込むアクションupload_to_testflight(pilot)外部への影響ビルドをTestFlightへ送る
書き込むアクションupload_to_app_store(deliver)外部への影響メタデータ・スクリーンショット・バイナリを送る
書き込むアクションupload_to_play_store(supply)外部への影響Google Playへメタデータやバイナリを送る
書き込むアクションupload_app_privacy_details_to_app_store外部への影響App Privacy Detailsを送る

注意したいのはdeliverです。ipaを指定しない場合は、アプリのメタデータだけがアップロードされます。バイナリを送らない実行でも、ストア上の説明文やスクリーンショットは書き換わります。「ipaを送らないから安全」とは言えません。

権限ルールはlane名しか見ない

Claude Codeの権限ルールは、deny、ask、allowの順に評価され、最初に一致したものが結果を決めます。広いdenyの中に狭いallowで例外を作ることはできません。askとallowの関係も同じで、askに一致する呼び出しは、より細かいallowがあっても確認が出ます。

これを使うと、lane名ごとに3段階の運用を置けます。次の例は、後述のlane名に合わせた.claude/settings.jsonの断片です。

{
  "permissions": {
    "allow": [
      "Bash(bundle exec fastlane build_only *)",
      "Bash(bundle exec fastlane verify *)",
      "Bash(bundle exec fastlane actions)",
      "Bash(bundle exec fastlane action *)"
    ],
    "ask": [
      "Bash(bundle exec fastlane beta *)",
      "Bash(bundle exec fastlane release *)",
      "Bash(bundle exec fastlane deliver *)",
      "Bash(bundle exec fastlane pilot *)",
      "Bash(bundle exec fastlane supply *)",
      "Edit(fastlane/**)"
    ],
    "deny": [
      "Bash(bundle exec fastlane submit_review *)",
      "Read(**/*.p8)"
    ]
  }
}

書き方で気をつける点が3つあります。

  1. 末尾の*の前にスペースを置く: Bash(... build_only *)は引数なしのbuild_onlyにも一致します。スペースがない書き方だと、別名のlaneにも一致してしまいます。
  2. bundle execは自動で外れない: Claude Codeが実行前に取り除くラッパーはtimeout、time、nice、nohup、stdbufなどの固定の一覧で、bundle execは含まれていません。プロジェクトで使う呼び方に合わせて書き、同じ形で実行するようCLAUDE.mdにも書いておきます。
  3. 直接呼びも塞ぐ: lane名だけ押さえても、fastlane deliverやfastlane pilotを直接呼べば同じ書き込みができます。そのためaskに直接呼びの形も入れています。

Claudeに渡す検証用laneを先に作る

確認を挟むだけでは、実行する側の判断材料が足りません。「送る前に何が起きるか」を安全に見られるlaneを別に用意すると、askの承認が形式で終わりません。

Fastfileの例を示します。オプション名はFastlaneのアクション解説に載っているものを使った形で、アプリ名、スキーム名、環境変数名は仮のものです。

default_platform(:ios)
 
platform :ios do
  lane :build_only do
    build_app(
      scheme: "MyApp",
      export_method: "app-store",
      output_directory: "./build"
    )
  end
 
  lane :verify do
    build_app(scheme: "MyApp", export_method: "app-store",
              output_directory: "./build")
    app_store_connect_api_key(
      key_id: ENV["ASC_KEY_ID"],
      issuer_id: ENV["ASC_ISSUER_ID"],
      key_filepath: ENV["ASC_KEY_PATH"]
    )
    deliver(verify_only: true)
  end
 
  lane :beta do
    build_app(scheme: "MyApp", export_method: "app-store",
              output_directory: "./build")
    app_store_connect_api_key(
      key_id: ENV["ASC_KEY_ID"],
      issuer_id: ENV["ASC_ISSUER_ID"],
      key_filepath: ENV["ASC_KEY_PATH"]
    )
    upload_to_testflight(
      changelog: "検証用ビルド",
      skip_submission: true
    )
  end
 
  lane :release do
    build_app(scheme: "MyApp", export_method: "app-store",
              output_directory: "./build")
    app_store_connect_api_key(
      key_id: ENV["ASC_KEY_ID"],
      issuer_id: ENV["ASC_ISSUER_ID"],
      key_filepath: ENV["ASC_KEY_PATH"]
    )
    deliver(
      submit_for_review: false,
      automatic_release: false
    )
  end
end

各lane、各オプションの役割は次のとおりです。

  • build_only: ipaを作るだけで、外には何も送りません。allowに置けます。
  • verify: deliverのverify_onlyは、アーカイブをApp Store Connectで検証し、アップロードはしないオプションです。バイナリが受理される形かを、送る前に確かめるために使います。
  • beta: skip_submission: trueは、ipaをアップロードするだけでテスターへの配布はしないオプションです。ビルド処理待ちを飛ばすskip_waiting_for_build_processingは、trueにするとdistribute_externalが効かなくなり、テスターへの配布もされません。CIの課金時間を抑える用途のオプションなので、ここでは使いません。
  • release: submit_for_reviewの既定値はfalse、automatic_releaseは「承認されたら全ユーザーに自動公開するか」の指定です。両方を明示的にfalseにしておけば、このlaneはアップロードまでで止まります。

deliverのforceはtrueにしません。forceを指定すると、アップロード前のHTMLレポートが作られなくなります。レポートが作られる状態のままにしておけば、送る内容を目で見られます。

審査提出は人が打つlaneに分ける

既にApp Store Connectにあるビルドを審査に出す処理は、deliverのbuild_number、submit_for_review: true、skip_binary_upload: trueなどを組み合わせたlaneとして書けます。コマンドならfastlane deliver submit_build --build_number 830の形です。

このlaneはsubmit_reviewという名前でFastfileに置き、前節のdenyに入れました。Claude Codeには「審査提出の直前まで」を任せ、最後の1回は自分の端末で打ちます。

lane :submit_review do
  deliver(
    submit_for_review: true,
    automatic_release: false,
    skip_metadata: true,
    skip_screenshots: true,
    skip_binary_upload: true
  )
end

build_numberを省くと、編集中のバージョンについて最新のビルド番号が自動で選ばれます。意図したビルドかどうかは、app_store_build_numberやlatest_testflight_build_numberで現在値を見てから提出します。

認証キーをClaudeに読ませない

Fastlaneの認証は、App Store Connect APIキーが推奨されています。2FA(二段階認証)が要らない点と、性能・信頼性の向上が利点に挙げられています。従来のApple ID認証は、クッキー方式のWebセッションを使います。app_store_connect_api_keyアクションに、キーID、発行者ID、.p8ファイルのパスを渡す形が基本になります。

キーの渡し方で、Claude Codeの運用に直結する点が2つあります。

  • キーの値は環境変数に置き、Fastfileには変数名だけを書きます。FastfileをClaudeが編集・表示してもキー本体は出ません。
  • .p8ファイルは、Read(**/*.p8)のdenyで読み取りを止めます。Readのdenyは、.envのようなファイル名のパターンでも書けます。

.p8は認証に使う秘密鍵です。リポジトリには入れず、.gitignoreにも載せておきます。

Fastfileそのものをaskで守る

ここが最大の穴です。lane名で権限を分けても、ClaudeがFastfileのbuild_onlyの中にupload_to_app_storeを足せば、allowのlaneが外部に書き込めます。またreleaseのsubmit_for_review: falseをtrueに直せば、askの承認を通った1回で審査提出まで進みます。

Edit(fastlane/**)をaskに入れたのは、このためです。Fastfile、Appfile、Deliverfileへの変更は毎回差分が見えます。承認画面で見るのは次の3点です。

  1. build_onlyとverifyに、upload_*やdeliverの呼び出しが増えていないか
  2. submit_for_review、automatic_release、forceの値が変わっていないか
  3. skip_*系のオプションで、意図しない範囲の書き込みが生まれていないか

より確実にしたい場合は、PreToolUseフックでFastfileの変更内容を検査する方法があります。終了コード2で終わるフックは、権限ルールの評価より前にツール呼び出しを止めます。たとえば編集後のFastfileにsubmit_for_review: trueが含まれていたら拒否する、といった判定です。フックの考え方は、実行後に走るPostToolUse hookでの後処理と同じ仕組みで、実行前に挟む点が異なります。

ルールが止められないもの

権限ルールは、Claudeが書いたコマンドの文字列に一致する範囲しか止められません。Bash(git push *)のdenyがgit -C . pushを止めないのと同じで、/usr/local/bin/fastlaneのようなパス指定やsh -c経由の実行には別の対処が要ります。権限ルールの限界として、ドキュメントにも「セキュリティ境界ではない」旨が書かれています。

そのため、次の層を組み合わせます。

層止めるもの向いている使い方
権限ルール(ask・deny)止めるもの通常の呼び方のlane実行向いている使い方日常の確認とログ
PreToolUseフック止めるものコマンド全文とFastfileの中身向いている使い方抜け道になる書き方の検査
サンドボックス止めるものファイルとネットワーク向いている使い方外部通信そのものの制限
CLAUDE.md止めるものClaudeの手順の選び方向いている使い方呼び方の統一(強制力はない)

CLAUDE.mdは強制力を持たないので、守らせたい制約の本体にはしません。呼び方の統一と、確認の手順を書く場所と割り切ります。

CLAUDE.mdに書く規約の断片

Claudeがlaneを選ぶ手がかりとして、次のような記述を置けます。

## リリース手順(Fastlane)
- 実行は必ず `bundle exec fastlane <lane>` の形にする
- 変更後はまず `build_only` と `verify` を実行し、結果を報告する
- `beta` と `release` は承認を得てから実行する。送信先と内容を事前に説明する
- `submit_review` は実行しない。必要なときは実行コマンドを提示して止まる
- Fastfile の変更では、upload 系アクションと submit_for_review の値を差分で示す
- APIキー(.p8)は読まない。キーは環境変数 ASC_KEY_ID / ASC_ISSUER_ID / ASC_KEY_PATH で渡される

実際に回す順序

初回は次の順序で進めると、どこで確認が入るかが体感できます。

手順

Fastlaneのリリース工程を回す順序

  1. 1

    Fastfileを書かせる

    build_only、verify、beta、release、submit_reviewの5つのlaneを作らせます。upload系はFastlaneのアクション名の一覧で確認させます。

  2. 2

    allowのlaneで動作を確かめる

    build_onlyでipaを作り、verifyでApp Store Connectでの検証だけを通します。承認は求められません。

  3. 3

    askのlaneで確認を受ける

    betaを実行させると、権限プロンプトが出ます。lane名と、これから外へ送るものを見て承認します。

  4. 4

    提出は自分で打つ

    submit_reviewは自分の端末で実行します。直前にapp_store_build_numberなどで対象のビルド番号を見ます。

Fastlaneで使えるアクションの名前とオプションは、fastlane actionsで一覧を、fastlane action アクション名で個別の説明を出せます。

bundle exec fastlane actions
bundle exec fastlane action upload_to_testflight

どちらも読むだけのコマンドです。Bash(bundle exec fastlane action *)はactionsに一致しないので、一覧用にBash(bundle exec fastlane actions)もallowに足します。

つまずきやすい点

落とし穴

askのlaneを直接のコマンドで迂回される

lane経由のbetaをaskにしても、bundle exec fastlane pilot uploadの直接呼びは別のコマンドです。pilot、deliver、supplyをaskに足していない設定では、承認なしで同じ書き込みが通ります。

もう1つは、環境変数の渡し方です。Claude Codeの子プロセスにASC_KEY_PATHなどが渡らないと、verifyが認証エラーで止まります。シェルの設定に書いたうえで、Claude Codeを起動したシェルの環境で動かします。

最後に、deliverをipaなしで直接呼ぶ癖です。メタデータだけが書き換わるため、askの対象に残しておく意味があります。

任せる範囲を狭く始める

Claude Codeに向いているのは、Fastfileの下書きと、ビルドエラーの読み解き、検証laneの反復です。外部に残る操作は、lane名のaskとdenyで線を引き、Fastfileの変更を差分で見る運用にすると、任せる範囲を広げても確認点が残ります。

最初はbuild_onlyとverifyだけをallowにし、betaをaskに加えるのは、検証laneの結果がClaudeの報告と一致することを何度か見てから、という進め方もあります。IDE内でのAI支援を使いたい場合は、Claude for Xcodeの使い方が入口になります。権限ルールで実行を絞る考え方は、OpenTofuでvalidateとplanだけを許可する権限設計と同じ型です。

この記事を共有:XはてブLinkedIn