feat(mcp): expose safe federation readback
This commit is contained in:
@@ -3,12 +3,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import json
|
||||
from copy import deepcopy
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
POLICY = "read_only_external_mcp_rag_integration_readback_v1"
|
||||
PUBLIC_FEDERATION_SCHEMA_VERSION = "ewoooc_mcp_federation_receipt_v1"
|
||||
PUBLIC_FEDERATION_POLICY = "public_aggregate_read_only_mcp_federation_v1"
|
||||
TAIPEI_TZ = ZoneInfo("Asia/Taipei")
|
||||
|
||||
_FEDERATED_PRODUCTS = (
|
||||
{
|
||||
"product_id": "ewoooc",
|
||||
"canonical_repo": "wooo/ewoooc",
|
||||
"runtime_role": "mcp_rag_automation_source_plane",
|
||||
},
|
||||
{
|
||||
"product_id": "momo-pro-system",
|
||||
"canonical_repo": "wooo/momo-pro-system",
|
||||
"runtime_role": "commerce_runtime_consumer_plane",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def _enabled(value: str | None) -> bool:
|
||||
@@ -25,6 +44,173 @@ def _controlled_apply_boundary() -> dict[str, bool]:
|
||||
}
|
||||
|
||||
|
||||
def _public_operation_boundaries() -> dict[str, bool]:
|
||||
"""V-New: 公開 receipt 只允許無副作用的聚合狀態讀回。"""
|
||||
return {
|
||||
"read_only_observation_allowed": True,
|
||||
"network_call_allowed": False,
|
||||
"db_write_allowed": False,
|
||||
"secret_read_allowed": False,
|
||||
"external_tool_call_allowed": False,
|
||||
"rag_write_allowed": False,
|
||||
"production_price_write_allowed": False,
|
||||
"request_or_response_body_storage_allowed": False,
|
||||
}
|
||||
|
||||
|
||||
def _safe_mcp_summary(snapshot: dict[str, Any]) -> dict[str, Any]:
|
||||
servers = snapshot.get("servers")
|
||||
servers = servers if isinstance(servers, dict) else {}
|
||||
registry = snapshot.get("tool_registry")
|
||||
registry = registry if isinstance(registry, dict) else {}
|
||||
tool_count = 0
|
||||
for server_map in registry.values():
|
||||
if not isinstance(server_map, dict):
|
||||
continue
|
||||
for tools in server_map.values():
|
||||
if isinstance(tools, (list, tuple, set)):
|
||||
tool_count += len(tools)
|
||||
return {
|
||||
"enabled": snapshot.get("enabled") is True,
|
||||
"server_count": len(servers),
|
||||
"server_ids": sorted(str(server_id) for server_id in servers),
|
||||
"caller_count": int(snapshot.get("caller_count") or 0),
|
||||
"tool_count": tool_count,
|
||||
}
|
||||
|
||||
|
||||
def _safe_rag_summary(snapshot: dict[str, Any]) -> dict[str, Any]:
|
||||
model = str(snapshot.get("embedding_model") or "")
|
||||
return {
|
||||
"enabled": snapshot.get("enabled") is True,
|
||||
"vector_store": str(snapshot.get("vector_store") or "pgvector"),
|
||||
"embedding_model": model,
|
||||
"embedding_dim": int(snapshot.get("embedding_dim") or 0),
|
||||
"embedding_signature": str(snapshot.get("embedding_signature") or ""),
|
||||
"embedding_version_state": (
|
||||
"floating_tag_detected" if model.endswith(":latest") else "explicit_or_unknown"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _safe_pixelrag_summary(snapshot: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"enabled": snapshot.get("enabled") is True,
|
||||
"platform_count": int(snapshot.get("platform_count") or 0),
|
||||
"platforms": sorted(
|
||||
str(platform) for platform in snapshot.get("platforms") or []
|
||||
),
|
||||
"visual_rag_stage": str(
|
||||
snapshot.get("visual_rag_stage") or "unavailable"
|
||||
),
|
||||
"formal_product_write_allowed": False,
|
||||
}
|
||||
|
||||
|
||||
def compute_public_federation_receipt_fingerprint(
|
||||
receipt: dict[str, Any],
|
||||
) -> str:
|
||||
"""Return the verifier-recomputable hash for normalized public fields."""
|
||||
covered = {
|
||||
key: value
|
||||
for key, value in receipt.items()
|
||||
if key not in {"receipt_id", "observed_at", "integrity"}
|
||||
}
|
||||
canonical = json.dumps(
|
||||
covered,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
)
|
||||
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def build_public_mcp_federation_receipt(
|
||||
*,
|
||||
runtime_version: str,
|
||||
observed_at: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Build two product-scoped, aggregate-only MCP/RAG runtime receipts.
|
||||
|
||||
This function performs no network call, database read/write, tool call, or
|
||||
RAG write. Internal endpoint URLs and raw tool registries are deliberately
|
||||
reduced to stable IDs and counts before reaching the public response.
|
||||
"""
|
||||
timestamp = observed_at or datetime.now(TAIPEI_TZ).isoformat(timespec="seconds")
|
||||
mcp = _safe_mcp_summary(_mcp_runtime_snapshot())
|
||||
rag = _safe_rag_summary(_rag_runtime_snapshot())
|
||||
pixelrag = _safe_pixelrag_summary(_pixelrag_snapshot())
|
||||
|
||||
blockers: list[str] = []
|
||||
if not mcp["enabled"]:
|
||||
blockers.append("mcp_router_runtime_not_enabled")
|
||||
if mcp["server_count"] == 0 or mcp["tool_count"] == 0:
|
||||
blockers.append("mcp_runtime_inventory_empty")
|
||||
if not rag["enabled"]:
|
||||
blockers.append("rag_runtime_not_enabled")
|
||||
if not rag["embedding_signature"]:
|
||||
blockers.append("rag_embedding_signature_missing")
|
||||
if rag["embedding_version_state"] == "floating_tag_detected":
|
||||
blockers.append("rag_embedding_model_not_immutable")
|
||||
if not pixelrag["enabled"]:
|
||||
blockers.append("pixelrag_runtime_not_enabled")
|
||||
blockers = sorted(blockers)
|
||||
|
||||
normalized_runtime = {
|
||||
"mcp": mcp,
|
||||
"rag": rag,
|
||||
"pixelrag": pixelrag,
|
||||
}
|
||||
receipts: list[dict[str, Any]] = []
|
||||
for product in _FEDERATED_PRODUCTS:
|
||||
receipt: dict[str, Any] = {
|
||||
"receipt_schema_version": PUBLIC_FEDERATION_SCHEMA_VERSION,
|
||||
"product_id": product["product_id"],
|
||||
"canonical_repo": product["canonical_repo"],
|
||||
"runtime_role": product["runtime_role"],
|
||||
"runtime_version": str(runtime_version or "unknown"),
|
||||
"health_status": "ready" if not blockers else "partial_degraded",
|
||||
"runtime": deepcopy(normalized_runtime),
|
||||
"data_boundaries": {
|
||||
"scope": "aggregate_runtime_metadata_only",
|
||||
"pixelrag": "public_visual_receipts_no_formal_product_write",
|
||||
"rag": "pgvector_internal_only_no_public_content",
|
||||
"mcp": "server_ids_and_counts_only_no_endpoint_or_payload",
|
||||
},
|
||||
"operation_boundaries": _public_operation_boundaries(),
|
||||
"blockers": list(blockers),
|
||||
}
|
||||
fingerprint = compute_public_federation_receipt_fingerprint(receipt)
|
||||
receipt["observed_at"] = timestamp
|
||||
receipt["receipt_id"] = (
|
||||
f"mcp-federation:{product['product_id']}:{fingerprint[:16]}"
|
||||
)
|
||||
receipt["integrity"] = {
|
||||
"algorithm": "sha256",
|
||||
"canonicalization": "json_sort_keys_compact_v1",
|
||||
"excluded_fields": ["receipt_id", "observed_at", "integrity"],
|
||||
"normalized_fingerprint_sha256": fingerprint,
|
||||
}
|
||||
receipts.append(receipt)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"schema_version": PUBLIC_FEDERATION_SCHEMA_VERSION,
|
||||
"policy": PUBLIC_FEDERATION_POLICY,
|
||||
"generated_at": timestamp,
|
||||
"status": "ready" if not blockers else "partial_degraded",
|
||||
"receipt_count": len(receipts),
|
||||
"receipts": receipts,
|
||||
"blockers": blockers,
|
||||
"operation_boundaries": _public_operation_boundaries(),
|
||||
"next_machine_action": (
|
||||
"pin_embedding_model_and_verify_runtime_receipts"
|
||||
if blockers
|
||||
else "continue_scheduled_read_only_federation"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _status_counts(items: list[dict[str, Any]]) -> dict[str, int]:
|
||||
counts: dict[str, int] = {}
|
||||
for item in items:
|
||||
@@ -304,5 +490,9 @@ def build_external_mcp_rag_integration_readback(
|
||||
|
||||
__all__ = [
|
||||
"POLICY",
|
||||
"PUBLIC_FEDERATION_POLICY",
|
||||
"PUBLIC_FEDERATION_SCHEMA_VERSION",
|
||||
"build_external_mcp_rag_integration_readback",
|
||||
"build_public_mcp_federation_receipt",
|
||||
"compute_public_federation_receipt_fingerprint",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user