一覧SE-08-3 · リリースと変更

リリースする成果物の検証

版名、ソースの識別子、成果物の識別子、承認の対象を分けて確認します。

説明

公開する版の名前だけでは、どのソースから何を作り、どのファイルを承認したかは特定できません。同じ名前のファイルを別の内容へ置き換えることもできます。ソースのコミット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 / シェル

1
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.0
2
python3 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))
3
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
approved=True
artifact_hash=True
version=True
commit=True
{"status": "ok"}
4
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.zip
approved=True
artifact_hash=False
version=False
commit=False
5
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"}
6
git tag -f v1.1.0 HEAD git rev-parse v1.1.0 cat approved.json
Updated tag 'v1.1.0' (was 01d5f28)
9d929f6962e61d86f3c504a8831846e69d9c39b4
{
  "version": "1.1.0",
  "commit": "01d5f281f2193cbf6561e078acee4f964c5a79ba",
  "artifact_sha256": "ade05d0a3150a147099c0c9462001c78f82f91a1fc51c5a692c2b1a334840c1a",
  "decision": "approved"
}
7
python3 verify_release.py approved.json artifacts/release-1.1.0.zip
approved=True
artifact_hash=True
version=True
commit=True
8
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
approved=True
artifact_hash=True
version=True
commit=True
{"status": "ok"}

演習完了