From a612c3cb4ad830ef78720579e9fe9abd7e545086 Mon Sep 17 00:00:00 2001 From: wangbo Date: Sat, 1 Aug 2026 00:10:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(acceptance):=20=E6=8C=89=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E9=9A=94=E7=A6=BB=E9=AA=8C=E6=94=B6=E8=BA=AB=E4=BB=BD=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 历史验收主身份仍引用固定 production-acceptance 组,严格隔离门禁因此在切换 validation 前正确阻断。 验收组改为包含 release SHA 的稳定键;历史身份保持可审计,本次分片及已有 API Key 幂等迁移到当前发布专属组,避免清理或影响正式身份。 验证:bash -n、ShellCheck、验收报告测试、线上引用关系只读审计。 --- docs/operations/production-acceptance.md | 2 ++ scripts/cluster/run-production-acceptance.sh | 38 +++++++++++--------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/docs/operations/production-acceptance.md b/docs/operations/production-acceptance.md index 450bf77..1589514 100644 --- a/docs/operations/production-acceptance.md +++ b/docs/operations/production-acceptance.md @@ -124,6 +124,8 @@ PNG 并通过验收 Key 上传到 Gateway。生产快照默认在已部署的 AP 文件中,不写入报告或日志。上述值仍可用 `AI_GATEWAY_ACCEPTANCE_*` 显式覆盖。脚本会以主 身份为模板幂等准备其余隔离身份;模型变量可省略,脚本会从当前启用候选中选择 Gemini 图片 编辑模型,以及 `omni_video.max_images >= 9` 的视频模型并优先 Seedance 2.0/fast。 +验收组按 release SHA 隔离;历史 Run 的用户和分片不会被清理或复用到新 release,本次需要的 +分片及其 API Key 会幂等迁移到当前 release 的专属组。 为保证请求严格各有一半命中宁波和香港,可以把两个 Gateway URL 配成两个节点的 `https://<节点IP>`,并设置 diff --git a/scripts/cluster/run-production-acceptance.sh b/scripts/cluster/run-production-acceptance.sh index ebfb6b6..6b83bef 100755 --- a/scripts/cluster/run-production-acceptance.sh +++ b/scripts/cluster/run-production-acceptance.sh @@ -156,6 +156,7 @@ api_image=$(node "$cluster_root/scripts/release-manifest.mjs" get "$release_mani } api_digest=${api_image##*@} worker_digest=$api_digest +acceptance_group_key=production-acceptance-${release_sha:0:12} if [[ $skip_local_acceptance != true ]]; then node "$cluster_root/scripts/acceptance/report.mjs" validate \ --input "$local_acceptance_report" >/dev/null @@ -736,12 +737,12 @@ ensure_acceptance_user_group() { local user_response=$temporary_root/acceptance-user.json local group_id group_body user_body isolation_state admin_request GET /api/admin/user-groups '' "$groups_response" - group_id=$(jq -r ' - [.items[] | select(.groupKey == "production-acceptance") | .id] + group_id=$(jq -r --arg groupKey "$acceptance_group_key" ' + [.items[] | select(.groupKey == $groupKey) | .id] | if length == 1 then .[0] else empty end ' "$groups_response") - group_body=$(jq -cn '{ - groupKey:"production-acceptance", + group_body=$(jq -cn --arg groupKey "$acceptance_group_key" '{ + groupKey:$groupKey, name:"Production Acceptance", description:"Dedicated production-isomorphic acceptance traffic", source:"gateway", @@ -754,8 +755,8 @@ ensure_acceptance_user_group() { status:"active" }') if [[ -z $group_id ]]; then - [[ $(jq '[.items[] | select(.groupKey == "production-acceptance")] | length' \ - "$groups_response") == 0 ]] || { + [[ $(jq --arg groupKey "$acceptance_group_key" \ + '[.items[] | select(.groupKey == $groupKey)] | length' "$groups_response") == 0 ]] || { echo 'acceptance user group lookup was ambiguous' >&2 return 1 } @@ -931,19 +932,22 @@ WITH primary_user AS ( AND deleted_at IS NULL AND COALESCE(key_secret, '') <> '' ), existing_keys AS ( - SELECT selected.id, selected.gateway_user_id, selected.key_secret + UPDATE gateway_api_keys key + SET user_group_id='$acceptance_group_id'::uuid, + updated_at=now() FROM shard_users shard - JOIN LATERAL ( - SELECT key.id, key.gateway_user_id, key.key_secret - FROM gateway_api_keys key - WHERE key.gateway_user_id=shard.id - AND key.name='Production Acceptance Shard' - AND key.status='active' - AND key.deleted_at IS NULL - AND COALESCE(key.key_secret, '') <> '' - ORDER BY key.created_at + WHERE key.id=( + SELECT selected.id + FROM gateway_api_keys selected + WHERE selected.gateway_user_id=shard.id + AND selected.name='Production Acceptance Shard' + AND selected.status='active' + AND selected.deleted_at IS NULL + AND COALESCE(selected.key_secret, '') <> '' + ORDER BY selected.created_at LIMIT 1 - ) selected ON true + ) + RETURNING key.id, key.gateway_user_id, key.key_secret ), new_key_material AS ( SELECT shard.id AS gateway_user_id, 'sk-gw-' || encode(gen_random_bytes(32), 'hex') AS secret