すでに wheel を生成するビルドジョブがあり、それを受け取るべきプライベートリポジトリがあります。誤りは、別のジョブにブランチから再ビルドさせ、その結果を同じリリースと呼ぶことです。テストしたファイルをそのまま移し、ダイジェストで名前を付け、アップロード用の資格情報は内側に置きます。以下の手順では、公開 CI ランナーから内部の公開先まで、一つの成果物を追います。

ソースがある場所でビルドする

ソース、ツールチェーン、テストスイートがそろっているジョブでビルドを実行します。プライベートリポジトリの何かが、そのジョブに到達を要求するわけではありません。ビルド用フロントエンドをプロジェクトがすでに使う環境に導入し、プロジェクトが両方の配布形式を出すなら両方を生成します。

python -m build --sdist --wheel --outdir dist
python -m twine check dist/*

出力ディレクトリは小さく、使い捨てにします。次のジョブが公開するファイルとそのハッシュだけを持ち越せば十分です。仮想環境やキャッシュを含むそれ以外は、記録したソースリビジョンから作り直せます。むだのない成果物はレビューもしやすくなります。中のどのファイルも、誰かが検査できるファイルだからです。

何が生成したかを記録します。ファイル名から読み取れるパッケージ名とバージョン、ソースリビジョン、そして生成したワークフロー実行です。バージョン文字列だけではファイルを特定できません。同じバージョンでも別のコミットから二度ビルドできるからです。成果物の説明にファイル名と並べてリビジョンを書き、その記録を受け渡しの一部として扱います。

再ビルドの指示ではなく、バイトを移す

二度目のビルドは別の製品です。タイムスタンプ、同梱される依存関係、ツールのバージョンはいずれもバイトを変えうるので、再ビルドには独自のテスト証拠と独自のレビューが要ります。代わりに、レビュー済みのファイルを昇格させます。

配布ファイルを CI プラットフォームが提供する成果物ストアにアップロードし、内部のジョブにはブランチ名ではなく、その特定の成果物への参照を渡します。

sha256sum dist/*.whl dist/*.tar.gz
# keep the digests beside the run id in the artifact description

プラットフォームが署名付きの来歴に対応しているなら、成果物の証明を求め、後で期待するリポジトリ、ワークフロー、ソースリビジョンを検証します。GitHub の証明のドキュメントがその形の主張を説明しています。有効な署名は来歴の証拠であり、脆弱性スキャンでも認可の判断でもありません。

アップロードの前に内側で検証する

内部のジョブは、受け取ったファイルが承認されたファイルであることを確認するところから始まります。ダイジェストはビルドジョブの記録と比べます。届いたものから計算し直した値と比べてはいけません。

sha256sum -c digests.txt
python -m twine check dist/*

次にメタデータを読みます。パッケージ名、バージョン、宣言された依存関係は、承認したレビューと一致するはずです。名前は正しそうなのに依存関係の固定が変わっている wheel は、同じラベルを付けた別のパッケージです。メタデータが動いていたら、その成果物は未承認として扱い、どのビルドが生成したかを突き止めます。

ダイジェストが一致しなければ、止めます。アップロードせず、その場で再ビルドして修復もしません。輸送中に何かが変わったという証拠を消してしまうからです。不一致は、成果物ストア、ダウンロード手順、記録のいずれかが誤っているという意味で、どれもリリースを公開する前に説明が要ります。

重複バージョンの応答を扱う

プライベートリポジトリは通常、既存バージョンの上書きを拒みます。その拒否は仕様です。バージョンが存在するためにアップロードが失敗したら、そのバージョンのリポジトリ記録を調べ、保持しているファイルを公開しようとしたダイジェストと比べます。

既存バージョンは、以前のアップロードが成功して応答が失われたことを意味する場合もあれば、誰かが同じ番号で別の中身を公開したことを意味する場合もあります。

バージョンを削除せず、エラーを避けるために新しい番号をでっち上げもしません。保存された中身が受け入れられるかをリリースの所有者と決め、その結果を記録します。中身が違うなら、それはバージョン管理の問題で、パイプラインの問題ではありません。

アップロード用の資格情報を片側に置く

リポジトリの資格情報が要るのは内部の公開先だけで、しかもアップロードの間だけです。トークンは対象リポジトリとアップロード操作に限定し、内部システムのシークレットストアに置き、ビルドジョブからは完全に外します。ビルドジョブが公開できるなら、ビルドを変えられる誰もが公開できます。

どの内部ワークフローが公開先を起動できるかも制限します。承認を必須にした手動トリガーはリリースの妥当な既定です。どのブランチへのプッシュでもよい、というのは違います。

完成したリリースは三つを残すべきです。配布ファイル、ソースリビジョン付きのダイジェスト、そして同じバージョンを示すリポジトリの記録です。

関連記事