クラウド上の Mac を「ただのランナー」として扱い続けると、フォークからの pull_request に本番署名キーが流れ込んだり、App Store 審査に近い実機を通さないビルドが出荷されたりします。本稿は 2026 年版として、プール分割が必要なチーム、3 つの分離モデルを 1 つの表で比較する方法、シークレットの流れ方、そして SSH 付き専用 Mac mini M4 で実行できる実装ステップ九項目をまとめます。
すでにMac mini M4 上のセルフホスト GitHub Actionsを運用しているなら、環境分離は第二プロダクトラインや外部コントリビュータを迎える前の成熟段階です。
混在プールがセキュリティとリリース負債を同時に増やす理由
Apple のツールチェーンはプロビジョニングプロファイル、Xcode キャッシュ、Derived Data、公証資格情報など長寿命状態を前提にします。同一ユーザーがフォーク由来ワークフローとストアアップロードの両方を実行できると、利便性の裏で監査とインシデント対応が難しくなります。プラットフォームチームは早めに境界を引かないと、「どのマシンが顧客データや署名素材に触れたか」を個別に説明できず、チェックリストだけが肥大化します。
- PR スクリプトのブラスト半径:悪意またはミスによる
run:ブロックはランナーのホームを読み取れます。App Store Connect API キーがディスクに残ったことがあると、到達範囲を後から縮小するのは困難です。 - 非決定的なリリース品質:ステージングでベータ Xcode や Rosetta 設定を変えると、次の本番ジョブに影響が残ります。イミュータブルイメージかホスト分離がなければ再現性を保証できません。
- 監査の疲労:コンプライアンスでは「どのマシンが署名に関与したか」を問われます。単一プールでは答えが常に「すべて」になり、提出資料とリードタイムが伸びます。
経験則:フォークから pull_request で起動しうるワークフローは、本番証明書を保持するワークフローとランナーラベルを共有してはいけません。ブランチ保護の強さは関係ありません。
意思決定マトリクス:Mac CI の分離をどこまで厳しくするか
| プールモデル | 月間運用工数の目安 | ブラスト半径 | 向いている場面 |
|---|---|---|---|
| 単一共通プール | 8 エンジニア時間未満 | 最大 | 社内リポのみ、フォークビルドなし、App Store アップロードなし |
| 論理分離(ラベル+環境) | 12〜20 エンジニア時間 | 中程度 | 信頼できるコントリビュータ、厳格な GitHub Environment、環境単位のシークレット |
| 物理分離(層ごと専用 Mac) | 24〜40 エンジニア時間 | 最小 | 規制業界、公開 OSS、モバイルと AI エージェントの並行ワークロード |
ラベル早見表:スケジューラを正直に保つ
mac-ci-dev は機能ブランチと実験 Xcode 向け。タグや release/* の保護パスは禁止。mac-ci-stg は main 統合と TestFlight ベータ向け。手承認なしのフォーク PR は禁止。mac-ci-prod はストアアップロード・公証・エンタープライズ IPA のみ。外部コラボレーターの pull_request は禁止。コードレビュー時に新規ワークフローの runs-on を必ず確認する運用にするとラベル逸脱を防げます。
シークレット、署名、監査に耐える昇格パス
分離はハードウェアだけでなく資格情報の流れです。本番ランナーは必須レビュア付き GitHub Environment 経由でのみシークレットを受け取り、ステージングは別名前空間の環境を使います。顧客向けバイナリを出せるトークンはすべて層にマッピングし、誤ってラベル付けされたランナーでフォーク PR が走った場合は 24 時間以内のキーローテーションとキーチェーン掃除を手順書に書いておくと、事後説明が格段に楽になります。
- シークレットを層に割り当てる:App Store Connect キー、エンタープライズ配布プロファイル、SaaS トークンを一覧化し、顧客向け成果物に繋がるものは本番ラベルホスト専用にします。
- 昇格ワークフローを使う:ステージングは未署名または ad hoc 成果物を出し、
workflow_dispatchまたは保護ブランチからruns-on: [self-hosted, macOS, prod]のみで動く別ジョブを起動します。 - インシデント後 24 時間以内にローテート:フォーク PR が誤タグのランナーで実行されたら、キーチェーン消去と API キー失効をオンコール手順に含めます。
- ディスクスナップショットを分ける:ステージング Mac は週次クリーン、本番はメンテナンスウィンドウのみ変更管理でアップグレードします。
- マシン ID を記録:シリアル番号や NodeMac インスタンス ID をランナー名と突合し、監査で物理 Mac とビルドを追跡できるようにします。
NodeMac クラウド Mac で分割プールを載せる九ステップ
香港・東京・ソウル・シンガポール・米国など、SSH と VNC 付きの専用 Mac mini M4 を NodeMac から借りる前提です。接続の基本はヘルプ/ドキュメントを参照してください。
- 最低 2 台の Mac miniを用意——ステージング用と本番用——AI エージェント用サンドボックスを分けるなら 3 台目も検討します。
- OS ユーザーを分ける(
runner-stgとrunner-prod)ことでホームディレクトリの漏えいを跨がせません。 - GitHub ランナー名を別々に登録し、その層のラベルだけを付与。同一 OS ユーザーに両方のラベル族を混在させないでください。
- Xcode 版を意図的に揃える:本番は 1 ビルドに固定、ステージングはマイナー 1 つまでの遅れを許容してコンパイラ回帰を早期検知します。
- 本番向け GitHub Environmentsに保護ルールと初回コントリビュータの必須レビューを設定します。
- ディスク衛生はステージングのみ自動化:空き容量が 120 GB を下回ったら DerivedData を削除する cron を。本番はサイレント削除ではなくアラートにします。
- テレメトリをエクスポート:ランナーログを可観測性基盤へ送り、本番 Mac のジョブ時間がローリング中央値の 2 倍 を超えたら通知——多くは競合か誤ルーティングです。
- 四半期ごとにゲームデイ:偽のフォーク PR で本番ラベルを取りに行き、GitHub のワークフローグラフでブロックされることを確認します。
- ロールバックを文書化:本番 Xcode アップグレード失敗時に備え、前の
.xipをコールドストレージに残し、45 分以内の再インストールをリハーサルします。
FAQ:ステージングと本番の Mac CI プール
ステージングと本番の CI には物理 Mac を分ける必要がありますか?
必須ではありませんが、ランナー ID・ラベル・シークレット範囲を分離し、信頼できない pull_request を実行したマシンが本番ジョブを取れないようにする必要があります。層ごとに専用 Mac mini M4 を置くのが最も強い分離であり、規制領域の質問票にも答えやすくなります。
本番用 Mac 1 台あたりの同時ジョブ数は?
コード署名と成果物アップロードを伴うリリースビルドでは、まず Mac あたり 1 ジョブから。ステージングはディスク IO、Swift パッケージグラフ、複数シミュレータの UI テストの有無に応じて M4 あたり 2〜4 の軽量ジョブが現実的です。
環境横断の汚染をいち早く検知するには?
本番ラベルなのに pull_request イベント由来のワークフローでないかアラートし、ステージング専用ホストにのみあるはずのプロファイルや App Store Connect キーを監視します。新しいモバイルチームのオンボーディング時は VNC でのスポット監査と組み合わせると効果的です。
地理的に分散したプールが必要なら、香港・日本・韓国・シンガポール・米国に Mac を追加し、ステージングは開発者の日常ルートに近づけ、本番は公証エンドポイントに近いリージョンに置けます。NodeMac の料金プランで層ごとの台数を見積もり、単一ホストの過剰割当を避けてください。
Mac mini M4 は層別 CI を経済的に現実的にします。Apple Silicon は Xcode の並列負荷に必要な CPU・GPU・Neural Engine のスループットを提供しつつ、アイドル時の消費電力は本番専用ランナーを常時オンにしても負担が小さい水準です。NodeMac は専用物理 Mac miniを提供し、過剰割当 VM のノイジーネイバーではありません。SSH と VNC の両方があり、署名失敗を対話的に追えます。香港・日本・韓国・シンガポール・米国をカバーするため、エンジニアの近くにステージング、Apple 公証ファブリックに近い場所に本番を置けます。資本的な一括購入は不要で、月額レンタルなら TCO を予測しやすく、分割プールモデルを検証してからフリート拡大へ進めます。