M13: harden MCP trust boundary

This commit is contained in:
NuklearRabbit
2026-08-10 03:24:17 +02:00
parent 15bdbe40ac
commit 218599af7d
6 changed files with 115 additions and 23 deletions
+2 -2
View File
@@ -75,7 +75,7 @@ def test_demo_reset_preserves_integration_telemetry(ops_client, client):
"/api/v1/integrations/mcp/operations-summary",
headers={
"X-Service-Token": settings.mcp_hub_service_token,
"X-Client-Id": "reset-probe",
"X-Client-Id": "itworx-mcp-hub:mobilityops:reset-probe",
},
)
assert probe.status_code == 200
@@ -83,4 +83,4 @@ def test_demo_reset_preserves_integration_telemetry(ops_client, client):
assert client.post("/api/v1/demo/login", json={"role": "operations_manager"}).status_code == 200
events = client.get("/api/v1/audit", params={"action": "mcp_tool_request"}).json()
assert any(event["actor_label"] == "reset-probe" for event in events)
assert any(event["actor_label"].endswith(":reset-probe") for event in events)
+23 -2
View File
@@ -5,7 +5,7 @@ def _headers(token: str | None = None, client_id: str = "test-mcp-client"):
settings = get_settings()
return {
"X-Service-Token": token if token is not None else settings.mcp_hub_service_token,
"X-Client-Id": client_id,
"X-Client-Id": f"itworx-mcp-hub:mobilityops:{client_id}",
}
@@ -16,12 +16,31 @@ def test_operations_summary_requires_service_token(client):
assert response.status_code == 401
def test_operations_summary_rejects_spoofed_client_identity(client):
settings = get_settings()
response = client.get(
"/api/v1/integrations/mcp/operations-summary",
headers={"X-Service-Token": settings.mcp_hub_service_token, "X-Client-Id": "spoofed"},
)
assert response.status_code == 403
def test_operations_summary_rejects_cross_tenant_request(client):
response = client.get(
"/api/v1/integrations/mcp/operations-summary",
headers={**_headers(), "X-Tenant-Id": "another-tenant"},
)
assert response.status_code == 403
def test_operations_summary_returns_metrics(client):
response = client.get("/api/v1/integrations/mcp/operations-summary", headers=_headers())
assert response.status_code == 200
body = response.json()
assert "metrics" in body
assert body["metrics"]["available"] >= 0
assert response.headers["x-correlation-id"]
assert response.headers["x-tenant-id"] == get_settings().ragcore_tenant
def test_attention_vehicles_filters_by_severity(client):
@@ -72,6 +91,8 @@ def test_search_knowledge_grounded_and_respects_max_sources(client):
body = response.json()
assert body["evidence_state"] == "grounded"
assert len(body["sources"]) == 1
assert int(response.headers["x-sources-available"]) >= 1
assert response.headers["x-sources-returned"] == "1"
def test_mcp_tool_requests_are_audited(client, ops_client):
@@ -118,7 +139,7 @@ def test_operations_summary_mints_correlation_id_when_none_supplied(client, ops_
)
assert response.status_code == 200
events = ops_client.get("/api/v1/audit", params={"action": "mcp_tool_request"}).json()
matching = [e for e in events if e["actor_label"] == "no-correlation-probe"]
matching = [e for e in events if e["actor_label"].endswith(":no-correlation-probe")]
assert len(matching) >= 1
assert matching[0]["correlation_id"] # a fresh UUID was minted, not left empty