You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.2 KiB
Python
138 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import replace
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
import app.mcp.tools as mcp_tools_module
|
|
from app.config import get_settings
|
|
from app.security.auth import AuthBackend
|
|
|
|
|
|
class _DummyCoreService:
|
|
def check_availability(
|
|
self,
|
|
start: str,
|
|
end: str,
|
|
calendar_ids: list[str] | None,
|
|
) -> SimpleNamespace:
|
|
return SimpleNamespace(
|
|
start=start,
|
|
end=end,
|
|
available=True,
|
|
busy_slots=[],
|
|
checked_calendars=calendar_ids or ["primary"],
|
|
)
|
|
|
|
def scan_mailbox(self, max_results: int) -> SimpleNamespace:
|
|
return SimpleNamespace(
|
|
scanned=max_results,
|
|
linkedin=0,
|
|
advertising=0,
|
|
veille_techno=0,
|
|
skipped=0,
|
|
failed=0,
|
|
)
|
|
|
|
|
|
class _DummyCtx:
|
|
def __init__(self, headers: dict[str, str]) -> None:
|
|
self.request_context = SimpleNamespace(
|
|
request=SimpleNamespace(headers=headers)
|
|
)
|
|
|
|
|
|
def test_mcp_check_availability_requires_auth(monkeypatch) -> None:
|
|
auth_settings = replace(
|
|
get_settings(),
|
|
auth_mode="api_key",
|
|
agent_api_key="mcp-key",
|
|
auth_jwt_secret="",
|
|
)
|
|
monkeypatch.setattr(mcp_tools_module, "auth_backend", AuthBackend(auth_settings))
|
|
monkeypatch.setattr(mcp_tools_module, "core_service", _DummyCoreService())
|
|
|
|
with pytest.raises(PermissionError):
|
|
mcp_tools_module.check_availability(
|
|
start="2026-03-10T09:00:00+01:00",
|
|
end="2026-03-10T10:00:00+01:00",
|
|
calendar_ids=["primary"],
|
|
ctx=_DummyCtx(headers={}),
|
|
)
|
|
|
|
|
|
def test_mcp_check_availability_with_api_key(monkeypatch) -> None:
|
|
auth_settings = replace(
|
|
get_settings(),
|
|
auth_mode="api_key",
|
|
agent_api_key="mcp-key",
|
|
auth_jwt_secret="",
|
|
)
|
|
monkeypatch.setattr(mcp_tools_module, "auth_backend", AuthBackend(auth_settings))
|
|
monkeypatch.setattr(mcp_tools_module, "core_service", _DummyCoreService())
|
|
|
|
payload = mcp_tools_module.check_availability(
|
|
start="2026-03-10T09:00:00+01:00",
|
|
end="2026-03-10T10:00:00+01:00",
|
|
calendar_ids=["primary"],
|
|
ctx=_DummyCtx(headers={"x-api-key": "mcp-key"}),
|
|
)
|
|
|
|
assert payload["available"] is True
|
|
assert payload["checked_calendars"] == ["primary"]
|
|
|
|
|
|
def test_mcp_scan_mailbox_requires_mail_scan_scope(monkeypatch) -> None:
|
|
auth_settings = replace(
|
|
get_settings(),
|
|
auth_mode="api_key",
|
|
agent_api_key="mcp-key",
|
|
auth_jwt_secret="",
|
|
)
|
|
monkeypatch.setattr(mcp_tools_module, "auth_backend", AuthBackend(auth_settings))
|
|
monkeypatch.setattr(mcp_tools_module, "core_service", _DummyCoreService())
|
|
|
|
payload = mcp_tools_module.scan_mailbox(
|
|
max_results=10,
|
|
ctx=_DummyCtx(headers={"x-api-key": "mcp-key"}),
|
|
)
|
|
assert payload["scanned"] == 10
|
|
|
|
|
|
def test_mcp_auth_mode_oauth_uses_bearer_token(monkeypatch) -> None:
|
|
mcp_settings = replace(
|
|
get_settings(),
|
|
auth_mode="api_key",
|
|
agent_api_key="api-key-not-used-for-mcp",
|
|
auth_jwt_secret="",
|
|
mcp_auth_mode="oauth",
|
|
mcp_oauth_introspection_url="https://issuer.example/introspect",
|
|
mcp_oauth_issuer="https://issuer.example",
|
|
mcp_oauth_audience="personal-agent-mcp",
|
|
)
|
|
backend = mcp_tools_module._build_mcp_auth_backend(mcp_settings)
|
|
monkeypatch.setattr(
|
|
backend,
|
|
"_introspect_oauth_token",
|
|
lambda _: {
|
|
"active": True,
|
|
"sub": "oauth-agent",
|
|
"iss": "https://issuer.example",
|
|
"aud": "personal-agent-mcp",
|
|
"scope": "availability:read",
|
|
},
|
|
)
|
|
monkeypatch.setattr(mcp_tools_module, "auth_backend", backend)
|
|
monkeypatch.setattr(mcp_tools_module, "core_service", _DummyCoreService())
|
|
|
|
payload = mcp_tools_module.check_availability(
|
|
start="2026-03-10T09:00:00+01:00",
|
|
end="2026-03-10T10:00:00+01:00",
|
|
calendar_ids=["primary"],
|
|
ctx=_DummyCtx(headers={"authorization": "Bearer oauth-token"}),
|
|
)
|
|
|
|
assert payload["available"] is True
|
|
assert payload["checked_calendars"] == ["primary"]
|