fix(ssl): replace verify=True with ssl.create_default_context() for corporate CA support
Core fix: all httpx.AsyncClient instances now use ssl.create_default_context() instead of bool verify=True, which uses certifi and ignores system CA store. This makes corporate CA certificates installed via update-ca-certificates visible to Python HTTP clients. Files: - async_network.py: AsyncAPIClient.__init__ converts True→SSLContext - client_registry.py: get_client converts bool→SSLContext before passing - notifications/providers.py: _get_http_client uses ssl.create_default_context() - services/git/_base.py: GitServiceBase uses ssl.create_default_context() - translate/_llm_async_http.py: _get_verify returns SSLContext (not string) Test: new integration test with 3-tier PKI (Root→Intermediate→Server), TLS-protected Superset container, and custom CA installation via update-ca-certificates or SSL_CERT_DIR fallback. - conftest.py: added ca_chain, install_custom_ca, superset_tls_env fixtures; parameterized superset_container for TLS mode - test_superset_tls_custom_ca.py: 8 tests (openssl -CApath, -CAfile certifi, httpx capath, httpx certifi, AsyncAPIClient, SupersetClient, fingerprint, verify=False)
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import ssl
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
@@ -31,19 +32,22 @@ DEFAULT_MAX_TOKENS: int = 8192
|
||||
|
||||
|
||||
# #region _get_verify [C:1] [TYPE Function] [SEMANTICS translate, ssl, verify]
|
||||
# @BRIEF Resolve SSL verification path from LLM_SSL_VERIFY env var.
|
||||
# @RATIONALE Используем capath=/etc/ssl/certs/ вместо cafile, потому что
|
||||
# OpenSSL 3.x не использует intermediate CA сертификаты из cafile для
|
||||
# построения цепочки (verify code 20). capath с хеш-симлинками работает
|
||||
# корректно (verify code 0).
|
||||
# @BRIEF Resolve SSL verification context from LLM_SSL_VERIFY env var.
|
||||
# @RATIONALE Используем capath=/etc/ssl/certs/ через ssl.create_default_context,
|
||||
# потому что OpenSSL 3.x не использует intermediate CA сертификаты из cafile
|
||||
# для построения цепочки (verify code 20). capath с хеш-симлинками работает
|
||||
# корректно (verify code 0). Возвращаем SSLContext вместо строки — httpx 0.28.x
|
||||
# депрекейтит строковый путь в verify=.
|
||||
# @REJECTED cafile отвергнут — OpenSSL 3.x не использует intermediate CA
|
||||
# из единого bundle-файла. Только capath с хеш-симлинками даёт code 0.
|
||||
# @POST Returns path to /etc/ssl/certs/ when enabled, False when disabled.
|
||||
def _get_verify() -> str | bool:
|
||||
# @REJECTED Строковый путь "/etc/ssl/certs/" отвергнут — httpx 0.28.x депрекейтит
|
||||
# строки в verify=, требует SSLContext.
|
||||
# @POST Returns ssl.SSLContext with capath when enabled, False when disabled.
|
||||
def _get_verify() -> ssl.SSLContext | bool:
|
||||
raw = os.getenv("LLM_SSL_VERIFY", "true").strip().lower()
|
||||
if raw in ("false", "0", "no", "off"):
|
||||
return False
|
||||
return "/etc/ssl/certs/"
|
||||
return ssl.create_default_context(capath="/etc/ssl/certs/")
|
||||
# #endregion _get_verify
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user