Skip to content

Conversation

@uphargaur
Copy link

@uphargaur uphargaur commented Jul 19, 2025

Add GitHub Webhook Handling and Cache Invalidation

What

  • Handle GitHub webhook events for repository visibility changes
  • Auto-clear cache when repositories change visibility
  • Support public and repository events
  • Webhook signature verification for security
  • Statistics endpoint for monitoring

How it Works

  • GitHub sends webhook to /api/v1/github/webhook when repository visibility changes
  • Webhook service processes events and clears cached data
  • Cache invalidation ensures fresh data on next API call
  • Optional signature verification prevents unauthorized requests

Events Supported

  • public: Repository made public/private
  • repository: Repository events (privatized, deleted, transferred)

Files Changed

  • app/modules/code_provider/github/github_webhook_service.py (new)
  • app/modules/code_provider/github/github_webhook_router.py (new)
  • app/modules/code_provider/github/github_service.py
  • app/main.py

Testing

  • ✅ Webhook endpoints work
  • ✅ Cache invalidation triggers correctly
  • ✅ Signature verification tested
  • ✅ Statistics endpoint functional

Environment Variables

  • GITHUB_WEBHOOK_SECRET (optional) - for signature verification

Summary by CodeRabbit

  • New Features

    • Added API endpoints to receive and process GitHub webhook events (repository visibility changes, privatizations, deletions).
    • Added an endpoint to report webhook processing statistics and status.
  • Bug Fixes

    • No user-facing bug fixes in this release.
  • Chores

    • Minor whitespace cleanup in existing service code.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 19, 2025

Walkthrough

A new GitHub webhook router and service were added; the main app now includes the router under /api/v1. The service validates signatures, processes public and repository events, clears repo cache via GithubService, and exposes webhook stats.

Changes

Cohort / File(s) Change Summary
Main app
app/main.py
Imported and registered the new GitHub webhook router: include_router(github_webhook_router, prefix="/api/v1", tags=["GitHub Webhooks"]).
Webhook router
app/modules/code_provider/github/github_webhook_router.py
Added FastAPI router with POST /webhook to receive/process GitHub events and GET /webhook/stats to return service statistics; depends on DB session.
Webhook service
app/modules/code_provider/github/github_webhook_service.py
Added GitHubWebhookService that verifies HMAC SHA256 signatures (if configured), parses events (public, repository), clears cache via GithubService, tracks stats, and maps errors to HTTP responses.
Existing service (whitespace)
app/modules/code_provider/github/github_service.py
Whitespace-only change (removed trailing newline); no functional changes.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant GH as GitHub
    participant API as FastAPI (/api/v1/github)
    participant WSvc as GitHubWebhookService
    participant DB as Database (Session)
    participant GSvc as GithubService (cache ops)

    Note over GH,API: Incoming webhook
    GH->>API: POST /webhook (payload + headers)
    API->>WSvc: process_webhook(request)  
    WSvc->>DB: obtain session
    WSvc->>WSvc: verify signature (HMAC SHA256) [if secret]
    alt signature invalid
        WSvc-->>API: HTTP 401
    else valid
        WSvc->>WSvc: parse event & action
        alt event == "public" or relevant "repository" actions
            WSvc->>GSvc: clear repo cache
            GSvc-->>WSvc: result
            WSvc-->>API: success payload
        else
            WSvc-->>API: ignored/ack payload
        end
    end
    Note over API,GH: HTTP response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

"I hopped to the webhook, nose twitching with glee,
Secrets checked and caches cleared, so repositories run free.
Stats counted neatly, each event told true,
A rabbit's small patch to help your CI crew.
🐇🔧"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "353 Add GitHub Webhook Handling and Cache Invalidation" directly aligns with the primary changes introduced in this changeset. The title accurately identifies the two main objectives: adding GitHub webhook handling (via the new github_webhook_router.py and github_webhook_service.py modules) and implementing cache invalidation (triggered when specific GitHub events occur). The title is concise, specific, and avoids vague language, making it clear to teammates reviewing the git history that this PR introduces GitHub webhook functionality with automatic cache management. The inclusion of the ticket number provides helpful context without compromising clarity.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@uphargaur
Copy link
Author

