feat(mcp): add governed cross-product control plane
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled

This commit is contained in:
ogt
2026-07-15 01:25:38 +08:00
parent f5243d99b9
commit 2480513061
16 changed files with 2351 additions and 19 deletions

View File

@@ -0,0 +1,116 @@
from __future__ import annotations
# ruff: noqa: E402
import json
import os
from pathlib import Path
from fastapi import FastAPI
from fastapi.testclient import TestClient
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
from src.api.v1.mcp_control_plane import router
from src.services.mcp_control_plane_service import (
build_mcp_control_plane_overview,
load_mcp_control_plane_catalog,
)
from src.services.product_governance_matrix_readback import (
load_latest_product_governance_matrix_readback,
)
_REPO_ROOT = Path(__file__).resolve().parents[3]
_OPERATIONS_DIR = _REPO_ROOT / "docs" / "operations"
def test_catalog_contains_exact_12_products_and_explicit_missing_rows() -> None:
catalog = load_mcp_control_plane_catalog(_OPERATIONS_DIR)
product_ids = {row["product_id"] for row in catalog["products"]}
assert len(product_ids) == 12
assert {"ewoooc", "momo-pro-system"}.issubset(product_ids)
assert catalog["architecture"]["separate_gateway_allowed"] is False
assert catalog["architecture"]["separate_rag_database_allowed"] is False
assert catalog["source_policy"]["github_allowed"] is False
assert catalog["security_policy"]["external_rag_auto_write_allowed"] is False
capabilities = {
row["capability_id"]: row for row in catalog["capabilities"]
}
assert capabilities["rejected.github"]["decision"] == "rejected"
assert capabilities["quarantine.agent-bounty-mcp"]["decision"] == "quarantine"
assert capabilities["external.smithery-site-audit-shadow"]["decision"] == "evaluation_shadow_candidate"
assert capabilities["external.smithery-site-audit-shadow"]["deployment_allowed"] is False
assert capabilities["rejected.smithery-technical-analysis"]["decision"] == "rejected"
assert "tool_output_contains_cross_tool_prompt_injection" in capabilities[
"quarantine.agent-bounty-mcp"
]["blockers"]
assert not any(
row["deployment_allowed"]
for row in catalog["capabilities"]
if row["source_type"] == "external"
)
def test_overview_joins_committed_product_matrix_without_runtime_claims() -> None:
catalog = load_mcp_control_plane_catalog(_OPERATIONS_DIR)
matrix = load_latest_product_governance_matrix_readback(_OPERATIONS_DIR)
payload = build_mcp_control_plane_overview(
catalog=catalog,
product_matrix=matrix,
generated_at="2026-07-15T19:00:00+08:00",
)
assert payload["schema_version"] == "mcp_control_plane_overview_v1"
assert payload["status"] == "partial_degraded_with_safe_next_action"
assert payload["summary"]["product_count"] == 12
assert payload["summary"]["mcp_source_detected_product_count"] == 7
assert payload["summary"]["external_promotion_ready_count"] == 0
assert payload["summary"]["github_in_scope_count"] == 0
assert payload["runtime"]["status"] == "not_requested"
products = {row["product_id"]: row for row in payload["products"]}
assert products["ewoooc"]["canonical_repo"] == "wooo/ewoooc"
assert products["momo-pro-system"]["canonical_repo"] == "wooo/momo-pro-system"
assert products["agent-bounty-protocol"]["inventory_state"] == "source_detected_quarantined"
def test_catalog_rejects_external_deployment_without_immutable_receipts(
tmp_path: Path,
) -> None:
catalog = load_mcp_control_plane_catalog(_OPERATIONS_DIR)
external = next(
row for row in catalog["capabilities"] if row["source_type"] == "external"
)
external["deployment_allowed"] = True
(tmp_path / "mcp-control-plane-catalog.snapshot.json").write_text(
json.dumps(catalog),
encoding="utf-8",
)
try:
load_mcp_control_plane_catalog(tmp_path)
except ValueError as exc:
assert "cannot deploy without immutable receipts" in str(exc)
else:
raise AssertionError("unsafe external deployment must be rejected")
def test_overview_endpoint_returns_real_committed_catalog_without_runtime() -> None:
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get(
"/api/v1/mcp-control-plane/overview?include_runtime=false"
)
assert response.status_code == 200
data = response.json()
assert data["summary"]["product_count"] == 12
assert data["runtime"]["status"] == "not_requested"
assert data["operation_boundaries"]["github_allowed"] is False
assert data["operation_boundaries"]["public_response_redacted_aggregate_only"] is True
assert data["operation_boundaries"]["mutation_endpoint_exposed"] is False
assert data["operation_boundaries"]["operator_auth_required_for_future_mutation"] is True

