`gh.sh` ラッパースクリプトのバリデーション強化とエラーメッセージの改善
issue-triage・dedupeワークフローで使用される gh.sh ラッパースクリプトに、入力バリデーションの厳格化と明示的な環境変数ピン留めが追加されました。これにより、誤った入力に対してサイレントに失敗していた挙動が、原因を説明する診断メッセージ付きの明示的なエラーへと改善されます。
背景
gh.sh は、Claude Codeのワークフロー内で gh CLIの実行を制限付きでラップするシェルスクリプトです。issue view・issue list・search issues・label list の4サブコマンドのみを許可するアローリスト方式を採用し、任意の gh コマンド実行を防いでいます。
従来の実装には、二つの課題がありました。一つ目は、バリデーション失敗時に exit 1 のみが実行され、何が問題だったかを一切出力しないため、ワークフローのデバッグが困難だった点です。二つ目は、GH_REPO や GH_GITHUB_REPOSITORY が未設定の場合、gh コマンドがgit-remoteの推論にフォールバックし、意図しないリポジトリに対して操作が実行される可能性があった点です。
本PRはanthropis/claude-code-actionリポジトリの claude-code-action#996 と同一の変更であり、両リポジトリで同期的に適用されています。
技術的な変更
変更の柱は三つあります:環境変数の明示的ピン留め、コマンドごとの引数バリデーション強化、そして全エラーパスへの診断メッセージ追加です。
環境変数のピン留めがスクリプト冒頭に移動・強化されました。
変更前:
REPO="${GH_REPO:-${GITHUB_REPOSITORY:-}}"
# (フラグ処理・コマンド解析の後で参照)
変更後:
export GH_HOST=github.com
REPO="${GH_REPO:-${GITHUB_REPOSITORY:-}}"
if [[ -z "$REPO" || "$REPO" == */*/* || "$REPO" != */* ]]; then
echo "Error: GH_REPO or GITHUB_REPOSITORY must be set to owner/repo format (e.g., GITHUB_REPOSITORY=anthropics/claude-code)" >&2
exit 1
fi
export GH_REPO="$REPO"
GH_HOST=github.com を明示的にエクスポートすることで、gh がGitHub Enterprise等の別ホストに接続することを防ぎます。また owner/repo フォーマットの検証として */*/* パターン(スラッシュ3つ以上)と */* パターン(スラッシュなし)の両方を弾くことで、形式不正なリポジトリ名での実行を早期に失敗させています。
サブコマンドごとのバリデーションも追加されました。特に issue view では、引数が数値1個であることを厳格に要求します:
elif [[ "$CMD" == "issue view" ]]; then
ISSUE_NUM="${POSITIONAL[0]:-}"
if [[ -z "$ISSUE_NUM" || ! "$ISSUE_NUM" =~ ^[0-9]+$ ]]; then
echo "Error: 'issue view' requires exactly one numeric issue number (e.g., ./scripts/gh.sh issue view 123)" >&2
exit 1
fi
gh "$SUB1" "$SUB2" "$ISSUE_NUM" --repo "$REPO" "${FLAGS[@]}"
URLやその他のフォーマットを拒否し、純粋な数値のみを受け付けます。issue list と label list については、これらのコマンドが位置引数を受け付けない仕様のため、ゼロ位置引数強制(positional引数があればエラー)が追加されています。
フラグバリデーション失敗時の出力も改善されました:
変更前:
if [[ "$matched" == false ]]; then
exit 1
fi
変更後:
if [[ "$matched" == false ]]; then
echo "Error: only --comments, --state, --limit, --label flags are allowed (e.g., ./scripts/gh.sh issue list --state open --limit 20)" >&2
exit 1
fi
すべてのエラーパスで、使用例付きの診断メッセージが標準エラー出力に書き出されるようになっています。
設計判断
フォーマット検証をglobパターンで実装する方式が採用されました。owner/repo の検証に正規表現ではなくシェルのglobマッチ(*/*/* と */* の組み合わせ)を使っている点は、外部コマンドや追加のサブシェルを必要とせず、純粋なシェル組み込み機能で完結する軽量な実装です。
環境変数のピン留めをスクリプトの先頭(引数解析よりも前)に移動した点も意図的な判断です。これにより、リポジトリが特定できない状態でのコマンド実行を、引数解析フェーズに入る前に確実に阻止できます。search issues の --repo オプション渡しは以前から存在していましたが、REPO が空でも gh がgit-remoteにフォールバックするためにチェックをすり抜ける余地がありました。今回の変更はそのリスクを根本から排除しています。
エラーメッセージにusage例を含める設計は、AIワークフローのコンテキストで特に有効です。エラー出力はワークフローのログや、Claude自身へのフィードバックとして利用されるため、次のアクションが自明な形式で情報を提供することが重要です。
まとめ
本PRは、セキュリティのためのアローリスト設計はそのままに、フェイルファスト(早期失敗)と診断可能性の両面を強化した変更です。環境変数を先頭でピン留めすることで意図しないリポジトリへの操作を防ぎ、全エラーパスに使用例付きメッセージを追加することで、ワークフローの問題解析コストを大幅に削減します。