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
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue