fix: tighten oauth and source resource handling

This commit is contained in:
lda
2026-06-14 00:53:42 +07:00 Verified
parent 2609679b87
commit d596898b96
19 changed files with 228 additions and 21 deletions
+28
View File
@@ -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",
},
)
+22
View File
@@ -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(
+11 -2
View File
@@ -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",
)
+8
View File
@@ -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(
+3
View File
@@ -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