Files
felhom.eu/.gitea/workflows/gates.yml
T
admin dd13f632c8
gates / gates (push) Failing after 7s
ci: a failed run sends its own alarm (R-168, probe P5)
P5 measured: a failed run produces NO mail, NO notification row and NO log line from Gitea.
A red tick in a web UI nobody watches is exactly the defect R-29 filed, rebuilt one layer
up, so the run alarms itself on the project's existing transactional path (Resend, the same
one the hub uses) and prints the provider's accepted id, making 'it was sent' an observable
rather than an assumption.

The key is a user-level Gitea Actions secret created out-of-band; it is in no committed
file. The recipient is the operator address the hub already uses and is not a secret.

This push is deliberately made while main is still carrying the Scenario B breakage, so the
resulting run fails and demonstrates the alarm end to end.
2026-08-02 16:23:56 +02:00

78 lines
4.0 KiB
YAML

# gates — re-run this repo's gate entry point on every push, on a machine that does not care who
# pushed or what they typed.
#
# *** THIS REPORTS. IT CANNOT REFUSE. ***
#
# felhom repos push straight to `main` with no pull request, so there is no merge for a status
# check to stand at. The refusing half is `.githooks/pre-push`, which is local to a clone and which
# `git push --no-verify` skips; this half is what notices when that happened. Neither half is the
# whole thing, and both are named in documentation/backlog/OPEN-ITEMS.md R-168.
#
# NO `uses:` STEP ANYWHERE, deliberately: JavaScript actions need a node runtime in the runner, and
# the runner is a host-mode container with python3 and git and nothing else (see
# homelab-manifests/gitea-system/act-runner.yaml for why it is not privileged). Probe P3 measured
# that a plain `git fetch` of the pushed SHA from the in-cluster Gitea service is enough.
#
# A failing run must reach a person — a detector nobody hears is the defect R-29 filed, rebuilt one
# layer up. That is the last step, and it runs ONLY on failure.
name: gates
on: [push]
jobs:
gates:
runs-on: felhom-gates
steps:
- name: Fetch the pushed commit
run: |
# Shallow, and pinned to the exact SHA that was pushed — not to the branch tip, which can
# move under us if two pushes race. Probe P3 proved the two are equal when done this way.
git init -q .
git remote add origin http://gitea.gitea-system.svc.cluster.local:3000/admin/felhom.eu.git
git fetch -q --depth 1 origin "$GITHUB_SHA"
git checkout -q FETCH_HEAD
echo "checked out $(git rev-parse HEAD)"
- name: Run the gate entry point
# The ONLY thing CI runs. No go build, no go test, no linting, no deploy — those are either
# 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 <monitoring@felhom.eu>",
"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'])"