Skip to content
Docs Operate Detent Mirrored upstream
webhook-freshness.md
Docs source v0.164.2 13d15fec6a14 View this file at the pinned commit ↗

GitHub Webhook Freshness

Back to README

A Hub with GitHub compatibility enabled accepts signed GitHub webhook deliveries at POST /api/v1/webhooks/github. Detent Cloud receives them through the product GitHub App; a self-hosted detent hub serve uses the same path on its own origin and verifies the signature itself with the secret named by --github-webhook-secret-env (default DETENT_HUB_GITHUB_WEBHOOK_SECRET). Without that secret the endpoint answers webhook_unavailable. See GitHub profiles for the App, its event subscriptions, and repository binding.

Detent verifies X-Hub-Signature-256 with HMAC-SHA256 against the raw request body. See GitHub's webhook signature validation and event payload reference.

GitHub must be able to reach the payload URL. For local testing, GitHub documents forwarding deliveries with smee.io. For a persistent host without public ingress, an outbound tunnel such as a Cloudflare Tunnel published application can route a public HTTPS hostname to the Hub. Configure relays and reverse proxies to preserve the raw request body and GitHub signature headers; modifying either causes signature verification to fail.

Cloud entry startup replay

The shared entry uses DETENT_HUB_GITHUB_APP_ID and DETENT_HUB_GITHUB_APP_PRIVATE_KEY to request App webhook redeliveries once per start. Before serving, it snapshots the newest accepted delivery timestamp across ready tenant inboxes. After serving begins, it requests redelivery of failed issues and issue_comment deliveries between that receipt and startup. It follows delivery pagination, uses the latest attempt per delivery GUID, and leaves successful deliveries alone. Tenant inboxes deduplicate redeliveries using X-GitHub-Delivery.

The pass has a five-minute deadline and logs the number of requests accepted. GitHub or tenant receipt read failures are logged without stopping the entry. There is no periodic replay. Without an accepted receipt, configured App credentials, or webhook verification secret, no historical replay is attempted. Deliveries older than the newest accepted receipt or outside GitHub's retained history require operator recovery.

Hub reconciliation

detent hub serve repairs deliveries that never reach the webhook endpoint. It runs a full repository repair at startup, incremental repairs every 10 minutes, and a full repair every 24 hours by default. Configure the intervals with --reconcile-interval and --full-repair-interval. Incremental issue reads use the repository update cursor, while repository and pull-request reads reuse GitHub ETags through conditional requests. A pending targeted hydration request rewinds the next incremental cursor so a delayed partial webhook cannot be skipped.

A full repair compares complete issue and pull-request inventories. It updates labels and repository transfers, imports items missed during a webhook gap, and marks source records absent from GitHub as deleted so they stop participating in scheduling. It also refreshes mergeability, checks, statuses, and reviews for every open pull request. Incremental passes fetch those details only for the exact webhook hydration requests captured when the pass starts; requests added or coalesced during the fetch remain pending for the next pass.

Query GET /api/v1/repositories/freshness for each repository's latest successful sync, webhook receipt, reconciliation, full repair, and most recent webhook/reconciliation errors. GET /health returns status: degraded with fresh, stale, and error repository counts whenever any mirror is older than two incremental intervals or has an unresolved sync error. The Hub remains available for local reads while degraded.