この記事で扱うこと
機能コードではなく、開発環境(ツール・ビルド・CI設定)そのものを整備した日だった。表面はそれぞれ違ったが —フックスクリプトが効かず、モノレポ公開が壊れ、自動リリースが回らず、危険なコマンドのガードを新しく付ける— 貫く教訓は一つだった。「動かないもの」への最初の疑いはツールのバグではなく、配線(引用符・バージョンプロトコル・ランナーラベル)だということ。
ここでは、その日に出会った概念を特定の会社・プロジェクトとは無関係の汎用知識としてのみ整理する。
一日のまとめ
| 概念 | どんな問題だったか | 学んだこと |
|---|---|---|
| シェルの単語分割・引用符 | 値は正しいのにコマンドだけ失敗 | 空白パスは "$VAR" で引用 |
| モノレポworkspace公開 | 内部依存が外部インストールで壊れる | workspace:* は pnpm publish で置換 |
| CIランナーの不一致 | 「リリースツールの誤動作」 | ログのない失敗=ランナー・権限の問題 |
| fail-openガード | 安全装置が作業を止める | 故障時は通過、明白な災厄だけ遮断 |
1. 値は正しいのにコマンドだけ失敗 — シェルの単語分割
どんな状況だったか。 自動実行されるフックスクリプトが ${PLUGIN_ROOT}/hook.sh を実行するのだが、パスに空白がある環境では何の反応もなかった。変数の値を出力してみると明らかに正しいのに、実行だけが失敗した。
何を学んだか。 シェル(bash・zsh)は変数を展開したあと、その結果を空白を基準に複数の引数へ分割する(単語分割、word splitting)。/tmp/My Files/hook.sh が /tmp/My + Files/hook.sh の二つの断片になり、スクリプトを見つけられない。"${PLUGIN_ROOT}/hook.sh" と引用すれば、値一つが引数一つとして保たれる。フックやCIのように人があまり見ないスクリプトでは、このミスは静かに壊れるので、パス・ファイル名は例外なく引用するのが基本だ。
2. 内部依存が外部インストールで壊れる — モノレポworkspace公開
どんな状況だったか。 複数のパッケージが一つのリポジトリに住むモノレポで、公開したパッケージを外部でインストールすると依存が解決されなかった。別のパッケージは存在しないバージョンを依存に埋め込んでいて、CIのインストールが404で落ちた。
何を学んだか。 モノレポは内部依存を "pkg": "workspace:*" でリンクし、ローカルのソースを即座に反映する。しかしこの workspace:* をそのまま公開すると、外部の利用者は解釈できない。pnpm publish(ワークスペースを理解するマネージャー)は公開時にこれを実際のバージョンへ置換するが、npm publish はできない。公開は依存の下(葉)から上げなければならず、pnpm publish は npm OIDC(トークンなし公開)ができないので、公開トークンが必要だ。
3.「ツールの誤動作」の正体はインフラ — CIランナーの不一致
どんな状況だったか。 自動リリースが「誤動作する」との報告。ところが失敗したジョブにはステップログがそもそもなかった。
何を学んだか。 CIジョブは runs-on ラベルで実行するランナー(ジョブを回すマシン)を選ぶ。組織がクラウドホスト型ランナーをやめてself-hostedに移したのに、リリースジョブだけ以前のラベル(ubuntu-latest)をそのままにすると、そのジョブは割り当てるランナーがなく開始すらできず、ログも残さない。ツールのバグではなくインフラ配線の問題だった。ログのないCI失敗は、コードではなくランナー・権限・トリガーをまず見る。 部分移行の残り(たまに回るジョブ)を見逃さないよう、リポジトリ全体の runs-on を一度に揃えるのが予防策だ。
4. 安全装置が壁にならないように — fail-openガード
どんな状況だったか。 危険なコマンドを止めるガードフックを新しく付けた。問題は、このガードが自ら故障すると(依存ツールの不在、パース失敗)、シェル全体を止めてしまいかねないことだ。
何を学んだか。 ガードが故障したとき、通過させればfail-open、遮断すればfail-closedだ。開発の利便性ツールのガードはfail-openにして(依存がなければ通過)、安全網が壁にならないようにする。逆に、認証・決済・データ破壊のようなセキュリティ境界はfail-closedだ。また、ガードは明白な災厄だけを止めるべきだ — 曖昧なものまで止めると誤検知が頻発し、ユーザーがガードを切ってしまい、網ごと消える。グローバル設定に入れる前に、危険・正常のケースでself-checkし、バックアップを残す。