mars: add generic Gitea webhook relay #2

Merged
darman merged 4 commits from feat/mars-gitea-webhook-relay into master 2026-08-23 05:14:36 +02:00
Collaborator

Summary

  • add a generic HMAC-validating Gitea webhook relay on Mars
  • normalize Gitea event, signature, and delivery headers for Hermes
  • forward authenticated JSON events without repository/event/action filtering
  • configure Hermes to own event selection and Telegram response behavior
  • provision the Gitea webhook idempotently from Jupiter

Validation

  • relay integration test passed: health, HMAC forwarding, event normalization, and invalid-signature rejection
  • arbitrary non-PR events are forwarded to Hermes for policy handling
  • nixosConfigurations.mars evaluation passed
  • nixosConfigurations.jupiter evaluation passed
  • git diff --check passed
  • no deployment performed

Deployment prerequisite

Add the same random gitea_hermes_webhook_secret to both host SOPS files before deployment. The secret is intentionally not included in this PR.

## Summary - add a generic HMAC-validating Gitea webhook relay on Mars - normalize Gitea event, signature, and delivery headers for Hermes - forward authenticated JSON events without repository/event/action filtering - configure Hermes to own event selection and Telegram response behavior - provision the Gitea webhook idempotently from Jupiter ## Validation - relay integration test passed: health, HMAC forwarding, event normalization, and invalid-signature rejection - arbitrary non-PR events are forwarded to Hermes for policy handling - `nixosConfigurations.mars` evaluation passed - `nixosConfigurations.jupiter` evaluation passed - `git diff --check` passed - no deployment performed ## Deployment prerequisite Add the same random `gitea_hermes_webhook_secret` to both host SOPS files before deployment. The secret is intentionally not included in this PR.
luna added 1 commit 2026-08-23 03:45:47 +02:00
darman requested review from darman 2026-08-23 03:50:04 +02:00
luna added 1 commit 2026-08-23 03:59:28 +02:00
luna added 1 commit 2026-08-23 04:31:36 +02:00
darman added 1 commit 2026-08-23 05:08:06 +02:00
The relay was forwarding X-Gitea-Event and re-signing the body into the
deprecated generic-V1 X-Webhook-Signature header. Neither is something
Hermes acts on, which left the PR's core premise — "Hermes owns event
selection" — impossible to reach:

  - Hermes reads the event name only from X-GitHub-Event/X-GitLab-Event,
    then payload event_type/type, then falls back to the literal string
    "unknown" (gateway/platforms/webhook.py). Gitea sends X-Gitea-Event and
    no such payload key, so every delivery arrived as "unknown" and
    `hermes webhook subscribe --events ...` could never select anything.
  - Gitea's addDefaultHeaders() already signs every webhook type with
    X-Hub-Signature-256 in GitHub's exact format, and Hermes accepts that
    header on any route with no per-route provider gating. Re-signing into
    V1 was both redundant and on a deprecated path.

So the relay now verifies the signature (accepting either X-Hub-Signature-256
or X-Gitea-Signature), forwards body and signature byte-for-byte, and copies
the one header Hermes actually needs. Authentication alone never justified
this service; that header copy does, and the module comment now says so.

Also fixed:
  - gitea-hermes-webhook-provision had no API readiness wait, unlike both
    sibling units in the same file. After=gitea.service does not mean gitea
    is serving HTTP, so under `set -e` a Type=oneshot with no Restart= would
    fail on first boot and stay failed, leaving the webhook unregistered.
  - podman-hermes-agent added to the secret's restartUnits. The secret
    reaches the container only via sops.templates, whose rendered path never
    changes, so systemd would not restart the container when the secret was
    first added — hermes-agent-webhook-route then read an empty value back
    out of it and subscribed with an empty secret.
  - Webhook provisioning passes the request body to curl on stdin rather
    than in argv, keeping the shared secret out of /proc/<pid>/cmdline.
  - Missing Content-Length now returns 411 rather than 413; dropped the
    unreachable non-2xx branch (urlopen raises on non-2xx); env-var secret
    fallback is stripped to match the credential-file path.

Adds gitea-hermes-webhook-relay-test.py, which drives the real relay over
real HTTP against a stub Hermes and covers the header copy as a regression
test. Both nixosConfigurations still evaluate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S94o42aQ8VkBmEWvDem5xa
darman approved these changes 2026-08-23 05:13:57 +02:00
darman merged commit bdd6107be1 into master 2026-08-23 05:14:36 +02:00
darman deleted branch feat/mars-gitea-webhook-relay 2026-08-23 05:14:36 +02:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: darman/homelab#2