Safe Public GitHub Release(安全な公開GitHubリリース)
基本ルール
公開の信頼をスピードより優先する。クリーンな公開スナップショット、リリースブランチPR/CIゲート、検証済みのGitHub Releaseアーティファクト、チェックサム、そして不可逆的な操作に対する明示的なメンテナの承認を推奨する。
プライベートな履歴をそのまま公開してはならない。クリーンな公開スナップショットとして作成され、最終的な仕上げのためにのみプライベートに保たれていたリポジトリは、最終スクラブゲートを通過した後にのみ公開可能とする。TestPyPI/PyPIは、Pythonパッケージ配信が実際にスコープ内にある場合のみ使用する。
ワークフロー
- 最初に調査する:
git status -sb、リモート、現在のブランチ、タグ、関連するワークフロー。- 公開リポジトリの可視性、デフォルトブランチ、リリース/タグの状態、および
ghを使ったGitHub環境。 - インストールパス、公開、Homebrew、TestPyPI、PyPI、プライベートリポジトリ、ローカルパス、またはハンドオフファイルに言及している既存のドキュメント。
- 公開範囲を明確にする:
- 公開ドキュメントとパッケージメタデータは、公開オーナー/リポジトリ、パッケージ名、公開タグ、公式インストールコマンドに言及してもよい。
- 公開ドキュメントは、プライベートリポジトリ名、ローカルホームパス、
HANDOFF.md、CONTINUITY.md、.local、.codex、トークン、キー、生の内部トランスクリプト、またはメンテナ専用の指示に言及してはならない。ただし、一般向けガイダンスとして書き換えられた場合は除く。 - READMEでは、リポジトリ内のドキュメントやメディアへの相対リンクを推奨する。絶対的なGitHubオーナー/リポジトリURLはリリースノートでは問題ないが、READMEでは不要なオーナー結合や公開範囲スクラブチェックでの誤検出を引き起こす可能性がある。
- GitHub リリースゲートを準備する:
- リモート変更の前にローカルでビルド/テストする。
- デフォルトでは、タグ付けの前に
release/vX.Y.Z-> PR -> CI -> マージを使用する。 - READMEまたはローカライズされたREADMEファイルが変更された場合は、マージ前にAkiによるGitHubレンダリング済みREADMEのビジュアル承認を必須とする。
- アップロード前にReleaseアセットを検証する:期待されるファイル名、バージョンメタデータ、チェックサム、アーカイブ内容、該当する場合はプラットフォーム固有の署名/公証チェック。
- macOS
.appzipアセットの場合、AppleDoubleやFinderメタデータなしでアーカイブをビルドする。COPYFILE_DISABLE=1 zipまたは同等のアーカイブコマンドを推奨し、__MACOSX、.DS_Store、._*ファイルを含むアーカイブは拒否する。これらの余分なファイルは、解凍後に署名済みアプリの検証を失敗させる可能性がある。 - アップロードする正確なアーカイブを一時ディレクトリに展開し、アプリ/パッケージのバージョンメタデータを確認し、展開されたペイロードに対して関連する署名/公証検証を実行することで、常に検証する。
- 次の順序でGitHubリリースを公開する:
mainを再フェッチし、最新のCIがグリーンであることを確認し、ローカルワークツリーがクリーンであることを確認する。- ターゲットタグとGitHub Releaseがまだ存在しないことを確認する。
- 検証済みの
mainコミットにタグを作成する。 - タグをプッシュする。
dist/...などのローカルパスではなく、リリース向けのベース名を使用して、最終的なアップロードファイルからチェックサムファイルを作成する。- 意図的なノートと意図的なアセットのみを含むGitHub Releaseを作成する。
- アセットタイプに有用な場合はチェックサムファイルをアップロードし、ユーザーがダウンロードを検証するのに役立つ場合はリリースノートにチェックサムを含める。
- GitHub公開後に検証する:
- タグが期待されるコミットを指していること。
- GitHub Releaseが期待されるURLで表示可能であること。
- Releaseアセットとチェックサムがローカルで検証されたファイルと一致すること。
- 公開されたReleaseアセットを一時ディレクトリにダウンロードし、ダウンロードしたコピーから検証する。チェックサム対応アーカイブの場合は
shasum -a 256 -c <asset>.sha256を実行し、macOS.appzipの場合はダウンロードしたアセットを解凍し、展開されたアプリに対してアプリバージョンとcodesign --verify --strict --deepチェックを実行する。 - 公開README/ドキュメントがライブリリースバージョンとアセット名と一致していること。
オプションのPyPI / TestPyPIサブセクション
このサブセクションは、GitHubリリースがPythonパッケージ、CLI、またはuvxインストールパスも公開する場合にのみ使用する。
testpypiとpypiのGitHub環境が存在することを確認する。pypiはメンテナの承認の背後に保つ。- 保存されたPyPIトークンの代わりに
id-token: writeとPyPIトラステッドパブリッシャーを使用する。 - 次の順序で公開する:
- 意図したタグからのビルドのみのワークフロー。
SHA256SUMSとアーティファクト証明を含むGitHub Releaseアーカイブ。- TestPyPIに公開し、インストールのスモークテストを実行する。
- TestPyPIがバージョンを示し、インストールのスモークテストが合格した後にのみPyPIに公開する。
- ライブインストールパスをプライマリにするためのドキュメント更新。
- 公開後に検証する:
- PyPI/TestPyPIのJSONに期待されるバージョンが含まれていること。
uvx --from <package> <command> --helpが機能すること。- 同じバージョンの再アップロードが準備完了チェックによってブロックされること。
- 公開README/ドキュメントがライブインストールパスと一致していること。
GitHubのみの公開スナップショットチェックリスト
ターゲットがPyPIなしのGitHubリポジトリまたはアプリリリースである場合に使用する。
- 最終ゲートが通過するまでリポジトリをプライベートに保つ。公開ターゲットが別の既に公開されているリポジトリである場合、プライベートな履歴をそのリポジトリに決してコピーせず、スクラブされたスナップショットコンテンツのみを移動する。
- 公開スナップショットにはデフォルトでリリースブランチとPRを使用する:
- 公開リポジトリに
release/vX.Y.Zを作成または更新する。 - そのブランチに準備されたスナップショットと公開ドキュメントをコミットする。
mainへのPRを開き、そこでCIを実行させる。- READMEまたはリリース向けドキュメントが変更された場合は、
readme-release-syncも使用して、公開コピーが読みやすく、バイリンガルで、出荷される動作と一致した状態を保つ。 - AkiにPR/ブランチのGitHubレンダリング済みREADMEリンクを提供し、マージ前に明示的なビジュアル承認を待つ。ローカルのMarkdownプレビュー、生ファイルビュー、スクリーンショット、または自動リンクチェックはこのゲートを代替しない。
- CIがグリーンで、公開範囲スクラブが通過した後にのみマージする。
- Akiが明示的にPRゲートをスキップするように依頼した場合にのみ、
mainに直接プッシュする。
- 公開リポジトリに
- ワーキングツリーだけでなく、追跡されたファイルをスクラブする:
- シークレット、ローカルパス、メンテナ名、古いプライベートリポジトリ名、ハンドオフファイル、生成されたアーカイブ、古い製品名。
git ls-filesで、偶発的な.mov、.mp4、ビルド出力、キャッシュ、大きなバイナリファイルをチェックする。
- READMEメディアを公開範囲の一部として扱う:
- インラインGIFは最も信頼性の高いGitHub READMEデモ形式であり、GitHubの実用的な画像/GIF制限内に収める。
- ローカルのREADME
<video>埋め込みとリポジトリローカルのMP4プレビューリンクは、失敗したり、不安定なGitHubファイルプレビューページを開いたりする可能性がある。 - オプションのMP4デモは、本当に必要な場合にのみGitHub Releaseアセットに配置し、製品に必要ない場合はそれらとリリースノートの参照を削除する。
- タグまたはGitHub Releaseを作成する前に、再フェッチする:
- PRマージ状態とマージ後の
mainの最新CIステータス git status -sb、git log --oneline -1、git tag --list、現在のリリースアセット- リポジトリが既に公開されている場合は、GitHub contents APIを介したREADMEと参照画像パス
- バイナリアップロードごとのアーカイブ内容と展開アセット検証結果
- PRマージ状態とマージ後の
- 可視性を変更する前に、再フェッチする:
gh repo view ... --json visibility,isPrivate,url,defaultBranchRef- デフォルトブランチの最新のActionsステータス
- Releaseアセットとリリースノート
- GitHub contents APIを介したREADMEと参照画像パス
- Akiが明示的に公開するように指示した場合にのみ可視性を変更し、
visibility=PUBLIC、公開README URLの可用性、Releaseアセット、クリーンなローカルワークツリーを検証する。
クリーンスナップショットから公開リポジトリへのフロー
プライベート/内部リポジトリが別の公開リポジトリにフィードする場合にこのフローを使用する。
- プライベートリポジトリで機能を完了し検証する。
- 公開ファイルの許可リストから一時的なスナップショットフォルダを作成する。
- スナップショットに公開命名を適用し、プライベート専用のサーフェスを削除する。
- シークレット、プライベートパス、ハンドオフファイル、古い製品名、生成されたアーカイブ、大きな偶発的なファイルについてスナップショットをスクラブする。
- スクラブされたスナップショットを公開リポジトリのワーキングツリーにコピーする。
release/vX.Y.Zを作成または切り替える。- そのブランチで、公開README、ローカライズされたREADME、変更ログ、バージョンメタデータ、リリースドラフトノート、READMEメディア参照を更新する。
git diff、READMEメディアリンク、バイリンガルパリティ、古い表現、公開範囲スキャン結果を検査する。- 関連するローカルビルド/テスト/パッケージチェックを実行する。
release/vX.Y.Zにリリース準備の変更をコミットし、ブランチをプッシュする。mainへのPRを開く。まだタグ付けやGitHub Releaseの作成は行わない。- CIを待ち、リリースブランチで失敗を修正し、チェックを再実行する。
- PR/ブランチ上の
README.mdとローカライズされたREADMEファイルのGitHubレンダリング済みREADME URLをAkiに送信する。READMEがGitHub上で正しく表示されていることの明示的なビジュアル承認を待つ。 - CI、スクラブゲート、およびAkiのGitHubレンダリング済みREADMEビジュアル承認のすべてが合格した後にのみPRをマージする。
mainを再フェッチし、マージされたコミットがクリーンでグリーンであることを検証する。vX.Y.Zの作成、アセットのアップロード、またはGitHub Releaseの作成/公開の前に、Akiの承認のために一時停止する。
公開リポジトリがまだない場合のフロー
プロジェクトがまだ公開リポジトリを持ったことがない場合にこのルートを使用する。
- プライベート/内部の作業リポジトリを公開しない。
- 新しいクリーンな公開リポジトリを作成し、最初はプライベートに保つ。
- プライベートな履歴からではなく、スクラブされた公開スナップショットからのみ初期化する。
- 最初から、公開向けの製品名、パッケージメタデータ、READMEファイル、ライセンス、変更ログ、リリースドラフトノート、スクリーンショット/GIF、ワークフローを使用する。
- 追跡されたファイルに対して、同じシークレット/プライベートパス/大規模ファイル/公開範囲のスクラブを実行する。
release/vX.Y.Z-> PR -> CI -> AkiのGitHubレンダリング済みREADMEビジュアル承認 -> マージを、リポジトリがまだプライベートであっても使用する。- 可能な場合はリポジトリがまだプライベートな間に意図したタグとGitHub Releaseドラフトを作成し、そこでのアセット/チェックを検証する。
- 可視性を変更する前にAkiの承認のために一時停止する。
- 最終スクラブ、グリーンCI、意図的なリリースアセット、および明示的なAkiの承認の後にのみ、可視性を公開に変更する。
- 可視性変更後、公開READMEの可用性、Releaseアセット、タグ、最新のActionsステータス、およびローカルのクリーンワークツリーを再フェッチして検証する。
重要な教訓
- GitHub Actionsのワークフロー定義は、ワークフローをディスパッチするために使用されるrefから取得される。新しいワークフロー入力またはガードが追加される前にタグが作成された場合、その古いタグからディスパッチしても新しい入力は認識されない。
- 将来のリリースでは、タグを作成する前にリリースガードを配置する必要がある。その後、ガードされた入力を使用してそのタグからディスパッチする。
- 1回限りの履歴タグがガードより古い場合は、推測しない。ローカルの準備完了チェックを実行し、最初にTestPyPIで証明し、アーティファクト/証明を検証し、例外を文書化する。
- Releaseアセットの衛生管理は重要である:試行的なアップロードの後、最終的な公開Releaseには意図的なアーティファクトのみを含める必要がある。公開前に不要なアセットを削除し、それらのSHA行またはリリースノートの言及を削除する。
詳細ラン・ブック
ステップバイステップのチェックリスト、コマンドパターン、公開ドキュメント監査パターンについては、references/pypi-trusted-release-runbook.mdを参照。