feat(http): HMAC-verified GitHub webhook route (3/5) - #14
Merged
Merged
Conversation
Extracts the length-checked timingSafeEqual comparison into timingSafeCompare so the Telegram secret check and the GitHub signature check use one implementation.
POST /github/webhook verifies X-Hub-Signature-256 over the raw body before parsing. It fails closed with 500 when GITHUB_WEBHOOK_SECRET is unset or the body cannot be read, returns 401 on a bad signature, and acknowledges ping, malformed payloads and not-yet-routed events with a logged 200.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Third PR of the
github-alertschain. It addsPOST /github/webhookwith signature verification. Event mapping, routing and Telegram delivery arrive in PR 4. Until then, verified events are acknowledged, logged and dropped.verifyGithubSignaturecomputes HMAC-SHA256 over the raw body bytes and compares it withX-Hub-Signature-256in constant time. The JSON is parsed only after the signature passes.GITHUB_WEBHOOK_SECRET. If the secret is unset or empty, every request gets a 500 and aConfigErrorreason in the log. The Telegram route and/healthare unaffected, and there is a test for that.timingSafeComparehelper (length check, thentimingSafeEqual).Status policy
pingignored:not-yet-routedThe payload, signature and secret are never logged. A test asserts this against the actual log output.
Size exception: about 670 lines. Production code is about 140 of them; the rest is tests and apply-progress notes.
Review
Full review with four lenses, since this is an authentication path. There were no blocker or critical findings. The risk and reliability lenses found nothing. The warnings were fixed:
The scoped fix-delta validator escalated one defect caused by that correction: an unreadable body was answered 200 before authentication. A failed read is a transient transport failure, not malformed content, so the design's policy calls for a 500 that GitHub shows as failed and lets you redeliver. The maintainer authorized a second correction: the test was changed to expect 500 and failed on the old code, then the route was fixed.
Test plan
npx vitest run: 287/287 passnpx tsc --noEmit: no errorsAfter merge
Operator step (
tasks.md6.1):npx wrangler secret put GITHUB_WEBHOOK_SECRET.