feat: add GEWU installer and service contracts
This commit is contained in:
1 parent
254edac2c5
commit
6c9653866c
36 files changed
+8953
-70
No files matched your search
@@ -0,0 +1,115 @@
|
||||
"""Verify or refresh the portable GEWU instruction-pack integrity manifest."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
MANIFEST = ROOT / "manifest.json"
|
||||
|
||||
|
||||
def normalized_bytes(path: Path) -> bytes:
|
||||
text = path.read_text(encoding="utf-8-sig")
|
||||
return text.replace("\r\n", "\n").replace("\r", "\n").encode("utf-8")
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
return hashlib.sha256(normalized_bytes(path)).hexdigest()
|
||||
|
||||
|
||||
def snapshot_digest(modules: list[dict[str, Any]]) -> str:
|
||||
compact = json.dumps(modules, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
||||
return hashlib.sha256(compact.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def load_manifest() -> dict[str, Any]:
|
||||
manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
|
||||
if not isinstance(manifest, dict) or not isinstance(manifest.get("modules"), list):
|
||||
raise ValueError("manifest.json has an invalid structure")
|
||||
return manifest
|
||||
|
||||
|
||||
def module_path(entry: str) -> Path:
|
||||
path = (ROOT / entry).resolve()
|
||||
if path != ROOT and ROOT not in path.parents:
|
||||
raise ValueError(f"module path escapes pack: {entry}")
|
||||
if not path.is_file():
|
||||
raise ValueError(f"module file is missing: {entry}")
|
||||
return path
|
||||
|
||||
|
||||
def verify(manifest: dict[str, Any]) -> None:
|
||||
modules = manifest["modules"]
|
||||
for module in modules:
|
||||
if not isinstance(module, dict) or not isinstance(module.get("entry"), str):
|
||||
raise ValueError("manifest module descriptor is invalid")
|
||||
if module.get("sha256") != sha256(module_path(module["entry"])):
|
||||
raise ValueError(f"module hash mismatch: {module.get('module_id')}")
|
||||
expected_snapshot = manifest.get("snapshot", {}).get("digest")
|
||||
if expected_snapshot != snapshot_digest(modules):
|
||||
raise ValueError("module snapshot digest mismatch")
|
||||
for contract in manifest.get("verified_service_contracts", []):
|
||||
if not isinstance(contract, dict) or not isinstance(contract.get("path"), str):
|
||||
raise ValueError("service contract descriptor is invalid")
|
||||
contract_path = module_path(contract["path"])
|
||||
if contract.get("sha256") != sha256(contract_path):
|
||||
raise ValueError(f"service contract hash mismatch: {contract.get('contract_id')}")
|
||||
service_contract = json.loads(contract_path.read_text(encoding="utf-8"))
|
||||
catalog_path = module_path(str(contract_path.parent / "catalog-v1.json"))
|
||||
catalog = json.loads(catalog_path.read_text(encoding="utf-8"))
|
||||
if service_contract.get("catalog_sha256") != sha256(catalog_path):
|
||||
raise ValueError("bundled service catalog hash mismatch")
|
||||
catalog_capabilities = {
|
||||
operation["capability"]
|
||||
for operation in catalog.get("operations", [])
|
||||
if "mcp" in operation.get("transports", [])
|
||||
}
|
||||
tool_names = {tool.get("name") for tool in service_contract.get("tools", [])}
|
||||
catalog_tool_names = {
|
||||
operation["name"]
|
||||
for operation in catalog.get("operations", [])
|
||||
if "mcp" in operation.get("transports", [])
|
||||
}
|
||||
if tool_names != catalog_tool_names:
|
||||
raise ValueError("MCP tool snapshot differs from the bundled catalog")
|
||||
for module in modules:
|
||||
required = module.get("required_service_capabilities", [])
|
||||
if not isinstance(required, list) or not set(required).issubset(catalog_capabilities):
|
||||
raise ValueError(
|
||||
f"service capability is not in the pinned catalog: {module.get('module_id')}"
|
||||
)
|
||||
for schema in service_contract.get("record_schemas", []):
|
||||
schema_path = module_path(str(contract_path.parent / schema["path"]))
|
||||
if schema.get("sha256") != sha256(schema_path):
|
||||
raise ValueError(f"bundled record schema hash mismatch: {schema.get('path')}")
|
||||
|
||||
|
||||
def refresh(manifest: dict[str, Any]) -> None:
|
||||
modules = manifest["modules"]
|
||||
for module in modules:
|
||||
if not isinstance(module, dict) or not isinstance(module.get("entry"), str):
|
||||
raise ValueError("manifest module descriptor is invalid")
|
||||
module["sha256"] = sha256(module_path(module["entry"]))
|
||||
module["hash_encoding"] = "utf8-no-bom-lf"
|
||||
manifest.setdefault("snapshot", {})["digest"] = snapshot_digest(modules)
|
||||
for contract in manifest.get("verified_service_contracts", []):
|
||||
contract["sha256"] = sha256(module_path(contract["path"]))
|
||||
MANIFEST.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) != 2 or sys.argv[1] not in {"refresh", "verify"}:
|
||||
raise SystemExit("usage: python scripts/manifest_tool.py refresh|verify")
|
||||
manifest = load_manifest()
|
||||
if sys.argv[1] == "refresh":
|
||||
refresh(manifest)
|
||||
manifest = load_manifest()
|
||||
verify(manifest)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user