code review jr: store path traversal...

emit workflow_run_failed

again?
This commit is contained in:
lda
2026-06-03 04:04:24 +07:00 Verified
parent 688dcb69a9
commit 969a5704bb
8 changed files with 200 additions and 13 deletions
+43 -2
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import asyncio
from wf_core import NodeUse
from wf_core import END, NodeUse, RunStatus
from wf_mcp.broker import WfMcpService
from wf_mcp.broker.service.source_catalog import SourceCatalogService
from wf_mcp.broker.service.specs import qualify_spec
@@ -12,7 +12,7 @@ from wf_mcp.storage import FileStore
from wf_platform import CapabilityBuckets, CapabilitySource, SourceVisibility
from ..test_support import echo_tool, local_temp_root
from .conftest import single_echo_plan
from .conftest import raw_plan, single_echo_plan
def _unused_tool_executor(connection: ConnectionConfig):
@@ -133,3 +133,44 @@ def test_workflow_runtime_service_runs_plan_and_emits_events() -> None:
"workflow_run_completed",
]
assert events[1].payload["status"] == "completed"
def test_workflow_runtime_service_emits_failed_event_for_failed_run() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "runtime_failed_event"))
run = asyncio.run(
service.workflow_runtime.run_workflow_from_plan(
raw_plan(
name="runtime_failed_event",
input_schema={"type": "object", "properties": {}},
state_schema={"type": "object", "properties": {}},
output_schema={"type": "object", "properties": {}},
start="fail",
nodes=[
{
"id": "fail",
"type": "node",
"node": "wf.std.runtime_error",
"input": [
{
"value": "boom",
"target": {
"root": "local",
"parts": ["message"],
},
}
],
}
],
edges=[{"from": "fail", "outcome": "ok", "to": END}],
),
{},
)
)
assert run.status == RunStatus.FAILED
assert [event.kind for event in service.list_events()][-2:] == [
"workflow_run_started",
"workflow_run_failed",
]
assert service.list_events()[-1].payload["status"] == "failed"
+41 -1
View File
@@ -1,6 +1,9 @@
from __future__ import annotations
from wf_mcp.models import AuthRecord
import pytest
from wf_mcp.connections import parse_connection_id
from wf_mcp.models import AuthRecord, CatalogSnapshot
from wf_mcp.storage import FileStore
from .test_support import local_temp_root
@@ -18,3 +21,40 @@ def test_file_store_round_trips_auth() -> None:
loaded = store.load_auth("demo.personal")
assert loaded == record
def test_parse_connection_id_rejects_path_traversal() -> None:
for connection_id in ("../personal", "demo/../../personal", ".hidden.personal"):
with pytest.raises(ValueError, match="connection id"):
parse_connection_id(connection_id)
def test_file_store_rejects_auth_connection_id_path_traversal(tmp_path) -> None:
store = FileStore(tmp_path / "store")
record = AuthRecord(
connection_id="../outside",
scheme="oauth",
payload={"token": "secret"},
)
with pytest.raises(ValueError, match="connection id"):
store.save_auth(record)
assert not (tmp_path / "outside.json").exists()
def test_file_store_rejects_catalog_connection_id_path_traversal(tmp_path) -> None:
store = FileStore(tmp_path / "store")
with pytest.raises(ValueError, match="connection id"):
store.load_catalog("../outside")
snapshot = CatalogSnapshot(
connection_id="../outside",
fetched_at_epoch_ms=0,
max_age_seconds=60,
)
with pytest.raises(ValueError, match="connection id"):
store.save_catalog(snapshot)
assert not (tmp_path / "outside.json").exists()