diff --git a/.gitea/workflows/ci-canary.yml b/.gitea/workflows/ci-canary.yml new file mode 100644 index 000000000..7959406a9 --- /dev/null +++ b/.gitea/workflows/ci-canary.yml @@ -0,0 +1,51 @@ +name: CI Canary Check +on: + schedule: + - cron: '*/30 * * * *' + workflow_dispatch: + +jobs: + canary: + runs-on: ci-l2 + timeout-minutes: 10 + steps: + - name: Canary (runner -> docker -> network -> gitea) + run: | + set -e + echo "== runner/container basic ==" + date; hostname; whoami + echo "== gitea api reachability ==" + code=$(curl -s -o /tmp/v.json -w '%{http_code}' -m 15 "$GITHUB_API_URL/version") + echo "gitea api http_code=$code" + [ "$code" = "200" ] || { echo "::error::Gitea API unreachable, http_code=$code"; exit 1; } + cat /tmp/v.json; echo + echo "== external egress ==" + ext=$(curl -s -o /dev/null -w '%{http_code}' -m 15 https://www.baidu.com || echo 000) + echo "external http_code=$ext" + echo "== gitea domain resolves NOT to loopback ==" + set -o pipefail + ip=$(getent hosts git.xiaoxiajianji.com | awk '{print $1}' | head -1) + echo "git.xiaoxiajianji.com -> $ip" + if [ -z "$ip" ]; then + echo "::error::DNS resolution failed, git.xiaoxiajianji.com unresolvable"; exit 1 + fi + if [ "$ip" = "127.0.0.1" ] || [ "$ip" = "::1" ]; then + echo "::error::Gitea domain resolves to loopback inside job container (hosts/DNS leak)"; exit 1 + fi + echo "CANARY OK" + - name: Notify failure + if: failure() + env: + CI_NOTIFY_WEBHOOK: ${{ secrets.CI_NOTIFY_WEBHOOK }} + run: | + set +e + if [ -n "$CI_NOTIFY_WEBHOOK" ]; then + MSG="🚨 CI 金丝雀失败:runner->docker->网络->Gitea 链路异常,时间 $(date '+%Y-%m-%d %H:%M:%S'),请立即检查构建服务器" + python3 - "$CI_NOTIFY_WEBHOOK" "$MSG" <<'PY' + import json,sys,urllib.request + hook,msg=sys.argv[1],sys.argv[2] + data=json.dumps({"msg_type":"text","content":{"text":msg}}).encode() + urllib.request.urlopen(urllib.request.Request(hook,data=data,headers={"Content-Type":"application/json"}),timeout=10) + PY + fi + exit 0