feat(mcp): expose safe federation readback
This commit is contained in:
@@ -71,3 +71,102 @@ def test_external_mcp_rag_ai_automation_route_returns_readback():
|
||||
assert payload["success"] is True
|
||||
assert {item["family"] for item in payload["inventory"]} == {"external_mcp"}
|
||||
assert payload["runtime"]["mcp"]["caller_count"] >= 1
|
||||
|
||||
|
||||
def test_public_federation_receipt_preserves_two_product_identities(monkeypatch):
|
||||
from services import external_mcp_rag_integration_service as service
|
||||
|
||||
monkeypatch.setattr(service, "_mcp_runtime_snapshot", lambda: {
|
||||
"enabled": True,
|
||||
"servers": {"firecrawl": "internal", "postgres": "internal"},
|
||||
"caller_count": 2,
|
||||
"tool_registry": {
|
||||
"collector": {"firecrawl": ["scrape_url"]},
|
||||
"diagnostics": {"postgres": ["query"]},
|
||||
},
|
||||
})
|
||||
monkeypatch.setattr(service, "_rag_runtime_snapshot", lambda: {
|
||||
"enabled": True,
|
||||
"vector_store": "pgvector",
|
||||
"embedding_model": "bge-m3:latest",
|
||||
"embedding_dim": 1024,
|
||||
"embedding_signature": "signature-v1",
|
||||
})
|
||||
monkeypatch.setattr(service, "_pixelrag_snapshot", lambda: {
|
||||
"enabled": True,
|
||||
"platform_count": 2,
|
||||
"platforms": ["shopee", "coupang"],
|
||||
"visual_rag_stage": "phase1_visual_evidence_receipts",
|
||||
})
|
||||
|
||||
payload = service.build_public_mcp_federation_receipt(
|
||||
runtime_version="V10.796",
|
||||
observed_at="2026-07-15T10:00:00+08:00",
|
||||
)
|
||||
receipts = {item["product_id"]: item for item in payload["receipts"]}
|
||||
|
||||
assert payload["receipt_count"] == 2
|
||||
assert set(receipts) == {"ewoooc", "momo-pro-system"}
|
||||
assert receipts["ewoooc"]["canonical_repo"] == "wooo/ewoooc"
|
||||
assert receipts["momo-pro-system"]["canonical_repo"] == "wooo/momo-pro-system"
|
||||
assert payload["status"] == "partial_degraded"
|
||||
assert "rag_embedding_model_not_immutable" in payload["blockers"]
|
||||
assert receipts["ewoooc"]["runtime"]["mcp"]["tool_count"] == 2
|
||||
assert receipts["ewoooc"]["operation_boundaries"]["db_write_allowed"] is False
|
||||
assert receipts["ewoooc"]["operation_boundaries"]["secret_read_allowed"] is False
|
||||
for receipt in receipts.values():
|
||||
assert (
|
||||
service.compute_public_federation_receipt_fingerprint(receipt)
|
||||
== receipt["integrity"]["normalized_fingerprint_sha256"]
|
||||
)
|
||||
|
||||
|
||||
def test_public_federation_receipt_does_not_expose_internal_endpoints(monkeypatch):
|
||||
from services import external_mcp_rag_integration_service as service
|
||||
|
||||
monkeypatch.setattr(service, "_mcp_runtime_snapshot", lambda: {
|
||||
"enabled": True,
|
||||
"servers": {"firecrawl": "http://192.168.0.188:3002"},
|
||||
"caller_count": 1,
|
||||
"tool_registry": {"collector": {"firecrawl": ["scrape_url"]}},
|
||||
})
|
||||
payload = service.build_public_mcp_federation_receipt(
|
||||
runtime_version="V10.796",
|
||||
observed_at="2026-07-15T10:00:00+08:00",
|
||||
)
|
||||
serialized = json.dumps(payload, ensure_ascii=False)
|
||||
|
||||
assert "192.168." not in serialized
|
||||
assert "http://" not in serialized
|
||||
assert "https://" not in serialized
|
||||
assert "scrape_url" not in serialized
|
||||
|
||||
|
||||
def test_public_federation_route_is_anonymous_aggregate_only(monkeypatch):
|
||||
from flask import Flask
|
||||
from routes import system_public_routes as routes
|
||||
from services import external_mcp_rag_integration_service as service
|
||||
|
||||
monkeypatch.setattr(service, "build_public_mcp_federation_receipt", lambda **_: {
|
||||
"success": True,
|
||||
"schema_version": service.PUBLIC_FEDERATION_SCHEMA_VERSION,
|
||||
"policy": service.PUBLIC_FEDERATION_POLICY,
|
||||
"status": "ready",
|
||||
"receipt_count": 2,
|
||||
"receipts": [
|
||||
{"product_id": "ewoooc"},
|
||||
{"product_id": "momo-pro-system"},
|
||||
],
|
||||
})
|
||||
app = Flask(__name__)
|
||||
app.register_blueprint(routes.system_public_bp)
|
||||
|
||||
response = app.test_client().get("/api/public/mcp-federation-readback")
|
||||
payload = response.get_json()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert payload["receipt_count"] == 2
|
||||
assert {item["product_id"] for item in payload["receipts"]} == {
|
||||
"ewoooc",
|
||||
"momo-pro-system",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user