mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-06 20:25:29 +00:00
Merge branch 'BerriAI:main' into ci-artifact
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user