MimiCatLab
← ホームに戻る
Unity

Unity ビルドへ .env の秘密情報を焼き込む:失敗時に残さない設計

Installer Asset に Webhook URL を書く運用をやめ、.env からビルド時だけ焼き込む。callbackOrder の向き、OnPostprocessBuild が呼ばれない失敗ビルド、BOM と引用符の往復バグ。

何に困っていたか

当初、YouTube 用の JWT や Discord の Webhook URL を、各パッケージの Installer Asset(ScriptableObject)に直接保存していた。Inspector から編集できて手軽だが、Asset はリポジトリにコミットされる。「この Asset を公開リポジトリへコミットしないでください」という注意書きを添えるしかなく、人間の注意力に依存していた。

さらに環境名が二重管理だった。YouTube 側の Installer が独自に環境名を持ち、Core の McSettings.Environment(Develop / Production)と切り替え場所が 2 か所に分かれていた。「本番の .env を読んでいるつもりで develop を読んでいた」が起きうる構造である。

どう設計したか

  • 秘密情報は .env.<環境名> に置き、Editor 実行時はファイルを直接読む。
  • ビルド時だけ、選択中の .env の全エントリを Resources 配下の一時 ScriptableObject(McEnvBakedSecrets)へ焼き込み、ビルド後に削除する。
  • 公開窓口は McEnv.TryGet の 1 本。追加パッケージは Core を通してだけ読む。
  • 環境名は McSettings.Environment に統合し、切り替えは Project Settings の 1 か所にする。
  • Installer の Inspector からの入力は書き込み専用の伏せ字欄にする。既存の値を読み戻さず、Asset にも保存せず、入力中の文字列もシリアライズしない。
// 読む側
McEnv.TryGet("MIMICATHUB_DISCORD_WEBHOOK_" + McEnv.ToKeySegment(key), out url, out reason);

// Installer から書く側(追加パッケージが触れる唯一の窓口)
McEnvEditorUtility.SetValue("MIMICATHUB_YOUTUBE_JWT", input.Trim());

ログには値もキー名も出さない。出すのは環境名とエントリ件数だけである。.env が無くてもビルドは止めず警告に留め、必要キーの有無は各パッケージの検証処理が判定する。

何が起きたか

焼き込みの順序が逆だった。 焼き込み処理の callbackOrder を当初 -1000 にしていた。追加パッケージ側の検証(callbackOrder = 0)より先に焼き込みが走るので、検証が BuildFailedException でビルドを止めても、秘密情報はすでに Assets 配下へ書き出されていた。+1000 に変えて「検証が通ってから焼き込む」順にした。

public int callbackOrder => 1000;   // 検証(0)より後に焼き込む

失敗ビルドでは OnPostprocessBuild が呼ばれない。 後処理での削除だけを想定していたので、失敗のたびに焼き込んだ Asset が残った。起動時の掃除([InitializeOnLoadMethod])を保険として入れたが、「次の Domain Reload まで残る」時間窓は消えない。最終的に McBuildPipeline.Buildfinally から必ず削除を呼ぶようにした。

.env の読み書きで刺さった。 先頭に UTF-8 の BOM が残っていると 1 行目のキーだけ読めない。前後に空白のある値や引用符付きの値をそのまま書くと、読み直した時に別の値になる。設定 Asset を新規作成した直後にキャッシュが古いまま残る。いずれも「単純な形式」ほど往復(書いて読む)テストを厚くすべき類型だった。

教訓

  1. 秘密情報が「残る」経路を全部数える。 正常系の後処理だけでは足りない。失敗・例外・中断のすべてで削除が走るか、finally まで降りて確認する。
  2. ビルドフックの実行順は仕様である。 callbackOrder の符号ひとつで「検証失敗時に秘密が書き出されるか」が変わる。意図をコメントに残す。
  3. 設定の持ち場所は 1 か所に寄せる。 二重管理は切り替え忘れの温床になる。
  4. 秘密情報の UI は書き込み専用が正しい既定。 読み戻さないので、画面共有経由の漏洩が構造的に消える。伏せ字欄は入力の有無が分からないので「入力中:N 文字」を併記する。
  5. テキスト設定ファイルは BOM・空白・引用符で必ず刺さる。

注意点

焼き込み先は暗号化していない。ビルド成果物を解析すれば値は読める。自分たちで運用する配信用ビルドを前提にしており、第三者へ配布するビルド向けの保存方式は別途設計する。起動時の掃除は保険として残しているが、これが発火したら finally を通らないビルド手段があったということなので、原因を追う。

Related Articles