diff --git a/main.py b/main.py index 7e7c1ae8..094bbea2 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ # Third-party imports import sentry_sdk -from fastapi import FastAPI, HTTPException, Request +from fastapi import FastAPI, Request from mangum import Mangum from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration @@ -47,13 +47,7 @@ async def handle_webhook(request: Request) -> dict[str, str]: print(f"Received event: {event_name} with content type: {content_type}") # Validate if the webhook signature comes from GitHub - try: - print("Webhook received") - await verify_webhook_signature(request=request, secret=GITHUB_WEBHOOK_SECRET) - print("Webhook signature verified") - except Exception as e: - print(f"Error: {e}") - raise HTTPException(status_code=401, detail=str(object=e)) from e + await verify_webhook_signature(request=request, secret=GITHUB_WEBHOOK_SECRET) # Process the webhook event but never raise an exception as some event_name like "marketplace_purchase" doesn't have a payload try: @@ -76,14 +70,7 @@ async def handle_webhook(request: Request) -> dict[str, str]: except Exception as e: # pylint: disable=broad-except print(f"Error in parsing JSON payload: {e}") - try: - await handle_webhook_event(event_name=event_name, payload=payload) - print("Webhook event handled") - - return {"message": "Webhook processed successfully"} - except Exception as e: - print(f"Error: {e}") - raise HTTPException(status_code=500, detail=str(object=e)) from e + await handle_webhook_event(event_name=event_name, payload=payload) @app.get(path="/") diff --git a/services/github/github_manager.py b/services/github/github_manager.py index f49e6543..57452216 100644 --- a/services/github/github_manager.py +++ b/services/github/github_manager.py @@ -342,18 +342,31 @@ def get_installation_access_token(installation_id: int) -> str | None: @handle_exceptions(default_return_value=[], raise_on_error=False) -def get_installed_owners_and_repos( - installation_id: str, token: str -) -> list[dict[str, str]]: +def get_installed_owners_and_repos(token: str) -> list[dict[str, str]]: """https://docs.github.com/en/rest/apps/installations?apiVersion=2022-11-28#list-repositories-accessible-to-the-app-installation""" - response: requests.Response = requests.get( - url=f"{GITHUB_API_URL}/user/installations/{installation_id}/repositories", - headers=create_headers(token=token), - timeout=TIMEOUT_IN_SECONDS, - ) - response.raise_for_status() - repos = response.json().get("repositories", []) - return [{"owner": repo["owner"]["login"], "repo": repo["name"]} for repo in repos] + owners_repos = [] + page = 1 + while True: + response: requests.Response = requests.get( + url=f"{GITHUB_API_URL}/installation/repositories", + headers=create_headers(token=token), + params={"per_page": 100, "page": page}, + timeout=TIMEOUT_IN_SECONDS, + ) + response.raise_for_status() + repos = response.json().get("repositories", []) + + # If there are no more repositories, break the loop. Otherwise, add them to the list + if not repos: + break + i = [{"owner": repo["owner"]["login"], "repo": repo["name"]} for repo in repos] + owners_repos.extend(i) + + # https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api?apiVersion=2022-11-28 + if "next" not in response.links: + break + page += 1 + return owners_repos @handle_exceptions(default_return_value=[], raise_on_error=False) @@ -532,6 +545,7 @@ def get_remote_file_tree( return [] +@handle_exceptions(raise_on_error=True) async def verify_webhook_signature(request: Request, secret: str) -> None: """Verify the webhook signature for security""" signature: str | None = request.headers.get("X-Hub-Signature-256") diff --git a/services/webhook_handler.py b/services/webhook_handler.py index 8aa43c29..5fd128be 100644 --- a/services/webhook_handler.py +++ b/services/webhook_handler.py @@ -19,6 +19,7 @@ ) from services.supabase import SupabaseManager from services.gitauto_handler import handle_gitauto +from utils.handle_exceptions import handle_exceptions # Initialize managers supabase_manager = SupabaseManager(url=SUPABASE_URL, key=SUPABASE_SERVICE_ROLE_KEY) @@ -49,6 +50,7 @@ async def handle_installation_deleted(payload: GitHubInstallationPayload) -> Non supabase_manager.delete_installation(installation_id=installation_id) +@handle_exceptions(default_return_value=None, raise_on_error=True) async def handle_webhook_event(event_name: str, payload: GitHubEventPayload) -> None: """Determine the event type and call the appropriate handler""" action: str = payload.get("action")