From d885b63d38ff151c5dc3e70ad51fbf1d56a5f7df Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:54:14 +0000 Subject: [PATCH] fix(api): pass base_url to OpenAI client in test endpoint to prevent UnsupportedProtocol error Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- app/api/openai.py | 6 ++++-- tests/test_api_openai.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/app/api/openai.py b/app/api/openai.py index 6101ae07..83f7155f 100644 --- a/app/api/openai.py +++ b/app/api/openai.py @@ -53,8 +53,10 @@ async def test_openai_connection(request: Request): logger.warning("No OpenAI API key configured") return {"status": "error", "message": "No OpenAI API key is configured"} - # Configure the client - client = openai.OpenAI(api_key=settings.openai_api_key) + # Configure the client, explicitly passing base_url so the sanitized + # value from Settings (strip_outer_quotes) is used instead of the raw + # OPENAI_BASE_URL env var which may contain literal quote characters. + client = openai.OpenAI(api_key=settings.openai_api_key, base_url=settings.openai_base_url) # Try to make a simple request to validate the key try: diff --git a/tests/test_api_openai.py b/tests/test_api_openai.py index b730e130..9d2c5d7b 100644 --- a/tests/test_api_openai.py +++ b/tests/test_api_openai.py @@ -44,6 +44,7 @@ class TestOpenAIConnectionErrors: def test_openai_api_key_validation_success(self, mock_settings, mock_openai_class, client): """Test OpenAI API key validation success.""" mock_settings.openai_api_key = "sk-test-key" + mock_settings.openai_base_url = "https://api.openai.com/v1" mock_client = MagicMock() mock_models = MagicMock() @@ -58,6 +59,35 @@ class TestOpenAIConnectionErrors: assert "valid" in data["message"].lower() assert data["models_available"] == 2 + @patch("openai.OpenAI") + @patch("app.api.openai.settings") + def test_openai_uses_configured_base_url(self, mock_settings, mock_openai_class, client): + """Test that the client is created with the configured base_url from settings. + + Regression test: previously the endpoint created openai.OpenAI without + base_url, causing the OpenAI library to read the raw OPENAI_BASE_URL + env var which may contain literal quote characters (e.g. in Kubernetes). + Those quotes are URL-encoded by httpx to %22 and produce an + UnsupportedProtocol error. + """ + mock_settings.openai_api_key = "sk-test-key" + mock_settings.openai_base_url = "http://litellm.example.com/v1" + + mock_client = MagicMock() + mock_models = MagicMock() + mock_models.data = [] + mock_client.models.list.return_value = mock_models + mock_openai_class.return_value = mock_client + + client.get("/api/openai/test") + + # The OpenAI client must be constructed with the configured base_url so + # that Settings' strip_outer_quotes sanitisation takes effect. + mock_openai_class.assert_called_once_with( + api_key="sk-test-key", + base_url="http://litellm.example.com/v1", + ) + @patch("openai.OpenAI") @patch("app.api.openai.settings") def test_openai_api_key_validation_auth_error(self, mock_settings, mock_openai_class, client):