diff --git a/.github/workflows/examples-ci.yml b/.github/workflows/examples-ci.yml index 3e3f90e8..310e6f14 100644 --- a/.github/workflows/examples-ci.yml +++ b/.github/workflows/examples-ci.yml @@ -103,7 +103,7 @@ jobs: with: python-version: "3.11" cache: "pip" - cache-dependency-path: examples/industrial-embodied-ai/requirements.txt + cache-dependency-path: examples/industrial-embodied-ai/requirements-presenter.txt - name: Install controller test dependencies run: python -m pip install --require-hashes -r ../requirements/controller-tests.txt @@ -113,12 +113,16 @@ jobs: - name: Install artifact validation dependencies if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository - run: python -m pip install -r requirements.txt + run: python -m pip install --require-hashes -r requirements-presenter.txt - name: Verify committed evidence artifacts if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository run: python validate_artifacts.py + - name: Rehearse the presenter demo and verify saved evidence offline + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository + run: python -m unittest discover -s tests -p 'live_*.py' -v + healthcare: runs-on: ubuntu-latest defaults: diff --git a/examples/industrial-embodied-ai/.gitignore b/examples/industrial-embodied-ai/.gitignore index 652dd802..2e46a5ba 100644 --- a/examples/industrial-embodied-ai/.gitignore +++ b/examples/industrial-embodied-ai/.gitignore @@ -3,3 +3,4 @@ __pycache__/ .venv/ audit.db trace-output/latest-*.json +trace-output/presenter-*/ diff --git a/examples/industrial-embodied-ai/PRESENTING.md b/examples/industrial-embodied-ai/PRESENTING.md new file mode 100644 index 00000000..d317bdfa --- /dev/null +++ b/examples/industrial-embodied-ai/PRESENTING.md @@ -0,0 +1,133 @@ +# Present the workflow-authority demo + +Message: a motion can be inside the controller's safety envelope and still be +outside the agent's authorized task. cMCP checks workflow scope before forwarding +the motion. The same request under the declared workflow is allowed, and the +resulting signed records can be checked after the services stop. + +Use one terminal with a large font. No frontend, dashboard, slide, or robot +animation is required. This is an AgenTrust cMCP demonstration; it does not run +Agent Governance Toolkit. Both the agent's requests and robot cell are +simulated, while the MCP gateway, Cedar policy evaluation, signatures, and +evidence verifier run locally against released packages. + +## Reproduce from a clean checkout + +Use Python 3.11 and Git on macOS or Linux. Install dependencies before the talk; +the walkthrough itself needs only local loopback networking, with ports 8080 +and 8443 free. No model API key, cloud account, robot hardware, or internet +connection is needed after installation. + +```bash +git clone https://github.com/agentrust-io/integrations.git +cd integrations/examples/industrial-embodied-ai +python3.11 -m venv .venv +source .venv/bin/activate +python -m pip install --require-hashes -r requirements-presenter.txt +python present.py --auto +python present.py +``` + +`--auto` rehearses all six steps without pauses. The interactive command waits +for Enter five times. Each run creates a fresh session, audit database, and +directory under `trace-output/presenter--/`. To choose a +location, pass `--output-dir /path/to/a/new-run`. The directory must not exist; +previous evidence is never overwritten. + +The launcher validates the committed example artifacts before starting the +services, checks readiness, and keeps service output in that run's log files. +It uses an ephemeral local bearer token and explicitly selects software-only +development mode. It stops only its own child processes, including on Ctrl+C, +closed input, startup failure, or a failed check. An occupied port causes a +failure without stopping its owner. Stop a previous manual instance yourself +before retrying; the example's catalog intentionally fixes the controller port. + +## Three-minute script + +Start the command and wait for **1/6 MISSION** before beginning the timed demo. +Treat these as speaking cues rather than text to read verbatim. + +| Time | Presenter action | What the audience sees and hears | +| --- | --- | --- | +| 0:00-0:20 | Show the mission. | "Move material to this station at 0.3 m/s. The controller checks the motion. Who checks whether the agent is authorized to do this task?" | +| 0:20-0:55 | Press Enter: undeclared workflow. | **SCOPE DENIED**. A fresh state token, approved target, and in-limit speed accompany the request. cMCP denies the workflow; the controller's measured motion-request counter stays **0 -> 0**. "Motion safety alone does not grant task authority." | +| 0:55-1:25 | Press Enter: declared workflow. | **AUTHORIZED**. The same motion parameters now use `industrial-material-movement`. cMCP allows it; the controller accepts the simulated motion; its counter becomes **0 -> 1**. | +| 1:25-1:45 | Press Enter: close and stop. | **SERVICES STOPPED**. The session closes, evidence is saved, and both demo-owned service processes exit. | +| 1:45-2:15 | Press Enter: offline verification. | **OFFLINE VERIFICATION**. TRACE signature, policy/catalog hashes, freshness, audit chain, and one controller receipt verify from files. Software-only limitations remain visible. | +| 2:15-2:50 | Press Enter: tamper check. | **TAMPER CHECK**. The original verifies; an altered copy of the signed outcome digest is rejected. "We need task authority beyond motion safety, and records we can check later." | + +The pauses happen **before** each state-read and motion pair. The controller's +five-second state-token expiry and replay checks remain active. You can pause +to speak without reusing an old observation. Do not add a pause between a state +read and its motion request. A slow or suspended machine can still exceed the +five-second interval during a pair; that run must fail and be restarted. + +The controller counter measures received `robot.request_motion` calls. State +reads do reach the controller, including before the denied motion. These +diagnostic counters and `observations.json` are local observations, not signed +hardware telemetry. The original three-path agent additionally demonstrates +controller rejection after authorization; see the [main guide](README.md#run-it). + +## Check the saved files independently + +Use the directory printed at the end of the run. For example, if you ran +`python present.py --auto --output-dir /tmp/industrial-demo-run`: + +```bash +python verify_evidence.py /tmp/industrial-demo-run/trust-record.json \ + /tmp/industrial-demo-run/audit-bundle.json +python verify_evidence.py /tmp/industrial-demo-run/trust-record.json \ + /tmp/industrial-demo-run/tampered-audit-bundle.json +``` + +The first command exits 0 and reports `EVIDENCE VERIFIED`; the second exits 1 +and reports `EVIDENCE REJECTED`. The verifier requires a controller receipt and +prints verification success only after all checks pass. It does not contact +the stopped services. Normal attestation freshness checks still apply: an old +record may be rejected even if it was valid at rehearsal time. + +Saved files include the original TRACE record and audit bundle, a separate +tampered bundle, the rejection reason, observed forwarding counts, the generated +runtime configuration and database, and preflight/runtime/controller logs. +Keep the original files together. Avoid publishing unreviewed logs or replacing +the committed teaching fixtures with generated session evidence. + +## Evidence boundaries + +- This demonstrates local workflow authorization and integrity of software + records. A signed simulated outcome is not proof of physical completion. +- The mock controller uses a public, deterministic teaching key. Anyone with + the source can reproduce that key; its signature is not independent + controller identity or hardware provenance. +- Runtime attestation is explicitly software-only. TRACE verification checks + the signing key in the record; this run establishes no hardware root of trust + or independently trusted runtime identity. +- Agent Manifest hashes/signature are checked offline by preflight. The runtime + does not cryptographically bind that manifest to the calling agent session. +- The tamper step changes `external_execution_evidence.evidence_hash`, the + digest of the recorded controller outcome. Verification detects the changed + signed evidence; it does not inspect a real robot or reconstruct motion. + +## Maintainer checks + +```bash +python -m unittest discover -s tests -v +python validate_artifacts.py +python -m unittest discover -s tests -p 'live_*.py' -v +``` + +The live suite runs two fresh sessions, tests both first pauses beyond five +seconds, verifies saved files with socket operations forbidden, rejects altered +claims/bundles, and checks cleanup after interruption and closed input. Run it +serially with ports 8080 and 8443 free. CI runs it on same-repository PRs and +pushes under the existing dependency-install policy; fork PRs still run the +controller and launcher unit tests. + +To refresh the hash lock deliberately with `uv` installed, use: + +```bash +uv pip compile requirements.txt --python-version 3.11 --generate-hashes \ + -o requirements-presenter.txt +``` + +Review package changes and repeat the live suite before committing the lock. diff --git a/examples/industrial-embodied-ai/README.md b/examples/industrial-embodied-ai/README.md index ccfb320d..a764a107 100644 --- a/examples/industrial-embodied-ai/README.md +++ b/examples/industrial-embodied-ai/README.md @@ -25,7 +25,7 @@ to produce durable evidence: 2. **Scope denied, the same motion out of scope:** the agent requests the same in-envelope motion as the authorized path (the same approved zone and in-limit speed, a fresh valid safety token) but under an undeclared workflow. - cMCP denies it on scope before the controller is consulted, so the safety + cMCP denies it on scope before the motion is forwarded, so the safety token is never checked. The only difference from the authorized path is the workflow scope, not the motion or its safety: the trust layer withholds the action because it is outside the agent's declared purpose. @@ -131,20 +131,28 @@ or agent identity. ## Run it +For a single-terminal walkthrough, use the [presenter guide](PRESENTING.md). +It starts and stops its own local services, pauses at five explicit steps, +measures motion forwarding, verifies saved evidence after shutdown, and rejects +an altered copy. It needs no frontend, model API, robot, or cloud account. +The original three-path runner below remains available for the safety-rejection +scenario as well. + Prerequisites: - Python 3.11 or newer - Git -The project is a developer preview. `requirements.txt` pins the TRACE commit -and a cMCP external-evidence PR commit used for this reproducible example -until the summit release stack is available from PyPI. +The project is a developer preview using released PyPI packages. +`requirements.txt` declares supported dependency ranges; +`requirements-presenter.txt` locks the complete Python 3.11 environment with +package hashes for reproducible rehearsals. ```bash cd industrial-embodied-ai python -m venv .venv source .venv/bin/activate -pip install -r requirements.txt +python -m pip install --require-hashes -r requirements-presenter.txt ``` Start the mock controller: diff --git a/examples/industrial-embodied-ai/present.py b/examples/industrial-embodied-ai/present.py new file mode 100644 index 00000000..3a52b627 --- /dev/null +++ b/examples/industrial-embodied-ai/present.py @@ -0,0 +1,347 @@ +#!/usr/bin/env python3 +"""One-terminal, presenter-controlled workflow-authority demonstration.""" + +from __future__ import annotations + +import argparse +import copy +from datetime import datetime, timezone +import json +import os +from pathlib import Path +import secrets +import socket +import subprocess +import sys +import time +from typing import Any + + +BASE = Path(__file__).resolve().parent +GATEWAY = "http://127.0.0.1:8443" +CONTROLLER = "http://127.0.0.1:8080" + + +def require(condition: bool, message: str) -> None: + if not condition: + raise RuntimeError(message) + + +def check_ports() -> None: + for port in (8080, 8443): + with socket.socket() as probe: + # A prior owned run can leave TCP connections in TIME_WAIT. + # Reuse permits a clean restart, never a second listening owner. + probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + probe.bind(("127.0.0.1", port)) + probe.listen() + except OSError as exc: + raise RuntimeError( + f"Port {port} is occupied. Stop its service or use another host. " + "No existing process was stopped." + ) from exc + + +class LocalServices: + """Own only the children started here; never search for or kill by port.""" + + def __init__(self, output: Path, run_id: str): + self.output = output + self.run_id = run_id + self.children: list[subprocess.Popen] = [] + self.token = secrets.token_urlsafe(32) + + def start_child(self, command: list[str], name: str, env: dict[str, str]) -> None: + with (self.output / f"{name}.log").open("wb") as log: + child = subprocess.Popen( + command, + cwd=self.output, + env=env, + stdin=subprocess.DEVNULL, + stdout=log, + stderr=subprocess.STDOUT, + ) + self.children.append(child) + + def check_alive(self) -> None: + require( + all(child.poll() is None for child in self.children), + f"A local service exited. See logs in {self.output}", + ) + + def wait_ready(self, client: Any, url: str, *, controller: bool = False) -> None: + import httpx + + deadline = time.monotonic() + 30 + while time.monotonic() < deadline: + self.check_alive() + try: + response = client.get(url, timeout=1) + except httpx.TransportError: + response = None + if response is not None and response.status_code == 200: + state = response.json() + require(state.get("status") == "ready", "Invalid readiness response") + if controller: + require( + state.get("run_id") == self.run_id, + "Controller belongs to another run", + ) + self.check_alive() + return + time.sleep(0.1) + raise RuntimeError(f"Readiness timed out for {url}. See {self.output}") + + def start(self, client: Any) -> None: + check_ports() + env = dict(os.environ) + # Keep all traffic local, independent of a presenter's corporate proxy. + for key in list(env): + if key.lower() in {"http_proxy", "https_proxy", "all_proxy", "no_proxy"}: + del env[key] + env.update( + CMCP_DEV_MODE="1", + CMCP_BEARER_TOKEN=self.token, + CMCP_OPERATOR_TOKEN=secrets.token_urlsafe(32), + PYTHONUNBUFFERED="1", + ) + hashes = json.loads((BASE / "artifact-hashes.json").read_text()) + env["CMCP_POLICY_HASH"] = hashes["cmcp_policy_bundle_hash"] + env["CMCP_CATALOG_HASH"] = hashes["cmcp_catalog_hash"] + config = { + "attestation": { + "provider": "auto", + "enforcement_mode": "enforcing", + "validity_seconds": 86400, + "staleness_policy": "fail_closed", + }, + "policy_bundle_path": str(BASE / "policy"), + "catalog_path": str(BASE / "catalog.json"), + "listen_addr": "127.0.0.1:8443", + "audit_db_path": str(self.output / "audit.db"), + } + config_path = self.output / "cmcp-config.json" + config_path.write_text(json.dumps(config, indent=2) + "\n") + with (self.output / "preflight.log").open("w") as log: + subprocess.run( + [sys.executable, str(BASE / "validate_artifacts.py")], + cwd=BASE, + env=env, + stdout=log, + stderr=subprocess.STDOUT, + timeout=30, + check=True, + ) + self.start_child( + [ + sys.executable, + str(BASE / "server/mock_robot_controller.py"), + "--run-id", + self.run_id, + ], + "controller", + env, + ) + self.wait_ready(client, f"{CONTROLLER}/health", controller=True) + self.start_child( + [ + sys.executable, + "-c", + "from cmcp_runtime.cli import main; main()", + "start", + "--config", + str(config_path), + ], + "runtime", + env, + ) + self.wait_ready(client, f"{GATEWAY}/readyz") + + def motion_count(self, client: Any) -> int: + self.check_alive() + response = client.get(f"{CONTROLLER}/health") + response.raise_for_status() + state = response.json() + require(state.get("run_id") == self.run_id, "Controller ownership changed") + count = state["motion_requests"] + require(type(count) is int and count >= 0, "Invalid motion counter") + return count + + def stop(self) -> None: + for child in reversed(self.children): + if child.poll() is None: + child.terminate() + try: + child.wait(timeout=5) + except subprocess.TimeoutExpired: + child.kill() + child.wait(timeout=5) + + +def pause(auto: bool, next_step: str) -> None: + if not auto: + try: + input(f"\n[Enter] {next_step}: ") + except EOFError as exc: + raise RuntimeError( + "Input closed. Use --auto for an unattended rehearsal." + ) from exc + print(flush=True) + + +def tampered_copy(bundle: dict[str, Any]) -> dict[str, Any]: + altered = copy.deepcopy(bundle) + for entry in altered.get("entries", []): + if entry.get("external_execution_evidence"): + # This field records the signed outcome digest, not a robot video + # or the physical outcome itself. Preserve every original file. + entry["external_execution_evidence"]["evidence_hash"] = "sha256:" + "0" * 64 + return altered + raise RuntimeError("Cannot demonstrate tampering without a controller receipt") + + +def run(output: Path, *, auto: bool) -> None: + import httpx + from agent.material_movement_agent import _read_state, _request_motion, _save_json + from verify_evidence import verify_files + + output.mkdir(parents=True, exist_ok=False) + print(f"Evidence and logs: {output}", flush=True) + services = LocalServices(output, secrets.token_hex(16)) + claim_path = output / "trust-record.json" + bundle_path = output / "audit-bundle.json" + try: + with httpx.Client( + headers={"Authorization": f"Bearer {services.token}"}, + trust_env=False, + timeout=10, + ) as client: + services.start(client) + print("1/6 MISSION\n Move material to transfer-station-b at 0.3 m/s.") + print(" Declared workflow: industrial-material-movement") + print(" Same motion, two workflow scopes. Live cMCP + Cedar enforcement.") + print(" Simulated agent/controller; software-only development evidence.") + + pause(auto, "Try the undeclared workflow") + before = services.motion_count(client) + # Never pause between observation and motion: the token lasts 5 s. + state = _read_state(client, GATEWAY, 1) + session_id = state["session_id"] + require(bool(session_id), "Runtime did not return a session id") + denied = _request_motion( + client, + GATEWAY, + 2, + state["payload"], + "presenter-move", + workflow_id="unapproved-diagnostics", + ) + require( + not denied["ok"] and denied["status_code"] == 403, + "The undeclared workflow was not denied by cMCP", + ) + after = services.motion_count(client) + require(before == after == 0, "Denied motion reached the controller") + print( + "2/6 SCOPE DENIED\n Same target and in-limit speed; fresh state token." + ) + print(" cMCP: denied (undeclared workflow)") + print(f" Measured motion requests at controller: {before} -> {after}") + print(" Motion safety alone does not grant task authority.") + + pause(auto, "Use the declared workflow") + state = _read_state(client, GATEWAY, 3) + require(state["session_id"] == session_id, "Runtime session changed") + allowed = _request_motion( + client, GATEWAY, 4, state["payload"], "presenter-move" + ) + require(allowed["ok"], f"Declared workflow failed: {allowed}") + require(allowed["session_id"] == session_id, "Runtime session changed") + payload = allowed["payload"] + require( + payload.get("controller_decision") == "accepted" + and payload.get("execution_status") == "completed", + "Controller did not complete the simulated motion", + ) + count = services.motion_count(client) + require(count == after + 1, "Expected exactly one forwarded motion") + print("3/6 AUTHORIZED\n cMCP: allowed (declared workflow)") + print(" Controller: accepted; simulated execution: completed") + print(f" Measured motion requests at controller: {after} -> {count}") + + pause(auto, "Close the session, save evidence, stop services") + close = client.post(f"{GATEWAY}/sessions/{session_id}/close") + close.raise_for_status() + audit = client.get( + f"{GATEWAY}/audit/export", params={"session_id": session_id} + ) + audit.raise_for_status() + _save_json(claim_path, close.json()) + _save_json(bundle_path, audit.json()) + _save_json( + output / "observations.json", + { + "session_id": session_id, + "denied_motion_requests": after - before, + "allowed_motion_requests": count - after, + }, + ) + finally: + services.stop() + print("4/6 SERVICES STOPPED\n Session closed; signed evidence saved.") + print(" Demo-owned runtime and controller processes exited.") + + pause(auto, "Verify the saved evidence offline") + print("5/6 OFFLINE VERIFICATION", flush=True) + print(verify_files(claim_path, bundle_path), end="") + print(" Original evidence: VERIFIED") + + pause(auto, "Alter a copy of the recorded outcome digest") + altered_path = output / "tampered-audit-bundle.json" + _save_json(altered_path, tampered_copy(json.loads(bundle_path.read_text()))) + try: + verify_files(claim_path, altered_path) + except (RuntimeError, ValueError) as exc: + print("6/6 TAMPER CHECK\n Original evidence: VERIFIED") + print(" Altered outcome digest: REJECTED") + (output / "tamper-rejection.txt").write_text(str(exc) + "\n") + else: + raise RuntimeError("Tampered evidence was accepted") + print( + "\nTask authority beyond motion safety, with independently checkable records." + ) + print("Teaching keys only; no hardware provenance or proof of physical completion.") + print(f"Saved run: {output}") + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--auto", action="store_true", help="Run all steps without pauses" + ) + parser.add_argument( + "--output-dir", type=Path, help="New directory for evidence and logs" + ) + args = parser.parse_args() + stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") + output = ( + args.output_dir + or BASE / "trace-output" / f"presenter-{stamp}-{secrets.token_hex(3)}" + ).resolve() + try: + run(output, auto=args.auto) + except KeyboardInterrupt: + print( + f"\nDemo interrupted; owned services stopped. Logs: {output}", + file=sys.stderr, + ) + return 130 + except (RuntimeError, OSError, ValueError, subprocess.SubprocessError) as exc: + print(f"DEMO FAILED: {exc}\nLogs: {output}", file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/industrial-embodied-ai/requirements-presenter.txt b/examples/industrial-embodied-ai/requirements-presenter.txt new file mode 100644 index 00000000..c8a592f8 --- /dev/null +++ b/examples/industrial-embodied-ai/requirements-presenter.txt @@ -0,0 +1,737 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.txt --python-version 3.11 --generate-hashes -o requirements-presenter.txt +agent-manifest==0.15.0 \ + --hash=sha256:62b10c22c0a3b0888a91f944c703d13f567430dcb25c7e4f71568854e4299017 \ + --hash=sha256:e6f33bc7b4a1243fded44154df535c5055e09e9f1603d6e9297482eaa6cfef77 + # via + # -r requirements.txt + # cmcp-runtime +agentrust-trace==0.11.0 \ + --hash=sha256:7de621eaf795449e365d04967a82a551a18d75c99d248b4a0923f6d593bdb09e \ + --hash=sha256:8b76de58ec74fad57417093bf7977fe826ce6ade5859b4d5be8ce3938f9fcb35 + # via cmcp-runtime +annotated-types==0.8.0 \ + --hash=sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7 \ + --hash=sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0 + # via pydantic +anyio==4.15.1 \ + --hash=sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101 \ + --hash=sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94 + # via + # cmcp-runtime + # httpx + # starlette +attrs==26.1.0 \ + --hash=sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 \ + --hash=sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32 + # via + # jsonschema + # referencing +cbor2==6.1.5 \ + --hash=sha256:015ed73f10e1f7b67306d41e36e0d7dc40e4a2100bc5c29b7a7f039ad3dc9061 \ + --hash=sha256:040cf628af473fe18cb6f56bdac556d2398102e56852aab5206fbeb3dbde6b52 \ + --hash=sha256:0529a95c1330c9c381286650dd65ff5b4ef136dcee06474ad30c028b5ae99a50 \ + --hash=sha256:09eeb76177758a0fdf1627a9428b384756872b048c6c0d7d158106b29b207d2c \ + --hash=sha256:0b1fa210f23b1f822ee0c9157c99b0e851fce93c6da1dc8441aa7fb3c4089d70 \ + --hash=sha256:0c1565bcd74a389b581e292592ccab0ed9c46286c6e986256820bc68c9ad7e8c \ + --hash=sha256:0fa113902a302c22429b32e2454251a8fd14b18204fdff647c869a54114c3ed1 \ + --hash=sha256:10d5237100190133d6a770181a63d93752cb67a2849c18484d196b5f8880784e \ + --hash=sha256:151f624186a6b607d14074dfffe7b601f403445ab430554e3d920390c3068b05 \ + --hash=sha256:1538e87b4b32764bc4940a37b6aa72e3bc6855033aac18d392d70daa89113a2b \ + --hash=sha256:1ebbc6e2d5ea8acf44cc2247d48ca4ccae724fcdb97eaa673903e2d87f0ffc5d \ + --hash=sha256:2634a4e8dbd86cfbdace0a546a1ded1fb024ebc4fbbeaea0232cc76721e6bc91 \ + --hash=sha256:30f88d1aff6c8c58ffec56591468f820d5ce6aee0bd64ae7443c0d7ef653eaf8 \ + --hash=sha256:40754de6aef3f3d37f2ab36bb431da145359d0e28fce739683f8717ad2e97280 \ + --hash=sha256:4144e2ba881534f62968cdb4a4f134e07a351e75c997d8debca65fcb2edd61c8 \ + --hash=sha256:42217c9de0ead6c5a6c1a6ca6b836204ac46b5bf4f57c758f522f308d7784bf0 \ + --hash=sha256:4c824355799799ab065686a05f65398319109955544db35cc797c60ad208b174 \ + --hash=sha256:4db32eefe9fc173939d114fb78e09f967e69627714ad2e3bca807d0ea9d386ad \ + --hash=sha256:4e298c8a88488ebbf5475e51273b8d80da08f7b47aebfa79eb904fc82da49474 \ + --hash=sha256:519f3f0d0d9467091c678f4a19a31e1b8756c10bbd6294cb3f906092f3da1597 \ + --hash=sha256:547c58e758462f06ba542b0af21afb150ee64c4c81d7ca6d1ecae0655c6a283d \ + --hash=sha256:5a5859d1f82dce094a1bdd6a5b318411b750262070bf5d37fbc9607d185f0b1b \ + --hash=sha256:65a677ff460f5c31f060a4bf8518f3e8184c321fddc0223a5ac2fac59a7f9f30 \ + --hash=sha256:68bcabc5b36a7c7c8825625b7b331a74098a4839d5d38b5cc29cb30a7acfee49 \ + --hash=sha256:694f75fdcdb8c6b9a71ab77f789f56be1deab20bbdbf948d5ff53cd7c2543dfc \ + --hash=sha256:6eb06160c42315ac0c4ded461c7d84d92fa18c69d13d17fc1dfc1fae96580c95 \ + --hash=sha256:6f340682e2481ab729c399f8b81147476c5a179cfef65d02402702aeb9429088 \ + --hash=sha256:73b97d92ce64a344015909f1888de0abec76211b9c1f33b075563a05512f3a98 \ + --hash=sha256:773ef85feea8beb5666a525e88197e3ef1c6629c6b6cf721e31b228c97cf6555 \ + --hash=sha256:789ef813f416d353aecd5c8824860ee4be94e0f1179a385eb2beccfbeb615e4f \ + --hash=sha256:7de5383eb059498291415f5b07f99e54dac4603dc99960eb0e2307c9cb2dc352 \ + --hash=sha256:7dfb68b65d6b0d0d90512626247bfa4993354f1e2b2d83b28b51785e63853422 \ + --hash=sha256:833db11fbea9808b080e5340d5f96615e28a6a6617618a4331e60082d0dc1ca4 \ + --hash=sha256:8665b7970e563fb807cca5c42815fe0741192a899b74bf9052557486a46f9188 \ + --hash=sha256:9140388e9a732f3748641abb91d257d30cc466a7ed13c2c5a3d1aaa6af37bd66 \ + --hash=sha256:9677ce1c3c0cb1fa5a4f721a127fc2cc06e8efc43ee8e5f94e292186d6b51953 \ + --hash=sha256:9907225060f8afcf31b5c97711cd057272160056a6b1b488313cc2b20c0afe74 \ + --hash=sha256:994b09c578e9dd7c5687a9f151f545bde705d12e47427b5a78c9d6cc970187f5 \ + --hash=sha256:9b3ba6f694ec196ebefc9c67ebc862b0fecdd3d6f85d5557378cf20ff8b1fb31 \ + --hash=sha256:a14edbdc9e02d9daa72c3b8805edb297a6025a35e708f7dd8ccbdf1b18adb40f \ + --hash=sha256:a4956f498cbf5eab192e0f838cc787e09bef4caab57f05ccbf00451935cacb8b \ + --hash=sha256:a9a154e010044662ce2e433f7c49e9c0f89ad7b86cb20e5d2e5afe6fd1753162 \ + --hash=sha256:af14089f5fb36f89b3f766acc7d4990cdfba7487ec0249d51bfa3a8caad25f0a \ + --hash=sha256:b586912cdb086dbad12052250acd5922fbe66a341ebee7031039eedf90fe84b1 \ + --hash=sha256:b70d7c47ea84d456034d2be02e89d92eef7044cfcedf6f05058e21d4452f0fef \ + --hash=sha256:b73d982e35a60e602a200feb2a9d272e850efdc9ff767b0f4887bdbc16d23e52 \ + --hash=sha256:bb58549a45e3f6355338345a2df449f42f45d55e4a20af24d4302d76a1578650 \ + --hash=sha256:c87272763122be24213c7bb3d47750a3af034da8755fbd3fcb0694c1efb6c3e8 \ + --hash=sha256:c916d7af4edcbf5dba157e9a8dd927bbf1fd66d3f137618226f7ad8b54bd944a \ + --hash=sha256:cf89dd755e9781bea60bb67c1569d32ca10c38412126ab58bbc0235c697d98fc \ + --hash=sha256:db607ae2b12c7eb85d463fe502a2f50111125bee69e70f85f793f0b7da7896e7 \ + --hash=sha256:dd3e4f08aaf25bca5db6274ac40e4d138b0e09890510c1fda20d5b7840e505fa \ + --hash=sha256:e1028f34af9158ee810c705a1c6c0b7c71f1e0a3c890fb343afd75725a80c191 \ + --hash=sha256:e1e8a6a72c7ab2f82579497cb1d5564987b02559ab980fe6a5f82a7d65031d19 \ + --hash=sha256:e6d54e11887e649345b2ecb491a8e2866f4abdb6d83abc2a1a52d5ee23785ff8 \ + --hash=sha256:eb30032171afc7ab95e524f13eee0c9a79af356b0414fa3a3736b3febca7d641 \ + --hash=sha256:eba54489d82683e8cdb9af80a2e55c2089e439e76b60cdb9fd4dfdc62ecfee3c \ + --hash=sha256:edc4a4dfa313b2cd78d7562cb99b51615e06c89832b78c0c02e2b5c2e27906ae \ + --hash=sha256:f02c339ab9942578b63a5d54c8956191f6e88f3d8b2c918024ff565f7faa1bde \ + --hash=sha256:f0bd6334302a5016a2b0f5530b7aea3ff588b6894523fd8491b49f7ce9e67f11 \ + --hash=sha256:f294e65db28424fe89985faf74648622e04da7977ca5401ac65c7d1b6538d08a \ + --hash=sha256:f850860e43d47312cb962bfdfe1cd879b180a04d0e7352f80e426b3852be8b79 \ + --hash=sha256:f8f85a49db66df77546d278de4d249772a4557d715df07ba8ae155cfa6a7fb31 \ + --hash=sha256:fd34b35b0a2b366f5b4bd53489ccd10d7576b0d4dd68db38ef64b4e617ea8f76 \ + --hash=sha256:fe81e4ff1b6bab72856d020dab89d86d4dcfbe18af4ff3fe2f391e1b03d0793c + # via agent-manifest +cedarpy==4.12.1 \ + --hash=sha256:14630de081249519d76a6c9aca9f677251aa5aa722a056ac4e1f365db392f1ed \ + --hash=sha256:1c765643cc3c1472d85324f42147f3732b1c8dd47f71ff066386e7c8afe109b7 \ + --hash=sha256:2609aaa1e2041599592a821de3741c56b2a778b9c20e87ac97c84a0531120dbd \ + --hash=sha256:28f99b8c3f8faf0cd78a82c2a845360f60f47d54ab8b97ba64e19b04a42e70d5 \ + --hash=sha256:3010ab38bd691387944d57d925aab6b743694a89a1cd3de4295421161bad1609 \ + --hash=sha256:333e89642a5914037bead6ddc16ad4d246d7a27f227856c5636db5524d16e27c \ + --hash=sha256:34316ad5eb18d5ed34beb5b00398b1928f9add67dca6fef7f12f6bf11eb86e8d \ + --hash=sha256:357002b436d06ad00cd24c1dc27287933af9c45af0541b0cd9d52036cccfe8c2 \ + --hash=sha256:35e7446894bf8889e5c04118391b8720afee7dcd2e9d4ebecfa646674301fb96 \ + --hash=sha256:3c216ce8e4e9f8edb03154424dd99611e99533c3fb2f552147f61b0fcde5ac22 \ + --hash=sha256:42e238d25695f92898d4249cd659b67e6d9cde0c3f5ab1403cc642af5e4f5b85 \ + --hash=sha256:46429641712af012e1b2579cc1083eb5ab1ea7df2e7117d94b965cfe515255ba \ + --hash=sha256:547fda0b8f9948634a8b4445a449d4736de4312c11a2133aa5df7deb1d2b99fb \ + --hash=sha256:6f814415d96eed4d724b2ea34f1017217a7022a958307986eb009d5878d482c9 \ + --hash=sha256:7047ff6368a9e52453dbd2ac33f8d7d062a67ff1ee3f3a887f41c0a857f3f6e4 \ + --hash=sha256:74b3d6deb0d482f9645b7709016ab81dc7405be83270b10790b646a60f475518 \ + --hash=sha256:7f71d2285a4cd048866bd66aac36c0cff791554d6755f4230a71987f0b601b71 \ + --hash=sha256:80dca63da4cea16969d023daff31a15665ba54a769f633fb26ac5594b7ffd291 \ + --hash=sha256:832bdcd9586bd9597e52b6adf248adc77c1e2b0c55f3cfc10259feb6627bcd96 \ + --hash=sha256:84aaac429b3cae8b9d496aef9ef99426c130bde390767f46738dea04b7a05714 \ + --hash=sha256:869e4318dbd827aea996fe0b858592866fb7ad1888484b71b5fdd15334eaf8a0 \ + --hash=sha256:91410cbd0027a91a1a3dadf919f1d54bc75a62705247b833a004c5e24add1803 \ + --hash=sha256:9497da64835f431a0acdc6f393a841235bc0657188978238badae2ded3653b02 \ + --hash=sha256:970ecd03259e691d8b947c972b03d3ae34c7dd1d3e9e39d03fbe62dccc03227f \ + --hash=sha256:a935e3ed9e5873f88348469eb917e816335f62387d0f9ebed7058fac76c9a547 \ + --hash=sha256:bbcfb99ef9dc0c155677473d7e5bea8baac6ff2abe27b89a530a7cabb184e3e0 \ + --hash=sha256:c5eea3a4ce98862f1dc06bef1038ae8edf52c74d36980e8e75b59a38168f53ab \ + --hash=sha256:d00d151a1b2bd3697d778fd89597cc16aa1fca11da25594d7a000c725477f151 \ + --hash=sha256:e8ed70991b958f344017663f753f044070cd0e61dfd4ffe408ba05d48c48dea4 \ + --hash=sha256:f164ca11999e1d3a1641548d17755c3c45a5385b2590a642ef3122a1196947ca + # via + # -r requirements.txt + # cmcp-runtime +certifi==2026.7.22 \ + --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \ + --hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55 + # via + # httpcore + # httpx +cffi==2.1.1 \ + --hash=sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e \ + --hash=sha256:06c72bb76605a4b0cd0aad6930b69d4baf7dd5d806cfc409b824191099700e66 \ + --hash=sha256:0beceaabe56af686895136a2de78db54ecd8e4046b236b8fd6d6cb61389e9bf2 \ + --hash=sha256:154852545011f779917b11c78db2358d095da62a9a172b78ad0a583ee5adc0d0 \ + --hash=sha256:194cffa889098ced9976c3fc6340305e43f6303657d298da55366907c05c22d6 \ + --hash=sha256:19ee6127ee34de7d83ce3d371ebc5ed91addbdcc39f9ab15ce4eb35a4e534971 \ + --hash=sha256:1a18a57b58cfb21fc28d72e876acf10eaed67a1ed96226f92af4df681d571c4c \ + --hash=sha256:1aa5645c30469b09530c4ebca77ebf8f17618293c58f8549cb1a543a50236e7d \ + --hash=sha256:1dea0e4d7d4f11f619fe8c1d76caf49e24405b4b5743c0e3be16a500ecd930c9 \ + --hash=sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517 \ + --hash=sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735 \ + --hash=sha256:246fa40ce8645a614ff682e0b70f37134e460eaf93a775e0cbe3cca585a67a80 \ + --hash=sha256:25792eac27877609e7bb06d42ff88278a6624fff2ba9bbb523c09616b117e80f \ + --hash=sha256:27350daa11d4f10c540e6e89dada4c54feb7256ad03e9a4dc075ebad7ba360d1 \ + --hash=sha256:28907ab9bfb6aa13184cfc17c6b8e1023c5ab6fd7076d8c20a35e59fe04f8f29 \ + --hash=sha256:2ae64be792b8966f2c69538199728b290e34726562896df1e5dc8ffd8d8188e8 \ + --hash=sha256:31348097ff5bbe827ccc41795d4dd099d9f0625e7def00ee653c137a490c2a6c \ + --hash=sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e \ + --hash=sha256:3222ba5d678f80a030e6afbcc33dc1ae5cb45facabb61cee2c7016b8432fde48 \ + --hash=sha256:3311ed60d36f83378794e1009ac6258bafbf81f7888b4caa7b35a521e3f95813 \ + --hash=sha256:334644fbac4eff73d985a17a91226df55d0f394160c4cfb880e084c8f7161cac \ + --hash=sha256:34e261f78cb6ceaaa36f42f2613f4380d94d9c759a9c73c769ee6e0247364632 \ + --hash=sha256:363e05fa78e15116c3c32c210ee36884fd6b9afa6d440e47112c3bd511d64cb6 \ + --hash=sha256:398aff33cee2767e3e781d2554c54bd0dff386bb437581e0d8011fde1a942ec1 \ + --hash=sha256:3d22a20b1fb1632cc72c22f95f7b0d2961c3e1c235f245ba4c606c4771035659 \ + --hash=sha256:42a494cee34437f05546455144f2b5d9ac09b1face62bcfce597d2e521066688 \ + --hash=sha256:42e2f76b9455f5a9a844f770bf3e200ed3da0e15f5df3db9c31fe80b04b3d004 \ + --hash=sha256:42f6930c31dc7f50732c9ae793c2786c7b6b044195967bbdde40bb9be81c4cc0 \ + --hash=sha256:456a61fa52d579ebf9df2e9552ead5129855dbaff6c1e5a9b1bc408809bdc062 \ + --hash=sha256:471cee653ae88de62096552e6d24ccb4a5adb8c8c9f10b5054d0122c15bf2779 \ + --hash=sha256:49cbc70e6542d4ccccb936558d1064a8012541e78f821f955cff24e357776c94 \ + --hash=sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50 \ + --hash=sha256:4be96343e422f2dfcd12ab5c9f5aebe03f82f737c6bffeca6830b3875cb44aab \ + --hash=sha256:4f42141fc14250de6dde5ee7ea4432be017252d91f19c5ad043c084cea629cac \ + --hash=sha256:507a24c282e0f42f8ed737cf048572cbf580468da5555764a8331735e9c736b6 \ + --hash=sha256:51b31d1c98274844cfd7838ce00bfc27c7423a4dc00fc0772fc3331c2cc90676 \ + --hash=sha256:58acb8ab8e295e6c5ea12f888cbb13cf21511ef2a3303a23f4325c29d17fe5c1 \ + --hash=sha256:5a59cc1c4442bc3d5c703bf720b51138d0bfc173618807c9ee2490a7541dd3d9 \ + --hash=sha256:5bb4e7ea95dcd6a014a6fef62e62467d67d8e582326443f3d68e71d6320a9fcf \ + --hash=sha256:5c58fe613dc5e5336357eff555824a314d8e43282600435c8d1cb6a7a2fedd13 \ + --hash=sha256:5e7cecbaadb83884793e05828cee59b210b24583b9c7425d0ba6a754fe22eb4e \ + --hash=sha256:616f097f2fe415bc92a247f02e11f634e1f9e9a83d327e3c915c15089c87869e \ + --hash=sha256:63bbfd5ded17c4840ac07cd8f1c21ba9d9708141f840b324f422f41b207e3973 \ + --hash=sha256:64faea20f4e2613363a1a9b9c7dd73058f3ecd00133a511e72ad7c511658f527 \ + --hash=sha256:661c298b4821edebead0c91edd2b00374d67ad7c5a1f7a91d4442633b79d6a72 \ + --hash=sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890 \ + --hash=sha256:6a8dddef476fab96d066d578fc88526767b836ab5ab21754e1d5bf3879c31c7c \ + --hash=sha256:6e192623c49c94421616a5778fba35cf0d5a8d000650c1967ef4448ee5cdd990 \ + --hash=sha256:7225e4514edb64eb6740324353e0da0711954fd8d7da4576755b1c6e09b697cd \ + --hash=sha256:75f80557d1389eddbd0de2681f6a390a0c5338c31ddaa821381c203fc3fd50d9 \ + --hash=sha256:770de9db11e84213beec501cfcaa013b019820ca881e03344dea5844f7876d94 \ + --hash=sha256:7750c6449dff7864bb9bb27ddfb0267756189201a3afc911d82b3caacd70dfc3 \ + --hash=sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80 \ + --hash=sha256:7ce713ace7c0e4520535b42b77eaa742c16dab813978064913e5a3cf82973b41 \ + --hash=sha256:7da0c5eff80f0197f3b3d1232ec5a682a9325f4ae9016a78f5f5ca35f9ced1f5 \ + --hash=sha256:7dbb61fe3a7699468030f71bbe5f8a0e326a151daa91beb11a6fc1f980c55e1c \ + --hash=sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a \ + --hash=sha256:8ef53b2de9bcb9197d31854256575d59dbac0cba72ac627bb291ef5eceb74be4 \ + --hash=sha256:937c0052c05a31ca1daf18de3158eed4dbfcb9cc107adbea227728d647be701e \ + --hash=sha256:9d2055050ea716bd38b7f7f1579c275386646b4894c155a3e2f3cd62ed41b7c6 \ + --hash=sha256:9f8d177621de5cb38ee3e731eda45d421db093ec0739f46a5594babda7987a98 \ + --hash=sha256:a2d7755bef5a12ed488f4ef1f1b69ee9191d7396083b755a5d2295f6edb4768b \ + --hash=sha256:a48d62ab9d6f4f98c983223a547af44be6ca3691074c31cecced6facd3ba2dc1 \ + --hash=sha256:a4f00aa42f75d6e4595e8866e748cc1705adc0cddfeb2ca86d0d03993d63ba03 \ + --hash=sha256:a6e721d4b0e45d5b65e87534470e67b18dcd092c83f68fba09f152b9cbc061af \ + --hash=sha256:a730a083190634c65cca36ba5f489531576ebd79bcd5c8e172130f6453127231 \ + --hash=sha256:a931079504ecc49efed7744c476a5c343a92fabf66dec2db95edb1b2fdc770e2 \ + --hash=sha256:aa9511c62d14da7aacc9b4bf51f3f697a621e83b2d6919008243c3aad168eea3 \ + --hash=sha256:ab36d55f9ed2d067327667c2fea18dda018eb628dd6347aa01dda6cf1f5d3836 \ + --hash=sha256:ad2c86c495b899d862ea0f4b42891b8713a3bd45dd4105c7fd51c2a72f39f3a5 \ + --hash=sha256:aeae0e330c9f6acd681f647d46cefd30c29f93e3392882e792e82080c9691399 \ + --hash=sha256:b0431303acaea1089ad4b3e9ce4e6518193def1118d4073ca848635ee4ea2e96 \ + --hash=sha256:b5bdfd1c873d4e093aabc0ca84c4ca6dbc4f752afb5c86f146d9742580c9da2e \ + --hash=sha256:baed1e86cc735622097354b9d1281406caf42ff42a886d29faa8e8d1630333be \ + --hash=sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf \ + --hash=sha256:c26608d2222fb1e94487e4a387d85f13eb55d5ed725cb25a0c589ac4ee60e7bc \ + --hash=sha256:c7659f22557c5a0bc4855cd635f55edec690cc008a40768527762cb9fb263455 \ + --hash=sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0 \ + --hash=sha256:c8d2c9fd1f2d16f780d15127abb050d13d1a76c03a4bd87d7e4980e45e511e12 \ + --hash=sha256:ca82be1a1d406ecfe1d25dc16cb33488e5a16bf4438c9fb590484ea29d92478b \ + --hash=sha256:cc572dace3f60ef98d7b12ff411d20f5362feb31a0439eab0085bbfd349982d7 \ + --hash=sha256:d18e5ac0f2f03f4f518d3e23db0f0cad7faa1da8620e9c09461d443bbf6e6692 \ + --hash=sha256:d28630f5854ab07ab1fd4aba756de52326c82e6be15d414b12793f1975048b54 \ + --hash=sha256:d9c275eaacd24aa73f94ffd6de08fc3f932424d8b6c376f4bed7cde376fe7bc3 \ + --hash=sha256:da0e573f9f97159390c89d9f1a9e41908b66d408cc5b58d08cf3847d844c531b \ + --hash=sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be \ + --hash=sha256:dddad92b554513a31f272570678ba307fb9f618f05e3d4a5eacafff9eae03e1d \ + --hash=sha256:df423d40ee8654634421812bc3b196da3f9bd7d32929da813f8394c4348a5358 \ + --hash=sha256:df913725b79db7bcf03448f36b7bf8815363417d5b58deecf9305e3e30f0f21a \ + --hash=sha256:e0bcb7e0f677f543555d2adff3bf19c05f66cdb4796e5ff602442ab2fe3c4ef7 \ + --hash=sha256:e2d65b31f36619cda3999b78b2aa9632e76b78448e7a56fc4240824200e7c4fc \ + --hash=sha256:e6e8cff14d6fb0be70a09c0bdc58096f501952d04624ebf867e0e56da2df8960 \ + --hash=sha256:f16c709686a78c727bbbf059f92b0bf41c6fc60deec706d2dc19f529175a6125 \ + --hash=sha256:f24fb43132a4c6b4cb4eb029492919b2db645be6808d738f244fd146c03c32cb \ + --hash=sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a \ + --hash=sha256:f5cfbc5fe74540d335175b656c725d74d90e3730c626d92575eea35029d9afaa \ + --hash=sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf \ + --hash=sha256:f8ec5e643a9a937f64e1999eb9f75d072263751912dc5cd06d3c85f8f44be7c3 \ + --hash=sha256:fb92203a88b3d3053034db775110081c49d28be6551923805e039924093761e4 \ + --hash=sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264 + # via cryptography +click==8.5.0 \ + --hash=sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360 \ + --hash=sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34 + # via + # cmcp-runtime + # uvicorn +cmcp-runtime==0.7.0 \ + --hash=sha256:3728a2ade10b7239b81815b2708900d4cfc6b9110091d58d19e62a93904dd06e \ + --hash=sha256:bdb083ab7925d44c36984de6b788b49d086d70fa8ee8b001dcef92804dcfc1b0 + # via -r requirements.txt +cryptography==50.0.2 \ + --hash=sha256:0ddc924c04591c2811ca024d62ecad4f7f6f08af8939c211438f48a16bd23602 \ + --hash=sha256:0ec5f09541743261e66e291b4a0cbf0fb2997aeaab6d9e9c740b9dba1b58d1c2 \ + --hash=sha256:0ecbc5652bdb6fc9eaf89a7d196e20941adfe812f43bc4ca05d9150496821047 \ + --hash=sha256:1981f1db4630889b9ef7803fadef12b056f428cb6b85c27ba57b774793b6093c \ + --hash=sha256:1ba34f04897fcdaa73f74145c25f3ec146fbd56593853e88adc2e811303c5f42 \ + --hash=sha256:241449bf940a5d27309bd317e6f9a2af6932113818bb2b8f5c59ddc7ef16da18 \ + --hash=sha256:25784ce8b9621c90c643efb9e1e2162ab3b0224cae446ad5e70e7fcb1ce18b51 \ + --hash=sha256:3dc4fd8058cea1644971207d530e1a03a184a805ffc8ebdddf0599d78a331b81 \ + --hash=sha256:4061c0079120205fb760c58acab6443e217307dcf05e3702cf970e0689972856 \ + --hash=sha256:4a20ce1e5cb4284a86692fdcba7cb8754185c6b2e5c56fcef3751cf451d3cdc2 \ + --hash=sha256:4e81d95e5bafc2d6e34e4bed780e53e4d5b9a2f928573428aa4d35fbec1eb0de \ + --hash=sha256:58a0c478eeca76fe5e07993c5a0703def34a6dc6a0cda4f5564639b33112ffe7 \ + --hash=sha256:58ddb5a8e3179d12f19e4ea34d2d32e9d63a4baa142c875c1eb59f41b7243acd \ + --hash=sha256:630ebfea3bf689d075f82316324ff7433dc447fe6bc1bfc76524b74b4a9567d2 \ + --hash=sha256:6f8700550aa1474a91e5dc07049c46f98b423b5b1ddd0483e0b51362eeeaf5be \ + --hash=sha256:78198641e5be9521beea5aa782bb551a58068d10e6eb04c9c680c1b69f2e7d45 \ + --hash=sha256:79def8d059362e7831389ed3be0ecdf58a89386e1271e35dd9f5af84e81bffd0 \ + --hash=sha256:7a8701d6b584d76e909e3d305b7d126b41439876a5aaf76cddc67fc230eafa2e \ + --hash=sha256:7afa5a6602a9f29af1f3a2965f831bae7c9d5d597b7cbb716d41ab3b7d89879c \ + --hash=sha256:7b46165bb56eb4704e2eaaf86f3c940d19154535d9b0ca7d6d590b04060e00d5 \ + --hash=sha256:7b75de3c8b3be1cdb1052747c929440c3eea46c1bc2cb8a6e3a48388e9b7b452 \ + --hash=sha256:7c6d0330c472d96f6a6afe24d80dfdf15176c33096f0a4397ae4c60f3dd3be48 \ + --hash=sha256:828d49b0ff5a0e3975865571c5d91dbbdd0d38d8289b249a163e9425413a5e05 \ + --hash=sha256:84f964e537f916e2cc85199e5a88742e964939b575ac8598b3f9d6cc416cdaf1 \ + --hash=sha256:85d0d9a31b9098e98534226d5686b47264b95e62ce459dc2e62fdfc809f9fe93 \ + --hash=sha256:87e9ce85beb6b328ba370cc6e6aea483c92617b4c95b1d33a49297eb662bfb04 \ + --hash=sha256:8c71ba2cd31fc93748c38e1b613200ff1c2665cbfd5341fe3a61cfde35a1430e \ + --hash=sha256:92e665960f25fcdc73725b9cec7a3824f279ba97a98653afe9ffac2e43668f67 \ + --hash=sha256:94e5e9f108ee10471288214d3d233fbfbb492840a8457eb85178d643ddeb32c7 \ + --hash=sha256:9c8402a82ea0dc4ceeab793db05f0fafa8ca139ca34fcde5df0f596103c74107 \ + --hash=sha256:9dab55f57c74c3cad24c323bacbbd04be4705ba6eb0d92e920b1fc4837ed5079 \ + --hash=sha256:a582ab2ae1d34f67112cadc86702774c9ea4374df6bca6afe672817203c99134 \ + --hash=sha256:a6557e5f38e065ca9fbdaf7cfc7435ecb1d113aa81a022d1b51921ee7432e227 \ + --hash=sha256:a9f7355e6fab51f6c369b86fb7571cffa05edee2c2121e0380a37fb9ac1cd5c1 \ + --hash=sha256:ab50ee449bf968271e820086f10a33d101dd060370abc10bcd22279be2656539 \ + --hash=sha256:ac9ed99d81760c62fe89d5f0815cdfa1ba9a35141cf30f1c2d044f04b4803d2e \ + --hash=sha256:b13478603dcd0a2479ff8e87e2c19a7d525734686fe3c49542472293a204212d \ + --hash=sha256:c423ab384a46c4dff7217b2ea5ba2e11cffdeab6441acd04cf65a369caf0366c \ + --hash=sha256:c5e67125c7dca78d199ec4e116aa93dbb83494808ecbb8211a2cb09b1bf41dbd \ + --hash=sha256:c71be1cbfa5cd9a41ee452acf1eccd82b2c05950358b106ec8ceb83411d1a020 \ + --hash=sha256:cbc8738fd8526d80f35cb3a40d41f41a2e7030bb3b18b09a6778ef63d291c2fd \ + --hash=sha256:ce47f66801c20ec6c6632453bb5960fe38939e9306970b48b3a5a26de7745d94 \ + --hash=sha256:d370b8d1dfcdf7130178137f6fbee6140774a1acc6cacefc4b42643ec11d0a3a \ + --hash=sha256:d38cdff612d06fa6a32840d5e1b1f7a27cee4a349aa9085d94a67789d6bfd408 \ + --hash=sha256:d8947001be83df1394050758ce0e745dd74fb134eef0a4b5124208dfc3a68c37 \ + --hash=sha256:deb9fde5c60e437ee4821bc9bc39ff31b42135c27e1dc61ef0a629389c1de62e \ + --hash=sha256:dfe9763530994147d9af1def057a5b9658b00e8f8fe8743d144d1e0911c2e454 \ + --hash=sha256:e105ab60406787da31fccc883fc0f733af1efd78f0136a4599692c4083a73d0c \ + --hash=sha256:e275096ea1e60cc595cda2836fd4a6c725d1125108b868be17f53684d164e2cc \ + --hash=sha256:edc3342adf8f697fc5f59c887a304356f147b397809440ed64e2fa6af2f50f37 \ + --hash=sha256:ee247f5c245c9a2fe7c8e2214e295918838e44e00a45a6718451e4004219e767 \ + --hash=sha256:eef4c2f3423810b3070ab391f85436d2f8bbfcb286ac15cbc73190b3563b1f1a \ + --hash=sha256:f21e8a22c8605750c7af886bab299a363721264061b4ac0a30efb73cfd58efc5 \ + --hash=sha256:f265528741e048bce55c3463ed721fb0aa45a5888d8add8cfeccb3035451bbdc \ + --hash=sha256:f2f9bd7f90c64fe89253f0a2c05e3c4856072660429ce8831b4235bf29403a67 \ + --hash=sha256:f785f6161f202ab04d8ca194158968798e480ca058943907972da5f12e2881e8 \ + --hash=sha256:f9f6143a8c75945eb960d9eb98905a441394abfa24afaae239d514ffb2586480 \ + --hash=sha256:fa8f5efb344d6908a1ce62f4a24e2e5780f825d6f53f5f50ec5ffacac72936cb \ + --hash=sha256:fdd28f912fccfec1846a94e2e1e8f9b0012f557f0c46fe4f3eb0d7a87afcf90b + # via + # agent-manifest + # agentrust-trace + # cmcp-runtime +h11==0.16.0 \ + --hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \ + --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 + # via + # httpcore + # uvicorn +httpcore==1.0.9 \ + --hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \ + --hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8 + # via httpx +httpx==0.28.1 \ + --hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \ + --hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad + # via + # -r requirements.txt + # cmcp-runtime +idna==3.20 \ + --hash=sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44 \ + --hash=sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c + # via + # anyio + # httpx +jsonschema==4.26.0 \ + --hash=sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326 \ + --hash=sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce + # via agentrust-trace +jsonschema-specifications==2025.9.1 \ + --hash=sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe \ + --hash=sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d + # via jsonschema +pycparser==3.11 \ + --hash=sha256:51d5a8ba2be0bbe440b99d2112604c95bbbc3c2748a64260186c541e1729cd80 \ + --hash=sha256:d875f09c3507d00e1aba0eecc6dcadc1352f30fff09dc6bff2f1c2935e97c2bc + # via cffi +pydantic==2.14.1 \ + --hash=sha256:9195d967ec791692a04438115466764fb8b9a27b31f14a760437694f40d6b454 \ + --hash=sha256:94f478203dd03404682a1ada216965651dd74b1d2d5ffd62e00e0837caab5c26 + # via + # agent-manifest + # agentrust-trace +pydantic-core==2.50.1 \ + --hash=sha256:0036473f5583e6a60e50b8b21651511564277a3f05cc5dab8cf579f552cd5f6c \ + --hash=sha256:0048b6dddc8ef4b64fccaad878bd143b0c3882ea9936279dc11d613f6b7dd1bc \ + --hash=sha256:009634b83993777ddcd69cad0ffcace43dabde692109528e35f0fde91e386a8b \ + --hash=sha256:028e2f212273d4a39b1ec1e0de8166b1165a65fc0f1111452a9d94fc7c625c63 \ + --hash=sha256:062e891facce5ca296a1c37098e5e466780457f86413894b399f0cf22934f769 \ + --hash=sha256:06e01fbbfdb9be777b316a71b6c49efaf4a08b615d0a98d678cda3023f79d019 \ + --hash=sha256:06ead20d39ffd6f2f6f2a8f8a6de67ff8bb1b4f14a8a30e058502514ee2ac685 \ + --hash=sha256:0b3a6f334c6a2345ca15318ff894502a90012536404b37c844a976c76c846e0b \ + --hash=sha256:0c003c3b7f49debb893d2d85ae099ac5959c9839e2f330fadb1fcdf7a6594482 \ + --hash=sha256:131059670f1d2444269b8585cb888963994871932447c08b39ac6a51fcfef658 \ + --hash=sha256:132529c83901437ff642f585216831bf5fd7a91df66829907e155192ead62498 \ + --hash=sha256:17e722e156d0444ecaefbe640bdb60928752bf2013e2b7a11cdb099aaae19bec \ + --hash=sha256:1a9006395dece0e32e704c315eff8a00bede494f6108546cfc5539c89fef4f9a \ + --hash=sha256:1c8632d4ac04e6f91128fca584b3a8a507d81604c24eeaaad00d4be42765c32b \ + --hash=sha256:1c96fd793b73d1b92e65570132505498fe7b21eaef73cdf74e67e5dfba7ac9e4 \ + --hash=sha256:1cf41f1ae3fa155cf167a72689ad044bcc1e3c97e064123677149bdfb5dafc4a \ + --hash=sha256:1deeacb112d14d3f4fcb16b165f7dbaf76c70ba6e82f37ba042bdab51970a0b8 \ + --hash=sha256:1ef800dd7d85bcdadf4c3076e4c94e43939493558a3b69a1ea830c706d4617bb \ + --hash=sha256:1fa4c8bc12c1354c5550c0c35c1852c8c1901e89e06561724e03f8d0342e1f87 \ + --hash=sha256:2005207aafe1231315718bf6ed5d064a7300fb4772754af35ee72fc68159492e \ + --hash=sha256:23923ab9292c40da026330b1ecf4dc2618c8e86e0422e5d1fbf50d94d64ca4f8 \ + --hash=sha256:23edad659e8dbd8ca7e4e877fe6c81573abbdf215bd25a68b53e1272f58b80c7 \ + --hash=sha256:2ab756b72bd5054e4c7ef3ded331b35786cbd3cf931531a508f79a9537517064 \ + --hash=sha256:2cbd1b75b09e976ed0d6b6ca297675632ca35df86130088457cdc60ef36970ae \ + --hash=sha256:2cf91809d0721ab81592ba67bea7694821679c10b1a2e3c3460082b286c1918a \ + --hash=sha256:2df1ff41884de2bc4b307bafd7c40a691094fad2ff8e767e5b45a319257bcf4e \ + --hash=sha256:2eb75304506894a281d346220a4f7481a1b8729577c5ed2a05395991966a8396 \ + --hash=sha256:2eedf82ee4753cdab8e50044c6bd569577eebc3859b11fecf4eb9223761ff966 \ + --hash=sha256:30ddf019d082c117b5d309e5b86710c2a78909907ec1a9381feec3eec02eca0b \ + --hash=sha256:325c23f3e35cfbf0fe3486fa5f7260d1e45885173002d30a28ca019994124255 \ + --hash=sha256:32fad3a91e51b6d2039c572db04a5a873260b399f6bd62c3552671fa7a4a2899 \ + --hash=sha256:36c426eac0af8d1529ff8467e612b933346caec1fdc0d774f78f67a1a11e16c1 \ + --hash=sha256:3a5fce22f1e87d181e924e12da7d81cfe031fb3881a5ddf26ad28f141756ca43 \ + --hash=sha256:3aa9de446b793de2beb6fa2d9d0961803126c4e2a99c2f25ab59b9fd6ea125c0 \ + --hash=sha256:3e46a9eb0a0901dd6275e6b06ac3a464885ef350ec4121fe486869de8053e4bb \ + --hash=sha256:3fde4fdc6487a58d944ca87cf5adc95d5f266e872c19599f5f4c0a8a1b1f9f9f \ + --hash=sha256:409e0ea40ec30d9158f33574fd758e689f6045a0f2596701828c27816ca9687d \ + --hash=sha256:40f523349960fa30f3ea51404308ff50f9997a90df639590f47a057c1f32b415 \ + --hash=sha256:41bc8237121bd8dc8d888dfd6279fc166ffc88c1f1bf3a8bf00869680533ca4c \ + --hash=sha256:42b54c2c90ad348b5e3a85e03e715d572c1fde357ef104cdfe3b03b697a404ea \ + --hash=sha256:455a773617b5913bf5c20d0692e5787b119e52c4d40ea644ca31f5758fd31be2 \ + --hash=sha256:45b11cac094aa25725581d9304eee93c9028516b9ea80dd9e175e13a5a2c840e \ + --hash=sha256:45c6266d071c241f2a168d45bf8c54344f0effce35e7e6b73afdec11f3687568 \ + --hash=sha256:46b3301d3b5c886f77de7546e47274a5842c622ea2020b8c6524c6b66913b4a6 \ + --hash=sha256:476f6ed8e43cd1e0b460920e23571700872b284e77331cb30c4faf459cf48a4b \ + --hash=sha256:48569b0ade9edfbe065cad1d700175546592aebbb42f02adcebcc26e75b896fe \ + --hash=sha256:49c2cbb2397fe4d0987e84606e691af6cb87bc0ee1bd3e7b737f7e10b4c142f9 \ + --hash=sha256:4a53d13cdfbedbfa87f08b83c1a0a5efcc767d785a4b41934fa9cb672670493a \ + --hash=sha256:4be846f55c9477f5f3ddde8f2ce941137e16862a56d018ed885d422bb6ae02f2 \ + --hash=sha256:4df197990c15b5a37c5a277d131d9f2c67de6133f2e5dafd80d9bba4b99f46f9 \ + --hash=sha256:4e834f6a8e4ff772dcc34f58ef5504147a3ea5b0f4eeb13b0f8eb2ca75ac57f1 \ + --hash=sha256:57f51b31ff826e2859120cf4737c5a758a48d96f3e97da40ccee1796d58078ff \ + --hash=sha256:5958c72adb417c39b12ac87525ac60b0d73315fcdc59e21f44ee4a5e2512c9ef \ + --hash=sha256:5dfe41f232befddb9c4377f6cfc702b51595e2d78ed082672adf8758d2c4619f \ + --hash=sha256:5f3cae32fc46121f787cb2486de9cf95a8bf72aec5cc78f64c606fa1735a6ef5 \ + --hash=sha256:64f6047f62a6c5ae08d0a6afb035667aa2d97c3d20d69762e034c5ea144d92a5 \ + --hash=sha256:6a733778df2f7087ec1100ed0b41533e4f3001976e99570fa34f57c66e7f8e3e \ + --hash=sha256:6b20a4bffabdad0db2927ac034ae3b8a681b1f7a0182f3e60b479ad2fde21ebb \ + --hash=sha256:6dbcbee53bf17196a7f745aa9bf5a9603953a1e365b1f020be3207c676a3e7c4 \ + --hash=sha256:6ed4f3cef55164b026fefb41341b7754cc6b624c75dfe7142d2ecceb5ad21c87 \ + --hash=sha256:704075d10b74f2f3c6e15407c696d88701df35fc8953f434a431add0d0074db0 \ + --hash=sha256:739dc730e6be3bd5ec2f4ab5cfc7eb047cc45fc1497b3bafec74ff2ed07df597 \ + --hash=sha256:7456d699b13954e9c0164dcb267250a10ae0dfb03e6e26d6796ab0d46e189c84 \ + --hash=sha256:756d669f04e62ec4148ecfe22be6a4484d9b1181a6ef32e205ebfd200540858b \ + --hash=sha256:7689580e72a642ab5ec64d5f55b2e33636fa43b4ebe63c0c2c965ef307c7d1aa \ + --hash=sha256:76e2e83fa6ec8cdc972d438dafc2522b3a47bee4ec0ae668b29cfb1977ab5242 \ + --hash=sha256:7816e98acc08119dc0f340ab167048ecc54126316330c1f0caf7c6756c88e28f \ + --hash=sha256:79490e33c4c0fcb933bbbcfc3a62184d8803b99f535863dfbb925e1bcb6945ad \ + --hash=sha256:7f476456ac2bb0d937f75191494a09c83a30765fea4f70f3b404942fe25f6cdf \ + --hash=sha256:844b869f118e22a41a091bdcedda8a71bc1b0f62c38d1a0c3211cece47e1d8fc \ + --hash=sha256:84bc765b282a9d5b7fe0348b8648904f25a6a04b2139da52b1dd30c8ac3a2c8f \ + --hash=sha256:84f34323a61a365b4e9295de6028474754829aaddd59c7bf1a040e7487ef8f3c \ + --hash=sha256:8812592c85d0edf423f10eadcef42716d71e8219085ad9e85b775057b7306133 \ + --hash=sha256:88e492e8b9d0312e7dc13667c30222abf284dc3b79b5302b3607b41a5784ce61 \ + --hash=sha256:8a6791afa2245e6c6b180122d105941644f5bd410bb18623b408808cc41a3102 \ + --hash=sha256:8b4c3df25bd323bf1d36a648d563cf1fc69d717451569927151bdad7cad07a77 \ + --hash=sha256:8daa7ee75245d43ad7d747e5c9ecc1b1d06552f72b14887e9276f787d57375f4 \ + --hash=sha256:93ba4e9d8210d941c200431a56b2c0400b131865947903937ed3ec5404307d2e \ + --hash=sha256:94845ff54dc5193f228cab81b2662a04bfbb892e95bdc15edf7399000ce57d54 \ + --hash=sha256:94be440c03fede26969a5ce75468e0e6a9927a1b46d9b679ee8adc1b057b0350 \ + --hash=sha256:9572c1369e9c9da2d64a7b7992c786d90ff295abc93964cfe3125e4290768070 \ + --hash=sha256:983a662de2571cb2502fc8ff47b6770b03d025d2eb314c92f77b3f07c74720ed \ + --hash=sha256:992c3514ec891fa7858099183e4d64e6bd5a5d4ff452fae29df22faa77a006bb \ + --hash=sha256:99ba9bc2b8062ea0c326a990f7f00e6530c23579de66dd246e72c4cafef950a5 \ + --hash=sha256:9d1bed94af6a63835461f3cf7502058eb166c58c4778e11d0f433cfb1bd69e19 \ + --hash=sha256:9e4472072de0137ee0d8e72d6620e85939c271d2f90f6bbb4b15c24638b79f92 \ + --hash=sha256:a27c09d86600f1bf2fe3f37e1ae697faf3143931c09322cd799da94deee923b5 \ + --hash=sha256:a29a061fec0b4e2d714f277e70a3a18125ecff803f2fea6eade2f2e53711d112 \ + --hash=sha256:a3cda0e538208e5d722bbf3698b24f19c0a7d05bc8d5f8a7f9b121ea7fa243d9 \ + --hash=sha256:a44101320cfe99432db74237545a63057dc7a88dfe792cbcad0647f2af56cb81 \ + --hash=sha256:a4aaaa791bdae1c972a7e81765f4f3571c926b8e0b9b6e47346499fb80079665 \ + --hash=sha256:a51eee75939cf811ac09b278745a6cee7dc873ccfbc8b9af3cc88fe4b7ce25b5 \ + --hash=sha256:a7c58106de36ac6a56314182958de20db8d3a29dfd5db527192cc754e4f8e7fb \ + --hash=sha256:aa8224f10880d9bf1b5993988ba153d42a8b4f3f4f511f93b1f09c93ff613c72 \ + --hash=sha256:acbf31f37c53a5ac0c34706c80b4f5107ba20b05fdd3816124bf236ef0c57dd2 \ + --hash=sha256:adc06d218a1cadfd2ec4628424d7d79ce4eba69c2965e7e7b55106f0da5208c8 \ + --hash=sha256:ae28183297fb0d2b8dc46a1f01d51f5e45825fc5afe76a835a6cb7fb34821295 \ + --hash=sha256:b0135bcdcaa0f23573f286e4cb5e0fd2962700964ed13df085b85f2b97aeab9e \ + --hash=sha256:b087b1c5be7ac687cf22eabfe4b6b608d40df23610651e93611e1f49118baf84 \ + --hash=sha256:b0d955195bbbe489ad343fcc956eacea9357b79cb22192c66cacdefcbc14b32f \ + --hash=sha256:b281a3b0f0822618fe5e3e0d8a2048b6356b14388505dc9374ccffeb69989713 \ + --hash=sha256:b6d0c2183008c188e19f4906d426b293bdc4f67ab17df8e180fe16cda208fa71 \ + --hash=sha256:bbce99252ba3167b2b6277f1829d5bf4b43b754524bddf7f944707c3db7d2253 \ + --hash=sha256:bc1f08f68dac9f9e83845a8039880aba2ab553eb9b2259c3243a313182c253fe \ + --hash=sha256:bc94f474417604bd383d2cd445d071b07dd55fedceed3ce33407bf1fcc107290 \ + --hash=sha256:bed5163e03b98bc1fa2eb05d74c63d9c5c95d8ed6254985481640fbf5e237dea \ + --hash=sha256:c17799a62c142d61b8a3c51752a7cbc87fe2ad4ccfab10e628a77b405075c662 \ + --hash=sha256:c18db21573bd2c6489f9a544b7499f0df2853958c568e5e783536ee1f690af41 \ + --hash=sha256:c3ede305158e75510be50869b319550ab072008c13d64d4ab1e094fb286b6f44 \ + --hash=sha256:c516cc5367ca3448995d42cb994bf3f4c9002d2a7c22eac9622551269ad1b807 \ + --hash=sha256:c531166c42ea7bdfecc8c50049581f05dd1993b09cc7c52bb36a14e96deaec7d \ + --hash=sha256:c73622ef819328873b53109ee4f77ceb598bffedd02daf916102be3228866b78 \ + --hash=sha256:c8dce1f1e0e5358b682a6ad3fa5e31b31d4560997b8e61417e9217c8d60f8a0c \ + --hash=sha256:cb57f304525a5e3c13333b772bf9a473f36326e9c821b2e8e1b2fd36f80ae2c3 \ + --hash=sha256:ce8c25ca38cc0e3d7753ba180808de2c0c8cb24eae0df64491e40921454e9831 \ + --hash=sha256:ceff0acc940be2715bd6ad17b24c0e5304abf44f6efd0f81ee8499e640f9dc86 \ + --hash=sha256:cf356f70551d40374eaffb1aa63f1eb6d2006681cbd7a9faea173ce0f4dd7cd2 \ + --hash=sha256:d2d82aa62521c55ddfb000ae70f88cdd8de974078f6024e821dfe5addd0c818f \ + --hash=sha256:d32f3acc081cc3923386d88f422cde8892335e95f034e0104bb4cf9310d9915f \ + --hash=sha256:d4193206b6587047437f6f11d7e776df23e1c1e23af2a54d9347275614791e10 \ + --hash=sha256:d5c0e32fdbce7f1e8ef4d11f655694bf5f4175c757a9f1dc2be09b8864e5bcf5 \ + --hash=sha256:d5e062c01286d861fd6a1c4ff6e063547b3e713067f2df033c0ff97ac2ca006b \ + --hash=sha256:d8f9e8a6c4ab04b78d61f78627370d834eb004b2869dcb28cfffa647b4ea1980 \ + --hash=sha256:d939de9c82e2126f7f48a7e658f8a85ed46d57662d53f44c49b8895fe94a3eb7 \ + --hash=sha256:de531ce1e2a3364e8767878b58f4ff728a434b4fde089781fe30b1e08e2396e0 \ + --hash=sha256:e50d7b94baac6c7d09927fa5ca5800a0c7ee5015c7fcff65beb3a1931b5a6e09 \ + --hash=sha256:e5faeaee74a57d32b3ab3aebad2e348f06d3ba946fc5d28c1728455f00a3d13a \ + --hash=sha256:e6f0cc1bb9900dc558960894adeb30b0c083366fc1d69b856209fb2ca5c36fe5 \ + --hash=sha256:e8e1d6ce820aa23317e8209a86bd65a540973c12dc7552b48a4f6c8e9926815e \ + --hash=sha256:ed1e728b39a383c81035b2459cfcb35d99dfb01f7d6ebe3a913bc1cc5b81e459 \ + --hash=sha256:ee6db2fbed51a7991302e8fac498cd67e336246026d0dfa84cf5166ce1412760 \ + --hash=sha256:efbecf43d321f7b9281441f1f213f7c21c66988b0e06c2730ba13ed47a46bb08 \ + --hash=sha256:f2c634642694e6a0dad2ab1d375589fa671fd442edd5caf7d9737b8f6ca22906 \ + --hash=sha256:f3377c8c2b3ce898423c5e5dd94c7982e30aa7717a7e6ab2470b9de364963709 \ + --hash=sha256:f5187624823423e1d1b82b1072ac41dc837389e18d3d0572cc19bbee46cd550a \ + --hash=sha256:f77ac30b19221cd9bd3fcfa3d4614eff93140d0572ab730cded17b64adca05f3 \ + --hash=sha256:fe90228920fd8ff2be62622b6bb8a2b11acd65046d50c6b130614b5879605a20 + # via pydantic +pyyaml==6.0.3 \ + --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ + --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \ + --hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \ + --hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \ + --hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \ + --hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \ + --hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \ + --hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \ + --hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \ + --hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \ + --hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \ + --hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \ + --hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \ + --hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \ + --hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \ + --hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \ + --hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \ + --hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \ + --hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \ + --hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \ + --hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \ + --hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \ + --hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \ + --hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \ + --hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \ + --hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \ + --hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \ + --hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \ + --hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \ + --hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \ + --hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \ + --hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \ + --hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \ + --hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \ + --hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \ + --hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \ + --hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \ + --hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \ + --hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \ + --hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \ + --hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \ + --hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \ + --hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \ + --hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \ + --hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \ + --hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \ + --hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \ + --hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \ + --hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \ + --hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \ + --hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \ + --hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \ + --hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \ + --hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \ + --hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \ + --hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \ + --hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \ + --hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \ + --hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \ + --hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \ + --hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \ + --hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \ + --hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \ + --hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \ + --hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \ + --hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \ + --hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \ + --hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \ + --hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \ + --hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \ + --hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \ + --hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \ + --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 + # via cmcp-runtime +referencing==0.37.0 \ + --hash=sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231 \ + --hash=sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8 + # via + # agentrust-trace + # jsonschema + # jsonschema-specifications +rfc3986-validator==0.1.1 \ + --hash=sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9 \ + --hash=sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055 + # via agentrust-trace +rfc8785==0.1.4 \ + --hash=sha256:520d690b448ecf0703691c76e1a34a24ddcd4fc5bc41d589cb7c58ec651bcd48 \ + --hash=sha256:e545841329fe0eee4f6a3b44e7034343100c12b4ec566dc06ca9735681deb4da + # via + # agentrust-trace + # cmcp-runtime +rpds-py==2026.9.1 \ + --hash=sha256:00ba2d8c7dd4ee537978ddf4b3fbd712bef2d8751603f7f3146b3f4287768e25 \ + --hash=sha256:01445c8d194aa032a08e944f16567672da1c62dbdbefd8b6d0693032e290cf68 \ + --hash=sha256:028ad274ea951dac64491b5d1e65712a4aeabfdbdb9fccf797b57bd899b0c495 \ + --hash=sha256:0483515261947e4e8b8e1375bf7463e7eb6ccfb3d86e7b554d90cd5285f20f32 \ + --hash=sha256:068c37bba854ec2fe42f7365c640af11dd9895890ccbf2df5070d0c059bd7f96 \ + --hash=sha256:074a4d198bc34d9a8ea425114fc3ded6d11ec01f6a314a8db67454a5152d8834 \ + --hash=sha256:07deecbfce94c78473018bc7d10b337cc651d12df87a1eb2cb3e4024bc9c33d0 \ + --hash=sha256:08dae4a4095150a7c4545a1fb40b98e1ab1744fbc2770d92c977b9dadaa49ab6 \ + --hash=sha256:0da298fb372dc192610a4b9ecbc68a0cd8b675bbbd1fc519d01b41cfd658333e \ + --hash=sha256:0f045bb053c9057720d72c56dffe30dffdc05997b2897a827b9325f0ab6623fa \ + --hash=sha256:10e208f2425d973938afcd56e28a7c4be32e27b6a60b5d381f49fb9d8acf9759 \ + --hash=sha256:136a1c3fe4402b7008bc81cb62ee538481795b61a7e83df88dff3b3f02b726ff \ + --hash=sha256:159a7aab5c5e8b112c8830f54717ce56da1252ebdbb526f5be2df2309280b9e7 \ + --hash=sha256:172e47169583f46ce118cbec68e6795d0da0f4606b488b6434f8276bca0a058c \ + --hash=sha256:1c2d1f6da5128eabf34e963d7163a818846075a52568250d006c4c953b40f903 \ + --hash=sha256:1d55198263bb51f557550c6ed2e6d1cb6a6fed6eb5c9120b741c5926bef8a45d \ + --hash=sha256:1d77b649e6f7cdf12ca5c2a98dad0ad37f9ea9b6f960408a92f0cb12bb3d04d9 \ + --hash=sha256:1e8d4d79d828299bf44a55db22a9388ab967b49d17132c88eab0f4360b48da8e \ + --hash=sha256:22ffd29a63d71fb1b81552c21f2c2b734949b7ac751a9be70675a939a900839b \ + --hash=sha256:2693b2728bbcc48d09a981a356954b0c47c53ff25b545856f28a889ea619f69a \ + --hash=sha256:270bdcdaac5d5b6f73c5e22e7e135c7f2a50e789f71d9e241d5be8d90026e19a \ + --hash=sha256:2711d29b653b3bce48a63d18b9c6b53274669e6d6c4094dddeb4d9a0e45128b2 \ + --hash=sha256:2c16ab111bc27c646ba8aa005d0527754edc538ebb636f0b1bf8e244b48d1945 \ + --hash=sha256:306ee1850d8105b5baf977e78d45fcadd12c1a54678d614c9baf217708446e91 \ + --hash=sha256:3231c4c0e521dafa5be0c9f114ee2c2ad46650836f2d72caa86801950c3e7044 \ + --hash=sha256:3890a6aa36e6baa53d5258a2a25d3ef8b37ad165a6ab27a892d7c3e3a432cd69 \ + --hash=sha256:3a72c11530d71abfb66c8d7696a2f86c43e63fca8b948f1a784ac490f4ec688e \ + --hash=sha256:3b5a6f40f0a1486b4b36c888123afc67acdbd9f33235927acf5ff295429a0ba3 \ + --hash=sha256:3c91c210ae7645626c608400e3519b4a642f837cce09ca830db3beb2e9f274d4 \ + --hash=sha256:3cd182d7291d29b92c521a0069d9c01ba6193628a9a105531d11b40a6d731a33 \ + --hash=sha256:3e524c7874ac72884d28e16dd5b8d839fd09e0fe76b020d3fbca23212a7b8c52 \ + --hash=sha256:3e93b2cd69a9830be33e03945cd7cda940a0a8bfcfbff41d6144f0cb0d3d8bd9 \ + --hash=sha256:3edae8c5ddfdb6985d49ae9d150516e5076888879022f91a26c2de9276ce0bdb \ + --hash=sha256:3f0e9ac28fc067d4d34b88ae43c48e9489455c97fee9633d851f7eeed5a05d35 \ + --hash=sha256:42e75466f83cd43f6026c81eab74246efb2bdadafb307b85700632d06c68f299 \ + --hash=sha256:44b32a7c4f0da3d28af31c259e38ddcff096f855e205ed0671d02fcf44f1ea1c \ + --hash=sha256:457866b85daf5034296666168b84a69e0b2e89dc4f1af102b46f6448a60b9063 \ + --hash=sha256:45bc6bccf78b20fd834237d18db64965d7ee68ba7f60440a26c7ab71e7b8d51a \ + --hash=sha256:46d80bc76b51a6c24f9944368c28d38b8bcbcea1da4f2f8d3ebc31a67e8c6ec6 \ + --hash=sha256:4793ef7f78268b124b73fa933440f01d258bbae01de9fa53e9080c9ab0425a12 \ + --hash=sha256:492e5e428cbe126221611f47e068f01660352feec4ad18bc0f5ea9b2ae88fb14 \ + --hash=sha256:4b26b03d9d2658ee2fa234f8f4f19f38a09773fe5261028025032e26d4d35af0 \ + --hash=sha256:4c0d2cb595a420b34d5086db0add011e26e2c09d6a024afbac4228bf8f863a30 \ + --hash=sha256:4cfaf02209061880210819934de2f4f6aa83dc04dafe6770276acc240a56da31 \ + --hash=sha256:501909f2e4a1e2dee528ef766fe3c469060ebc17e54a8383d404ba07a81a6f02 \ + --hash=sha256:50906f5aea24b5a865cbd0a589698288631d9f3a54c3a937c83aefa95a0d14af \ + --hash=sha256:54ac2158a6f96cfbabff0b2eedaf94b90c5ec7ca8317fcadc61e1c2b2e0ff6ef \ + --hash=sha256:56c6952a9b15047466d0c2347c446a761d4527f89976156341e68f0ce5cc08b0 \ + --hash=sha256:56cd8b3f77d7b6812f533b662186a1f28316931166ddc00fb893b1b0db7e9888 \ + --hash=sha256:57492a550a1d88d29d003247e5f78dd8cf04a701fac0e4c8db8745a6d2504e0a \ + --hash=sha256:5943980471829f6de242a20b109de3111ba6b77e3af0ffc587028ac854b05e6c \ + --hash=sha256:5c6ee90dee3e85e055ddfd502d611643d9b0fd94c818220bda84ec3dacd9b27b \ + --hash=sha256:5c90e7fa02e8f5de0d10c17595c568ada48c5302e749462c0ea1a4c362111a86 \ + --hash=sha256:5ce8943f79c2210f7abcc28e86367b03b28d95027fd01c46d2472373ae70c86f \ + --hash=sha256:617f59cde379b4f648a09797b7f683d04b90a46344cddab85639da5aff0f5531 \ + --hash=sha256:6307a0da524939decb8ca4a3933b8ab62525794411d6984fca6726e732804af6 \ + --hash=sha256:684fd492fff4fead00587544e059be2bbcb6f93454f21fa2a91b66fc7508be82 \ + --hash=sha256:6b5b393eda5ea42cca1c1a6665f2a4882b4fd5d1777e41ce0545a107fb008c9d \ + --hash=sha256:6b723eb406dec5bc9ec516c73ab9c3239a3284e017f7eb89ee2b3258bd504fb7 \ + --hash=sha256:6b9bf3135b4ad5981df9a73d71a35272d650a2985ae9c2746357b24d59de2448 \ + --hash=sha256:6beb738155fe8ab8091afdfa5a3226b21c2b1593f1e50ebb90eb25b44dbc0391 \ + --hash=sha256:6c0dbbcc19735fe5f8b0a54c07659d154a9e69f47e15d0a6ab7299215daf62cb \ + --hash=sha256:6cdc537c8633d7fd92a82e2e0d2ab74320a3f63d5e59fb9cf08711e08fe151c4 \ + --hash=sha256:6eae33003518fd4cb4f83a218d5371469dd3001aa3b87128c005b07762f7fe5e \ + --hash=sha256:740d0a99cf9de0b17a3943388e9294a59becf75e7c43421f387bd3c7a9901f7c \ + --hash=sha256:75c38c50ab9aca840225d9a9a3810bf11d04bd5c1f186cabbb8aee56db3e9b15 \ + --hash=sha256:761fdae6728ceb99ab182fad2f0cc1e262f610834dc891aea1d1a2a2e634776f \ + --hash=sha256:7664419f27db41d4f1c43a78dccda7dd6e8ef2428df3ee01d0c2a07a6b071297 \ + --hash=sha256:76d3af9732d2dab69f28179b40ba2d87e2f1d5824b4a694780aa787d685e8f36 \ + --hash=sha256:78326f4cb4427a56ba4996c0762b63be45f06b85f086526420d2b3a66e40f84d \ + --hash=sha256:7868b85224291c6cb6759f9b5adb9745f486d226f62b16a614dd5a2a5ab2b35b \ + --hash=sha256:815d26356930846a40c7bc1366e7b1b0320ab8a063e66c11298a208bed0fd237 \ + --hash=sha256:8171b44a054e5c67fd748ada04187f1250bf35b95f85e52ab64bcf3331a923bb \ + --hash=sha256:821b2755db9194409254012f429c56643416fb96ef9be090be82ec8826b7f477 \ + --hash=sha256:837c6b305e26fe0f75b15c92cf3b2ba29e0ae19dc40b1c557b026cb426347d0c \ + --hash=sha256:839dde845559254f34885267c6878f60d61d5205180226d976fe488d45fa128e \ + --hash=sha256:84a6ecc0c940169190d2c23bd969debd48c94dbc855acd60188a68d71d421608 \ + --hash=sha256:8601470267d938bcb7f3ab1a336100af51a4fd5b6ed030ef52461bb3ef5e7e07 \ + --hash=sha256:88b5268892fde430d5531f95bc560b6efbbd67c929662c586afd729a96e7461c \ + --hash=sha256:8aa5dda18d39b6143eb24809d158f9252c88f402749b6f1b62a506cc7d96cc35 \ + --hash=sha256:926bdd3e3b5998ddf70cc64bc8cf57209571f9044542913afb673799fec77dd0 \ + --hash=sha256:96beca19ec79de272e8668585380ff9092c47077c1d7a1e098e00bbd921f4785 \ + --hash=sha256:9a0460d43603d1fd9ef59c30278531e15d78581721ddb538fa560aa7817ea4ad \ + --hash=sha256:a03d57b86d2a51d0a66c92177e2be154ad015f357791d306e714569999cdb4cc \ + --hash=sha256:a36b70596407634ca82d4b989a3729074a008537a0522e4c8046a67c729103e9 \ + --hash=sha256:a3a52a3ba86436ab3aef510fbe21512abc2ddd1993005dfe50514bd2284ef025 \ + --hash=sha256:a3dbc5ed9514908d5046107d7b1346bde71eea61de6e0e4919c19354f97e769f \ + --hash=sha256:a431156bb41865fc14cd5d79bb9d7bbed83110b0159e34e62ae30951f96c0009 \ + --hash=sha256:a575404ebc9cf2e91edd32eaf570ec1430eb900d4f56724ba7dd4bc1fc9c176d \ + --hash=sha256:a5cf77eb04f20b720be95265a3e00eb2a14814074255cc27069c551b2db53118 \ + --hash=sha256:a8763f20692da7df39b0afdd1ba3042b004c50a45994f76c2d9a25641f7673db \ + --hash=sha256:ab4b2fda7c2b542f7f9d886cc6a838c5079d2b76f72e6081411faba11adde2c9 \ + --hash=sha256:addeda51556dac7c1a2f14cda62db8b621cd12afba3091d03a96c72932387eab \ + --hash=sha256:b242c27c8f836305a4a72df9cdd564386ac57b807bd252a063223331c9316b37 \ + --hash=sha256:b4f062343e7ad3fa94f2c66e5ae667dee47ee74dd41a9057c4fbe163236a123d \ + --hash=sha256:b5b8b0753718d258fd454283fbd57e14545d3b40583fa672e27cb4f987626bcc \ + --hash=sha256:be3e47e2d91aa3942ff9bf4077a505226005abfc39b6f7554a91c1b9393986b9 \ + --hash=sha256:befc2d6a953e563f8a7bfd87a42c22ebf8a3e980dcb7b6a4d17b70b0e914e8a3 \ + --hash=sha256:bf35d0568abda97233239ce32896d3ad53fccc537832c104e30c94aa5fb93569 \ + --hash=sha256:c933c6678c6f116ff8af47a4c6db0868b8ace74af0343016c0ef00f00272ea69 \ + --hash=sha256:c9d1aca01f49170fdcf5c92761b1fafe97f554b721ca4570c5949fff778f0d4b \ + --hash=sha256:cdeaa99ce822dca76cfb1b993e9120c5ea212f2eb66d48950ad63c349668a018 \ + --hash=sha256:ce4d4f52e2a4324396caddbd45a97d8d7be5f42edd25d2355282a9c34f9b2f7f \ + --hash=sha256:d1028417bb44037eb3069c1009bd7b7277212876cda22fbe565b0bca9fab6d2c \ + --hash=sha256:d151e148117294133bf8af7eeace085e7e87432db15ab6adf640330298a47f6f \ + --hash=sha256:d7841166b7fa64c9c56404617ae4341448847482d45933b13135d26c130519e5 \ + --hash=sha256:d7fca4eb6df565e2a928f1c7dad92d27db8f9df0f449e76423ed5d7e713ed445 \ + --hash=sha256:d95a354e02393eada6d7351184671aced9d4cce109dabf927cb7aa99624352a1 \ + --hash=sha256:d9edf30457d74eebfd76b045535e36f1cd89062566a128a0db2145ca042d787e \ + --hash=sha256:dbc2673f9223d420c91145599b3ba45a8a50c207d1976908e5fb5ddb0c9b9429 \ + --hash=sha256:e01b3c878c8641913e688edd1b3f08658c6783d29cf6b826bd3c0d1ae7a1ffaa \ + --hash=sha256:e21c1429e205828ea886a2293a4a2c8e01f4c25d9893ca330e97a6cf73f52e7b \ + --hash=sha256:e43d4a1f673e8a1cbd8533e809e02b4bf9d4f2280269bb640436556312121250 \ + --hash=sha256:e6d198bad4e49dd6732fbd636e2fc5c082f45c8cad0b4acb756b00c82c76072e \ + --hash=sha256:e6ea1cda8d8c688278430e4268a42f5e5da3bdd74578dfadc0820c3f1766ce83 \ + --hash=sha256:ea394a937f17a54c51239348bdbe2e3518124c8d4a8951ba04a311d3095bd18f \ + --hash=sha256:eac2f5dbafd585dfe31f86a23ebf0d3ba480a9d49ebc87947267b5608d4ea0cd \ + --hash=sha256:eb61be926bb81567c1f48bdc8aa22b9855048dc2efd53871f9f7e6e9a5632346 \ + --hash=sha256:eba5d173f7d5708b22a93815017a4611873ed54db9f268077c0dd1ed99cfc858 \ + --hash=sha256:ec450527cbf485e13c8d3602a54f428ab0432fdade0ede75efd74b735421c871 \ + --hash=sha256:eef6a03b0b6d08d0835ccfa8ec8d1bc70525e3801387567137b50c557695e6da \ + --hash=sha256:ef0d8c843e2827d6c120ab4687e9423fb1d893db1df27b7c1506615bcb9734a0 \ + --hash=sha256:ef6b65b03247c54692ad4fd9ee97cb772781927db72e3cb05e70b3db6d1ff14f \ + --hash=sha256:f3d6ed6a98cfd19155996605474982cc470d7601746a6439078f1a5a3fa8b050 \ + --hash=sha256:fce4b85234a0cbad67bf8e6e1201ee815d172c9aebad75f25645bc4d834f8e31 \ + --hash=sha256:fda1d96e542c37b6c804547dbf489c129fe7c97183a76a5ec275909ba1a063df \ + --hash=sha256:fdcd198979b4ecffcc1beba366a7fbcf4eb41243691a82fe52ceb0b902f09c12 \ + --hash=sha256:fe5ad0664ec772b02c45859041aa17655709cced7a31005817fbbbd988c25567 + # via + # jsonschema + # referencing +starlette==1.8.0 \ + --hash=sha256:1565dc0b35d5737a271ed1e0e04e949f4e81198799f216d2667b0a0fb9cf9522 \ + --hash=sha256:dfdd6b29c26483288088d990eee59631dedadd66ce20d203402a7ca8e3c4656f + # via cmcp-runtime +typing-extensions==4.16.0 \ + --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \ + --hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5 + # via + # anyio + # pydantic + # pydantic-core + # referencing + # starlette + # typing-inspection +typing-inspection==0.4.4 \ + --hash=sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47 \ + --hash=sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147 + # via pydantic +uvicorn==0.54.0 \ + --hash=sha256:505bdb0f318731d45f1f712071fc781a8981f6847a31c902c9f5e652d4f67faf \ + --hash=sha256:a2e33cbfaa0306f8e6b0c13e0cb89d7d7a2da3e62b90c66e18c33d9807b28620 + # via cmcp-runtime diff --git a/examples/industrial-embodied-ai/server/mock_robot_controller.py b/examples/industrial-embodied-ai/server/mock_robot_controller.py index 674ece6b..8be2f54a 100644 --- a/examples/industrial-embodied-ai/server/mock_robot_controller.py +++ b/examples/industrial-embodied-ai/server/mock_robot_controller.py @@ -3,6 +3,7 @@ from __future__ import annotations +import argparse import json import sys from http.server import BaseHTTPRequestHandler, HTTPServer @@ -21,6 +22,8 @@ token_key=b"development-only-mock-controller-key" ) completed_motions = 0 +motion_requests = 0 +run_id = "manual" def _read_safety_state(arguments: dict[str, Any]) -> dict[str, Any]: @@ -36,7 +39,8 @@ def _read_safety_state(arguments: dict[str, Any]) -> dict[str, Any]: def _request_motion(arguments: dict[str, Any]) -> dict[str, Any]: - global completed_motions + global completed_motions, motion_requests + motion_requests += 1 try: result = controller.request_motion(arguments) completed_motions += 1 @@ -71,7 +75,24 @@ def _with_execution_receipt(result: dict[str, Any], call_id: object) -> dict[str } +class LocalHTTPServer(HTTPServer): + allow_reuse_address = True + + class Handler(BaseHTTPRequestHandler): + def do_GET(self) -> None: # noqa: N802 + if self.path != "/health": + self._reply(404, {"error": "not found"}) + return + self._reply( + 200, + { + "status": "ready", + "run_id": run_id, + "motion_requests": motion_requests, + }, + ) + def do_POST(self) -> None: # noqa: N802 if self.path != "/mcp": self._reply(404, {"error": "not found"}) @@ -133,8 +154,9 @@ def log_message(self, fmt: str, *args: Any) -> None: if __name__ == "__main__": - print( - "Mock Robot Cell MCP Server listening on :8080 " - f"(tools: {', '.join(TOOLS)})" - ) - HTTPServer(("127.0.0.1", PORT), Handler).serve_forever() + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--run-id", default="manual") + args = parser.parse_args() + run_id = args.run_id + print(f"Mock Robot Cell MCP Server listening on :8080 (tools: {', '.join(TOOLS)})") + LocalHTTPServer(("127.0.0.1", PORT), Handler).serve_forever() diff --git a/examples/industrial-embodied-ai/tests/live_presenter.py b/examples/industrial-embodied-ai/tests/live_presenter.py new file mode 100644 index 00000000..90681bff --- /dev/null +++ b/examples/industrial-embodied-ai/tests/live_presenter.py @@ -0,0 +1,242 @@ +"""Full-stack tests: install requirements-presenter.txt before running these.""" + +from __future__ import annotations + +import contextlib +import io +import json +import os +from pathlib import Path +import queue +import signal +import subprocess +import sys +import tempfile +import threading +import time +import unittest +from unittest import mock + + +BASE = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(BASE)) +from present import GATEWAY, LocalServices, check_ports, run # noqa: E402 + + +class LivePresenterTests(unittest.TestCase): + def command(self, output: Path, *args: str) -> list[str]: + return [ + sys.executable, + str(BASE / "present.py"), + "--output-dir", + str(output), + *args, + ] + + def verify_offline( + self, output: Path, *, tampered: bool = False + ) -> subprocess.CompletedProcess: + # Audit hooks reject socket creation, DNS and connections. Dependencies + # may be imported, but any attempt to use the network fails this test. + script = """ +import sys +def deny_network(event, args): + if event.startswith('socket.'): + raise RuntimeError('network forbidden during offline verification') +sys.addaudithook(deny_network) +from verify_evidence import main +raise SystemExit(main()) +""" + bundle = "tampered-audit-bundle.json" if tampered else "audit-bundle.json" + return subprocess.run( + [ + sys.executable, + "-c", + script, + str(output / "trust-record.json"), + str(output / bundle), + ], + cwd=BASE, + capture_output=True, + text=True, + timeout=20, + ) + + def test_two_fresh_runs_and_offline_tamper_rejection(self) -> None: + with tempfile.TemporaryDirectory() as directory: + sessions = [] + for index in range(2): + output = Path(directory) / str(index) + result = subprocess.run( + self.command(output, "--auto"), + cwd=BASE, + capture_output=True, + text=True, + timeout=60, + ) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertIn("Altered outcome digest: REJECTED", result.stdout) + observed = json.loads((output / "observations.json").read_text()) + self.assertEqual(observed["denied_motion_requests"], 0) + self.assertEqual(observed["allowed_motion_requests"], 1) + sessions.append(observed["session_id"]) + check_ports() # Both children really exited before verification. + verified = self.verify_offline(output) + self.assertEqual(verified.returncode, 0, verified.stderr) + self.assertIn("EVIDENCE VERIFIED", verified.stdout) + rejected = self.verify_offline(output, tampered=True) + self.assertNotEqual(rejected.returncode, 0) + self.assertIn("EVIDENCE REJECTED", rejected.stderr) + self.assertNotIn("receipts: verified", rejected.stdout) + # Neither altered claims nor absent receipts can pass as valid. + audit_path = output / "audit-bundle.json" + original_bundle = audit_path.read_text() + bundle = json.loads(original_bundle) + for entry in bundle["entries"]: + entry["external_execution_evidence"] = None + audit_path.write_text(json.dumps(bundle)) + self.assertNotEqual(self.verify_offline(output).returncode, 0) + audit_path.write_text(original_bundle) + claim = json.loads((output / "trust-record.json").read_text()) + claim["trace"]["session_id"] = "changed-session" + (output / "trust-record.json").write_text(json.dumps(claim)) + self.assertNotEqual(self.verify_offline(output).returncode, 0) + self.assertNotEqual(*sessions) + + def test_original_three_path_runner(self) -> None: + import httpx + + with tempfile.TemporaryDirectory() as directory: + output = Path(directory) + services = LocalServices(output, "original-runner-regression") + try: + with httpx.Client(trust_env=False) as client: + services.start(client) + result = subprocess.run( + [ + sys.executable, + str(BASE / "agent/material_movement_agent.py"), + "--claim-out", + str(output / "trust-record.json"), + "--audit-out", + str(output / "audit-bundle.json"), + ], + cwd=BASE, + env={**os.environ, "CMCP_BEARER_TOKEN": services.token}, + capture_output=True, + text=True, + timeout=30, + ) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertIn("SAFETY REJECT", result.stdout) + self.assertIn("controller receipts: verified (2)", result.stdout) + finally: + services.stop() + check_ports() + + def interactive(self, output: Path, *, interrupt: bool) -> tuple[int, str]: + child = subprocess.Popen( + self.command(output), + cwd=BASE, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + ) + chunks: queue.Queue = queue.Queue() + + def read_output() -> None: + while char := child.stdout.read(1): + chunks.put(char) + + reader = threading.Thread(target=read_output, daemon=True) + reader.start() + transcript = "" + prompts = 0 + deadline = time.monotonic() + 60 + try: + while child.poll() is None and time.monotonic() < deadline: + try: + char = chunks.get(timeout=0.1) + except queue.Empty: + continue + transcript += char + if transcript.count("[Enter]") == prompts + 1 and transcript.endswith( + ": " + ): + prompts += 1 + if interrupt: + child.send_signal(signal.SIGINT) + break + if prompts <= 2: + # A pause longer than the 5-second token lifetime must + # work because observation happens AFTER Enter. + time.sleep(5.2) + child.stdin.write("\n") + child.stdin.flush() + child.wait(timeout=15) + reader.join(timeout=2) + while not chunks.empty(): + transcript += chunks.get_nowait() + if not interrupt: + self.assertEqual(prompts, 5, transcript) + return child.returncode, transcript + finally: + if child.poll() is None: + child.send_signal(signal.SIGINT) + child.wait(timeout=15) + child.stdin.close() + child.stdout.close() + + def test_presenter_pauses_do_not_stale_the_safety_token(self) -> None: + with tempfile.TemporaryDirectory() as directory: + code, transcript = self.interactive( + Path(directory) / "paused", interrupt=False + ) + self.assertEqual(code, 0, transcript) + self.assertIn("Altered outcome digest: REJECTED", transcript) + check_ports() + + def test_interrupt_and_closed_input_release_services(self) -> None: + with tempfile.TemporaryDirectory() as directory: + code, transcript = self.interactive( + Path(directory) / "interrupt", interrupt=True + ) + self.assertEqual(code, 130, transcript) + check_ports() + result = subprocess.run( + self.command(Path(directory) / "eof"), + cwd=BASE, + input="", + capture_output=True, + text=True, + timeout=60, + ) + self.assertEqual(result.returncode, 1, result.stdout + result.stderr) + self.assertIn("Input closed", result.stderr) + check_ports() + + def test_partial_startup_failure_reaps_owned_children(self) -> None: + original_wait = LocalServices.wait_ready + children = [] + + def fail_gateway(services, client, url, **kwargs): + if url.startswith(GATEWAY): + children.extend(services.children) + raise RuntimeError("injected readiness failure") + return original_wait(services, client, url, **kwargs) + + with tempfile.TemporaryDirectory() as directory: + with mock.patch.object(LocalServices, "wait_ready", fail_gateway): + with contextlib.redirect_stdout(io.StringIO()): + with self.assertRaisesRegex( + RuntimeError, "injected readiness failure" + ): + run(Path(directory) / "partial", auto=True) + self.assertEqual(len(children), 2) + self.assertTrue(all(child.poll() is not None for child in children)) + check_ports() + + +if __name__ == "__main__": + unittest.main() diff --git a/examples/industrial-embodied-ai/tests/test_presenter.py b/examples/industrial-embodied-ai/tests/test_presenter.py new file mode 100644 index 00000000..73fa7780 --- /dev/null +++ b/examples/industrial-embodied-ai/tests/test_presenter.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import json +from pathlib import Path +import socket +import subprocess +import sys +import tempfile +import unittest + + +BASE = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(BASE)) + +from present import LocalServices, check_ports, tampered_copy # noqa: E402 + + +class PresenterTests(unittest.TestCase): + def test_tampering_preserves_original(self) -> None: + original = { + "entries": [ + { + "external_execution_evidence": { + "evidence_hash": "sha256:" + "a" * 64, + "signature": "original-signature", + } + } + ] + } + before = json.dumps(original, sort_keys=True) + altered = tampered_copy(original) + self.assertEqual(json.dumps(original, sort_keys=True), before) + self.assertNotEqual(altered, original) + self.assertEqual( + altered["entries"][0]["external_execution_evidence"]["signature"], + "original-signature", + ) + + def test_missing_receipt_cannot_produce_tamper_success(self) -> None: + with self.assertRaisesRegex(RuntimeError, "without a controller receipt"): + tampered_copy({"entries": []}) + + def test_occupied_port_is_left_alone(self) -> None: + with socket.socket() as occupant: + try: + occupant.bind(("127.0.0.1", 8080)) + except OSError: + self.skipTest("Port 8080 already in use") + occupant.listen() + with self.assertRaisesRegex(RuntimeError, "Port 8080 is occupied"): + check_ports() + with socket.create_connection(("127.0.0.1", 8080), timeout=1): + pass + + def test_cleanup_stops_owned_child_only(self) -> None: + with tempfile.TemporaryDirectory() as directory: + services = LocalServices(Path(directory), "test-run") + outsider = subprocess.Popen( + [sys.executable, "-c", "import time; time.sleep(60)"] + ) + try: + services.start_child( + [sys.executable, "-c", "import time; time.sleep(60)"], "test", {} + ) + services.stop() + services.stop() # Cleanup after an exception is safe to repeat. + self.assertIsNotNone(services.children[0].poll()) + self.assertIsNone(outsider.poll()) + finally: + outsider.terminate() + outsider.wait(timeout=5) + + def test_exited_service_is_not_ready(self) -> None: + with tempfile.TemporaryDirectory() as directory: + services = LocalServices(Path(directory), "test-run") + services.start_child( + [sys.executable, "-c", "raise SystemExit(2)"], "test", {} + ) + services.children[0].wait(timeout=5) + with self.assertRaisesRegex(RuntimeError, "service exited"): + services.check_alive() + + +if __name__ == "__main__": + unittest.main() diff --git a/examples/industrial-embodied-ai/verify_evidence.py b/examples/industrial-embodied-ai/verify_evidence.py new file mode 100644 index 00000000..e6c20ea9 --- /dev/null +++ b/examples/industrial-embodied-ai/verify_evidence.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Verify saved example evidence without contacting any service.""" + +from __future__ import annotations + +import argparse +import contextlib +import io +import json +from pathlib import Path +import sys +from typing import Any + + +def verify(claim: dict[str, Any], bundle: dict[str, Any]) -> str: + # Keep this import lazy so controller-only tests need no runtime packages. + from agent.material_movement_agent import _verify_evidence + + receipts = [ + entry + for entry in bundle.get("entries", []) + if entry.get("external_execution_evidence") + ] + if not receipts: + raise RuntimeError("No controller-signed motion receipt in the bundle") + # The existing verifier prints intermediate results. Publish them only if + # every check passes, including the signatures on the external receipts. + output = io.StringIO() + with contextlib.redirect_stdout(output): + _verify_evidence(claim, bundle, require_hardware=False) + return output.getvalue() + + +def verify_files(claim_path: Path, bundle_path: Path) -> str: + return verify( + json.loads(claim_path.read_text()), json.loads(bundle_path.read_text()) + ) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("claim", type=Path) + parser.add_argument("bundle", type=Path) + args = parser.parse_args() + try: + report = verify_files(args.claim, args.bundle) + except (RuntimeError, ValueError, KeyError, TypeError, OSError) as exc: + print(f"EVIDENCE REJECTED: {exc}", file=sys.stderr) + return 1 + print(report, end="") + print("EVIDENCE VERIFIED (software-only development evidence)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())