mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-26 21:53:03 +08:00
fix(api): rename verify endpoint and redact 422 request input
Rename the deployment provider credential verification route to /deployments/providers/verify and sanitize RequestValidationError responses so raw request payloads are not echoed back in 422 errors. Update route/tests accordingly, including regression coverage for input redaction.
This commit is contained in:
committed by
himavarshagoutham
parent
0d60609104
commit
e598dc954c
@ -8,13 +8,14 @@ import warnings
|
||||
from contextlib import asynccontextmanager, suppress
|
||||
from http import HTTPStatus
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from typing import TYPE_CHECKING, Any, cast
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import anyio
|
||||
import httpx
|
||||
import sqlalchemy
|
||||
from fastapi import FastAPI, HTTPException, Request, Response, status
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
@ -78,6 +79,11 @@ async def log_exception_to_telemetry(exc: Exception, context: str) -> None:
|
||||
await logger.awarning(f"Failed to log {context} exception to telemetry")
|
||||
|
||||
|
||||
def _sanitize_validation_errors(errors: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
"""Strip request payload echoes from validation errors to avoid leaking submitted data."""
|
||||
return [{key: value for key, value in error.items() if key != "input"} for error in errors]
|
||||
|
||||
|
||||
class RequestCancelledMiddleware(BaseHTTPMiddleware):
|
||||
def __init__(self, app) -> None:
|
||||
super().__init__(app)
|
||||
@ -560,6 +566,13 @@ def create_app():
|
||||
# Discover and register additional routers from plugins (langflow.plugins entry-point)
|
||||
load_plugin_routes(app)
|
||||
|
||||
@app.exception_handler(RequestValidationError)
|
||||
async def request_validation_exception_handler(_request: Request, exc: RequestValidationError):
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
content={"detail": _sanitize_validation_errors(exc.errors())},
|
||||
)
|
||||
|
||||
@app.exception_handler(Exception)
|
||||
async def exception_handler(_request: Request, exc: Exception):
|
||||
if isinstance(exc, HTTPException):
|
||||
|
||||
@ -134,6 +134,24 @@ async def test_create_project_validation_error(client: AsyncClient, logged_in_he
|
||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
|
||||
|
||||
async def test_create_project_validation_error_does_not_echo_request_input(client: AsyncClient, logged_in_headers):
|
||||
"""Regression test: request-validation 422 responses must not echo submitted payloads."""
|
||||
sensitive_marker = "secret-api-key-should-not-echo"
|
||||
response = await client.post(
|
||||
"api/v1/projects/",
|
||||
# Send a JSON string (instead of object) to trigger RequestValidationError consistently.
|
||||
content=json.dumps(sensitive_marker),
|
||||
headers={**logged_in_headers, "Content-Type": "application/json"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
detail = response.json()["detail"]
|
||||
assert isinstance(detail, list)
|
||||
assert detail
|
||||
assert all("input" not in error for error in detail)
|
||||
assert sensitive_marker not in response.text
|
||||
|
||||
|
||||
async def test_delete_project_then_404(client: AsyncClient, logged_in_headers, basic_case):
|
||||
create_resp = await client.post("api/v1/projects/", json=basic_case, headers=logged_in_headers)
|
||||
proj_id = create_resp.json()["id"]
|
||||
|
||||
Reference in New Issue
Block a user