diff --git a/docs/runbooks/production-first-activation.md b/docs/runbooks/production-first-activation.md index a92cf84..fc906c5 100644 --- a/docs/runbooks/production-first-activation.md +++ b/docs/runbooks/production-first-activation.md @@ -44,7 +44,7 @@ ./scripts/github/configure.sh --environment production --enable-production ``` - 预期:Environment 只保留五项新架构应用 Secret;production 仅允许 `main`,且需要 `kysonzou` 审批。旧 VM 不读取 GitHub Environment Secret,不受本步骤影响。 + 预期:Environment 只保留五项新架构应用 Secret;production 仅允许 `main`,且需要当前登录的 GitHub 身份审批。旧 VM 不读取 GitHub Environment Secret,不受本步骤影响。 4. 在 GitHub Actions 的 `main` 手动运行 `Infrastructure apply`,选择 `production/bootstrap`,完成 Environment 审批后确认零变更。再手动运行 `Infrastructure plan`,选择 `production/platform`,核对只会在 `kyson-proxy-prod` 创建 `proxy-*` 资源和新的 `proxy-ipv4`。 diff --git a/scripts/github/audit.sh b/scripts/github/audit.sh index 06fc74f..79b7a97 100755 --- a/scripts/github/audit.sh +++ b/scripts/github/audit.sh @@ -58,9 +58,10 @@ read_variable() { jq -er --arg name "$2" '.variables[] | select(.name == $name) [[ "$(read_variable "$environment_variables" GCP_DEPLOY_SERVICE_ACCOUNT)" == "$deploy_sa" ]] || { printf '%s\n' 'deploy service account variable does not match bootstrap state' >&2; exit 1; } if [[ "$environment" == "production" ]]; then + reviewer_id="$(gh api user --jq '.id')" protection="$(gh api "repos/${repo}/environments/production")" - jq -e ' - (.protection_rules | any(.type == "required_reviewers" and (.reviewers | any(.reviewer.login == "kysonzou")))) and + jq -e --argjson reviewer_id "$reviewer_id" ' + (.protection_rules | any(.type == "required_reviewers" and (.reviewers | any(.reviewer.id == $reviewer_id)))) and (.deployment_branch_policy.protected_branches == false) and (.deployment_branch_policy.custom_branch_policies == true) ' <<<"$protection" >/dev/null || { printf '%s\n' 'production environment protection is incomplete' >&2; exit 1; } diff --git a/scripts/github/test-tools.sh b/scripts/github/test-tools.sh index 8544de4..4e8b99a 100755 --- a/scripts/github/test-tools.sh +++ b/scripts/github/test-tools.sh @@ -21,10 +21,14 @@ printf '%s\n' '#!/usr/bin/env bash' 'set -euo pipefail' \ 'if [[ "$1" == "api" && "$*" == *"--input -"* ]]; then cat >/dev/null; exit 0; fi' \ 'if [[ "$1" == "api" && "$*" == *"repos/kyson-dev/proxy-builder/actions/variables"* && "$*" != *"--method DELETE"* ]]; then' \ ' extra=""; [[ "${FAKE_AUDIT_EXTRA:-0}" == "1" ]] && extra='\'',{"name":"DEV_LEGACY","value":"legacy"}'\''' \ - ' printf '\''{"variables":[{"name":"DEV_GCP_WIF_PROVIDER","value":"projects/123/locations/global/workloadIdentityPools/pool/providers/provider"},{"name":"DEV_GCP_PLAN_SERVICE_ACCOUNT","value":"plan@example.iam.gserviceaccount.com"}%s]}\n'\'' "$extra"; exit 0' \ + ' printf '\''{"variables":[{"name":"DEV_GCP_WIF_PROVIDER","value":"projects/123/locations/global/workloadIdentityPools/pool/providers/provider"},{"name":"DEV_GCP_PLAN_SERVICE_ACCOUNT","value":"plan@example.iam.gserviceaccount.com"},{"name":"PROD_GCP_WIF_PROVIDER","value":"projects/123/locations/global/workloadIdentityPools/pool/providers/provider"},{"name":"PROD_GCP_PLAN_SERVICE_ACCOUNT","value":"plan@example.iam.gserviceaccount.com"}%s]}\n'\'' "$extra"; exit 0' \ 'fi' \ 'if [[ "$1" == "api" && "$*" == *"environments/development/variables"* ]]; then printf '\''{"variables":[{"name":"GCP_APPLY_SERVICE_ACCOUNT","value":"apply@example.iam.gserviceaccount.com"},{"name":"GCP_DEPLOY_SERVICE_ACCOUNT","value":"deploy@example.iam.gserviceaccount.com"}]}\n'\''; exit 0; fi' \ 'if [[ "$1" == "api" && "$*" == *"environments/development/secrets"* ]]; then printf '\''{"secrets":[{"name":"REALITY_PRIVATE_KEY"},{"name":"OBFS_PASSWORD"},{"name":"HY2_CERT_PEM"},{"name":"HY2_KEY_PEM"},{"name":"PROXY_USERS_JSON"}]}\n'\''; exit 0; fi' \ + 'if [[ "$1" == "api" && "$*" == *"environments/production/variables"* ]]; then printf '\''{"variables":[{"name":"GCP_APPLY_SERVICE_ACCOUNT","value":"apply@example.iam.gserviceaccount.com"},{"name":"GCP_DEPLOY_SERVICE_ACCOUNT","value":"deploy@example.iam.gserviceaccount.com"}]}\n'\''; exit 0; fi' \ + 'if [[ "$1" == "api" && "$*" == *"environments/production/secrets"* ]]; then printf '\''{"secrets":[{"name":"REALITY_PRIVATE_KEY"},{"name":"OBFS_PASSWORD"},{"name":"HY2_CERT_PEM"},{"name":"HY2_KEY_PEM"},{"name":"PROXY_USERS_JSON"}]}\n'\''; exit 0; fi' \ + 'if [[ "$1" == "api" && "$*" == *"environments/production/deployment-branch-policies"* ]]; then printf '\''{"total_count":1,"branch_policies":[{"name":"main"}]}\n'\''; exit 0; fi' \ + 'if [[ "$1" == "api" && "$*" == *"environments/production"* && "$*" != *"--method DELETE"* ]]; then printf '\''{"protection_rules":[{"type":"required_reviewers","reviewers":[{"reviewer":{"id":123456}}]}],"deployment_branch_policy":{"protected_branches":false,"custom_branch_policies":true}}\n'\''; exit 0; fi' \ 'if [[ "$1" == "api" && "$2" == "user" && "$*" == *"--jq .id"* ]]; then printf '\''123456\n'\''; exit 0; fi' \ 'if [[ "$1" == "api" && "$*" == *"repos/kyson-dev/proxy-builder"* && "$*" == *"--jq .id"* ]]; then printf '\''986343343\n'\''; exit 0; fi' \ 'if [[ "$1" == "api" && "$*" == *"environments/development"* && "$*" != *"--method DELETE"* ]]; then printf '\''{}\n'\''; exit 0; fi' \ @@ -71,6 +75,8 @@ variable_line="$(rg -n 'gh variable set' "$command_log" | cut -d: -f1 | head -n1 : >"$command_log" PATH="${fake_bin}:$PATH" FAKE_COMMAND_LOG="$command_log" \ "$script_dir/audit.sh" --environment development --bootstrap-output "$bootstrap_output" >"${test_root}/audit.log" +PATH="${fake_bin}:$PATH" FAKE_COMMAND_LOG="$command_log" \ + "$script_dir/audit.sh" --environment production --bootstrap-output "$bootstrap_output" >"${test_root}/production-audit.log" set +e PATH="${fake_bin}:$PATH" FAKE_COMMAND_LOG="$command_log" FAKE_AUDIT_EXTRA=1 \ "$script_dir/audit.sh" --environment development --bootstrap-output "$bootstrap_output" >/dev/null 2>&1