v2.13.0 (#733)
Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai> Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com> Co-authored-by: Peter Evers <peter.evers@mistral.ai> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Val <102326092+vdeva@users.noreply.github.com> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
parent
198277af3f
commit
ad0d5c9520
61 changed files with 969 additions and 461 deletions
140
tests/backend/test_ssl_integration.py
Normal file
140
tests/backend/test_ssl_integration.py
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from ipaddress import IPv4Address
|
||||
from pathlib import Path
|
||||
import ssl
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.x509.oid import ExtendedKeyUsageOID, NameOID
|
||||
import pytest
|
||||
|
||||
from tests.e2e.mock_server import StreamingMockServer
|
||||
from vibe.core.config import ModelConfig, ProviderConfig
|
||||
from vibe.core.llm.backend.generic import GenericBackend
|
||||
from vibe.core.types import Backend, LLMMessage, Role
|
||||
from vibe.core.utils import build_ssl_context, configure_ssl_context
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class _TLSMaterial:
|
||||
ca_file: str
|
||||
cert_file: str
|
||||
key_file: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class _HttpsStreamingMockServer:
|
||||
server: StreamingMockServer
|
||||
ca_file: str
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def https_streaming_mock_server(tmp_path: Path) -> Iterator[_HttpsStreamingMockServer]:
|
||||
tls = _write_tls_material(tmp_path)
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ssl_context.load_cert_chain(certfile=tls.cert_file, keyfile=tls.key_file)
|
||||
server = StreamingMockServer(ssl_context=ssl_context)
|
||||
server.start()
|
||||
try:
|
||||
yield _HttpsStreamingMockServer(server=server, ca_file=tls.ca_file)
|
||||
finally:
|
||||
server.stop()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generic_backend_streaming_uses_ssl_cert_file(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
https_streaming_mock_server: _HttpsStreamingMockServer,
|
||||
) -> None:
|
||||
monkeypatch.setenv("SSL_CERT_FILE", https_streaming_mock_server.ca_file)
|
||||
monkeypatch.delenv("SSL_CERT_DIR", raising=False)
|
||||
configure_ssl_context(enable_system_trust_store=False)
|
||||
build_ssl_context.cache_clear()
|
||||
|
||||
chunks = []
|
||||
try:
|
||||
provider = ProviderConfig(
|
||||
name="mock-provider",
|
||||
api_base=https_streaming_mock_server.server.api_base,
|
||||
api_key_env_var="MISTRAL_API_KEY",
|
||||
backend=Backend.GENERIC,
|
||||
)
|
||||
model = ModelConfig(
|
||||
name="mock-model", provider="mock-provider", alias="mock-model"
|
||||
)
|
||||
|
||||
async with GenericBackend(provider=provider, timeout=5.0) as backend:
|
||||
chunks = [
|
||||
chunk
|
||||
async for chunk in backend.complete_streaming(
|
||||
model=model, messages=[LLMMessage(role=Role.user, content="Greet")]
|
||||
)
|
||||
]
|
||||
finally:
|
||||
configure_ssl_context(enable_system_trust_store=False)
|
||||
build_ssl_context.cache_clear()
|
||||
|
||||
content = "".join(chunk.message.content or "" for chunk in chunks)
|
||||
request_payload = https_streaming_mock_server.server.requests[-1]
|
||||
assert content == "Hello from mock server"
|
||||
assert request_payload.get("stream") is True
|
||||
assert request_payload.get("model") == "mock-model"
|
||||
|
||||
|
||||
def _write_tls_material(tmp_path: Path) -> _TLSMaterial:
|
||||
now = datetime.now(UTC)
|
||||
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "Vibe test CA")])
|
||||
ca_cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(ca_name)
|
||||
.issuer_name(ca_name)
|
||||
.public_key(ca_key.public_key())
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(now - timedelta(minutes=1))
|
||||
.not_valid_after(now + timedelta(days=1))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.sign(ca_key, hashes.SHA256())
|
||||
)
|
||||
|
||||
server_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
server_name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "127.0.0.1")])
|
||||
server_cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(server_name)
|
||||
.issuer_name(ca_cert.subject)
|
||||
.public_key(server_key.public_key())
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(now - timedelta(minutes=1))
|
||||
.not_valid_after(now + timedelta(days=1))
|
||||
.add_extension(
|
||||
x509.SubjectAlternativeName([x509.IPAddress(IPv4Address("127.0.0.1"))]),
|
||||
critical=False,
|
||||
)
|
||||
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
|
||||
.add_extension(
|
||||
x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]), critical=False
|
||||
)
|
||||
.sign(ca_key, hashes.SHA256())
|
||||
)
|
||||
|
||||
ca_file = tmp_path / "ca.pem"
|
||||
cert_file = tmp_path / "server.pem"
|
||||
key_file = tmp_path / "server.key"
|
||||
ca_file.write_bytes(ca_cert.public_bytes(serialization.Encoding.PEM))
|
||||
cert_file.write_bytes(server_cert.public_bytes(serialization.Encoding.PEM))
|
||||
key_file.write_bytes(
|
||||
server_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
)
|
||||
return _TLSMaterial(
|
||||
ca_file=str(ca_file), cert_file=str(cert_file), key_file=str(key_file)
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue