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:
Clément Drouin 2026-05-29 16:17:54 +02:00 committed by GitHub
parent 198277af3f
commit ad0d5c9520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 969 additions and 461 deletions

View file

@ -5,13 +5,15 @@ from unittest.mock import MagicMock, patch
import pytest
from vibe.core.utils.http import build_ssl_context
from vibe.core.utils.http import build_ssl_context, configure_ssl_context
@pytest.fixture(autouse=True)
def _clear_ssl_cache():
configure_ssl_context(enable_system_trust_store=False)
build_ssl_context.cache_clear()
yield
configure_ssl_context(enable_system_trust_store=False)
build_ssl_context.cache_clear()
@ -20,6 +22,42 @@ def test_build_ssl_context_returns_ssl_context():
assert isinstance(ctx, ssl.SSLContext)
def test_build_ssl_context_uses_certifi_by_default(monkeypatch):
monkeypatch.delenv("SSL_CERT_FILE", raising=False)
monkeypatch.delenv("SSL_CERT_DIR", raising=False)
mock_ctx = MagicMock(spec=ssl.SSLContext)
with (
patch("vibe.core.utils.http.certifi.where", return_value="/certifi.pem"),
patch(
"vibe.core.utils.http.ssl.create_default_context", return_value=mock_ctx
) as create_default_context,
):
build_ssl_context()
create_default_context.assert_called_once_with(cafile="/certifi.pem")
def test_build_ssl_context_uses_system_trust_store_when_configured(monkeypatch):
monkeypatch.delenv("SSL_CERT_FILE", raising=False)
monkeypatch.delenv("SSL_CERT_DIR", raising=False)
configure_ssl_context(enable_system_trust_store=True)
mock_ctx = MagicMock(spec=ssl.SSLContext)
with (
patch(
"vibe.core.utils.http.truststore.SSLContext", return_value=mock_ctx
) as truststore_context,
patch(
"vibe.core.utils.http.ssl.create_default_context"
) as create_default_context,
):
build_ssl_context()
truststore_context.assert_called_once_with(ssl.PROTOCOL_TLS_CLIENT)
create_default_context.assert_not_called()
def test_build_ssl_context_loads_custom_cert_file(monkeypatch, tmp_path):
cert_file = tmp_path / "custom.pem"
cert_file.write_text("dummy")
@ -37,6 +75,24 @@ def test_build_ssl_context_loads_custom_cert_file(monkeypatch, tmp_path):
)
def test_build_ssl_context_loads_custom_cert_file_with_system_trust_store(
monkeypatch, tmp_path
):
cert_file = tmp_path / "custom.pem"
cert_file.write_text("dummy")
monkeypatch.setenv("SSL_CERT_FILE", str(cert_file))
monkeypatch.delenv("SSL_CERT_DIR", raising=False)
configure_ssl_context(enable_system_trust_store=True)
mock_ctx = MagicMock(spec=ssl.SSLContext)
with patch("vibe.core.utils.http.truststore.SSLContext", return_value=mock_ctx):
build_ssl_context()
mock_ctx.load_verify_locations.assert_called_once_with(
cafile=str(cert_file), capath=None
)
def test_build_ssl_context_loads_custom_cert_dir(monkeypatch, tmp_path):
cert_dir = tmp_path / "certs"
cert_dir.mkdir()

View file

