hermes: write the webhook routes as config, and add a PR-review route
`hermes webhook subscribe` has no --toolsets flag, so a webhook run got
Hermes's constrained default (web_search, web_extract, vision_analyze,
clarify) -- no shell, no file access, which meant neither prompt could
actually be carried out: luna was woken, read the comment, and had no way
to act on it. Upstream's documented answer is to add the `toolsets` key to
webhook_subscriptions.json by hand, and a hand edit does not survive this
unit's re-provision. So the whole route definition moves here and the CLI
is not used at all.
The file is written host-side with jq. hermesHome is the bind-mount source
for /opt/data, so the container sees the same inode and hot-reloads it on
the next delivery -- no podman exec, no readiness loop, and no quoting
chain between nix and the prompt text. The merge is per-route: routes this
unit does not name survive, created_at is carried over, and every other
key is replaced outright so a hand-added `deliver_only` or `filters`
cannot linger.
The secret now comes from the sops file directly instead of being read
back out of the container's environment, which drops podman-hermes-agent
from restartUnits (the ordering constraint it existed for is gone) and
takes GITEA_HERMES_WEBHOOK_SECRET out of an env var luna can read.
The new gitea-pr-reviews route covers reviews with a body and
changes-requested. Those are not IssueCommentPayloads: gitea sends a
PullRequestPayload with action "reviewed" and a `review` object of exactly
{type, content} -- no review id, no line comments. So the prompt fetches
them with `tea pulls review-comments` and acts only on ones whose
`resolver` is empty, resolving each as it goes; with no stable id in the
payload, resolved state is the only workable duplicate-delivery guard.
An empty review body is deliberately NOT a drop, unlike in the comment
filter: a review whose substance is entirely in line comments has none.
Approvals are left unsubscribed -- an approval is darman signing off, not
asking for work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S94o42aQ8VkBmEWvDem5xa
This commit is contained in:
+13
-20
@@ -28,27 +28,21 @@
|
||||
sops.secrets.opencode_go_api_key = { };
|
||||
sops.secrets.telegram_bot_token = { };
|
||||
sops.secrets.hermes_dashboard_oidc_client_secret = { };
|
||||
# Add the same value to secrets/mars.yaml before deploying Mars, and store
|
||||
# it WITHOUT a trailing newline: it reaches Hermes through the env template
|
||||
# below, where a newline would both corrupt the env file and change the key
|
||||
# the HMAC is computed with. `scripts/edit_secrets` writes a bare value.
|
||||
# Same value as in secrets/jupiter.yaml (the sending side), stored WITHOUT a
|
||||
# trailing newline — a stray newline would change the key the HMAC is
|
||||
# computed with and fail every delivery. `scripts/edit_secrets` writes a
|
||||
# bare value. hermes-agent.nix trims one anyway, belt and braces.
|
||||
#
|
||||
# podman-hermes-agent is in restartUnits for a reason that is easy to miss:
|
||||
# the secret reaches the container only through sops.templates, whose
|
||||
# rendered PATH never changes, so the container unit's definition is
|
||||
# identical before and after the secret is added and systemd will NOT
|
||||
# restart it on its own. Without this line the very first deploy leaves the
|
||||
# container holding an empty GITEA_HERMES_WEBHOOK_SECRET, and
|
||||
# hermes-agent-webhook-route (which reads it back out of the running
|
||||
# container) subscribes with an empty secret — every delivery then fails
|
||||
# signature validation inside Hermes with no obvious cause. That unit now
|
||||
# refuses to subscribe on an unset secret rather than doing it quietly, but
|
||||
# the ordering here is still what makes the rotation correct.
|
||||
# This is NOT in the container's env any more. It used to be, because
|
||||
# hermes-agent-webhook-route ran `hermes webhook subscribe` inside the
|
||||
# container and read the secret back out of its environment — which meant
|
||||
# podman-hermes-agent had to be restarted first on rotation, or the
|
||||
# subscription silently pinned the stale value. The route config is now
|
||||
# written host-side (hermes-agent-webhook-routes reads this file directly),
|
||||
# so that ordering constraint is gone and the secret no longer sits in an
|
||||
# env var luna can read with `env`.
|
||||
sops.secrets.gitea_hermes_webhook_secret = {
|
||||
restartUnits = [
|
||||
"podman-hermes-agent.service"
|
||||
"hermes-agent-webhook-route.service"
|
||||
];
|
||||
restartUnits = [ "hermes-agent-webhook-routes.service" ];
|
||||
};
|
||||
sops.templates."hermes-agent.env".content = ''
|
||||
OPENCODE_GO_API_KEY=${config.sops.placeholder.opencode_go_api_key}
|
||||
@@ -57,7 +51,6 @@
|
||||
TELEGRAM_ALLOWED_USERS=15151223
|
||||
WEBHOOK_ENABLED=true
|
||||
WEBHOOK_PORT=8644
|
||||
GITEA_HERMES_WEBHOOK_SECRET=${config.sops.placeholder.gitea_hermes_webhook_secret}
|
||||
HERMES_DASHBOARD_OIDC_CLIENT_SECRET=${config.sops.placeholder.hermes_dashboard_oidc_client_secret}
|
||||
'';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user