refactor: move mcp auth record ownership

This commit is contained in:
lda
2026-06-06 15:01:39 +07:00 Verified
parent 0028528269
commit a28ca5434a
150 changed files with 557 additions and 549 deletions
+17 -20
View File
@@ -7,20 +7,19 @@ from dataclasses import replace
from pathlib import Path
from typing import Any
from tests.wf_mcp.test_support import echo_tool
from wf_api.artifacts import WorkflowArtifactApi
from wf_artifacts import (
FileWorkflowArtifactStore,
FileDraftWorkspaceStore,
FileWorkflowArtifactStore,
RequiredCapability,
WorkflowArtifact,
)
from wf_api.artifacts import WorkflowArtifactApi
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from tests.wf_mcp.test_support import echo_tool
def _echo_draft() -> dict[str, Any]:
@@ -145,7 +144,9 @@ def test_save_artifact_stores_and_returns_saved(tmp_path: Path) -> None:
assert saved.id == "echo"
def test_list_artifacts_returns_empty_page_without_artifact_store(tmp_path: Path) -> None:
def test_list_artifacts_returns_empty_page_without_artifact_store(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_no_store")
_api, service = _artifact_api(artifact_store)
context = replace(context_from_service(service), artifact_store=None)
@@ -158,10 +159,10 @@ def test_list_artifacts_returns_empty_page_without_artifact_store(tmp_path: Path
assert result["total"] == 0
def test_create_artifact_from_plan_saves_with_observed_node_specs(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "artifacts_from_plan"
)
def test_create_artifact_from_plan_saves_with_observed_node_specs(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_from_plan")
api, _service = _artifact_api(artifact_store, register_echo=True)
result = asyncio.run(
@@ -180,10 +181,10 @@ def test_create_artifact_from_plan_saves_with_observed_node_specs(tmp_path: Path
assert saved.id == "echo"
def test_create_artifact_from_workspace_returns_saved_false_when_invalid(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "artifacts_workspace_invalid"
)
def test_create_artifact_from_workspace_returns_saved_false_when_invalid(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_workspace_invalid")
api, service = _artifact_api(artifact_store, register_echo=True)
draft = _echo_draft()
draft["routes"]["echo"] = {"typo": "__end__"}
@@ -213,9 +214,7 @@ def test_create_artifact_from_workspace_returns_saved_false_when_invalid(tmp_pat
def test_create_wrapper_from_workspace_saves_kind_wrapper(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "artifacts_wrapper_workspace"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_wrapper_workspace")
api, service = _artifact_api(artifact_store, register_echo=True)
from wf_api.drafts import WorkflowDraftApi
@@ -258,9 +257,7 @@ def test_inspect_artifact_returns_stable_fields(tmp_path: Path) -> None:
def test_handler_delegation_for_inspect_artifact(tmp_path: Path) -> None:
"""WorkflowSurfaceHandlers.inspect_artifact delegates to WorkflowArtifactApi."""
artifact_store = FileWorkflowArtifactStore(
tmp_path / "artifacts_delegation"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_delegation")
mcp_root = artifact_store.root / "delegation_mcp"
service = WfMcpService(
store=FileStore(mcp_root),
+3 -4
View File
@@ -4,6 +4,7 @@ from pathlib import Path
import pytest
from tests.wf_mcp.workflow_surface.conftest import echo_artifact
from wf_api.artifact_plans import plan_field, plan_nodes, raw_plan_from_artifact
from wf_api.artifact_refs import artifact_capability_id
from wf_api.capability_requirements import (
@@ -11,8 +12,6 @@ from wf_api.capability_requirements import (
required_capability_payloads,
)
from tests.wf_mcp.workflow_surface.conftest import echo_artifact
def test_artifact_capability_id_uses_workflow_ref_shape() -> None:
artifact = echo_artifact()
@@ -66,12 +65,12 @@ def test_required_capability_payloads_sorts_by_name() -> None:
def test_observed_node_specs_projects_enabled_context_specs(tmp_path: Path) -> None:
from tests.wf_mcp.test_support import echo_tool
from wf_artifacts import FileWorkflowArtifactStore
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from tests.wf_mcp.test_support import echo_tool
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_req_helpers")
service = WfMcpService(
+10 -23
View File
@@ -5,16 +5,15 @@ from pathlib import Path
import pytest
from wf_artifacts import FileWorkflowArtifactStore, FileDraftWorkspaceStore
from tests.wf_mcp.test_support import echo_tool
from tests.wf_mcp.workflow_surface.conftest import echo_artifact, failing_tool
from wf_api.capabilities import WorkflowCapabilityApi
from wf_artifacts import FileDraftWorkspaceStore, FileWorkflowArtifactStore
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from tests.wf_mcp.test_support import echo_tool
from tests.wf_mcp.workflow_surface.conftest import echo_artifact, failing_tool
def _capability_api(
@@ -64,9 +63,7 @@ def test_list_capabilities_returns_planner_visible_sources(tmp_path: Path) -> No
def test_list_capabilities_filters_by_source(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "cap_api_list_filter"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_list_filter")
api, _service = _capability_api(artifact_store, register_echo=True)
result = asyncio.run(api.list_capabilities(source_id="wf.std", query="truthy"))
@@ -91,9 +88,7 @@ def test_inspect_capability_returns_detail_with_wrapper_hints(tmp_path: Path) ->
def test_inspect_capability_raises_on_unknown(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "cap_api_inspect_unknown"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_inspect_unknown")
api, _service = _capability_api(artifact_store, register_echo=True)
with pytest.raises(KeyError, match="no.such.capability"):
@@ -136,9 +131,7 @@ def test_call_capability_node_spec_failure(tmp_path: Path) -> None:
def test_list_capabilities_includes_saved_wrapper(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "cap_api_wrapper_list"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_wrapper_list")
artifact_store.save_artifact(
echo_artifact().model_copy(
update={
@@ -167,9 +160,7 @@ def test_list_capabilities_includes_saved_wrapper(tmp_path: Path) -> None:
def test_inspect_capability_saved_wrapper(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "cap_api_wrapper_inspect"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_wrapper_inspect")
artifact_store.save_artifact(
echo_artifact().model_copy(update={"id": "echo_wrapper", "kind": "wrapper"})
)
@@ -196,9 +187,7 @@ def test_inspect_capability_saved_wrapper(tmp_path: Path) -> None:
def test_call_capability_saved_wrapper(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "cap_api_wrapper_call"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_wrapper_call")
artifact_store.save_artifact(
echo_artifact().model_copy(update={"id": "echo_wrapper", "kind": "wrapper"})
)
@@ -217,9 +206,7 @@ def test_call_capability_saved_wrapper(tmp_path: Path) -> None:
def test_create_draft_workspace_from_capability(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "cap_api_draft_bootstrap"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_draft_bootstrap")
api, _service = _capability_api(artifact_store, register_echo=True)
result = asyncio.run(
+6 -11
View File
@@ -7,22 +7,21 @@ from dataclasses import replace
from pathlib import Path
from typing import Any, cast
from tests.wf_mcp.test_support import echo_tool
from wf_api.deployments import WorkflowDeploymentApi
from wf_artifacts import (
FileWorkflowArtifactStore,
RequiredCapability,
WorkflowArtifact,
WorkflowDeployment,
)
from wf_api.deployments import WorkflowDeploymentApi
from wf_mcp.broker import WfMcpService
from wf_mcp.models import AuthRecord, ConnectionConfig
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.capabilities import DiscoveredTool
from wf_mcp.models import AuthRecord, ConnectionConfig
from wf_mcp.sdk import BackendAdapter
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from tests.wf_mcp.test_support import echo_tool
def _echo_artifact() -> WorkflowArtifact:
@@ -172,9 +171,7 @@ def test_delete_deployment_removes_one(tmp_path: Path) -> None:
def test_validate_deployment_returns_runnable_for_valid_binding(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "deploy_validate_runnable"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_validate_runnable")
api, service = _deployment_api(artifact_store, register_echo=True)
artifact_store.save_artifact(_echo_artifact())
artifact_store.save_deployment(
@@ -204,9 +201,7 @@ class FailingLivenessAdapter:
def test_validate_deployment_live_check_calls_live_checker(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "deploy_validate_live"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_validate_live")
api, service = _deployment_api(artifact_store, register_echo=True)
artifact_store.save_artifact(_echo_artifact())
artifact_store.save_deployment(
+2 -3
View File
@@ -3,20 +3,19 @@ from __future__ import annotations
import asyncio
from pathlib import Path
from wf_artifacts import FileWorkflowArtifactStore
from tests.wf_mcp.test_support import echo_tool
from wf_api import WorkflowApi
from wf_api.artifacts import WorkflowArtifactApi
from wf_api.capabilities import WorkflowCapabilityApi
from wf_api.deployments import WorkflowDeploymentApi
from wf_api.drafts import WorkflowDraftApi
from wf_api.runs import WorkflowRunApi
from wf_artifacts import FileWorkflowArtifactStore
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from tests.wf_mcp.test_support import echo_tool
def _api(root: Path) -> WorkflowApi:
service = WfMcpService(
+17 -30
View File
@@ -4,15 +4,14 @@ import asyncio
from pathlib import Path
from typing import Any
from wf_artifacts import FileWorkflowArtifactStore, FileDraftWorkspaceStore
from tests.wf_mcp.test_support import echo_tool
from wf_api.drafts import WorkflowDraftApi
from wf_artifacts import FileDraftWorkspaceStore, FileWorkflowArtifactStore
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from tests.wf_mcp.test_support import echo_tool
def _echo_draft() -> dict[str, Any]:
@@ -96,9 +95,7 @@ def test_patch_draft_applies_json_patch(tmp_path: Path) -> None:
def test_create_draft_workspace_creates_workspace(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_create_workspace"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_create_workspace")
api, _service = _draft_api(artifact_store)
result = asyncio.run(
@@ -119,10 +116,10 @@ def test_create_draft_workspace_creates_workspace(tmp_path: Path) -> None:
assert fetched["draft"]["steps"]["echo"]["use"] == "demo.personal.echo_tool"
def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_list_workspaces"
)
def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_list_workspaces")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
@@ -150,9 +147,7 @@ def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(tmp_path:
def test_delete_draft_workspace_is_idempotent(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_delete_workspace"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_delete_workspace")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
@@ -175,9 +170,7 @@ def test_delete_draft_workspace_is_idempotent(tmp_path: Path) -> None:
def test_patch_draft_workspace_updates_revision(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_patch_workspace"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_patch_workspace")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
@@ -198,10 +191,10 @@ def test_patch_draft_workspace_updates_revision(tmp_path: Path) -> None:
assert patched["status"] == "valid"
def test_draft_workspace_patch_helpers_update_revision_and_bindings(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_patch_helpers"
)
def test_draft_workspace_patch_helpers_update_revision_and_bindings(
tmp_path: Path,
) -> None:
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_patch_helpers")
api, _service = _draft_api(artifact_store)
asyncio.run(
api.create_draft_workspace(
@@ -267,9 +260,7 @@ def test_draft_workspace_patch_helpers_update_revision_and_bindings(tmp_path: Pa
def test_validate_draft_workspace_refreshes_status(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_validate_workspace"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_validate_workspace")
api, service = _draft_api(artifact_store, register_echo=True)
draft = _echo_draft()
draft["routes"]["echo"] = {"typo": "__end__"}
@@ -290,9 +281,7 @@ def test_validate_draft_workspace_refreshes_status(tmp_path: Path) -> None:
def test_create_minimal_draft_workspace_minimal_success_path(tmp_path: Path) -> None:
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_minimal_workspace"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_minimal_workspace")
api, _service = _draft_api(artifact_store, register_echo=True)
result = asyncio.run(
@@ -326,9 +315,7 @@ def test_create_minimal_draft_workspace_minimal_success_path(tmp_path: Path) ->
def test_delegation_smoke_validate_draft_equivalence(tmp_path: Path) -> None:
"""WorkflowSurfaceHandlers.validate_draft delegates to WorkflowDraftApi."""
artifact_store = FileWorkflowArtifactStore(
tmp_path / "drafts_delegation_smoke"
)
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_delegation_smoke")
mcp_root = artifact_store.root / "delegation_mcp"
service = WfMcpService(
store=FileStore(mcp_root),
+17 -14
View File
@@ -5,24 +5,23 @@ from pathlib import Path
import pytest
from wf_artifacts import (
FileWorkflowArtifactStore,
FileRunStore,
WorkflowDeployment,
)
from wf_api.runs import WorkflowRunApi
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
from tests.wf_mcp.test_support import echo_tool
from tests.wf_mcp.workflow_surface.conftest import (
echo_artifact,
failing_artifact,
failing_tool,
)
from wf_api.runs import WorkflowRunApi
from wf_artifacts import (
FileRunStore,
FileWorkflowArtifactStore,
WorkflowDeployment,
)
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.workflow_operation_context import context_from_service
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
class SimpleTraceRange:
@@ -160,7 +159,9 @@ def test_run_api_rejects_resume_for_completed_run(tmp_path: Path) -> None:
)
def test_run_api_inspect_uses_pinned_environment_after_deployment_deleted(tmp_path: Path) -> None:
def test_run_api_inspect_uses_pinned_environment_after_deployment_deleted(
tmp_path: Path,
) -> None:
root = tmp_path / "run_api_inspect_after_deployment_deleted"
service, artifact_store = _service_with_echo(root)
context = context_from_service(service)
@@ -217,7 +218,9 @@ class ExplodingRunStore(FileRunStore):
raise AssertionError("run store must not be read before trace_range validation")
def test_run_api_rejects_invalid_trace_range_before_store_lookup(tmp_path: Path) -> None:
def test_run_api_rejects_invalid_trace_range_before_store_lookup(
tmp_path: Path,
) -> None:
root = tmp_path / "run_api_invalid_trace_range"
service, _ = _service_with_echo(root)
service.run_store = ExplodingRunStore(root / "exploding_runs")
@@ -26,10 +26,14 @@ def test_compat_shim_import_from_wf_mcp() -> None:
def test_shim_symbols_are_identical_to_canonical() -> None:
from wf_api.runtime_dependencies import (
RuntimeDependencies as CanonicalRuntimeDependencies,
)
from wf_api.runtime_dependencies import (
resolve_runtime_dependencies as canonical_resolve,
)
from wf_mcp.workflow_surface.runtime_dependencies import (
RuntimeDependencies as ShimRuntimeDependencies,
)
from wf_mcp.workflow_surface.runtime_dependencies import (
resolve_runtime_dependencies as shim_resolve,
)