diff --git a/.gitea/workflows/gates.yml b/.gitea/workflows/gates.yml index 1ef297a..1ded8bf 100644 --- a/.gitea/workflows/gates.yml +++ b/.gitea/workflows/gates.yml @@ -37,3 +37,41 @@ jobs: # already reliably run by a person or none of CI's business. The exit code IS the result: # no `|| true`, no pipe that could swallow it. run: python3 scripts/repo_gates.py --fast + + - name: Alarm on failure + # 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. + if: failure() + env: + RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} + run: | + python3 - > payload.json <<'PY' + import json, os + 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({ + "from": "Felhom CI ", + "to": ["admin@felhom.eu"], + "subject": "[felhom CI] gates FAILED in %s" % repo, + "text": ( + "The gate entry point exited non-zero.\n\n" + "Repository : %s\n" + "Commit : %s\n" + "Run : %s/%s/actions/runs/%s\n\n" + "The failing gate names itself in the run log.\n\n" + "If the local pre-push hook was GREEN for this commit, then CI and the hook\n" + "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), + })) + 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'])"