diff --git a/.gitea/workflows/gates.yml b/.gitea/workflows/gates.yml index 1ded8bf..b158f14 100644 --- a/.gitea/workflows/gates.yml +++ b/.gitea/workflows/gates.yml @@ -42,19 +42,30 @@ jobs: # THE POINT OF THE WHOLE THING. Probe P5 measured that a failed run produces NO mail, NO # notification row and NO log line from Gitea itself — a red tick in a web UI nobody watches # is exactly the shape R-29 filed against. So the run sends its own alarm, on the project's - # existing transactional path (Resend, the same one the hub uses), and it prints the - # provider's accepted id so "it was sent" is an observable rather than an assumption. + # existing transactional path (Resend, the same one the hub uses), and prints the provider's + # accepted id so "a message left the machine" is an observable, not an assumption. + # + # Pure python3 and urllib, NOT curl: the runner image carries python3 and git and nothing + # else on purpose, and the first version of this step died on `curl: command not found`. + # Reaching for a bigger image to send one HTTP request would have been the wrong trade. if: failure() env: RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} run: | - python3 - > payload.json <<'PY' - import json, os + python3 - <<'PY' + import json, os, sys, urllib.request, urllib.error + + key = os.environ.get("RESEND_API_KEY", "") + if not key: + sys.exit("ALARM FAILED: RESEND_API_KEY is empty — the alarm cannot be sent, and a " + "silent alarm is worse than none. Set the user-level Actions secret.") + repo = os.environ.get("GITHUB_REPOSITORY", "?") sha = os.environ.get("GITHUB_SHA", "?") run = os.environ.get("GITHUB_RUN_NUMBER", "?") srv = os.environ.get("GITHUB_SERVER_URL", "https://gitea.dooplex.hu") - print(json.dumps({ + + body = json.dumps({ "from": "Felhom CI ", "to": ["admin@felhom.eu"], "subject": "[felhom CI] gates FAILED in %s" % repo, @@ -68,10 +79,15 @@ jobs: "disagree - that is a finding about the gates themselves, not about CI, and it\n" "outranks whatever the push was for.\n" ) % (repo, sha, srv, repo, run), - })) + }).encode() + + req = urllib.request.Request( + "https://api.resend.com/emails", data=body, method="POST", + headers={"Authorization": "Bearer %s" % key, + "Content-Type": "application/json"}) + try: + with urllib.request.urlopen(req, timeout=30) as r: + print("RESEND-ACCEPTED id=%s" % json.load(r)["id"]) + except urllib.error.HTTPError as e: + sys.exit("ALARM FAILED: Resend returned HTTP %s: %s" % (e.code, e.read().decode()[:300])) PY - curl -sS --fail-with-body -X POST https://api.resend.com/emails \ - -H "Authorization: Bearer $RESEND_API_KEY" \ - -H "Content-Type: application/json" \ - --data @payload.json > resend-response.json - python3 -c "import json;print('RESEND-ACCEPTED id=%s' % json.load(open('resend-response.json'))['id'])"