Skip to content

feat(api): add GitHub webhook receiver for evented refresh#1317

Open
jonnii wants to merge 1 commit into
jonnii/20260623024903/add-GitHub-webhook-signature-push-parsing-helperfrom
jonnii/20260623025415/add-GitHub-webhook-receiver-for-evented-refresh
Open

feat(api): add GitHub webhook receiver for evented refresh#1317
jonnii wants to merge 1 commit into
jonnii/20260623024903/add-GitHub-webhook-signature-push-parsing-helperfrom
jonnii/20260623025415/add-GitHub-webhook-receiver-for-evented-refresh

Conversation

@jonnii

@jonnii jonnii commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

POST /api/v1/webhooks/github turns a verified push into an immediate refresh of
the matching managed checkout, so server state tracks GitHub without waiting for
the next interval tick. The interval loop stays as a backstop.

  • The route bypasses the session/CSRF gate (GitHub carries neither) but stays
    rate-limited, mirroring how /config is mounted on the public mux. It is
    authenticated solely by the X-Hub-Signature-256 HMAC and fails closed (404)
    when STACKIT_GITHUB_WEBHOOK_SECRET is unset, so it is never an open trigger —
    the correct posture for local/dev servers GitHub cannot reach.
  • The handler acks immediately (202) and runs the mirror-fetch in the
    background, since a fetch can outlast GitHub's delivery timeout. Coalescing
    bursts is a follow-up.
  • The shared *reposync.Syncer is now built once in NewServer (guarding the
    typed-nil provider trap) and drives both the interval loop and the webhook,
    so on-demand refresh works even with the loop disabled. handlers depends on it
    only through a narrow RepoSyncer interface.

Stack

Auto-generated by Stackit

POST /api/v1/webhooks/github turns a verified push into an immediate refresh of
the matching managed checkout, so server state tracks GitHub without waiting for
the next interval tick. The interval loop stays as a backstop.

- The route bypasses the session/CSRF gate (GitHub carries neither) but stays
  rate-limited, mirroring how /config is mounted on the public mux. It is
  authenticated solely by the X-Hub-Signature-256 HMAC and fails closed (404)
  when STACKIT_GITHUB_WEBHOOK_SECRET is unset, so it is never an open trigger —
  the correct posture for local/dev servers GitHub cannot reach.
- The handler acks immediately (202) and runs the mirror-fetch in the
  background, since a fetch can outlast GitHub's delivery timeout. Coalescing
  bursts is a follow-up.
- The shared *reposync.Syncer is now built once in NewServer (guarding the
  typed-nil provider trap) and drives both the interval loop and the webhook,
  so on-demand refresh works even with the loop disabled. handlers depends on it
  only through a narrow RepoSyncer interface.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant