Dependency to verify GitHub webhook signature and return parsed JSON data.
(
request: Request, settings: Settings = Depends(get_settings)
)
| 407 | |
| 408 | |
| 409 | async def _verify_github_webhook( |
| 410 | request: Request, settings: Settings = Depends(get_settings) |
| 411 | ) -> tuple[dict, str]: |
| 412 | """Dependency to verify GitHub webhook signature and return parsed JSON data.""" |
| 413 | |
| 414 | signature = request.headers.get("X-Hub-Signature-256") |
| 415 | event = request.headers.get("X-GitHub-Event") |
| 416 | |
| 417 | if not signature: |
| 418 | raise HTTPException(status_code=401, detail="Missing signature") |
| 419 | |
| 420 | if not event: |
| 421 | raise HTTPException(status_code=400, detail="Missing event type") |
| 422 | |
| 423 | payload = await request.body() |
| 424 | secret = settings.github_app_webhook_secret.encode() |
| 425 | hash_obj = hmac.new(secret, msg=payload, digestmod=hashlib.sha256) |
| 426 | expected_signature = f"sha256={hash_obj.hexdigest()}" |
| 427 | |
| 428 | if not hmac.compare_digest(signature, expected_signature): |
| 429 | raise HTTPException(status_code=401, detail="Invalid signature") |
| 430 | |
| 431 | data = await request.json() |
| 432 | |
| 433 | return data, event |
| 434 | |
| 435 | |
| 436 | @router.post("/webhook", name="github_webhook") |
nothing calls this directly
no outgoing calls
no test coverage detected