リリースする成果物の検証
版名、ソースの識別子、成果物の識別子、承認の対象を分けて確認します。
説明
公開する版の名前だけでは、どのソースから何を作り、どのファイルを承認したかは特定できません。同じ名前のファイルを別の内容へ置き換えることもできます。ソースのコミットIDと成果物のハッシュを記録すると、判断対象と配置物を対応付けられます。
実Gitの二つのコミットから作った1.1.0と1.2.0のZIPを使います。承認記録は1.1.0のコミットとZIPのSHA-256を指定しています。別のZIPを同じような名前で配置した場合と、タグの参照先を動かした場合を確認し、承認した内容へ戻します。
版名、ソースの識別子、成果物の識別子、承認の対象を分けて確認します。
1承認記録の対象を読む
用意した承認記録と、二つのソースコミットを読みます。
cat approved.json承認した版・コミット・成果物のハッシュを読む
git log -2二つのソース変更を確認する --format="%h %s"記録はversion・commit・artifact_sha256を持ちます。版名だけでなく、どのソースとバイト列を対象に判断したかを残しています。
2成果物に含まれる情報を確認
1.1.0のZIPからメタデータとプログラムを読みます。
python3 inspect_artifact.py artifacts/release-1.1.0.zipZIP内の版情報とコードを読むメタデータのcommitは承認記録と一致し、プログラムはstatus=okを出す内容です。ただしZIP内の自己申告だけで承認対象と同じとは判断せず、次にZIP全体のハッシュも比較します。
3配置後のバイト列を照合する
承認したZIPをdeployed/app.zipへコピーし、そのコピーを検査して実行します。
cp artifacts/release-1.1.0.zip deployed/app.zip承認した成果物を配置先へコピーする
python3 verify_release.py approved.json deployed/app.zip配置物を承認記録と照合する
python3 run_artifact.py deployed/app.zip照合したZIP内のプログラムを実行する承認状態・成果物ハッシュ・版名・コミットがすべてTrueで、status=okが出ます。作成元だけでなく、実際の配置先のファイルを検査しています。
4ファイル名を変えても中身は変わらない
1.2.0のZIPをrelease-1.1.0.zipという名前で置き、その内容をapp.zipとして配置します。
cp artifacts/release-1.2.0.zip deployed/release-1.1.0.zip別内容のZIPに古い版名を付ける
cp deployed/release-1.1.0.zip deployed/app.zip
python3 verify_release.py approved.json deployed/app.zip名前ではなく実際の内容を照合する承認済みの記録自体はTrueですが、成果物ハッシュ・版名・コミットはFalseです。ファイル名だけを頼りにすると、承認対象と異なる内容を配置してしまいます。
5取り違えた内容を読む
現在の配置物を開き、何が異なるか確認します。
python3 inspect_artifact.py deployed/app.zip配置したZIP内の版情報を確認する
python3 run_artifact.py deployed/app.zip実際の動作の違いを確認するメタデータは1.2.0で、出力にもfeature=newが加わっています。正常に実行できることと、その成果物が今回の承認対象であることは別です。
6タグ名も参照先を変更できる
この専用リポジトリでv1.1.0タグを最新コミットへ付け替えます。承認記録は変更しません。
git tag -f v1.1.0 HEADタグの参照先を最新へ移す
git rev-parse v1.1.0付け替え後のIDを読む
cat approved.jsonタグが指すIDと承認記録のcommitが違う状態になります。タグ名を版の目印に使う場合でも、承認時のコミットIDを別に保存しておくと、後の付け替えと区別できます。
7元の成果物は承認記録と一致する
保存していた1.1.0のZIPを再び照合します。
python3 verify_release.py approved.json artifacts/release-1.1.0.zip保存してある承認対象を再照合するすべてTrueです。タグを動かしても、保存済みのZIPのバイト列や承認記録の値は自動では変わりません。版名から引き直すのではなく、承認対象そのものを保持する意味があります。
8承認対象へ戻して配置先を再検査
承認したZIPを配置し直し、配置後の内容を照合してから実行します。
cp artifacts/release-1.1.0.zip deployed/app.zip保持していた承認対象へ戻す
python3 verify_release.py approved.json deployed/app.zip配置後の内容をもう一度確認する
python3 run_artifact.py deployed/app.zipすべて一致し、出力はstatus=okへ戻りました。ハッシュは内容の一致を調べる値であり、誰が承認したかを証明する署名ではありません。実運用では承認記録そのものの管理も必要です。
まとめ
版名は目印、コミットIDはソース、成果物ハッシュは作られたバイト列の識別に使います。
正常動作する別成果物でも、今回の承認対象とは限りません。実際の配置先を照合します。
タグの参照先が変わっても、承認時のコミットと成果物を保持していれば対象を確認できます。
操作履歴と解説を振り返れます。
Python 3 / シェル
cat approved.json
git log -2 --format="%h %s"{
"version": "1.1.0",
"commit": "01d5f281f2193cbf6561e078acee4f964c5a79ba",
"artifact_sha256": "ade05d0a3150a147099c0c9462001c78f82f91a1fc51c5a692c2b1a334840c1a",
"decision": "approved"
}
9d929f6 Release 1.2.0
01d5f28 Release 1.1.0python3 inspect_artifact.py artifacts/release-1.1.0.zip{"commit": "01d5f281f2193cbf6561e078acee4f964c5a79ba", "version": "1.1.0"}
import json
print(json.dumps({'status': 'ok'},sort_keys=True))cp artifacts/release-1.1.0.zip deployed/app.zip
python3 verify_release.py approved.json deployed/app.zip
python3 run_artifact.py deployed/app.zipapproved=True
artifact_hash=True
version=True
commit=True
{"status": "ok"}cp artifacts/release-1.2.0.zip deployed/release-1.1.0.zip
cp deployed/release-1.1.0.zip deployed/app.zip
python3 verify_release.py approved.json deployed/app.zipapproved=True artifact_hash=False version=False commit=False
python3 inspect_artifact.py deployed/app.zip
python3 run_artifact.py deployed/app.zip{"commit": "9d929f6962e61d86f3c504a8831846e69d9c39b4", "version": "1.2.0"}
import json
print(json.dumps({'status': 'ok', 'feature': 'new'},sort_keys=True))
{"feature": "new", "status": "ok"}git tag -f v1.1.0 HEAD
git rev-parse v1.1.0
cat approved.jsonUpdated tag 'v1.1.0' (was 01d5f28)
9d929f6962e61d86f3c504a8831846e69d9c39b4
{
"version": "1.1.0",
"commit": "01d5f281f2193cbf6561e078acee4f964c5a79ba",
"artifact_sha256": "ade05d0a3150a147099c0c9462001c78f82f91a1fc51c5a692c2b1a334840c1a",
"decision": "approved"
}python3 verify_release.py approved.json artifacts/release-1.1.0.zipapproved=True artifact_hash=True version=True commit=True
cp artifacts/release-1.1.0.zip deployed/app.zip
python3 verify_release.py approved.json deployed/app.zip
python3 run_artifact.py deployed/app.zipapproved=True
artifact_hash=True
version=True
commit=True
{"status": "ok"}演習完了