From aab50471329b502adea77461fa4470dabb1cf663 Mon Sep 17 00:00:00 2001 From: himavarshagoutham Date: Tue, 14 Apr 2026 09:58:10 -0400 Subject: [PATCH] revert(api): remove verification endpoint follow-up changes Keep this PR focused on wxO adapter tenant validation via model-list fetch and drop API-layer validation endpoint and request-redaction changes. --- .../langflow/api/v1/schemas/deployments.py | 7 +++++++ src/backend/base/langflow/main.py | 15 +-------------- src/backend/tests/unit/api/v1/test_projects.py | 18 ------------------ 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/backend/base/langflow/api/v1/schemas/deployments.py b/src/backend/base/langflow/api/v1/schemas/deployments.py index 56e6be5dc3..b13eea1bf4 100644 --- a/src/backend/base/langflow/api/v1/schemas/deployments.py +++ b/src/backend/base/langflow/api/v1/schemas/deployments.py @@ -39,6 +39,9 @@ from pydantic import AfterValidator, BaseModel, Field, ValidationInfo, model_val from langflow.services.database.models.deployment_provider_account.schemas import ( DeploymentProviderKey, ) +from langflow.services.database.models.deployment_provider_account.utils import ( + validate_provider_url, +) # --------------------------------------------------------------------------- # Shared validation helpers @@ -79,6 +82,10 @@ NonEmptyStr = Annotated[str, AfterValidator(_strip_nonempty)] """String type that strips whitespace and rejects empty/whitespace-only values.""" +ValidatedUrl = Annotated[str, AfterValidator(validate_provider_url)] +"""URL type that enforces HTTPS and normalizes.""" + + def _validate_flow_version_ids(values: list[UUID] | None) -> list[UUID] | None: """AfterValidator for optional flow_version_ids query parameter.""" if values is None: diff --git a/src/backend/base/langflow/main.py b/src/backend/base/langflow/main.py index c13e4f4d22..fd1d3db7dc 100644 --- a/src/backend/base/langflow/main.py +++ b/src/backend/base/langflow/main.py @@ -8,14 +8,13 @@ import warnings from contextlib import asynccontextmanager, suppress from http import HTTPStatus from pathlib import Path -from typing import TYPE_CHECKING, Any, cast +from typing import TYPE_CHECKING, 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 @@ -79,11 +78,6 @@ 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) @@ -566,13 +560,6 @@ 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): diff --git a/src/backend/tests/unit/api/v1/test_projects.py b/src/backend/tests/unit/api/v1/test_projects.py index 8ddaf9678f..c48c06baa0 100644 --- a/src/backend/tests/unit/api/v1/test_projects.py +++ b/src/backend/tests/unit/api/v1/test_projects.py @@ -134,24 +134,6 @@ 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"]