From 2e2fd1a8f67b8453b9957a39ada02ff0afab617b Mon Sep 17 00:00:00 2001 From: sagarshresti18 Date: Sat, 14 Feb 2026 01:09:46 +0530 Subject: [PATCH 1/3] feat: add schema validation and error handling for GitHub webhook handler --- backend/routes.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/backend/routes.py b/backend/routes.py index 7dbd6463..50e10a8f 100644 --- a/backend/routes.py +++ b/backend/routes.py @@ -7,17 +7,24 @@ from app.core.events.base import BaseEvent from app.core.handler.handler_registry import HandlerRegistry from pydantic import BaseModel +from typing import Optional, Dict, Any router = APIRouter() class RepoRequest(BaseModel): repo_url: str +class GitHubWebhookPayload(BaseModel): + action: Optional[str] = None + sender: Optional[Dict[str, Any]] = None + pull_request: Optional[Dict[str, Any]] = None + logging.basicConfig(level=logging.INFO) handler_registry = HandlerRegistry() event_bus = EventBus(handler_registry) + # Sample handler function to process events async def sample_handler(event: BaseEvent): logging.info(f"Handler received event: {event.event_type} with data: {event.raw_data}") @@ -35,9 +42,17 @@ def register_event_handlers(): event_bus.register_handler(EventType.PR_COMMENTED, sample_handler, PlatformType.GITHUB) event_bus.register_handler(EventType.PR_MERGED, sample_handler, PlatformType.GITHUB) +register_event_handlers() + @router.post("/github/webhook") async def github_webhook(request: Request): - payload = await request.json() + try: + raw_payload = await request.json() + payload = GitHubWebhookPayload(**raw_payload) + except Exception as e: + logging.error(f"Invalid webhook payload: {e}") + raise HTTPException(status_code=400, detail="Invalid webhook payload") + event_header = request.headers.get("X-GitHub-Event") logging.info(f"Received GitHub event: {event_header}") @@ -45,7 +60,7 @@ async def github_webhook(request: Request): # Handle issue events if event_header == "issues": - action = payload.get("action") + action = payload.action if action == "opened": event_type = EventType.ISSUE_CREATED elif action == "closed": @@ -55,27 +70,27 @@ async def github_webhook(request: Request): # Handle issue comment events elif event_header == "issue_comment": - action = payload.get("action") + action = payload.action if action == "created": event_type = EventType.ISSUE_COMMENTED # Handle pull request events elif event_header == "pull_request": - action = payload.get("action") + action = payload.action if action == "opened": event_type = EventType.PR_CREATED elif action == "edited": event_type = EventType.PR_UPDATED elif action == "closed": # Determine if the PR was merged or simply closed - if payload.get("pull_request", {}).get("merged"): + if payload.pull_request and payload.pull_request.get("merged"): event_type = EventType.PR_MERGED else: logging.info("Pull request closed without merge; no event dispatched.") # Handle pull request comment events elif event_header in ["pull_request_review_comment", "pull_request_comment"]: - action = payload.get("action") + action = payload.action if action == "created": event_type = EventType.PR_COMMENTED @@ -83,13 +98,13 @@ async def github_webhook(request: Request): if event_type: event = BaseEvent( id=str(uuid.uuid4()), - actor_id=str(payload.get("sender", {}).get("id", "unknown")), + actor_id=str(payload.sender.get("id", "unknown")) if payload.sender else "unknown", event_type=event_type, platform=PlatformType.GITHUB, - raw_data=payload + raw_data=raw_payload ) await event_bus.dispatch(event) else: - logging.info(f"No matching event type for header: {event_header} with action: {payload.get('action')}") + logging.warning(f"No matching event type for header: {event_header} with action: {payload.action}") return {"status": "ok"} From 4e08d234d5fd4f0391f4689b3329bb89ff9f2659 Mon Sep 17 00:00:00 2001 From: sagarshresti18 Date: Sat, 14 Feb 2026 08:35:06 +0530 Subject: [PATCH 2/3] refactor: improve webhook validation with structured JSON and schema error handling --- backend/routes.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/routes.py b/backend/routes.py index 50e10a8f..796cdde7 100644 --- a/backend/routes.py +++ b/backend/routes.py @@ -6,7 +6,7 @@ from app.core.events.enums import EventType, PlatformType from app.core.events.base import BaseEvent from app.core.handler.handler_registry import HandlerRegistry -from pydantic import BaseModel +from pydantic import BaseModel, ValidationError from typing import Optional, Dict, Any router = APIRouter() @@ -48,10 +48,15 @@ def register_event_handlers(): async def github_webhook(request: Request): try: raw_payload = await request.json() - payload = GitHubWebhookPayload(**raw_payload) except Exception as e: - logging.error(f"Invalid webhook payload: {e}") - raise HTTPException(status_code=400, detail="Invalid webhook payload") + logging.error("Failed to parse JSON payload") + raise HTTPException(status_code=400, detail="Invalid JSON payload") from e + + try: + payload = GitHubWebhookPayload(**raw_payload) + except ValidationError as e: + logging.error(f"Webhook schema validation failed: {e}") + raise HTTPException(status_code=422, detail="Invalid webhook schema") from e event_header = request.headers.get("X-GitHub-Event") logging.info(f"Received GitHub event: {event_header}") From 3422790f7935afcd694519b657c3c63176574025 Mon Sep 17 00:00:00 2001 From: sagarshresti18 Date: Sat, 14 Feb 2026 09:02:52 +0530 Subject: [PATCH 3/3] refactor: improve webhook validation and exception handling --- backend/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/routes.py b/backend/routes.py index 796cdde7..3b9daad3 100644 --- a/backend/routes.py +++ b/backend/routes.py @@ -94,7 +94,7 @@ async def github_webhook(request: Request): logging.info("Pull request closed without merge; no event dispatched.") # Handle pull request comment events - elif event_header in ["pull_request_review_comment", "pull_request_comment"]: + elif event_header in ["pull_request_review_comment", "pull_request_review"]: action = payload.action if action == "created": event_type = EventType.PR_COMMENTED