@dhirenmathur please check

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
app/modules/code_provider/github/github_webhook_router.py (1)

1-1: Remove unused import.

The logging import is not used in this file.

-import logging
app/modules/code_provider/github/github_webhook_service.py (3)

6-6: Remove unused import.

Optional from typing is imported but never used.

-from typing import Dict, Any, Optional
+from typing import Dict, Any

11-11: Remove unused import.

config_provider is imported but never used in this file.

-from app.core.config_provider import config_provider

38-41: Simplify nested conditional statements.

The nested if statements can be combined for better readability.

-            if self.webhook_secret:
-                if not self._verify_webhook_signature(payload, headers):
+            if self.webhook_secret and not self._verify_webhook_signature(payload, headers):
                    logger.warning("Webhook signature verification failed")
                    raise HTTPException(status_code=401, detail="Invalid webhook signature")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 213eaf0 and 9a951d0.

📒 Files selected for processing (4)
  • app/main.py (2 hunks)
  • app/modules/code_provider/github/github_service.py (1 hunks)
  • app/modules/code_provider/github/github_webhook_router.py (1 hunks)
  • app/modules/code_provider/github/github_webhook_service.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
app/modules/code_provider/github/github_webhook_router.py (2)
app/core/database.py (1)
  • get_db (29-34)
app/modules/code_provider/github/github_webhook_service.py (3)
  • GitHubWebhookService (17-169)
  • process_webhook (28-68)
  • get_webhook_stats (162-169)
app/modules/code_provider/github/github_webhook_service.py (2)
app/modules/code_provider/github/github_service.py (1)
  • GithubService (28-772)
app/modules/code_provider/github/github_webhook_router.py (1)
  • get_webhook_stats (38-46)
🪛 Ruff (0.12.2)
app/modules/code_provider/github/github_webhook_router.py

1-1: logging imported but unused

Remove unused import: logging

(F401)


16-16: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


34-34: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


39-39: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


46-46: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

app/modules/code_provider/github/github_webhook_service.py

6-6: typing.Optional imported but unused

Remove unused import: typing.Optional

(F401)


11-11: app.core.config_provider.config_provider imported but unused

Remove unused import: app.core.config_provider.config_provider

(F401)


38-39: Use a single if statement instead of nested if statements

(SIM102)


48-48: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


68-68: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🔇 Additional comments (7)
app/modules/code_provider/github/github_service.py (1)

772-772: LGTM! Whitespace cleanup.

The trailing newline removal is a minor formatting improvement with no functional impact.

app/main.py (2)

16-16: LGTM! Proper router import.

The import follows the established pattern used by other routers in the application.


104-104: LGTM! Router integration follows established patterns.

The router inclusion is consistent with the existing codebase patterns, using the same prefix and tagging approach as other routers.

app/modules/code_provider/github/github_webhook_router.py (1)

10-46: Webhook endpoint security and cache invalidation verified

  • process_webhook invokes _verify_webhook_signature(payload, headers) when webhook_secret is set, rejecting invalid signatures with HTTP 401.
  • JSON decoding errors return HTTP 400 and unexpected errors return HTTP 500 as intended.
  • Cache is cleared for both "public" and relevant "repository" events via _clear_repository_cache, which calls self.github_service.clear_repository_cache(repo_name) and updates stats["cache_purges"].

No changes required.

app/modules/code_provider/github/github_webhook_service.py (3)

140-160: LGTM! Excellent webhook signature verification implementation.

