Merge branch 'BerriAI:main' into ci-artifact

This commit is contained in:
Cole McIntosh
2025-06-26 10:59:17 -06:00
committed by GitHub
6 changed files with 127 additions and 7 deletions
@@ -1,14 +1,14 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# SSL Security Settings
# SSL, HTTP Proxy Security Settings
If you're in an environment using an older TTS bundle, with an older encryption, follow this guide.
LiteLLM uses HTTPX for network requests, unless otherwise specified.
1. Disable SSL verification
## 1. Disable SSL verification
<Tabs>
@@ -35,7 +35,7 @@ export SSL_VERIFY="False"
</TabItem>
</Tabs>
2. Lower security settings
## 2. Lower security settings
<Tabs>
<TabItem value="sdk" label="SDK">
@@ -63,4 +63,29 @@ export SSL_CERTIFICATE="/path/to/certificate.pem"
</TabItem>
</Tabs>
## 3. Use HTTP_PROXY environment variable
Both httpx and aiohttp libraries use `urllib.request.getproxies` from environment variables. Before client initialization, you may set proxy (and optional SSL_CERT_FILE) by setting the environment variables:
<Tabs>
<TabItem value="sdk" label="SDK">
```python
import litellm
litellm.aiohttp_trust_env = True
```
```bash
export HTTPS_PROXY='http://username:password@proxy_uri:port'
```
</TabItem>
<TabItem value="proxy" label="PROXY">
```bash
export HTTPS_PROXY='http://username:password@proxy_uri:port'
export AIOHTTP_TRUST_ENV='True'
```
</TabItem>
</Tabs>
@@ -307,6 +307,7 @@ router_settings:
| AGENTOPS_SERVICE_NAME | Service Name for AgentOps logging integration
| AISPEND_ACCOUNT_ID | Account ID for AI Spend
| AISPEND_API_KEY | API Key for AI Spend
| AIOHTTP_TRUST_ENV | Flag to enable aiohttp trust environment. When this is set to True, aiohttp will respect HTTP(S)_PROXY env vars. **Default is False**
| ALLOWED_EMAIL_DOMAINS | List of email domains allowed for access
| ARIZE_API_KEY | API key for Arize platform integration
| ARIZE_SPACE_KEY | Space key for Arize platform
+1
View File
@@ -323,6 +323,7 @@ priority_reservation: Optional[Dict[str, float]] = None
use_aiohttp_transport: bool = (
True # Older variable, aiohttp is now the default. use disable_aiohttp_transport instead.
)
aiohttp_trust_env: bool = False # set to true to use HTTP_ Proxy settings
disable_aiohttp_transport: bool = False # Set this to true to use httpx instead
disable_aiohttp_trust_env: bool = False # When False, aiohttp will respect HTTP(S)_PROXY env vars
force_ipv4: bool = (
+10 -1
View File
@@ -580,15 +580,24 @@ class AsyncHTTPHandler:
- True: use default SSL verification (equivalent to ssl.create_default_context())
"""
from litellm.llms.custom_httpx.aiohttp_transport import LiteLLMAiohttpTransport
from litellm.secret_managers.main import str_to_bool
connector_kwargs = AsyncHTTPHandler._get_ssl_connector_kwargs(
ssl_verify=ssl_verify, ssl_context=ssl_context
)
#########################################################
# Check if user enabled aiohttp trust env
# use for HTTP_PROXY, HTTPS_PROXY, etc.
########################################################
trust_env: bool = litellm.aiohttp_trust_env
if str_to_bool(os.getenv("AIOHTTP_TRUST_ENV", "False")) is True:
trust_env = True
verbose_logger.debug("Creating AiohttpTransport...")
return LiteLLMAiohttpTransport(
client=lambda: ClientSession(
connector=TCPConnector(**connector_kwargs)
connector=TCPConnector(**connector_kwargs),
trust_env=trust_env,
),
)
@@ -123,6 +123,34 @@ async def test_ssl_verification_with_aiohttp_transport():
assert transport_connector._ssl == aiohttp_session.connector._ssl
@pytest.mark.asyncio
async def test_aiohttp_transport_trust_env_setting(monkeypatch):
"""Test that trust_env setting is properly configured in aiohttp transport"""
# Test 1: Default trust_env behavior
transport = AsyncHTTPHandler._create_aiohttp_transport()
client_session = transport._get_valid_client_session()
# Default should be False (litellm.aiohttp_trust_env default)
default_trust_env = getattr(litellm, 'aiohttp_trust_env', False)
assert client_session._trust_env == default_trust_env
# Test 2: Environment variable override
monkeypatch.setenv("AIOHTTP_TRUST_ENV", "True")
transport_with_env = AsyncHTTPHandler._create_aiohttp_transport()
client_session_with_env = transport_with_env._get_valid_client_session()
# Should be True when environment variable is set
assert client_session_with_env._trust_env is True
# Test 3: Verify environment variable with False value
monkeypatch.setenv("AIOHTTP_TRUST_ENV", "False")
transport_with_false_env = AsyncHTTPHandler._create_aiohttp_transport()
client_session_with_false_env = transport_with_false_env._get_valid_client_session()
# Should respect the litellm.aiohttp_trust_env setting when env var is False
assert client_session_with_false_env._trust_env == default_trust_env
def test_get_ssl_context():
"""Test that _get_ssl_context() returns a proper SSL context with certifi CA bundle"""
with patch('ssl.create_default_context') as mock_create_context:
@@ -103,10 +103,12 @@ def test_mock_create_audio_file(mocker: MockerFixture, monkeypatch, llm_router:
"""
Asserts 'create_file' is called with the correct arguments
"""
import litellm
from litellm import Router
from litellm.proxy.utils import ProxyLogging
mock_create_file = mocker.patch("litellm.files.main.create_file")
# Mock create_file as an async function
mock_create_file = mocker.patch("litellm.files.main.create_file", new=mocker.AsyncMock())
proxy_logging_obj = ProxyLogging(
user_api_key_cache=DualCache(default_in_memory_ttl=1)
@@ -114,6 +116,61 @@ def test_mock_create_audio_file(mocker: MockerFixture, monkeypatch, llm_router:
proxy_logging_obj._add_proxy_hooks(llm_router)
# Add managed_files hook to ensure the test reaches the mocked function
from litellm.llms.base_llm.files.transformation import BaseFileEndpoints
class DummyManagedFiles(BaseFileEndpoints):
async def acreate_file(self, llm_router, create_file_request, target_model_names_list, litellm_parent_otel_span, user_api_key_dict):
# Handle both dict and object forms of create_file_request
if isinstance(create_file_request, dict):
file_data = create_file_request.get("file")
purpose_data = create_file_request.get("purpose")
else:
file_data = create_file_request.file
purpose_data = create_file_request.purpose
# Call the mocked litellm.files.main.create_file to ensure asserts work
await litellm.files.main.create_file(
custom_llm_provider="azure",
model="azure/chatgpt-v-2",
api_key="azure_api_key",
file=file_data,
purpose=purpose_data,
)
await litellm.files.main.create_file(
custom_llm_provider="openai",
model="openai/gpt-3.5-turbo",
api_key="openai_api_key",
file=file_data,
purpose=purpose_data,
)
# Return a dummy response object as needed by the test
from litellm.types.llms.openai import OpenAIFileObject
return OpenAIFileObject(
id="dummy-id",
object="file",
bytes=len(file_data[1]) if file_data else 0,
created_at=1234567890,
filename=file_data[0] if file_data else "test.wav",
purpose=purpose_data,
status="uploaded",
)
async def afile_retrieve(self, file_id, litellm_parent_otel_span):
raise NotImplementedError("Not implemented for test")
async def afile_list(self, purpose, litellm_parent_otel_span):
raise NotImplementedError("Not implemented for test")
async def afile_delete(self, file_id, litellm_parent_otel_span):
raise NotImplementedError("Not implemented for test")
async def afile_content(self, file_id, litellm_parent_otel_span):
raise NotImplementedError("Not implemented for test")
# Manually add the hook to the proxy_hook_mapping
proxy_logging_obj.proxy_hook_mapping["managed_files"] = DummyManagedFiles()
monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", llm_router)
monkeypatch.setattr(
"litellm.proxy.proxy_server.proxy_logging_obj", proxy_logging_obj
@@ -133,8 +190,7 @@ def test_mock_create_audio_file(mocker: MockerFixture, monkeypatch, llm_router:
headers={"Authorization": "Bearer test-key"},
)
print(f"response: {response.text}")
# assert response.status_code == 200
assert response.status_code == 200
# Get all calls made to create_file
calls = mock_create_file.call_args_list