Publish curated Unraid-AppOps-Gateway source from 28831bd43867347a132f1c2b0f388632b9cb561e
This commit is contained in:
1 parent
41fd48f0bc
commit
2d50064a8f
4 files changed
+92
-7
No files matched your search
@@ -6,6 +6,7 @@ import json
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
from pydantic import StrictBool
|
||||
from fastapi.testclient import TestClient
|
||||
from mcp import Client
|
||||
from sqlmodel import Session, SQLModel, create_engine, select
|
||||
@@ -1410,3 +1411,74 @@ def test_mcp_typed_schema_rejection_never_echoes_opaque_input(
|
||||
|
||||
asyncio.run(exercise())
|
||||
assert mcp_server._MCP_EXECUTION_LOCK.locked() is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("name", "argument", "shape"), [
|
||||
(name, argument, shape)
|
||||
for name, argument in [
|
||||
("enrollment.preflight", "plan"),
|
||||
("target.enroll", "plan"),
|
||||
("deployment.preflight", "plan"),
|
||||
("deployment.apply", "plan"),
|
||||
("deployment.rollback", "plan"),
|
||||
("forge.bootstrap.apply", "profile"),
|
||||
]
|
||||
for shape in ["string", "list", "idempotency"]
|
||||
if shape != "idempotency" or name != "enrollment.preflight"
|
||||
])
|
||||
def test_mcp_sdk_argument_rejection_never_echoes_input_or_logs(
|
||||
integration_client, monkeypatch, caplog, name, argument, shape,
|
||||
):
|
||||
from backend.app import mcp_server
|
||||
canary = "syntheticSdkOpaqueInput_6Q8XZ"
|
||||
arguments = {argument: [canary] if shape == "list" else canary}
|
||||
if shape == "idempotency":
|
||||
arguments = {argument: {}, "idempotencyKey": [canary]}
|
||||
elif name != "enrollment.preflight":
|
||||
arguments["idempotencyKey"] = "schema-redaction-fixture"
|
||||
|
||||
def forbidden_service(*_args, **_kwargs):
|
||||
pytest.fail("invalid SDK arguments must not reach execution services")
|
||||
|
||||
monkeypatch.setattr(mcp_server, "EnrollmentPlane", forbidden_service)
|
||||
monkeypatch.setattr(mcp_server, "DeploymentControlPlane", forbidden_service)
|
||||
caplog.set_level("INFO")
|
||||
|
||||
async def exercise():
|
||||
async with Client(mcp_server.appops_mcp) as client:
|
||||
result = await client.call_tool(name, arguments)
|
||||
assert result.is_error is True
|
||||
assert [item.text for item in result.content] == ["invalid_tool_arguments"]
|
||||
assert canary not in json.dumps(result.model_dump(mode="json"))
|
||||
|
||||
asyncio.run(exercise())
|
||||
assert canary not in caplog.text
|
||||
assert mcp_server._MCP_EXECUTION_LOCK.locked() is False
|
||||
|
||||
|
||||
def test_mcp_sdk_redaction_preserves_schema_valid_calls_and_domain_denials():
|
||||
from backend.app.mcp_server import _InputRedactingMCPServer
|
||||
from mcp.server.mcpserver.exceptions import ToolError
|
||||
|
||||
server = _InputRedactingMCPServer("redaction-compatibility-fixture")
|
||||
calls = []
|
||||
|
||||
@server.tool(name="governed.fixture")
|
||||
def governed(allowed: StrictBool) -> dict[str, str]:
|
||||
calls.append(allowed)
|
||||
if not allowed:
|
||||
raise ToolError("policy_denied")
|
||||
return {"status": "allowed"}
|
||||
|
||||
async def exercise():
|
||||
async with Client(server) as client:
|
||||
listing = await client.list_tools()
|
||||
assert listing.tools[0].input_schema["properties"]["allowed"]["type"] == "boolean"
|
||||
accepted = await client.call_tool("governed.fixture", {"allowed": True})
|
||||
assert accepted.is_error is False
|
||||
assert accepted.structured_content == {"status": "allowed"}
|
||||
denied = await client.call_tool("governed.fixture", {"allowed": False})
|
||||
assert denied.is_error is True
|
||||
assert "policy_denied" in denied.content[0].text
|
||||
asyncio.run(exercise())
|
||||
assert calls == [True, False]
|
||||
Reference in new issue
Block a user