The HMAC SHA256 signature verification follows GitHub's webhook security best practices:

  • Proper signature header validation
  • Secure HMAC comparison using hmac.compare_digest()
  • Correct handling of the 'sha256=' prefix
  • Appropriate error handling for verification failures

This implementation effectively prevents webhook spoofing attacks.


17-27: LGTM! Well-structured service initialization.

The service properly initializes with:

  • Database session dependency injection
  • GithubService integration for cache operations
  • Optional webhook secret configuration
  • Statistics tracking for monitoring

The architecture follows good separation of concerns.


54-61: LGTM! Proper event filtering and handling.

The event type filtering correctly handles the supported GitHub webhook events ('public' and 'repository') while gracefully ignoring unsupported events. This approach ensures the service is resilient to new GitHub webhook event types.

Comment on lines +13 to +35
@router.post("/webhook")
async def handle_github_webhook(
request: Request,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""
Handle GitHub webhooks for repository visibility changes.
Supported events:
- 'public': Repository changed from private to public
- 'repository': Repository events including privatization, publicization, deletion
This endpoint automatically purges cache when repository visibility changes.
"""
try:
webhook_service = GitHubWebhookService(db)
result = await webhook_service.process_webhook(request)
return result
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve exception handling with proper chaining.

The current exception handling loses the original error context. Use raise ... from err to preserve the exception chain for better debugging.

    except HTTPException:
        raise
    except Exception as e:
-        raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}")
+        raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@router.post("/webhook")
async def handle_github_webhook(
request: Request,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""
Handle GitHub webhooks for repository visibility changes.
Supported events:
- 'public': Repository changed from private to public
- 'repository': Repository events including privatization, publicization, deletion
This endpoint automatically purges cache when repository visibility changes.
"""
try:
webhook_service = GitHubWebhookService(db)
result = await webhook_service.process_webhook(request)
return result
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}")
@router.post("/webhook")
async def handle_github_webhook(
request: Request,
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""
Handle GitHub webhooks for repository visibility changes.
Supported events:
- 'public': Repository changed from private to public
- 'repository': Repository events including privatization, publicization, deletion
This endpoint automatically purges cache when repository visibility changes.
"""
try:
webhook_service = GitHubWebhookService(db)
result = await webhook_service.process_webhook(request)
return result
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Webhook processing error: {str(e)}"
) from e
🧰 Tools
🪛 Ruff (0.12.2)

16-16: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


34-34: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
In app/modules/code_provider/github/github_webhook_router.py around lines 13 to
35, the exception handling in the webhook endpoint catches generic exceptions
but raises a new HTTPException without preserving the original error context.
Modify the except block to use "raise HTTPException(...) from e" to maintain the
exception chain and improve debugging.

Comment on lines +37 to +46
@router.get("/webhook/stats")
async def get_webhook_stats(
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get webhook service statistics and status"""
try:
webhook_service = GitHubWebhookService(db)
return await webhook_service.get_webhook_stats()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error getting webhook stats: {str(e)}") No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve exception handling with proper chaining.

Same issue as the webhook handler - preserve the exception chain for better error traceability.

    except Exception as e:
-        raise HTTPException(status_code=500, detail=f"Error getting webhook stats: {str(e)}")
+        raise HTTPException(status_code=500, detail=f"Error getting webhook stats: {str(e)}") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@router.get("/webhook/stats")
async def get_webhook_stats(
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get webhook service statistics and status"""
try:
webhook_service = GitHubWebhookService(db)
return await webhook_service.get_webhook_stats()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error getting webhook stats: {str(e)}")
@router.get("/webhook/stats")
async def get_webhook_stats(
db: Session = Depends(get_db)
) -> Dict[str, Any]:
"""Get webhook service statistics and status"""
try:
webhook_service = GitHubWebhookService(db)
return await webhook_service.get_webhook_stats()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error getting webhook stats: {str(e)}") from e
🧰 Tools
🪛 Ruff (0.12.2)

39-39: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


46-46: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
In app/modules/code_provider/github/github_webhook_router.py around lines 37 to
46, the exception handling in get_webhook_stats does not preserve the original
exception chain, which reduces error traceability. Modify the except block to
use "raise HTTPException(...) from e" to properly chain the original exception
when raising the HTTPException.

Comment on lines +46 to +48
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON in webhook payload: {e}")
raise HTTPException(status_code=400, detail="Invalid JSON payload")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve exception handling with proper chaining.

Preserve the original JSON decode error for better debugging.

            except json.JSONDecodeError as e:
                logger.error(f"Invalid JSON in webhook payload: {e}")
-                raise HTTPException(status_code=400, detail="Invalid JSON payload")
+                raise HTTPException(status_code=400, detail="Invalid JSON payload") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON in webhook payload: {e}")
raise HTTPException(status_code=400, detail="Invalid JSON payload")
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON in webhook payload: {e}")
raise HTTPException(status_code=400, detail="Invalid JSON payload") from e
🧰 Tools
🪛 Ruff (0.12.2)

48-48: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
In app/modules/code_provider/github/github_webhook_service.py around lines 46 to
48, the JSONDecodeError is caught and logged but the original exception is not
chained when raising the HTTPException. Modify the raise statement to include
"from e" to preserve the original exception context for better debugging and
traceback.

Comment on lines +65 to +68
except Exception as e:
self.stats["errors"] += 1
logger.error(f"Error processing webhook: {e}")
raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve exception handling with proper chaining.

Preserve the original exception for better error traceability.

        except Exception as e:
            self.stats["errors"] += 1
            logger.error(f"Error processing webhook: {e}")
-            raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}")
+            raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except Exception as e:
self.stats["errors"] += 1
logger.error(f"Error processing webhook: {e}")
raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}")
except Exception as e:
self.stats["errors"] += 1
logger.error(f"Error processing webhook: {e}")
raise HTTPException(status_code=500, detail=f"Webhook processing error: {str(e)}") from e
🧰 Tools
🪛 Ruff (0.12.2)

68-68: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
In app/modules/code_provider/github/github_webhook_service.py around lines 65 to
68, the exception handling currently logs and raises a new HTTPException without
preserving the original exception context. Modify the raise statement to use
"raise HTTPException(...) from e" to maintain proper exception chaining and
improve error traceability.

Comment on lines +130 to +138
async def _clear_repository_cache(self, repo_name: str):
"""Clear cache for a specific repository"""
try:
await self.github_service.clear_repository_cache(repo_name)
self.stats["cache_purges"] += 1
logger.info(f"Cache cleared for repository: {repo_name}")
except Exception as e:
logger.error(f"Error clearing cache for {repo_name}: {e}")
raise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

Verify that GithubService has the clear_repository_cache method.

The service calls self.github_service.clear_repository_cache(repo_name) but this method doesn't appear to exist in the GithubService class based on the provided code.


🏁 Script executed:

#!/bin/bash
# Description: Verify if clear_repository_cache method exists in GithubService

# Search for the clear_repository_cache method implementation
ast-grep --pattern 'async def clear_repository_cache($$$) {
  $$$
}'

# Also check for any cache clearing related methods
rg -A 5 "clear.*cache|cache.*clear" app/modules/code_provider/github/github_service.py

Length of output: 159


Implement missing clear_repository_cache in GithubService

The call in GithubWebhookService._clear_repository_cache (app/modules/code_provider/github/github_webhook_service.py:130–138) invokes self.github_service.clear_repository_cache(...), but no such method exists. Add it to your service:

# app/modules/code_provider/github/github_service.py

class GithubService:
    # … existing methods …

    async def clear_repository_cache(self, repo_name: str):
        """
        Clear any in-memory or persisted cache for the given repository.
        """
        # TODO: implement cache-clearing logic here
        pass

• app/modules/code_provider/github/github_webhook_service.py (lines 130–138) – invocation of the nonexistent method
• app/modules/code_provider/github/github_service.py – implement the new method

🤖 Prompt for AI Agents
In app/modules/code_provider/github/github_service.py, add a new async method
clear_repository_cache that accepts repo_name as a parameter. This method should
contain the logic to clear any in-memory or persisted cache related to the
specified repository. This will resolve the missing method error when called
from app/modules/code_provider/github/github_webhook_service.py lines 130 to
138.

@nndn nndn self-requested a review August 18, 2025 06:15
Comment on lines +22 to +26
self.stats = {
"webhooks_received": 0,
"cache_purges": 0,
"errors": 0
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please review these changes. It's storing a local state of stats which isn't needed. Please clean this up

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acknowledged

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a951d0 and 5cb9597.

📒 Files selected for processing (1)
  • app/main.py (2 hunks)
🔇 Additional comments (1)
app/main.py (1)

16-16: LGTM: Import follows existing conventions.

The import statement is correctly formatted and follows the same pattern as other router imports in the file.

self.app.include_router(projects_router, prefix="/api/v1", tags=["Projects"])
self.app.include_router(search_router, prefix="/api/v1", tags=["Search"])
self.app.include_router(github_router, prefix="/api/v1", tags=["Github"])
self.app.include_router(github_webhook_router, prefix="/api/v1", tags=["GitHub Webhooks"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify webhook route paths and address tag capitalization inconsistency.

The router registration follows the correct pattern. However, there are two items to address:

  1. Tag capitalization inconsistency: Line 105 uses tags=["Github"] while this line uses tags=["GitHub Webhooks"]. Consider using consistent capitalization (e.g., "GitHub" on line 105).

  2. Route path verification: According to the PR objectives, the final webhook endpoints should be at /api/v1/github/webhook and /api/v1/github/webhook/stats. Since this registration uses prefix="/api/v1", the github_webhook_router must define its routes with a /github prefix. Please verify this is correctly implemented in the router definition.


🏁 Script executed:

#!/bin/bash
# Verify that the github_webhook_router defines routes with /github prefix
# to ensure final endpoints match /api/v1/github/webhook as stated in PR objectives

echo "Checking github_webhook_router route definitions..."
rg -n -A 5 'APIRouter\(' app/modules/code_provider/github/github_webhook_router.py

echo -e "\nChecking route decorator definitions..."
rg -n '@router\.(get|post|put|delete|patch)' app/modules/code_provider/github/github_webhook_router.py

Length of output: 323


CRITICAL: Fix router prefix definition to prevent duplicate API path segments.

The verification reveals a critical issue with the route paths:

  • github_webhook_router.py line 10 defines: prefix="/api/v1/github"
  • main.py line 106 includes it with: prefix="/api/v1"

In FastAPI, nested prefixes are concatenated. This produces routes at /api/v1/api/v1/github/webhook instead of the intended /api/v1/github/webhook.

Fix required: Change the router definition in app/modules/code_provider/github/github_webhook_router.py line 10 from:

router = APIRouter(prefix="/api/v1/github", tags=["GitHub Webhooks"])

to:

router = APIRouter(prefix="/github", tags=["GitHub Webhooks"])

Additionally, update main.py line 105 tag from "Github" to "GitHub" for consistency.

🤖 Prompt for AI Agents
In app/main.py around line 106 and
app/modules/code_provider/github/github_webhook_router.py around line 10: the
router prefix is duplicated because main.py includes the router with prefix
"/api/v1" while the router itself uses "/api/v1/github", producing paths like
"/api/v1/api/v1/github/...". Remove the duplicated segment by changing the
router declaration in app/modules/code_provider/github/github_webhook_router.py
line 10 to use prefix "/github" instead of "/api/v1/github"; also update the tag
string in app/main.py line 105 from "Github" to "GitHub" for consistent casing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants