HH-443: establish production CI and supply-chain evidence (#93)
* ci: enforce production release gates * ci: close release gate review blockers * ci: preserve verified digests during promotion * ci: serialize and verify release cleanup * ci: build govulncheck with Shangwutong toolchain --------- Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
delete_package_version() {
|
||||
local endpoint=$1 tag=$2 digest=$3 attempt versions version_id
|
||||
local retries=${RELEASE_RETRY_COUNT:-5} delay=${RELEASE_RETRY_DELAY:-2}
|
||||
|
||||
for ((attempt = 1; attempt <= retries; attempt++)); do
|
||||
if versions=$(gh api --paginate --slurp "$endpoint?per_page=100") &&
|
||||
version_id=$(jq -er --arg tag "$tag" --arg digest "$digest" \
|
||||
'[.[][] | select(.name == $digest and ((.metadata.container.tags // []) | index($tag)))] | if length == 1 then .[0].id else empty end' \
|
||||
<<< "$versions") &&
|
||||
[[ $version_id =~ ^[0-9]+$ ]] &&
|
||||
gh api --method DELETE "$endpoint/$version_id"; then
|
||||
return 0
|
||||
fi
|
||||
((attempt == retries)) || sleep "$delay"
|
||||
done
|
||||
|
||||
echo "Could not delete package version for $tag at $digest" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_tag_absent() {
|
||||
local target=$1 attempt output
|
||||
local retries=${RELEASE_RETRY_COUNT:-5} delay=${RELEASE_RETRY_DELAY:-2}
|
||||
|
||||
for ((attempt = 1; attempt <= retries; attempt++)); do
|
||||
if output=$(crane digest "$target" 2>&1); then
|
||||
:
|
||||
elif grep -Eiq 'MANIFEST_UNKNOWN|manifest unknown|not found|404' <<< "$output"; then
|
||||
return 0
|
||||
fi
|
||||
((attempt == retries)) || sleep "$delay"
|
||||
done
|
||||
|
||||
[[ -z $output ]] || printf '%s\n' "$output" >&2
|
||||
echo "Tag still resolves after cleanup: $target" >&2
|
||||
return 1
|
||||
}
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
||||
source "$root/.github/scripts/release_helpers.sh"
|
||||
|
||||
export RELEASE_RETRY_COUNT=5 RELEASE_RETRY_DELAY=0
|
||||
delete_attempts=0
|
||||
deleted_path=
|
||||
|
||||
gh() {
|
||||
if [[ $* == *'--paginate --slurp'* ]]; then
|
||||
printf '%s\n' '[[
|
||||
{"id": 11, "name": "sha256:correct", "metadata": {"container": {"tags": ["rollback-other"]}}},
|
||||
{"id": 22, "name": "sha256:wrong", "metadata": {"container": {"tags": ["rollback-123-1"]}}},
|
||||
{"id": 33, "name": "sha256:correct", "metadata": {"container": {"tags": ["rollback-123-1"]}}}
|
||||
]]'
|
||||
return
|
||||
fi
|
||||
((++delete_attempts))
|
||||
deleted_path=${4:-}
|
||||
((delete_attempts >= 3))
|
||||
}
|
||||
|
||||
delete_package_version /users/owner/packages/container/repo/versions rollback-123-1 sha256:correct
|
||||
[[ $delete_attempts -eq 3 ]]
|
||||
[[ $deleted_path == /users/owner/packages/container/repo/versions/33 ]]
|
||||
|
||||
counter_file=$(mktemp)
|
||||
trap 'rm -f "$counter_file"' EXIT
|
||||
printf '0\n' > "$counter_file"
|
||||
crane() {
|
||||
local count
|
||||
count=$(< "$counter_file")
|
||||
((++count))
|
||||
printf '%s\n' "$count" > "$counter_file"
|
||||
if ((count < 3)); then
|
||||
printf '%s\n' sha256:rollback
|
||||
return
|
||||
fi
|
||||
echo MANIFEST_UNKNOWN >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_tag_absent ghcr.io/owner/repo:1.2.3
|
||||
[[ $(< "$counter_file") -eq 3 ]]
|
||||
|
||||
python3 - "$root/.github/workflows/ci.yml" <<'PY'
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
workflow = Path(sys.argv[1]).read_text()
|
||||
release = re.search(r"(?ms)^ release:\n(.*?)(?=^ [a-zA-Z0-9_-]+:\n|\Z)", workflow)
|
||||
assert release, "release job missing"
|
||||
body = release.group(1)
|
||||
assert re.search(
|
||||
r"(?m)^ concurrency:\n group: release-promotion\n cancel-in-progress: false$",
|
||||
body,
|
||||
), "all release tags must share one non-cancelling promotion lock"
|
||||
assert "github.ref" not in re.search(r"(?ms)^ concurrency:\n(.*?)(?=^ \S)", body).group(1)
|
||||
PY
|
||||
|
||||
echo "release promotion checks passed"
|
||||
Reference in New Issue
Block a user