View File

@@ -123,3 +123,41 @@ async def test_execute_tool_resolves_provider_by_tool_manifest(
assert parameters["_mcp_audit"]["gateway_path"] == "awooop_mcp_gateway"
assert parameters["_mcp_audit"]["incident_id"] == "INC-GW"
assert parameters["_mcp_audit"]["flywheel_node"] == "sense"
@pytest.mark.asyncio
async def test_execute_tool_redacts_input_and_output_at_gateway_boundary(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class SensitiveProvider(FakeProvider):
async def execute(self, tool_name: str, parameters: dict) -> MCPToolResult:
self.calls.append((tool_name, parameters))
return MCPToolResult(
success=True,
execution_id="provider-redacted",
output={
"connection": "postgresql://reader:plain-password@10.0.1.5/prod"
},
)
provider = SensitiveProvider()
monkeypatch.setattr(
gateway_module,
"get_provider_registry",
lambda: FakeProviderRegistry(provider),
)
result = await McpGateway(FakeDb())._execute_tool(
GatewayContext(
project_id="awoooi",
agent_id="pre_decision_investigator",
tool_name="kubectl_get",
),
SimpleNamespace(tool_name="kubectl_get"),
{"namespace": "awoooi-prod", "api_key_value": "do-not-store"},
)
sent = provider.calls[0][1]
assert sent["api_key_value"] == "[REDACTED:CREDENTIAL_ISOLATION]"
assert "plain-password" not in str(result.output)
assert "10.0.1.5" not in str(result.output)

View File

@@ -8,6 +8,7 @@ from src.plugins.mcp import gateway as gateway_module
from src.plugins.mcp.gateway import (
GateApprovalError,
GateCheckResult,
GateRateLimitError,
GatewayContext,
McpGateway,
)
@@ -24,6 +25,11 @@ class FakeRedis:
async def aclose(self) -> None:
self.closed = True
async def eval(self, _script: str, _keys: int, key: str, _window: int) -> int:
value = int(self.values.get(key, "0")) + 1
self.values[key] = str(value)
return value
@pytest.mark.asyncio
async def test_gate5_uses_shared_redis_pool_without_closing(
@@ -102,3 +108,48 @@ async def test_gate5_read_scope_skips_redis(
assert called is False
assert gate_result.gate5_approval is True
@pytest.mark.asyncio
async def test_gateway_distributed_rate_limit_uses_redis_and_sets_receipt(
monkeypatch: pytest.MonkeyPatch,
) -> None:
redis = FakeRedis()
monkeypatch.setattr(gateway_module, "get_redis", lambda: redis)
gate_result = GateCheckResult()
await McpGateway(db=None)._enforce_distributed_rate_limit(
GatewayContext(
project_id="awoooi",
agent_id="openclaw-sre",
tool_name="k8s_get",
required_scope="read",
),
gate_result,
)
assert gate_result.distributed_rate_limit is True
assert redis.values[
"mcp_rate_limit:awoooi:openclaw-sre:k8s_get:read"
] == "1"
@pytest.mark.asyncio
async def test_gateway_distributed_rate_limit_fails_closed_when_redis_is_down(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def unavailable() -> FakeRedis:
raise RuntimeError("redis unavailable")
monkeypatch.setattr(gateway_module, "get_redis", unavailable)
with pytest.raises(GateRateLimitError):
await McpGateway(db=None)._enforce_distributed_rate_limit(
GatewayContext(
project_id="awoooi",
agent_id="openclaw-sre",
tool_name="k8s_apply",
required_scope="write",
),
GateCheckResult(),
)