fix(acceptance): 完善跨版本验收状态收口

生产流量处于旧失败验收 Run 的 validation 状态时,允许新验收接管任意已验证的 Git 祖先 release,而非仅允许 release manifest 的直接 base;仍保留 Run 状态、镜像 digest、revision 与当前集群 release CAS 校验。\n\n允许 pending Run 在激活前异常时直接标记为 failed,避免验收工具在 CAS 或网络错误后遗留无法结束的 Run。新增祖先关系脚本测试及临时 PostgreSQL 集成验证。\n\n验证:Go 全量测试、go vet、临时 PostgreSQL 集成测试、bash -n、ShellCheck、manual-release-test。
This commit is contained in:
2026-08-01 13:59:37 +08:00
parent 4d84210344
commit 8749f38eb3
5 changed files with 58 additions and 3 deletions
+5
View File
@@ -266,6 +266,11 @@ WHERE (
id = $1::uuid id = $1::uuid
AND status = 'running' AND status = 'running'
) )
OR (
id = $1::uuid
AND $2::text = 'failed'
AND status = 'pending'
)
OR ( OR (
id = $1::uuid id = $1::uuid
AND $2::text = 'failed' AND $2::text = 'failed'
@@ -56,6 +56,11 @@ WHERE setting_key = $1`, SystemSettingGatewayTrafficMode)
if strings.Contains(string(encoded), token) { if strings.Contains(string(encoded), token) {
t.Fatal("acceptance run response exposed the raw token") t.Fatal("acceptance run response exposed the raw token")
} }
if failed, err := db.FinishAcceptanceRun(ctx, FinishAcceptanceRunInput{
RunID: run.ID, Passed: false, FailureReason: "pre-activation gate failed",
}); err != nil || failed.Status != "failed" {
t.Fatalf("finish pending acceptance run after pre-activation failure=%+v err=%v", failed, err)
}
mode, err := db.ActivateAcceptanceRun(ctx, run.ID) mode, err := db.ActivateAcceptanceRun(ctx, run.ID)
if err != nil { if err != nil {
t.Fatalf("activate acceptance run: %v", err) t.Fatalf("activate acceptance run: %v", err)
+9 -3
View File
@@ -190,7 +190,6 @@ fi
node "$cluster_root/scripts/release-manifest.mjs" validate "$release_manifest" >/dev/null node "$cluster_root/scripts/release-manifest.mjs" validate "$release_manifest" >/dev/null
release_sha=$(node "$cluster_root/scripts/release-manifest.mjs" get "$release_manifest" sourceSha) release_sha=$(node "$cluster_root/scripts/release-manifest.mjs" get "$release_manifest" sourceSha)
base_sha=$(node "$cluster_root/scripts/release-manifest.mjs" get "$release_manifest" baseReleaseSha)
api_image=$(node "$cluster_root/scripts/release-manifest.mjs" get "$release_manifest" images.api) api_image=$(node "$cluster_root/scripts/release-manifest.mjs" get "$release_manifest" images.api)
[[ $release_sha =~ ^[0-9a-f]{40}$ && $api_image =~ @sha256:[0-9a-f]{64}$ ]] || { [[ $release_sha =~ ^[0-9a-f]{40}$ && $api_image =~ @sha256:[0-9a-f]{64}$ ]] || {
echo 'release manifest is not full-SHA and digest pinned' >&2 echo 'release manifest is not full-SHA and digest pinned' >&2
@@ -1315,6 +1314,13 @@ deploy_protocol_emulator() {
-n "$namespace" --timeout=300s -n "$namespace" --timeout=300s
} }
is_release_ancestor() {
local ancestor=$1
local descendant=$2
[[ $ancestor =~ ^[0-9a-f]{40}$ && $descendant =~ ^[0-9a-f]{40}$ ]] &&
git -C "$cluster_root" merge-base --is-ancestor "$ancestor" "$descendant"
}
create_and_activate_run() { create_and_activate_run() {
local create_response=$temporary_root/create-run.json local create_response=$temporary_root/create-run.json
local activate_response=$temporary_root/activate-run.json local activate_response=$temporary_root/activate-run.json
@@ -1393,8 +1399,8 @@ create_and_activate_run() {
echo 'current-release validation mode has unexpected image digests' >&2 echo 'current-release validation mode has unexpected image digests' >&2
return 1 return 1
} }
elif [[ -z $base_sha || $traffic_release != "$base_sha" ]]; then elif ! is_release_ancestor "$traffic_release" "$release_sha"; then
echo 'refusing to replace validation mode outside the direct release base' >&2 echo 'refusing to replace validation mode owned by a non-ancestor release' >&2
return 1 return 1
fi fi
body=$(jq -cn \ body=$(jq -cn \
+1
View File
@@ -307,5 +307,6 @@ if grep -Fq 'archive_timeout: 60s' "$root/deploy/kubernetes/production/database.
fi fi
"$root/tests/release/cluster-release-helper-test.sh" >/dev/null "$root/tests/release/cluster-release-helper-test.sh" >/dev/null
"$root/tests/release/production-acceptance-script-test.sh" >/dev/null
echo 'manual_release_tests=PASS' echo 'manual_release_tests=PASS'
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
script=$root/scripts/cluster/run-production-acceptance.sh
awk '
/^is_release_ancestor\(\)/ { capture = 1 }
capture && /^create_and_activate_run\(\)/ { exit }
capture { print }
' "$script" >"$tmp/is-release-ancestor.sh"
# shellcheck source=/dev/null
source "$tmp/is-release-ancestor.sh"
cluster_root=$tmp/repository
git init -q "$cluster_root"
git -C "$cluster_root" config user.name 'Acceptance Script Test'
git -C "$cluster_root" config user.email 'acceptance-script-test@example.invalid'
git -C "$cluster_root" commit --allow-empty -qm first
first=$(git -C "$cluster_root" rev-parse HEAD)
git -C "$cluster_root" commit --allow-empty -qm second
git -C "$cluster_root" commit --allow-empty -qm third
third=$(git -C "$cluster_root" rev-parse HEAD)
is_release_ancestor "$first" "$third"
if is_release_ancestor "$third" "$first"; then
echo 'descendant release was accepted as an ancestor' >&2
exit 1
fi
if is_release_ancestor invalid "$third"; then
echo 'invalid release identifier was accepted as an ancestor' >&2
exit 1
fi
echo 'production_acceptance_script_tests=PASS'