python-ci について
Python リポジトリの GitHub Actions 品質ゲートを設定し、堅牢化するスキルです。CI を管理する開発者向けに、バージョン別チェック、必須ステータスの集約、ブランチルール、ワークフローの安全性検証を扱います。
主な機能
- 01lint、型チェック、テストの設定
- 02Python バージョン別マトリックス
- 03安定した必須チェックの集約
- 04カバレッジ結果の統合
- 05Actions とトークン権限の強化
- 06ワークフローとブランチルールの検証
活用シーン
- 01Python リポジトリの CI ゲート構築
- 02マージキューでのマトリックス検査
- 03スキップされたジョブの誤通過防止
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ paldom/ python-skills --skill python-ciインストール後、Claude Code で/python-ciを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/ci-workflow-template.mdrequired-checks-and-rulesets.mdworkflow-hardening.mdscripts/check_workflows.py詳細
python-ci
目的
Python リポジトリ向けの GitHub Actions 品質ゲートを構築します。Python バージョンのマトリックス全体で lint、型チェック、テストを実行するワークフローを、1 つの all-checks-passed 集約ジョブにまとめ、ブランチルールセットで必須ステータスチェックとして適用し、CI が気づかないうちに弱体化する原因(成功扱いになるスキップ済みジョブ、PR を立ち往生させる名前変更済みマトリックスの各ジョブ、変更可能なアクションタグ、過度に広い GITHUB_TOKEN のスコープ、pull_request_target とキャッシュの信頼境界の穴)に対する堅牢性を高めます。CI は --no-verify で回避できない唯一の強制レイヤーです。ワークフローファイル自体を本番コードとして扱ってください。
使用しない場合
- リリース/公開ワークフロー(タグをトリガーとする PyPI 公開、信頼された公開、バージョン更新)— インストールされている場合は python-release スキルが担当します。このスキルが保証するのは、リリースジョブが
needs:で依存できる品質ゲートのみです。 - pre-commit 設定またはその CI ミラージョブ — python-precommit スキル。
- coverage.py の設定(
fail_underの値、relative_files、ソースパス)— python-testing スキル。このスキルがワークフローを通じて扱うのは、カバレッジのワークフロー内での連携(各ジョブのアーティファクト、結合ジョブの配置)のみです。 - Dependabot、シークレットスキャン、CodeQL、Scorecard、SBOM、CODEOWNERS — python-supply-chain スキル。
- CI が報告する失敗の修正(lint エラー、型エラー、テスト失敗)— python-lint/python-typing スキル、または通常のデバッグ。
ワークフロー
1. YAML を書く前にリポジトリを調査する
pyproject.tomlを読み、設定されているツール([tool.ruff]、mypy/pyright/ty、 pytest)、requires-pythonの範囲(マトリックスを定義します)、依存関係グループ (devまたはdependency-groups)を確認します。- コミット済みの
uv.lockがあるか確認します。ある場合、CI ではuv sync --lockedを使う必要があります。 ランナー内でロックファイルを再生成してはいけません。ロックファイルの変更はコミットに含めます。 - 既存の
.github/workflows/ファイルを一覧表示し、意図を持って拡張または置き換えます。また、リポジトリ設定でマージキューが有効か確認します(トリガーの組み合わせが変わります。手順 5 を参照)。 - CI ではリポジトリにすでに定義されている処理を実行します。新しいツールや、より緩い代替手段を導入してはいけません。ゲートでは開発者がローカルで実行するものと同じコマンドをチェックモード(
ruff check、ruff format --check)で実行する必要があります。先行するレイヤーが自動修正を行う場合、CI では検証のみを行います。--fixを実行するmake checkを CI のステップとして再利用してはいけません。 - 既存のコードベースで初めて CI を実行する場合は、まず lint/型チェック/テストのコマンドをローカルで実行します。一度も lint されていないリポジトリでゲートを有効にすると、確実に失敗します。ゲートを有効にする前に、クリーンアップのコミットを追加するか、該当するスキルに作業を引き継いでください。
2. 品質ゲートのワークフローを作成する
.github/workflows/ci.yml を作成します。カバレッジとアグリゲータージョブを組み込んだ、注釈付きの完全なテンプレートはこちらです:references/ci-workflow-template.md。
重要な選択肢は次のとおりです。
name: CI
on:
push:
branches: [main]
pull_request:
merge_group: # without this, merge-queue validation silently never reports
permissions:
contents: read # job-level blocks widen this only where needed
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
- ジョブ:
lint(ruff check と format --check)、typecheck(リポジトリで設定されている型チェッカー)、test(マトリックス全体で pytest)。有効な実行順序は2通りあります。どちらかを選び、理由を説明してください。3つすべてを並列実行する(実時間でのフィードバックが最速)か、test: needs: lint(10秒で済む lint の失敗時に、時間のかかるマトリックスをスキップできる一方、lint が通る場合はフィードバックが遅くなります)です。小規模なテストスイートでは、並列実行がより安全なデフォルトです。 - 環境:
enable-cache: trueとpython-version: ${{ matrix.python-version }}の入力を指定してastral-sh/setup-uvを使用します。別途actions/setup-pythonを使う必要はありません。uv sync --locked --group devでインストールし、ツールはuv run <tool>で実行します。(uv を使わない場合は、actions/setup-python@v7にcache: pipを指定し、pip install -e . --group dev(pip >= 25.1 は PEP 735 グループを読み込みます)とツールの直接実行コマンドを使う方法が代替案です。一度だけ説明したら先に進んでください。) - マトリックス:
requires-pythonにあるすべてのバージョンを引用符で囲みます。['3.11', '3.12', '3.13', '3.14'](3.10 は 2026-10 に EOL を迎え、3.15 は 2026-10-01 にリリースされます)。引用符のない3.10は YAML では浮動小数点数の3.1になります。fail-fastの選択基準は、すべてのバージョンの結果を確認する場合はfalse(ここではデフォルト)、最初の失敗が分かれば十分な迅速な PR サイクルではtrueです。パッケージがプラットフォーム依存の処理を行う場合に限り OS 軸を追加してください。軸ごとに課金対象の分数が増えます(1回のワークフロー実行で最大256ジョブ)。 - すべてのアクションを、後回しにせず初稿の段階から完全なコミット SHA(手順6)で固定してください。
3. マトリックス全体でカバレッジを連携する(ワークフロー側のみ)
リポジトリでカバレッジを測定する場合、各レッグでのゲート設定は誤りです。バージョン固有のコードを実行しないレッグがあっても、合算したカバレッジが十分であれば失敗させるべきではありません。
- 各マトリックスレッグで
COVERAGE_FILE=.coverage.py${{ matrix.python-version }}を設定してpytest --cov --cov-fail-under=0を実行し、成果物としてアップロードします。成果物名にはマトリックスの値を含めて一意にし、.coverage.*ファイルは隠しファイルなのでinclude-hidden-files: trueを指定します(pytest-cov はレッグごとに.coverageを1つ出力し、指示がない限り設定のfail_underを各レッグに適用します)。 coverageジョブ(needs: test)で全レッグの成果物をダウンロードし、uv run coverage combineとuv run coverage reportを実行します。しきい値の値と、(ランナーをまたいで結合するために必要な)relative_files = trueは、リポジトリのカバレッジ設定に記述します。これは python-testing の範囲です。このスキルでは、結合ジョブにゲートを設定するだけです。- 外部サービス(Codecov など)にアップロードしますか?結合ジョブまたは代表となる1つのレッグからアップロードしてください。すべてのレッグからアップロードすると、レポートが重複したり競合したりします。
4. アグリゲータージョブを追加する — 必須チェックはこれ1つだけ
マトリックスのレッグ名やジョブ名は変わりますが、ブランチ設定はそれらに追従しません。安定した1つのジョブでゲートを設定してください。
all-checks-passed:
runs-on: ubuntu-latest
needs: [lint, typecheck, test, coverage]
if: always() # without this the job is SKIPPED when a dep fails — and skipped counts as success
steps:
- name: Fail if any needed job did not succeed
run: |
if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}" == "true" ]]; then
echo "::error::A required job failed, was cancelled, or was skipped."
exit 1
fi
echo "All checks passed."
skippedをテストに含めるのは意図的です。依存先のif:の設定ミスを、何もせずに通過させず、表面化させられます。一部のジョブを意図的にパスフィルターの対象にする場合に限り、これを削除し、その理由を記載してください(リファレンスにはパスフィルターを使う例があります)。- ジョブ名は安定したままにしてください。名前を変更する場合、同じ PR でブランチ設定も更新しないと、何もマージできなくなります。
5. 必須にする — ルールセットまたはブランチ保護
まずワークフローを一度実行してください(ブランチをプッシュする/テスト用 PR を開く)。チェックが必須チェックの選択欄に表示されるのは、少なくとも一度結果が報告された後です。
ルールセットを推奨します(複数を重ねて適用でき、タグも対象にでき、組織レベルで設定でき、「評価」プレビューモードや、詳細に設定できるバイパス対象者を利用できます)。単一のシンプルなリポジトリなら従来のブランチ保護でも問題ありません。設定のずれを防ぐため、API 経由で設定してください。従来のブランチ保護の場合:
# --field/-F send strings (and coerce bools/ints), never nested objects — give the
# API a JSON body instead.
gh api repos/{owner}/{repo}/branches/main/protection --method PUT --input - <<'JSON'
{ "required_status_checks": { "strict": true, "contexts": ["all-checks-passed"] },
"enforce_admins": true,
"required_pull_request_reviews": { "required_approving_review_count": 1, "dismiss_stale_reviews": true },
"restrictions": null }
JSON
- 必須にするのは
all-checks-passedのみにしてください。マトリックスの各ジョブを個別に必須チェックにすると、マトリックスが変更された途端、すべての PR が停止します(「ステータスが報告されるのを待機中」)。 - 「バイパスを許可しない」を有効にする/
enforce_adminsをオンのままにしてください。そうしないと、管理者(または管理者トークンを持つエージェント)がすべてのチェックを無視してマージできます。 strict: true(ブランチが最新であることを必須にする)は、更新の多い main ではリベースを繰り返すことになります。構造的な解決策はマージキューです。マージキューを使う場合、ワークフローは 必ずmerge_groupでトリガーし、必須チェックはキューへの追加時に検証されます。- リリースのタグ付け直しをブロックするタグ保護は、ルールセットの機能です。リポジトリでアーティファクトを公開する場合は、タグのルールセットを追加してください。
ルールセットの JSON、マージキューの詳細、「PR はすべて成功しているのにマージできない」場合の診断手順については、references/required-checks-and-rulesets.md を参照してください。
6. ワークフローを強化する
詳細、理由、インシデント履歴については、references/workflow-hardening.md を参照してください。
-
すべてのアクションを SHA で固定する — 変更可能なタグは別のコミットを指すように変更されることがあります(2025 年の tj-actions の侵害では、
@vを使うすべての利用者に悪意のあるコードが配信されました)。タグを解決します。git ls-remote https://github.com/astral-sh/setup-uv refs/tags/v10\* # the `^{}` line is the commit SHA for annotated tags — pin that one形式:
uses: owner/action@<40-hex-sha> # v10.0.1— バージョンコメントは残してください。astral-sh/setup-uvは 8.0.0 でメジャー/マイナーの可変タグを削除したため、@v10は解決できず、完全なバージョンまたは SHA のみが使えます。更新ツールも人間も、このコメントを基準にします。 -
GITHUB_TOKENの権限を最小限にする:ワークフローレベルではpermissions: contents: readを設定し、ジョブレベルでは必要な場合にのみ権限を追加します。リポジトリ全体のデフォルト権限に頼らないでください。 -
zizmor でワークフローを静的解析する(テンプレートインジェクション、危険なトリガー、過剰な権限などを検出)。バージョンを固定します。
uvx zizmor==1.30.1 .github/workflows/最新リリースを https://github.com/zizmorcore/zizmor で確認し、意図的に固定バージョンを更新してください。actionlint(PyPI:
actionlint-py。検証したリリースを固定してください)を使うと、フォーマッターでは検出できない構造や構文のエラーも検出できます。 -
信頼境界:十分に理解していない限り、
pull_request_targetは避けてください。PR コードのチェックアウトやキャッシュの読み書きと組み合わせると、シークレットの流出やキャッシュ汚染につながる実際の攻撃経路になります。Actions のキャッシュはリポジトリごとの名前空間で共有されます。シークレットは決してキャッシュせず、フォークからの PR が書き込めるキャッシュは、後続の信頼されたジョブに対する信頼できない入力として扱ってください。 -
以下の
scripts/check_workflows.pyを実行し、上記すべての回帰を確実に検出してください。
7. エンドツーエンドで検証する
python3 "${CLAUDE_SKILL_DIR}/scripts/check_workflows.py" --repo . # unpinned actions, float versions, missing if: always(), ...
uvx zizmor==1.30.1 .github/workflows/ # security findings
git switch -c ci-setup && git push -u origin ci-setup
gh pr create --fill && gh pr checks --watch # every job green, aggregator reports
その後、ブランチルールで all-checks-passed を選択でき、選択済みであることを確認してください。また、マージキューが有効な場合は、キューに追加した PR が実際にマージされることも確認してください。
出力仕様 — 完了状態の定義
.github/workflows/ci.yml:lint + typecheck + test-matrix + (coverage)+all-checks-passedを含むこと。トリガーにpull_requestとmerge_groupを含め、ワークフローレベルでpermissions: contents: readを設定し、PR の同時実行をキャンセルし、すべてのアクションをバージョンコメント付きの SHA で固定し、マトリックスのバージョンを引用符で囲み、uv sync --lockedを使うこと。mainのブランチルールセット(または従来の保護設定)で、all-checks-passedのみを必須にし、管理者も対象に含め、古いレビューを却下する設定を有効にすること。- 最終ツリーに対して
scripts/check_workflows.pyと zizmor がどちらも終了コード 0 を返すこと。 - フルゲートが成功した PR を用意すること。また、PR の説明に、ゲートで検証する内容と、ジョブ名を変更する場合は同じ PR でブランチ設定も更新する必要があることを明記すること。
失敗のパターンと注意点
| 症状/リスク | 原因と対処 |
|---|---|
| PR が「ステータスの報告待ち」のまま止まる | 必須チェックが、名前を変更または削除したジョブやマトリックスの実行対象に紐づいています。アグリゲーターを条件に設定し、設定とジョブ名を同じ PR で更新します。 |
| ジョブが失敗しているのにアグリゲーターが成功になる | if: always() がありません。ジョブがスキップされ、スキップされた必須チェックは成功として扱われます。明示的な結果チェックは不可欠です。 |
| PR のチェックは通過したのにマージキューが止まる | ワークフローに merge_group トリガーがないため、キュー処理時に必須チェックが報告されません。 |
| マトリックスで Python 3.1 が実行される | 引用符のない 3.10 が浮動小数点数として解析されています。すべてのバージョンを引用符で囲みます。 |
| 1 つの失敗でマトリックスの全対象がキャンセルされる | fail-fast のデフォルトは true です。デバッグ時や全バージョンの結果が必要な場合は false に設定します。 |
| ある対象でカバレッジが失敗するが、全体では問題ない | 対象ごとにしきい値が適用されています。先に結果をまとめ、結合ジョブで一度だけ判定します。 |
| 設定で必須チェックを選択できない | まだ一度も実行されていません。ワークフローを一度(push/PR で)トリガーしてから選択します。 |
| すべて通過したのにマージがブロックされる | ワークフローファイル間でジョブ名が重複すると、チェックのコンテキストが曖昧になります。リポジトリ全体でジョブ名が重複しないようにします。 |
| エージェントの PR 後に CI は通過するが、ゲートが弱くなっている | ワークフローの差分で || true、削除されたステップ、緩和されたトリガー、編集されたしきい値を確認します。サーバー側の必須チェックと管理者による適用だけが、ローカルエージェントによる自己変更を防げる層です。.github/ への CODEOWNERS(サプライチェーンスキル)を設定すれば、レビューを追加できます。 |
| ボットによる push/タグ付け後にワークフローがトリガーされない | デフォルトの GITHUB_TOKEN で作成されたイベントは、新しいワークフローの実行を開始しません。ワークフローを連鎖させるには、GitHub App トークンまたは PAT が必要です(python-release の範囲です)。 |
| Ruff のリリース直後にフォーマットチェックが失敗する | ツールのバージョンはロックファイルから取得する必要があるため(uv sync --locked)、CI とローカル実行で同じバージョンが使われます。ワークフローのステップで、バージョンを固定せずに pip install ruff を実行しないでください。 |
| フォークからの PR によるキャッシュ汚染 | pull_request_target とキャッシュ書き込みの組み合わせは、権限昇格につながる経路です。2026-06-26 以降、信頼できないトリガー(pull_request_target、issue_comment、フォークからの workflow_run)では、デフォルトブランチのスコープに対して読み取り専用のキャッシュトークンが付与されます。これを最低限の対策としつつ、フォークから書き込み可能なキャッシュは悪意あるものとして設計してください。 |
同梱リソース
- references/ci-workflow-template.md —
コメント付きの完全な
ci.yml(マトリックス、カバレッジの結合、アグリゲーター)と、 バリエーション:needs:で連鎖させたジョブ、パスフィルター付きアグリゲーター、動的マトリックス。 - references/required-checks-and-rulesets.md —
アグリゲーターパターンの選択肢、ルールセットと従来の保護設定、
gh apiのレシピ、 マージキュー、タグルールセット、マージブロックの診断手順。 - references/workflow-hardening.md — SHA
のピン留め(および Dependabot-alerts とのトレードオフ)、
GITHUB_TOKENのスコープ設定、zizmor と actionlint の使い方、pull_request_targetとキャッシュの信頼境界。 scripts/check_workflows.py—.github/workflows/用の読み取り専用ハイジーンスキャナー。 検出事項がある場合は終了コードが 0 以外になり、検出事項ごとに機械可読な行を 1 行出力します。手順 7 と、ワークフローを編集した後に実行してください。