fix(security): consolidated HTTP 500 info-disclosure hardening + regression tests - #832
Conversation
…d 500 handlers Addresses CodeRabbit review on the HTTP-500 info-disclosure hardening (PR #814): - real_api_endpoints.py: add `except HTTPException: raise` ahead of the broad `except Exception` in batch_process_videos and search_youtube_videos so the explicit 400 guards (>20 videos, >50 results) are no longer masked as 500. This was a real regression: the sanitization catch-all swallowed the deliberate 4xx responses. - cloud_ai_routes.py / cloud_api_endpoints.py / real_api_endpoints.py: add `exc_info=True` to the 500-path logger.error calls that lacked it, so operators keep full server-side tracebacks after sanitizing the client body. - test_real_api_endpoints.py: tighten the >20-video and >50-result assertions from `in (400, 500)` to `== 400`, locking in the fix. Verification: pytest tests/unit/test_500_info_disclosure.py tests/unit/test_real_api_endpoints.py -> 82 passed. Lint-neutral (ruff 35 -> 35). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018QkL23nC1aXbwJ99zrbK4p
…well-75m66e # Conflicts: # tests/unit/test_cloud_routes.py
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
…well-75m66e # Conflicts: # src/youtube_extension/backend/cloud_api_endpoints.py # src/youtube_extension/backend/real_api_endpoints.py # tests/unit/test_real_api_endpoints.py
There was a problem hiding this comment.
Pull request overview
Hardens cloud and real API error handling against HTTP 500 information disclosure and adds regression coverage.
Changes:
- Replaces dynamic 500 details with a generic response while retaining server-side tracebacks.
- Preserves explicit 400 responses in batch and search endpoints.
- Updates and adds security regression tests.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/youtube_extension/backend/cloud_ai_routes.py |
Sanitizes cloud AI error responses. |
src/youtube_extension/backend/cloud_api_endpoints.py |
Sanitizes cloud processing errors. |
src/youtube_extension/backend/real_api_endpoints.py |
Sanitizes real API errors and preserves 4xx responses. |
tests/unit/test_500_info_disclosure.py |
Adds a source-scanning regression guard. |
tests/unit/test_cloud_routes.py |
Tightens the sanitized-detail assertion. |
tests/unit/test_real_api_endpoints.py |
Verifies sanitized errors and preserved 400 responses. |
| except ConfigurationError as e: | ||
| logger.error(f"Configuration error: {e}") | ||
| raise HTTPException(status_code=500, detail=f"Configuration error: {str(e)}") | ||
| logger.error(f"Configuration error: {e}", exc_info=True) | ||
| raise HTTPException(status_code=500, detail="Internal server error") |
| logger.error(f"Multi-provider analysis failed: {e}", exc_info=True) | ||
| raise HTTPException(status_code=500, detail="Internal server error") |
| # detail is a static string; error_msg (with the exception) is logged above only | ||
| raise HTTPException(status_code=500, detail="Internal server error") |
| _DYNAMIC_DETAIL = re.compile( | ||
| r"""detail\s*=\s*(?: | ||
| str\( # detail=str(...) | ||
| | f["'][^"']*\{ # detail=f"...{...}..." | ||
| )""", |
|
|
||
| # Match a single `raise HTTPException(...)` call, capturing its argument list, | ||
| # tolerant of the call spanning multiple lines. | ||
| _HTTP_EXC = re.compile(r"HTTPException\((?P<args>.*?)\)", re.DOTALL) |
…E-209) Rebased onto current main, which already sanitizes the 500 HTTPException/ JSONResponse details, the 503 CloudAIError, and the cloud-AI exception ordering (via #832 and follow-ups). This narrows #831 to the leaks main still carries: handlers that *return* a dict body placing the caught exception under an "error" key — a 200 "degraded"/"failed" payload that discloses internal state to clients just like a 500 detail would. - cloud_api_endpoints.py: /api/v3/queue/stats and /api/v3/cloud-status (the three per-service checks + the outer handler) now return a static status string and log the exception server-side with exc_info=True. - real_api_endpoints.py: cost-dashboard, usage-analytics, optimization, and service-status handlers likewise return "Internal server error" / "Service unavailable" and log with exc_info=True. - tests/unit/test_500_info_disclosure.py: extend main's AST guard with a response-body scanner (reusing _refs_exception_or_request) that flags `{"error": <exception>}` bodies, scoped to the two handlers hardened here. The same pattern exists more widely (services/, api/v1/router.py, websocket_service.py) and is tracked as a separate sweep. Existing endpoint tests assert status/degraded/key-presence, not the exception string, so behavior is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01He4GxmJcWW8XdwxYQQh8Sa
Summary
Sanitizes all HTTP 500 responses across the cloud/real API routers so exception
detail never leaks internal state to clients, and adds a dedicated regression
test. This is the merge-clean, consolidated version of the 500-hardening
work — it is rebased on current
main(post #812/#822) and its targeted suiteis green.
Changes
backend/cloud_ai_routes.py,cloud_api_endpoints.py,real_api_endpoints.py:500 handlers now return exactly
"Internal server error"— no appendedexception text, dict, or variable state.
HTTPExceptions untouched and keeps full tracebacks in serverlogs (only the client-facing body is sanitized).
tests/unit/test_500_info_disclosure.pyasserts 500 bodies contain nointernal detail.
test_cloud_routes.py/test_real_api_endpoints.pyassertions to thestrict sanitized contract (
detail == "Internal server error").Verification
pytest tests/unit/test_500_info_disclosure.py tests/unit/test_cloud_routes.py tests/unit/test_real_api_endpoints.py→ 163 passed locally.main(one trivial test-assertion conflict resolved toward the stricter contract).Context — duplicate cluster
The repo currently has ~15 open PRs attempting this same 500-hardening fix
(#804, #807, #810, #814, #815, #816, #818, #819, #820, #821, #826, #827, and
related).
mainis already green and one earlier variant (#805) merged. This PRis intended to supersede that cluster: land this one, then close the rest.
Left as draft pending a human decision on which candidate to merge to the
protected
mainbranch.🤖 Generated with Claude Code
Generated by Claude Code