gitea: subscribe the review hook to pull_request_review

The hook registered with no events at all and delivered nothing.
"pull_request_review_comment" and "pull_request_review_rejected" are real
HookEventTypes and real X-GitHub-Event-Type values, but they are not
things gitea's hook API accepts. updateHookEvents
(routers/api/v1/utils/hook.go) matches a fixed list of api names and
silently ignores anything else, so every event flag stayed false, the POST
succeeded, and the hook sat there inert.

There is no narrower api name: HasEvent (models/webhook/webhook.go)
collapses approved, rejected and review-comment onto
HookEventPullRequestReview, so `pull_request_review` is a single switch for
all three. Approvals consequently cannot be excluded at the hook any more.
They now cross the wire as "pull_request_approved", which is not in the
route's event list, so Hermes ignores them on the event match -- before the
filter script and before any LLM call. Gitea's delivery log will show them
answered 200/ignored, which is intended.

That makes three namespaces for the same event rather than two, so the
tables in both nix files and the README now carry the api column, and the
README warns about the silent-ignore behaviour that hid this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S94o42aQ8VkBmEWvDem5xa
This commit is contained in:
2026-08-24 03:27:52 +02:00
co-authored by Claude Opus 5
parent 152c38b56b
commit b99337adb7
4 changed files with 83 additions and 52 deletions
+23 -13
View File
@@ -42,13 +42,16 @@ run. Each service module opens its own firewall ports.
Jupiter's Gitea registers one webhook per Hermes route, straight at Hermes on
mars (`http://mars.orbit.sol:8644/webhooks/<route>`), with no relay in between:
| route | subscribed gitea events | wakes luna on |
| route | gitea hook event | wakes luna on |
| --- | --- | --- |
| `gitea-pr-comments` | `pull_request_comment` | a timeline comment on a PR |
| `gitea-pr-reviews` | `pull_request_review_comment`, `pull_request_review_rejected` | a review with a body, or changes requested |
| `gitea-pr-reviews` | `pull_request_review` | a review with a body, or changes requested |
Approvals are deliberately not subscribed: an approval is darman signing off,
not asking for work. Gitea's `addDefaultHeaders` signs every webhook type with
Approvals cannot be excluded at the hook — `pull_request_review` is one switch
for all three review types — so they are delivered and then dropped by the
Hermes route, which does not list `pull_request_approved`. Expect them in
gitea's delivery log answered 200/ignored; that is the design, not a failure.
Gitea's `addDefaultHeaders` signs every webhook type with
`X-Hub-Signature-256` in GitHub's exact format and sends `X-GitHub-Event`
unconditionally — which is exactly what Hermes validates against the route
secret and reads the event name from, so the two speak the same protocol
@@ -61,17 +64,24 @@ defaults to `external` and does NOT include tailnet addresses
gitea classifies it). `services/dev/gitea.nix` sets it accordingly; without
that, deliveries fail with `webhook can only call allowed HTTP servers`.
Gitea names webhook events twice, and the two namespaces collide. The hook's
`events` array takes the *subscription* name; `X-GitHub-Event`, which is what
each Hermes route matches its `events` against, carries a lossy *wire* name
from `HookEventType.Event()`:
Gitea spells the same event three ways, and two of the spellings collide. The
hook's `events` array takes an *api* name (`updateHookEvents` in
`routers/api/v1/utils/hook.go`), which is a coarser set than the internal
`HookEventType`; `X-GitHub-Event`, which is what each Hermes route matches its
`events` against, carries a lossy *wire* name from `HookEventType.Event()`:
| subscription | wire | what it is |
| HookEventType | wire (mars route) | api (gitea hook) |
| --- | --- | --- |
| `pull_request_comment` | `issue_comment` | comment on a PR |
| `pull_request_review_comment` | `pull_request_comment` | review with a body |
| `pull_request_review_rejected` | `pull_request_rejected` | changes requested |
| `pull_request_review_approved` | `pull_request_approved` | approval |
| `issue_comment` | `issue_comment` | `issue_comment` |
| `pull_request_comment` | `issue_comment` | `pull_request_comment` |
| `pull_request_review_comment` | `pull_request_comment` | `pull_request_review` |
| `pull_request_review_rejected` | `pull_request_rejected` | `pull_request_review` |
| `pull_request_review_approved` | `pull_request_approved` | `pull_request_review` |
Watch the api column: `updateHookEvents` **silently ignores strings it does not
recognise**, so a plausible-looking name that is a valid `HookEventType` but
not a valid api event leaves the hook registered with no events at all — no
error, no deliveries. Check a new hook's event list in the UI after adding it.
So `services/dev/gitea.nix` and `hosts/mars/hermes-agent.nix` deliberately name
the same event differently, and neither is a typo. `X-GitHub-Event-Type`