From 7ff226d6220e3a2e0bdd69d83d6b8026525a6f7d Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 12 Jul 2026 23:12:33 +0900 Subject: [PATCH] fix(ci): verify upstream ci before deploy --- .gitea/workflows/deploy-prod.yml | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/.gitea/workflows/deploy-prod.yml b/.gitea/workflows/deploy-prod.yml index 09a13572..7739cd80 100644 --- a/.gitea/workflows/deploy-prod.yml +++ b/.gitea/workflows/deploy-prod.yml @@ -111,6 +111,55 @@ jobs: echo "✓ Workflow dispatch mode — release chain verification skipped" fi + - name: Validate Upstream CI Success + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + REPO: ${{ env.REPO }} + EXPECTED_SHA: ${{ github.event.workflow_run.head_sha }} + run: | + python3 - <<'PY' + import json + import os + import sys + import urllib.request + + token = os.environ["GITEA_TOKEN"] + repo = os.environ["REPO"] + expected_sha = os.environ.get("EXPECTED_SHA", "") + if not expected_sha: + print("✓ Workflow dispatch mode — upstream CI validation skipped") + sys.exit(0) + + url = f"https://gitea.taxbaik.com/api/v1/repos/{repo}/actions/runs?limit=20" + req = urllib.request.Request(url, headers={"Authorization": f"token {token}"}) + with urllib.request.urlopen(req, timeout=30) as resp: + payload = json.load(resp) + + latest_ci = None + for run in payload.get("workflow_runs", []): + path = str(run.get("path") or "") + if "ci.yml@" not in path: + continue + if run.get("status") != "completed" or run.get("conclusion") != "success": + continue + latest_ci = run + break + + if not latest_ci: + print("ERROR: No successful ci.yml run found in recent history") + sys.exit(1) + + actual_sha = str(latest_ci.get("head_sha") or "") + if actual_sha != expected_sha: + print("ERROR: Latest successful ci.yml SHA does not match upstream release SHA") + print(f"Expected: {expected_sha}") + print(f"Actual: {actual_sha}") + print(f"Run ID: {latest_ci.get('id')}") + sys.exit(1) + + print(f"✓ Upstream CI verified: {actual_sha} (run {latest_ci.get('id')})") + PY + - name: Download Release Artifact run: | ARTIFACT="${{ steps.fetch.outputs.artifact }}"