#10 PyPI公開自動化 (Trusted Publishing) - Python OSS開発記録
タグをpushするたびに「PyPIにログインして、パッケージアップロードして...」ってやっていませんか?
Trusted Publishingを使えば、シークレット不要で自動公開できます。wagtail-reusable-blocksでの設定を振り返ります。
KEY TAKEAWAYS
この記事でわかること
- リリース自動化の本質(PyPI/k8s/EC2、考え方は同じ)
- Trusted Publishingの仕組みとメリット
- TestPyPI → PyPIの2フェーズリリースの実装
用語の定義
TERM 01
Trusted Publishing
PyPIの公式機能です。OIDC (OpenID Connect) を使った認証方式で、APIトークン不要でパッケージを公開できます。GitHub Actionsと連携し、シークレット管理が不要になります。2025年9月時点で100万ファイル以上がこの方式で公開されています。
TERM 02
TestPyPI
PyPIのテスト環境です。本番公開前に動作確認ができます。データは定期的にリセットされるので、失敗を恐れず試せる場所として活用できます。URL: https://test.pypi.org/
TERM 03
OIDC (OpenID Connect)
OAuth 2.0ベースの認証プロトコルです。GitHub ActionsがPyPIに対して「このワークフローは信頼できる」と証明する仕組みで、短命トークン(最大15分で失効)を使うためトークン漏洩リスクがありません。
TERM 04
GitHub Environments
GitHub Actionsのデプロイ先環境設定です。承認ゲート・シークレット管理・保護ルールを設定でき、testpypi/pypi等の環境を分離できます。
Source: PyPI Trusted Publishers Documentation, Internals and Technical Details
リリース自動化の本質
この記事ではPyPI公開を扱いますが、企業プロジェクトのk8s/EC2デプロイも考え方は全く同じです。
共通のパターン
OSS (Pythonパッケージ)
PyPI公開
- タグpush (
v0.1.0) - GitHub Actions実行
- パッケージビルド
- TestPyPI公開
- PyPI公開
企業 (Kubernetes)
k8sデプロイ
- タグpush (
v0.1.0) - CI/CD実行
- Dockerイメージビルド
- Staging環境デプロイ
- Production環境デプロイ
企業 (EC2)
EC2デプロイ
- タグpush (
v0.1.0) - CI/CD実行
- アプリケーションビルド
- Staging EC2デプロイ
- Production EC2デプロイ
本質は同じ: タグ → 自動リリース
デプロイ先がPyPI/k8s/EC2のどれでも、「バージョンタグをpushしたら自動でリリース」という仕組みは同じです。 CI/CDツールも、GitHub Actionsでなくても構いません(GitLab CI、CircleCI、Jenkins等)。 この記事ではwagtail-reusable-blocksの実例(PyPI公開)を通じて、リリース自動化の考え方を学びます。
Trusted Publishingのメリット
wagtail-reusable-blocksはOSSのPythonパッケージなので、PyPIに公開します。 従来は「APIトークンをGitHub Secretsに登録して...」という面倒な設定が必要でしたが、Trusted Publishingを使えばシークレット不要です。
| 比較項目 | 従来(APIトークン方式) | Trusted Publishing (OIDC) |
|---|---|---|
| 初期設定 | PyPIでトークン発行 → GitHub Secretsに登録 | PyPI側で信頼設定のみ |
| シークレット管理 | 必要(トークン漏洩リスクあり) | 不要(漏洩リスクなし) |
| トークン有効期限 | 長期間有効(手動で取り消すまで) | 短命トークン(最大15分で自動失効) |
| メンテナンス | トークン更新が必要 | メンテナンスフリー |
| アテステーション | 手動で設定が必要 | v1.11.0以降デフォルトで有効(PEP 740準拠) |
Source: Introducing 'Trusted Publishers' - PyPI Blog, Security Model and Considerations
PyPI側でTrusted Publisher設定
まずはPyPI(およびTestPyPI)で信頼するリポジトリとワークフローを登録します。
設定項目
PyPIにログインし、プロジェクトページ → Publishing → Add a new publisher から設定します。 まだプロジェクトが存在しない場合は、「Pending publisher」として事前登録することも可能です。
- PyPI Project Name: パッケージ名
- Owner: GitHubユーザー名またはOrg名
- Repository: リポジトリ名
- Workflow name: ワークフローファイル名
- Environment name: 環境名(pypi または testpypi)
TestPyPIも同様に設定してください(Environment name: testpypi)
PyPI Project Name: wagtail-reusable-blocks Owner: kkm-horikawa Repository name: wagtail-reusable-blocks Workflow name: publish.yml Environment name: pypi
Source: Publishing with a Trusted Publisher - PyPI Docs, Creating a PyPI Project with a Trusted Publisher
GitHub Actions ワークフローの設定
次にGitHub側でワークフローを作成します。wagtail-reusable-blocksの実際の設定を見ていきましょう。
トリガー設定
v*パターンのタグがpushされたときにワークフローが実行されます。
3つのジョブで構成されています。
- build: パッケージをビルド
- publish-testpypi: TestPyPIに公開
- publish-pypi: PyPIに公開
name: Publish to PyPI on: push: tags: - "v*" jobs: build: ... publish-testpypi: ... publish-pypi: ...
ジョブ1: build(パッケージビルド)
ソースコードをチェックアウトし、uvでパッケージをビルドします。
fetch-depth: 0: 全履歴取得(hatch-vcsがタグを読むため)uv build: パッケージビルドupload-artifact: 後続ジョブに渡す
build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install uv uses: astral-sh/setup-uv@v4 - name: Build package run: uv build - name: Upload dist uses: actions/upload-artifact@v4 with: name: dist path: dist/
ジョブ2: publish-testpypi
TestPyPIに公開します。シークレット不要なのがポイントです。
environment: testpypi: 環境指定id-token: write: OIDC有効化(必須)repository-url: TestPyPI指定
publish-testpypi: needs: build runs-on: ubuntu-latest environment: testpypi permissions: id-token: write steps: - name: Download dist uses: actions/download-artifact@v4 with: name: dist path: dist/ - name: Publish to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/
ジョブ3: publish-pypi
TestPyPI成功後、PyPIに公開します。repository-url省略時はPyPIがデフォルトです。
needs: publish-testpypi: TestPyPI成功後のみ実行environment: pypi: 本番環境指定- TestPyPI → PyPI の順でリリース
publish-pypi: needs: publish-testpypi runs-on: ubuntu-latest environment: pypi permissions: id-token: write steps: - name: Download dist uses: actions/download-artifact@v4 with: name: dist path: dist/ - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1
Source: pypa/gh-action-pypi-publish - GitHub, Python Packaging User Guide
実際の動作フロー
タグをpushしてから公開されるまでの流れを見ていきましょう。
- 01
開発者: タグをpush
git tag v0.1.0 && git push origin v0.1.0 - 02
GitHub Actions: ワークフロー実行開始
トリガー条件:
tags: v* - 03
ジョブ1 (build): パッケージビルド
uvでビルド → dist/ に .whl と .tar.gz を生成
- 04
ジョブ2 (publish-testpypi): TestPyPIに公開
OIDC認証 → TestPyPIに公開 → 動作確認可能
- 05
ジョブ3 (publish-pypi): PyPIに公開
OIDC認証 → PyPIに公開 → pip install で誰でもインストール可能に
所要時間: 約5分
開発者がやることはタグをpushするだけ。あとは全て自動でビルド・公開されます。
OSS vs 企業プロジェクト: リリース自動化の応用
OSS: PyPI公開の詳細
wagtail-reusable-blocksでは、TestPyPI → PyPI の2フェーズリリースを採用しています。
なぜTestPyPI経由なのか
- 本番公開前の最終確認: TestPyPIで実際にインストールして動作確認できる
- ミスの検出: パッケージ名・依存関係・メタデータの間違いを事前に発見
- ロールバック不可: PyPIは一度公開したバージョンを削除できない(TestPyPIで確認必須)
- 心理的安全性: 「失敗してもTestPyPIだけ」という安心感
実際のリリースフロー
git tag v0.1.0 && git push origin v0.1.0でタグpush- GitHub Actions自動実行
- TestPyPIに公開 →
pip install --index-url https://test.pypi.org/simple/ wagtail-reusable-blocksで確認 - 問題なければPyPIに自動公開
pip install wagtail-reusable-blocksで誰でもインストール可能に
Trusted Publishingのメリット再確認
APIトークン管理不要、漏洩リスクなし、メンテナンスフリー。 「シークレット管理を忘れてトークン漏洩」という事故が起きない。
企業: k8s/EC2デプロイへの応用
企業プロジェクトでは、PyPIの代わりにk8sクラスタやEC2にデプロイします。 でも考え方は全く同じです。
Kubernetesデプロイの例
ワークフローの流れ(PyPIと対応)
git tag v0.1.0 && git push origin v0.1.0← トリガーは同じ- CI/CD実行(GitHub Actions / GitLab CI / CircleCI等)
- Dockerイメージビルド ← PyPIのパッケージビルドと同じ役割
- Staging k8sクラスタにデプロイ ← TestPyPIと同じ役割
- Production k8sクラスタにデプロイ ← PyPIと同じ役割
なぜ立ち上げ時点で組むべきか
リリース自動化は、後から本番環境で検証するのが非常に難しいです。
立ち上げ時点で組んだ場合
- 開発環境で自動デプロイを検証
- Staging環境で本番同様の動作確認
- 問題があれば何度でも修正可能
- 本番リリース時には既に安定稼働
- 誰でもリリースできる
後から組もうとした場合
- 本番稼働中なのでテストできない
- 「失敗したら本番が止まる」と萎縮
- 手動運用が定着して変更困難
- 結局、手動デプロイのまま
- 永遠に属人化
技術的理解のあるPMが必要な理由
リリース自動化を設計・実装できるのは、技術的理解のある人だけです。 プロジェクト立ち上げ時点で、技術的理解のある人がPMとして仕切り、自動化を組むべきです。後からでは遅い。
よくある質問
A: はい、完全無料です。
PyPI/TestPyPIのTrusted Publishingは無料で利用可能です。 GitHub Actionsの無料枠内で動作します(Publicリポジトリなら無制限)。
A: 技術的には可能ですが、推奨しません。
TestPyPIは本番公開前の最終確認の場です。 PyPIは一度公開したバージョンを削除できないため、TestPyPIでの確認を強く推奨します。
A: はい、簡単に移行できます。
PyPI側でTrusted Publisher設定 → workflowからPYPI_API_TOKEN削除 →
permissions: id-token: write追加。
シークレット削除でセキュリティ向上します。
A: Trusted Publishing利用時は必須です。
PyPI側のTrusted Publisher設定でEnvironment nameを指定するため、GitHub側でも同名の環境が必要です。
Settings → Environments → New environment で作成してください。
A: GitHub Actionsを手動キャンセルできます。
ActionsタブでWorkflowを開き、Cancelボタンで実行中止可能です。 TestPyPIに公開済みでも問題ありません(テスト環境なので)。 PyPIに公開されてしまった場合、そのバージョンは削除できないため、次のバージョンで修正します。
A: はい、考え方は全く同じです。
「バージョンタグpush → 自動リリース」という仕組みはPyPI/k8s/EC2で共通です。 デプロイ先が違うだけで、ワークフローの構造(build → staging → production)は同じ。 「OSS vs 企業プロジェクト」タブの企業側を参考にしてください。
A: はい、複数のプロバイダーに対応しています。
GitHub Actions以外にも、GitLab CI/CD、Google Cloud、ActiveStateがサポートされています。 ただし、GitLabは現時点でgitlab.comのみ対応で、セルフホスト版は未対応です。
Source: GitHub Docs - Configuring OIDC in PyPI, OpenSSF - Trusted Publishers for All Package Repositories


まだコメントはありません。最初のコメントを残しませんか?