Skip to main content

Module webhook

Module webhook 

Source
Expand description

POST /api/webhooks/{source} — the console’s webhook ingress (#5089 step 3).

Why: ADR-0032 removed every sibling daemon’s HTTP listener, and ADR-0034 rules that console terminates the GitHub request and relays inward over UDS. The two handlers this path replaced both acknowledged GitHub before the work ran and downgraded every later failure to a log line. GitHub never retries an acknowledged delivery, so each of those failures was permanent, silent loss with every health signal still green. #5181 deleted them — trusty-review’s POST /pr/github/webhook and trusty-analyze’s POST /webhooks/github now 404 — so this route is the only HTTP webhook surface in the workspace, and the only holder of the shared secret.

What: one route, multiplexed by {source} over both targets. The order of operations is the fix and is not negotiable:

  1. unknown {source}404, before any secret handling;
  2. HMAC verified once, over the exact received bytes; unset secret and bad signature both → 401 (ADR-0034 §2 unifies the policy to fail-closed);
  3. the delivery is written and fsync’d to the spool — on failure 500, and no 202 is ever sent, so GitHub keeps the delivery redeliverable;
  4. the relay runs, and its outcome is recorded durably: an explicit ack deletes the entry, anything else leaves it pending with an incremented attempt count;
  5. 202, because step 3 succeeded — not because step 4 did.

🔴 Explicitly absent, per ADR-0034 §2: let _ = relay(...), a bare tracing::warn! as the sole record of a failed relay, and any 202 issued before the spool write returns.

Spawn-on-demand — console starting a target that is not resident — landed in #5182 alongside the targets’ listeners: spawn::TargetSupervisor runs ensure_running before each relay. A target that will not start is still relay::RelayOutcome::Unreachable, which is a durable pending state, not a dropped delivery.

Test: tests.rs.

Re-exports§

pub use schedule::BackoffPolicy;

Modules§

health
Oldest-pending-age as a red health state on /api/console/metrics/*.
relay
Sending a spooled delivery to its target, and deciding what counts as an acknowledgement.
schedule
Who may relay an entry, and when — the two guards that keep one delivery from becoming several relays.
spawn
Starting a relay target that is not running (#5182, ADR-0034 §1).
spool
The durable spool: a delivery is on disk and fsync’d before console acknowledges GitHub.

Structs§

SweepReport
Counts from one WebhookIngress::retry_pending_once pass.
Target
One relay target reachable through /api/webhooks/{source}.
WebhookIngress
The webhook ingress: spool, secret, and one relay per target.

Enums§

IngestOutcome
Result of one ingress attempt, before it becomes an HTTP response.

Constants§

MAX_WEBHOOK_BODY_BYTES
Largest webhook body the ingress route accepts.
SECRET_ENV
Environment variable holding the shared webhook secret.

Functions§

default_spool_root
The spool root, for callers that need it before an ingress exists.
metrics_webhooks_handler
GET /api/console/metrics/webhooks — oldest-pending-age as a health state.
start_retry_sweep
Run WebhookIngress::retry_pending_once on an interval, forever.
webhook_handler
POST /api/webhooks/{source} — the axum front door.