fix: tighten oauth and source resource handling
This commit is contained in:
@@ -151,3 +151,31 @@ def test_auth_record_from_compat_maps_oauth_refresh_token() -> None:
|
||||
assert record.auth.client_id == "client"
|
||||
assert str(record.auth.token_url) == "https://oauth2.googleapis.com/token"
|
||||
assert record.auth.scopes == ("https://www.googleapis.com/auth/drive.readonly",)
|
||||
|
||||
|
||||
def test_auth_record_from_compat_rejects_bad_oauth_refresh_token_payload() -> None:
|
||||
from wf_api.auth import auth_record_from_compat
|
||||
|
||||
with pytest.raises(ValueError, match="client_secret"):
|
||||
auth_record_from_compat(
|
||||
id="google.drive.personal",
|
||||
scheme="oauth_refresh_token",
|
||||
payload={
|
||||
"client_id": "client",
|
||||
"client_secret": "",
|
||||
"refresh_token": "refresh",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
},
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="token_url is invalid"):
|
||||
auth_record_from_compat(
|
||||
id="google.drive.personal",
|
||||
scheme="oauth_refresh_token",
|
||||
payload={
|
||||
"client_id": "client",
|
||||
"client_secret": "secret",
|
||||
"refresh_token": "refresh",
|
||||
"token_url": "not a url",
|
||||
},
|
||||
)
|
||||
|
||||
@@ -39,6 +39,28 @@ async def test_read_resource_resolves_logical_source_and_bounds_text() -> None:
|
||||
assert result.text == "abcde"
|
||||
|
||||
|
||||
async def test_read_resource_preserves_upstream_truncated_signal() -> None:
|
||||
async def handler(source_id: str, uri: str, max_chars: int):
|
||||
return {
|
||||
"contents": [{"type": "text", "text": "abc", "mimeType": "text/plain"}],
|
||||
"truncated": True,
|
||||
}
|
||||
|
||||
platform = SourceBindingPlatformContext(
|
||||
source_bindings={"drive": "drive.personal"},
|
||||
read_resource_handler=handler,
|
||||
)
|
||||
|
||||
result = await read_resource(
|
||||
SourceResourceRef(logical_source="drive", uri="gdrive://file/abc"),
|
||||
RuntimeContext(current_node_id="read", platform=platform),
|
||||
max_chars=5,
|
||||
)
|
||||
|
||||
assert result.truncated is True
|
||||
assert result.text == "abc"
|
||||
|
||||
|
||||
async def test_read_resource_requires_platform_context() -> None:
|
||||
with pytest.raises(RuntimeError, match="platform context"):
|
||||
await read_resource(
|
||||
|
||||
@@ -15,6 +15,7 @@ from wf_config import OAuthProviderConfig
|
||||
def _oauth_provider(
|
||||
*,
|
||||
scopes: tuple[str, ...] = (),
|
||||
extra_authorize_params: dict[str, str] | None = None,
|
||||
) -> OAuthProviderConfig:
|
||||
return OAuthProviderConfig(
|
||||
kind="oauth_authorization_code_pkce",
|
||||
@@ -23,6 +24,7 @@ def _oauth_provider(
|
||||
client_id_env="GOOGLE_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GOOGLE_OAUTH_CLIENT_SECRET",
|
||||
scopes=scopes,
|
||||
extra_authorize_params=extra_authorize_params or {},
|
||||
)
|
||||
|
||||
|
||||
@@ -85,12 +87,14 @@ class _FakeOAuthClient:
|
||||
return {
|
||||
"refresh_token": "refresh",
|
||||
"scope": "https://www.googleapis.com/auth/drive.readonly",
|
||||
"sub": "user-123",
|
||||
}
|
||||
|
||||
|
||||
async def test_oauth_code_login_flow_uses_injected_client() -> None:
|
||||
provider = _oauth_provider(
|
||||
scopes=("https://www.googleapis.com/auth/drive.readonly",),
|
||||
extra_authorize_params={"access_type": "offline", "prompt": "consent"},
|
||||
)
|
||||
clients: list[_FakeOAuthClient] = []
|
||||
|
||||
@@ -109,6 +113,7 @@ async def test_oauth_code_login_flow_uses_injected_client() -> None:
|
||||
)
|
||||
|
||||
assert result.refresh_token == "refresh"
|
||||
assert result.subject == "user-123"
|
||||
assert result.scopes == ("https://www.googleapis.com/auth/drive.readonly",)
|
||||
client = clients[0]
|
||||
assert client.init_kwargs["redirect_uri"] == provider.redirect_uri
|
||||
@@ -173,11 +178,15 @@ def test_auth_oauth_login_saves_record_from_provider_profile(monkeypatch, tmp_pa
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"client_id_env": "GOOGLE_OAUTH_CLIENT_ID",
|
||||
"scopes": ["https://www.googleapis.com/auth/drive.readonly"],
|
||||
}
|
||||
"scopes": ["https://www.googleapis.com/auth/drive.readonly"],
|
||||
"extra_authorize_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
@@ -472,6 +472,10 @@ def test_workflow_config_parses_oauth_provider_profile() -> None:
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/drive.readonly",
|
||||
],
|
||||
"extra_authorize_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,3 +486,7 @@ def test_workflow_config_parses_oauth_provider_profile() -> None:
|
||||
assert provider.kind == "oauth_authorization_code_pkce"
|
||||
assert provider.client_id_env == "GOOGLE_OAUTH_CLIENT_ID"
|
||||
assert provider.scopes == ("https://www.googleapis.com/auth/drive.readonly",)
|
||||
assert provider.extra_authorize_params == {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent",
|
||||
}
|
||||
|
||||
@@ -286,6 +286,26 @@ async def test_read_resource_by_source_uri_reads_upstream() -> None:
|
||||
assert result["contents"][0]["text"] == "Welcome from the fake adapter resource."
|
||||
|
||||
|
||||
async def test_read_resource_by_source_uri_bounds_text() -> None:
|
||||
service = WfMcpService(
|
||||
store=FileStore(local_temp_root() / "content_source_uri_bound")
|
||||
)
|
||||
service.register_connection(
|
||||
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
||||
)
|
||||
service.register_adapter("demo", FakeAdapter())
|
||||
await service.refresh_connection_catalog("demo.personal")
|
||||
|
||||
result = await service.content_access.read_resource_by_source_uri(
|
||||
source_id="demo.personal",
|
||||
uri="demo://docs/welcome",
|
||||
max_chars=7,
|
||||
)
|
||||
|
||||
assert result["contents"][0]["text"] == "Welcome"
|
||||
assert result["truncated"] is True
|
||||
|
||||
|
||||
async def test_read_resource_by_source_uri_rejects_unknown_resource() -> None:
|
||||
service = WfMcpService(
|
||||
store=FileStore(local_temp_root() / "content_source_uri_unknown")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from wf_mcp.broker.service.source_diagnostics import SourceDiagnosticsProvider
|
||||
from wf_mcp.connections import ConnectionRegistry
|
||||
from wf_mcp.models import ConnectionConfig
|
||||
@@ -18,7 +20,7 @@ def _connection(**metadata: object) -> ConnectionConfig:
|
||||
)
|
||||
|
||||
|
||||
def _provider(tmp_path, connection: ConnectionConfig) -> SourceDiagnosticsProvider:
|
||||
def _provider(tmp_path: Path, connection: ConnectionConfig) -> SourceDiagnosticsProvider:
|
||||
registry = ConnectionRegistry()
|
||||
registry.register(connection)
|
||||
return SourceDiagnosticsProvider(
|
||||
|
||||
@@ -97,6 +97,9 @@ async def test_httpx_oauth_refresher_posts_refresh_token_grant(
|
||||
return {"access_token": "access-token", "expires_in": 3600}
|
||||
|
||||
class _Client:
|
||||
def __init__(self, **kwargs: object) -> None:
|
||||
assert kwargs["timeout"] == 10.0
|
||||
|
||||
async def __aenter__(self) -> "_Client":
|
||||
return self
|
||||
|
||||
|
||||
Reference in New Issue
Block a user