Skip to content

[P2] Webhook rejects valid HMAC-signed GitHub deliveries before signature verification #761

Description

@itsmiso-ai

Ask: Authenticate GitHub webhook deliveries by their valid HMAC signature so direct deliveries work in production auth modes.
Expected files: src/app/api/pr-followup/webhook/route.ts, src/app/api/pr-followup/webhook/route.test.ts, src/middleware.ts, docs/pr-review-fix-queue.md

Problem: POST /api/pr-followup/webhook runs authorizeRequest(request) before HMAC verification. Real GitHub webhook deliveries carry no Authorization header — GitHub authenticates with x-hub-signature-256 only. So the documented "verify" mode (WEBHOOK_SECRET set, direct GitHub delivery, no gateway) returns 401 Unauthorized at the auth layer before the signature is ever checked. The route only works today when DISPATCH_AUTH_MODE=disabled or behind a gateway that injects header auth (WEBHOOK_GATEWAY_MODE=true). In basic mode the middleware rejects the delivery even earlier. Every signature test in the suite passes Authorization: Bearer …, so the GitHub-shaped request (signature only, no auth header) is never exercised.

Evidence:

  • src/app/api/pr-followup/webhook/route.ts: const auth = await authorizeRequest(request) runs before verifyWebhookSignature(...)
  • src/middleware.ts: matcher /((?!api/auth|api/health|...).*) enforces Basic/Bearer on /api/pr-followup/webhook in basic mode
  • Reproduction (2026-08-12, vitest harness): POST with x-github-event: pull_request_review + valid x-hub-signature-256 and no Authorization header → 401 {"error":"Unauthorized"}; same request with Bearer header → processed
  • src/app/api/pr-followup/webhook/route.test.ts: all signature cases include Authorization: Bearer ${mockToken}; no test covers signature-only delivery
  • docs/pr-review-fix-queue.md: documents WEBHOOK_SECRET HMAC verification as the primary mode, gateway as the exception

Acceptance:

  • A request carrying a valid x-hub-signature-256 (with WEBHOOK_SECRET set, WEBHOOK_GATEWAY_MODE unset, and no Authorization header) reaches event processing and returns 200 in oidc/legacy/basic auth modes
  • A test asserting exactly that GitHub-shaped delivery is added and passes
  • Invalid-signature deliveries still 401; basic-mode middleware no longer blocks the webhook path when signature verification is enabled

Metadata

Metadata

Assignees

No one assigned

    Labels

    auditAudit, review, or investigation work.priority/p2Normal priority.status/readyReady for Dispatch worker pickup.type/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions