`gh.sh` ラッパースクリプトのバリデーション強化とエラーメッセージの改善

anthropics/claude-code

issue-triage・dedupeワークフローで使用される gh.sh ラッパースクリプトに、入力バリデーションの厳格化と明示的な環境変数ピン留めが追加されました。これにより、誤った入力に対してサイレントに失敗していた挙動が、原因を説明する診断メッセージ付きの明示的なエラーへと改善されます。

背景

gh.sh は、Claude Codeのワークフロー内で gh CLIの実行を制限付きでラップするシェルスクリプトです。issue viewissue listsearch issueslabel list の4サブコマンドのみを許可するアローリスト方式を採用し、任意の gh コマンド実行を防いでいます。

従来の実装には、二つの課題がありました。一つ目は、バリデーション失敗時に exit 1 のみが実行され、何が問題だったかを一切出力しないため、ワークフローのデバッグが困難だった点です。二つ目は、GH_REPOGH_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 listlabel 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は、セキュリティのためのアローリスト設計はそのままに、フェイルファスト(早期失敗)と診断可能性の両面を強化した変更です。環境変数を先頭でピン留めすることで意図しないリポジトリへの操作を防ぎ、全エラーパスに使用例付きメッセージを追加することで、ワークフローの問題解析コストを大幅に削減します。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
8e4dd7c6

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「総論→各論→結論」の3部構成が記事全体に適用されており、リード文、背景、技術的な変更、設計判断、まとめの各要素がすべて含まれ、明確に構成されています。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトは正しく使用されています。しかし、別リポジトリへのPRリンク `[claude-code-action#996](URL)` が、ガイドラインが例示する `[#123](URL)` 形式とは異なります。リポジトリを明示するため実用上は適切ですが、厳密にはガイドラインの例と一致していません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

内容はシェルスクリプトやGitHub Actionsに関する知識を持つエンジニア向けであり、専門用語のレベルや説明の粒度が対象読者に適切です。過度な初心者向けの説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションの冒頭に要旨が述べられ、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が非常によく守られています。1段落1トピック、適切な段落長も遵守されており、可読性が高いです。

Diff内容との照合 ⚠ WARNING

コードブロックとDiff内容の一致

提供されたDiffに含まれるコード引用は正確です。しかし、`issue view`のバリデーションに関するコードブロックは提供されたDiffスニペットに含まれておらず、完全な照合ができませんでした。ただし、PRのDescriptionとの整合性は高く、コードも技術的に妥当です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`gh CLI`, `アローリスト`, `git-remoteの推論`, `globパターン`といった技術用語が、PR情報と一致しており、文脈上も正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

環境変数のピン留めやリポジトリ名のフォーマット検証ロジックなど、技術的な変更点に関する説明は、Diffの内容と整合性が取れており、論理的かつ正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事で述べられているすべての主張(従来の課題、変更の目的、関連PRの存在など)は、提供されたPRのタイトル、Description、Diffの内容によって裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#30066)、関連PR番号(claude-code-action#996)、コマンド名、環境変数名などの数値・固有名詞はすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルは、元のPRのタイトル「Improve gh.sh wrapper: stricter validation and better error messages」の内容を的確に反映しており、主題のズレはありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に記載のない、バージョンのサポート状況やリリース日程といった外部知識の追記は見られませんでした。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「従来」「...していた挙動が」といった時間表現は、PR内の「previously」などの記述と一致しており、正確です。