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
+19 -2
View File
@@ -332,7 +332,17 @@ in
admin_token="$(cat "$TOKEN_FILE")"
secret="$(cat "$SECRET_FILE")"
auth=(-H "Authorization: token $admin_token")
target="http://mars.orbit.sol:8645/gitea"
# The path carries the Hermes route the relay should forward into, so
# each Hermes subscription gets its own hook here and the relay itself
# stays generic. Adding one is a new subscribe + a new hook URL.
relay="http://mars.orbit.sol:8645"
target="$relay/gitea/gitea-pr-comments"
# Retire the pre-rename hook, which posted to the relay's bare path and
# would now double-deliver alongside $target. Matched by its EXACT old
# URL, deliberately: anything else pointing at $relay is a hook for a
# different Hermes route and must survive.
legacy_target="$relay/gitea"
# Same readiness gate as gitea-ci-bot-provision / gitea-luna-provision
# above: After=gitea.service only means the process started, not that it
@@ -351,7 +361,14 @@ in
--argjson events '${builtins.toJSON giteaWebhookEvents}' \
'{type: "gitea", config: {content_type: "json", url: $url, secret: $secret}, events: $events, active: true}')"
hook_id="$(curl -fsS "''${auth[@]}" "$api/repos/darman/homelab/hooks" \
hooks="$(curl -fsS "''${auth[@]}" "$api/repos/darman/homelab/hooks")"
for stale in $(printf '%s' "$hooks" \
| jq -r --arg url "$legacy_target" '.[] | select(.type == "gitea" and .config.url == $url) | .id'); do
curl -fsS "''${auth[@]}" -X DELETE "$api/repos/darman/homelab/hooks/$stale" >/dev/null
done
hook_id="$(printf '%s' "$hooks" \
| jq -r --arg url "$target" 'first(.[] | select(.type == "gitea" and .config.url == $url)) | .id // empty')"
if [ -n "$hook_id" ]; then
printf '%s' "$body" | curl -fsS "''${auth[@]}" -H 'Content-Type: application/json' \