relay: take the Hermes route from the request path

Renames the subscription to gitea-pr-comments (it handles one event; the old
gitea-events name promised more than it delivered) and drops --deliver.

Rather than move the hardcoded route from one constant to another, the relay
now reads it from the request path: POST /gitea/<route> forwards to
<base>/webhooks/<route>. The route name was the last thing tying this service
to a specific subscription, so a second Hermes route is now a `hermes webhook
subscribe <name>` plus a Gitea hook at /gitea/<name>, with no relay change --
previously it would also have needed a second relay URL baked in here.

The path segment is interpolated into an outbound URL, so it is validated
against ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ and refused rather than sanitised
when it does not match. The path is matched raw and never URL-decoded, so
percent-encoded separators fail the charset check instead of surviving it;
requiring an alphanumeric first character also rejects "." and "..". Without
this, POST /gitea/..%2fadmin would let anything that can reach the relay
steer it at other Hermes endpoints. Tests cover traversal, encoded traversal,
embedded slashes, leading dot/dash, and the length bound, and assert nothing
reaches the stub Hermes in any of those cases.

Dropping --deliver leaves it at its default of `log`. The prompt tells her to
answer in the pull request, so the PR comment is the delivery and a Telegram
copy would only duplicate it; this also removes the hardcoded chat id that
was a third copy of TELEGRAM_HOME_CHANNEL.

Provisioning retires the pre-rename hook by its EXACT old URL rather than by
"points at the relay". Now that sibling hooks for other routes are the
intended pattern, a prefix match would delete them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S94o42aQ8VkBmEWvDem5xa
This commit is contained in:
2026-08-23 06:52:52 +02:00
co-authored by Claude Opus 5
parent 31ba001d06
commit f982c6dc14
5 changed files with 142 additions and 25 deletions
+8 -1
View File
@@ -44,7 +44,14 @@ authenticated request body and Gitea's own signature to Hermes over localhost
completely unchanged, and copies `X-Gitea-Event` into `X-GitHub-Event`. It has
no event, repository, action, payload, or prompt policy; Hermes owns
interpretation and response behavior. Jupiter's Gitea provisioning service
registers the webhook idempotently at `http://mars.orbit.sol:8645/gitea`.
registers the webhook idempotently at
`http://mars.orbit.sol:8645/gitea/gitea-pr-comments`.
The path after `/gitea/` names the Hermes route to forward into, so the relay
is not tied to any one subscription: another Hermes route needs a
`hermes webhook subscribe <name>` and a Gitea hook pointing at
`/gitea/<name>`, and no relay change. Route names are validated against a
strict charset before being used in the outbound URL.
That one header copy is the entire reason the relay exists. Gitea signs every
webhook with `X-Hub-Signature-256` in GitHub's exact format, which Hermes