Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai>
Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com>
Co-authored-by: Hdandria <henri.dandria@mistral.ai>
Co-authored-by: Ivana Dunisijevic <ivana.dunisijevic@mistral.ai>
Co-authored-by: Jean Burellier <sheplu@users.noreply.github.com>
Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai>
Co-authored-by: Mert Unsal <mert.unsal@mistral.ai>
Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com>
Co-authored-by: Paul VEZIA <166131032+le-codeur-rapide@users.noreply.github.com>
Co-authored-by: Pierre Rossinès <pierre.rossines@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: renovate-mistral[bot] <253709520+renovate-mistral[bot]@users.noreply.github.com>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Clément Drouin 2026-06-19 11:01:24 +02:00 committed by GitHub
parent 564a14365e
commit 6bedf271ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
223 changed files with 10533 additions and 6947 deletions

View file

@ -4,6 +4,8 @@ import asyncio
from collections.abc import Callable, Iterator
from contextlib import suppress
import socket
from types import TracebackType
from unittest.mock import patch
import urllib.parse
import httpx
@ -11,6 +13,7 @@ import keyring
from keyring.backend import KeyringBackend
import keyring.backends.fail
import keyring.errors
from mcp.client.auth import OAuthFlowError
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
import pytest
import respx
@ -21,6 +24,7 @@ from vibe.core.auth.mcp_oauth import (
LoopbackCallbackHandler,
MCPOAuthError,
MCPOAuthHeadlessError,
MCPOAuthLoginFailed,
MCPOAuthPortInUse,
build_oauth_provider,
perform_oauth_login,
@ -366,6 +370,26 @@ class TestBuildOAuthProvider:
)
assert provider.context.client_metadata_url == "https://vibe.example/cm.json"
@pytest.mark.asyncio
async def test_client_id_is_exposed_as_fallback_client_info(
self, memory_keyring: _MemoryKeyring
) -> None:
srv = _oauth_server(client_id="pre-registered-client")
async def on_url(_url: str) -> None:
return None
async def cb() -> tuple[str, str | None]:
return "code", None
provider = build_oauth_provider(
srv, redirect_handler=on_url, callback_handler=cb
)
client_info = await provider.context.storage.get_client_info()
assert client_info is not None
assert client_info.client_id == "pre-registered-client"
@pytest.mark.asyncio
async def test_rejects_static_auth(self, memory_keyring: _MemoryKeyring) -> None:
from vibe.core.config import MCPStaticAuth
@ -388,6 +412,39 @@ class TestBuildOAuthProvider:
class TestPerformOAuthLogin:
@pytest.mark.asyncio
async def test_oauth_flow_error_becomes_login_failed(
self, memory_keyring: _MemoryKeyring
) -> None:
srv = _oauth_server(name="demo")
class OAuthFlowFailingClient:
def __init__(self, *args: object, **kwargs: object) -> None:
pass
async def __aenter__(self) -> OAuthFlowFailingClient:
return self
async def __aexit__(
self,
exc_type: type[BaseException] | None,
exc: BaseException | None,
traceback: TracebackType | None,
) -> None:
pass
async def get(self, _url: str) -> None:
raise OAuthFlowError("cancelled")
async def on_url(_url: str) -> None:
pass
with patch(
"vibe.core.auth.mcp_oauth.httpx.AsyncClient", new=OAuthFlowFailingClient
):
with pytest.raises(MCPOAuthLoginFailed, match="cancelled"):
await perform_oauth_login(srv, on_url=on_url)
@pytest.mark.asyncio
async def test_full_flow_persists_tokens_and_fingerprint(
self, memory_keyring: _MemoryKeyring