@ -2,8 +2,10 @@ from __future__ import annotations
import json
from pathlib import Path
import ssl
import tomllib
from typing import Literal, TypedDict, Unpack
from unittest.mock import MagicMock, patch
import pytest
import tomli_w
@ -23,6 +25,7 @@ from vibe.core.config.harness_files import (
from vibe.core.paths import VIBE_HOME
from vibe.core.trusted_folders import trusted_folders_manager
from vibe.core.types import Backend
from vibe.core.utils.http import build_ssl_context, configure_ssl_context
from vibe.setup.onboarding.context import OnboardingContext
@ -198,6 +201,73 @@ class TestSaveUpdates:
assert result == {"tools": {"bash": {"default_timeout": 600}}}
class TestSystemTrustStoreConfig:
def test_load_configures_ssl_context_from_toml(self, config_dir: Path) -> None:
config_file = config_dir / "config.toml"
with config_file.open("rb") as f:
data = tomllib.load(f)
data["enable_system_trust_store"] = True
with config_file.open("wb") as f:
tomli_w.dump(data, f)
with patch("vibe.core.config._settings.configure_ssl_context") as configure:
config = VibeConfig.load()
assert config.enable_system_trust_store is True
configure.assert_called_once_with(enable_system_trust_store=True)
def test_load_configures_ssl_context_from_env(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setenv("VIBE_ENABLE_SYSTEM_TRUST_STORE", "true")
with patch("vibe.core.config._settings.configure_ssl_context") as configure:
config = VibeConfig.load()
assert config.enable_system_trust_store is True
configure.assert_called_once_with(enable_system_trust_store=True)
def test_load_clears_cached_ssl_context_when_setting_changes(
self, config_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.delenv("SSL_CERT_FILE", raising=False)
monkeypatch.delenv("SSL_CERT_DIR", raising=False)
configure_ssl_context(enable_system_trust_store=False)
build_ssl_context.cache_clear()
try:
config_file = config_dir / "config.toml"
with config_file.open("rb") as f:
data = tomllib.load(f)
data["enable_system_trust_store"] = False
with config_file.open("wb") as f:
tomli_w.dump(data, f)
default_ctx = MagicMock(spec=ssl.SSLContext)
with patch(
"vibe.core.utils.http.ssl.create_default_context",
return_value=default_ctx,
):
VibeConfig.load()
assert build_ssl_context() is default_ctx
data["enable_system_trust_store"] = True
with config_file.open("wb") as f:
tomli_w.dump(data, f)
truststore_ctx = MagicMock(spec=ssl.SSLContext)
with patch(
"vibe.core.utils.http.truststore.SSLContext",
return_value=truststore_ctx,
):
VibeConfig.load()
assert build_ssl_context() is truststore_ctx
finally:
configure_ssl_context(enable_system_trust_store=False)
build_ssl_context.cache_clear()
class TestSetThinking:
def test_persists_thinking_to_toml(self, config_dir: Path) -> None:
config_file = config_dir / "config.toml"
@ -821,6 +891,7 @@ class TestOnboardingContextResolution:
def test_load_uses_env_overrides(self, monkeypatch: pytest.MonkeyPatch) -> None:
reset_harness_files_manager()
monkeypatch.setenv("VIBE_ACTIVE_MODEL", "env-model")
monkeypatch.setenv("VIBE_VIBE_BASE_URL", "https://env-vibe.example.com")
monkeypatch.setenv(
"VIBE_PROVIDERS",
json.dumps([
@ -842,6 +913,7 @@ class TestOnboardingContextResolution:
assert context.provider.name == "env-provider"
assert context.provider.api_key_env_var == "ENV_API_KEY"
assert context.vibe_base_url == "https://env-vibe.example.com"
def test_load_prefers_explicit_overrides_over_toml_and_env(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch

View file

@ -331,17 +331,13 @@ class TestTelemetryClient:
client = TelemetryClient(config_getter=lambda: config)
client.send_auto_compact_triggered(
nb_context_tokens_before=123,
nb_context_tokens_after=45,
auto_compact_threshold=100,
status="success",
nb_context_tokens_before=123, auto_compact_threshold=100, status="success"
)
assert len(telemetry_events) == 1
assert telemetry_events[0]["event_name"] == "vibe.auto_compact_triggered"
assert telemetry_events[0]["properties"] == {
"nb_context_tokens_before": 123,
"nb_context_tokens_after": 45,
"auto_compact_threshold": 100,
"status": "success",
}
@ -674,7 +670,6 @@ class TestTelemetryClient:
client.send_auto_compact_triggered(
nb_context_tokens_before=123,
nb_context_tokens_after=45,
auto_compact_threshold=100,
status="success",
session_id="original-session-id",

View file

@ -4,7 +4,7 @@ from pathlib import Path
import pytest
from vibe.core.utils import compact_reduction_display, get_server_url_from_api_base
from vibe.core.utils import compact_complete_display, get_server_url_from_api_base
import vibe.core.utils.io as io_utils
from vibe.core.utils.io import decode_safe, read_safe, read_safe_async
@ -23,22 +23,18 @@ def test_get_server_url_from_api_base(api_base, expected):
assert get_server_url_from_api_base(api_base) == expected
class TestCompactReductionDisplay:
class TestCompactCompleteDisplay:
def test_includes_session_ids_when_available(self) -> None:
assert compact_reduction_display(
177_017,
23_263,
assert compact_complete_display(
old_session_id="11111111-1111-1111-1111-111111111111",
new_session_id="22222222-2222-2222-2222-222222222222",
) == (
"Compaction complete: 177,017 → 23,263 tokens (-87.%)\n"
"Compaction completed.\n"
"session: 11111111 (before compaction) → 22222222 (after compaction)"
)
def test_returns_base_message_without_session_ids(self) -> None:
assert compact_reduction_display(177_017, 23_263) == (
"Compaction complete: 177,017 → 23,263 tokens (-87.%)"
)
assert compact_complete_display() == "Compaction completed."
class TestReadSafe: