fix(#121): Remediate security issues from ORCH-121 review
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

Priority Fixes (Required Before Production):

H3: Add rate limiting to webhook endpoint
- Added slowapi library for FastAPI rate limiting
- Implemented per-IP rate limiting (100 req/min) on webhook endpoint
- Added global rate limiting support via slowapi

M4: Add subprocess timeouts to all gates
- Added timeout=300 (5 minutes) to all subprocess.run() calls in gates
- Implemented proper TimeoutExpired exception handling
- Removed dead CalledProcessError handlers (check=False makes them unreachable)

M2: Add input validation on QualityCheckRequest
- Validate files array size (max 1000 files)
- Validate file paths (no path traversal, no null bytes, no absolute paths)
- Validate diff summary size (max 10KB)
- Validate taskId and agentId format (non-empty)

Additional Fixes:

H1: Fix coverage.json path resolution
- Use absolute paths resolved from project root
- Validate path is within project boundaries (prevent path traversal)

Code Review Cleanup:
- Moved imports to module level in quality_orchestrator.py
- Refactored mock detection logic into separate helper methods
- Removed dead subprocess.CalledProcessError exception handlers from all gates

Testing:
- Added comprehensive tests for all security fixes
- All 339 coordinator tests pass
- All 447 orchestrator tests pass
- Followed TDD principles (RED-GREEN-REFACTOR)

Security Impact:
- Prevents webhook DoS attacks via rate limiting
- Prevents hung processes via subprocess timeouts
- Prevents path traversal attacks via input validation
- Prevents malformed input attacks via comprehensive validation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-04 11:49:40 -06:00
parent 3a98b78661
commit 5d683d401e
15 changed files with 445 additions and 43 deletions

View File

@@ -5,6 +5,8 @@ from typing import Any
from fastapi import APIRouter, Header, HTTPException, Request
from pydantic import BaseModel, Field
from slowapi import Limiter
from slowapi.util import get_remote_address
from .config import settings
from .security import verify_signature
@@ -13,6 +15,9 @@ logger = logging.getLogger(__name__)
router = APIRouter()
# Initialize limiter for this module
limiter = Limiter(key_func=get_remote_address)
class WebhookResponse(BaseModel):
"""Response model for webhook endpoint."""
@@ -34,6 +39,7 @@ class GiteaWebhookPayload(BaseModel):
@router.post("/webhook/gitea", response_model=WebhookResponse)
@limiter.limit("100/minute") # Per-IP rate limit: 100 requests per minute
async def handle_gitea_webhook(
request: Request,
payload: GiteaWebhookPayload,