diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 958db208..683a7d18 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -43,5 +43,7 @@ jobs: - name: Test AGT Marketplace snapshot generation run: python -m pytest tests/test_generate_agt_marketplace_catalog.py -q - name: Test confidential workflow harness - run: python -m unittest discover -s tests -v + run: | + python -m pip install --require-hashes -r ../../requirements/confidential-workflow-probe.txt + python -m unittest discover -s tests -v working-directory: integrations/agentrust-confidential-workflow-harness diff --git a/integrations/agentrust-confidential-workflow-harness/EDRG-FEDERATION-SOFTWARE-2026-10-16.md b/integrations/agentrust-confidential-workflow-harness/EDRG-FEDERATION-SOFTWARE-2026-10-16.md new file mode 100644 index 00000000..710f826d --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/EDRG-FEDERATION-SOFTWARE-2026-10-16.md @@ -0,0 +1,98 @@ +# Evidence-driven release gate: composed first-party SOFTWARE federation + +**Date:** October 16, 2026 +**Scope:** AgenTrust integrations #199, Frequency two-host software laboratory +**Decision:** **Software integration pilot PASS; full independently accepted +confidential workflow gate remains OPEN.** + +## Verified execution boundary + +The origin first uses released `cmcp-runtime==0.7.0` for `conduit.inspect` +authorization. A separately restricted SSH forced-command peer on the VPS +then challenges the caller and verifies the released +`ca2a-runtime==0.4.0` signed delegation/holder proof against an explicitly +pinned issuer. A persistent SQLite ledger consumes the challenge before any +side effect. The remote peer launches only Frequency Conduit's fixed +network-disabled `inspect` job, observes its completion, and returns the +authenticated released cA2A 0.4.0 response envelope. + +The VPS separately signs a TRACE 0.11.0 / TRACE v0.2 Level 0 +**software-only** provenance record and companion receipt-binding manifest. +The origin verifies both with the pinned remote Ed25519 key; the semantic +`policy.bundle_hash` remains the hash of the actual scope/repo/root policy, +not a disguised execution artifact. The signed manifest separately binds the +exact request hash, transaction, nonce, job result, start/end receipt hashes, +and TRACE record hash. + +**Real sample transaction:** +`live-ca2a-a40f23585ad2451f9c738971ae64c050` + +**Pinned replay fixture:** `evidence/live-software-20261016.json` + +**Historical TRACE record hash:** +`sha256:f830659f2af40ff74a42b48e04b1a6c544c41f25e9863c18aae56adc70ff77a5` + +**Fixture SHA-256:** +`402a8f0cc05bc517d2918e7a49b10051cb60122fcac8909f1a9ed308c12fdc13` + +## Adversarial evidence + +The live two-host matrix passed **11/11** scenarios on October 16, including +valid control, local cMCP denial, remote untrusted issuer, expired signed delegation, missing TRACE trust, +wrong TRACE public key, mutated credential scope, response MAC alteration, +post-execution receipt loss reported as unknown, a fresh valid replay twin, +and a consumed challenge replay refused by the peer. + +The repository unit/mutation suite passed **81/81** on Prometheus, +including signature/refusal controls, offline software TRACE replay and +historical evidence tampering. Source and dependency versions are pinned in +the PR and hash-locked requirements, and the captured packet includes only +a public, non-confidential `inspect` execution. + +## Required acceptance outcomes + +| Gate | Result | Qualification | +|---|---|---| +| cMCP permission before dispatch | PASS | Released gateway | +| cA2A signed delegation + holder proof | PASS | VPS independently checks proof within same-operator trust domain | +| Remote transport / bounded execution | PASS | Pinned SSH forced command and Conduit sandbox | +| Persistent replay refusal | PASS | SQLite consumed challenge, not hardware anti-replay | +| cA2A authenticated response | PASS | Live source, ephemeral session MAC | +| TRACE signature and companion result binding | PASS | Level 0 signed software evidence | +| Positive / refusal adversarial controls | PASS | Local suite and 11-case live matrix | +| Offline independently runnable signature check | PASS | Public packet; key provenance remains self-asserted | +| External independently operated peer | OPEN | No second organizational trust domain | +| Confidential model/tool execution and disclosure | OPEN | Only a read-only `inspect` job was exercised | +| Independently enrolled revocation/custody | OPEN | No authoritative revocation snapshot or external signer custody | +| Physical TPM / TEE confidential execution | OPEN | No hardware-backed measurement or key release | +| Independent replay by Dinakar | OPEN | Requires another reviewer to perform and record it | +| Maintainer signoff/merge | OPEN | Cannot be self-issued or bypassed | + +## Non-equivalence rules + +A successful software Level 0 TRACE record proves the pinned software +signing key endorsed its claims and the content was not altered since signing. +It does **not** prove a hardware identity, a confidential runtime, complete +monitoring, independent custody or any claim about a secret not exercised by +this test. Likewise, a positive cA2A response is not proof of independent +organizational acceptance. A missing post-dispatch response is an **unknown +execution state**, never a clean refusal or proof of no side effect. + +Historical offline replay validates signatures while deliberately not making +a *freshness* claim. The live cA2A per-occurrence state is non-exportable and +must be freshly exercised to verify the session. + +For implementation About, licensing boundaries, protocol/version pinning, +dependency attribution and glossary mapping, see +[REMOTE-CA2A-PEER.md](REMOTE-CA2A-PEER.md), the reproducible packet in +[evidence/](evidence/), and the original [README](README.md). + +## Replay-observation qualification + +The exact old-request replay row observes a returned status 403 only. Its +original client occurrence has already been consumed, so the matrix does not +verify a second response MAC for it. The row reports +`response_authentication: not-verified`; it is not an authenticated cA2A +refusal claim. A fresh client occurrence reusing the consumed challenge can +provide a separately authenticated refusal control. The historical packet's +peer channel key is also unsigned metadata, as reported by the offline verifier. diff --git a/integrations/agentrust-confidential-workflow-harness/LIVE-CONDUIT-EDRG.md b/integrations/agentrust-confidential-workflow-harness/LIVE-CONDUIT-EDRG.md new file mode 100644 index 00000000..14b98f29 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/LIVE-CONDUIT-EDRG.md @@ -0,0 +1,64 @@ +# Live Frequency Conduit bridge acceptance, October 16 2026 + +The `harness.conduit_live` bounded adapter performs cMCP 0.7.0 authorization +before dispatching one fixed `inspect` intent to the VPS with the preexisting +Frequency Conduit CLI. That CLI uses restricted-key SSH transport and a +whitelisted, resource-limited, network-disabled worker intent. + +The consumer verifies the start and finish receipt hashes, immediate hash-chain +link, session identity, remote node identity, clean worktree, pinned commit, +network-disabled plan, and successful completion. It fails closed to unknown +rather than treating a lost response as refusal or confirmed execution. + +Reproduced locally as 45 unit tests passing (six new controls). Live run: + +- Transaction: `edrg-632c5f773d8d42d980f59b4dbcaf72fb` +- Result: `observed-live-conduit-inspect` +- VPS commit: `53c3399c1fa74a985cd74de3c40d48ca02e53bfb` +- Start receipt: `24656869ff9decd0bc3fff92f06f8932eb68f14f268b71eb0236cce8c2eedfe5` +- Final receipt: `80474eeaa16bdc78cd6c6bf5bc3f3c146049d74be02c2bd9c7d6c798de8eb2a8` +- Classification: live two-host, same operator; SHA-256 chained software receipts + +Run the *optional, host-specific* probe on a configured Prometheus: +`PYTHONPATH=integrations/agentrust-confidential-workflow-harness python -c 'from harness.conduit_live import run; print(run(transaction_id="unique-id", repo="/home/ubuntu/src/integrations", cli="/home/triangulatorium/.local/bin/frequency-conduit"))'` + +This bridge does **not** issue a cA2A credential, verify a real cA2A peer +attestation, create a remote cA2A authenticated response, or produce a TRACE +standard-conforming externally attested execution receipt. It also does not +provide independently operated or hardware-backed evidence. The validated +hash-chain alone is not a digital signature and is not tamper proof against +the operator who controls the receipt store. Those distinctions remain release +gates for upstream Issue #199 and should not be elided. + +## Released cA2A holder-bound delegation preflight + +The `released_delegation` and `delegated_conduit` modules now verify a +released `ca2a-runtime==0.4.0` signed delegation against an explicitly supplied +trusted root, a challenge-bound holder-possession proof, requested capability, +and local policy **before** the cMCP/Conduit job begins. Negative tests prove +untrusted roots, holder substitution, and altered scope cannot dispatch. This +extends the local composition to 55 tests. + +The challenge and peer appraisal are process-local to the origin and the test +keys are ephemeral. The remote VPS has not checked a cA2A credential. Therefore +this remains **not cA2A peer delivery or independently enrolled verification**. +Neither cryptographic authentication of the remote Conduit job receipt nor a +TRACE-standard external attestation has been added. Do not mark full Issue #199 +acceptance complete based on these tests. + +### Composed software live control (October 16) + +The origin verified an ephemeral signed cA2A 0.4.0 delegation and +holder-possession proof, then the published cMCP 0.7.0 tool gate, then invoked +the existing VPS Conduit restricted `inspect` job over SSH. Results: + +- Origin transaction: `composed-14243eb31122473282b779da9daf0551` +- Software Conduit start receipt SHA-256: `425dd606ea4a887424d18be6981abd4a72a5aced60d96d1a207b3e8bb845d4d6` +- Software Conduit final receipt SHA-256: `a37c5933fb472416fa8fb0cd9d5b7d2cafd5ad15ba5733fbe882eec93a8df92b` +- Result: `observed-live-conduit-inspect` +- cA2A peer transport: **false**; remote TRACE verification: **false** + +The issuer and holder keys were generated and trusted on the origin during this +experiment. No separate remote peer enrolled or verified them. This is genuine +remote Conduit software execution after origin-side preflight, not a claim of +end-to-end remotely enforced cA2A delegation or TRACE acceptance. diff --git a/integrations/agentrust-confidential-workflow-harness/README.md b/integrations/agentrust-confidential-workflow-harness/README.md index a352a39f..adc546c8 100644 --- a/integrations/agentrust-confidential-workflow-harness/README.md +++ b/integrations/agentrust-confidential-workflow-harness/README.md @@ -6,7 +6,7 @@ and preserves unavailable evidence instead of inferring success from dispatch. ## Scope of this PR -This initial implementation provides: +The expanded experimental implementation provides: - a fixed harness core; - machine-readable manifest and result schemas; @@ -16,8 +16,10 @@ This initial implementation provides: - branch-preserving observations for retries; - causal provenance fields (`caused_by`) on observations. -It does **not** claim cMCP or cA2A conformance, live-peer acceptance, hardware -attestation, or completion of the full software milestone. +The published release API calls and one first-party software peer path are +exercised, but this is not a claim of independently established protocol +conformance, hardware attestation or completed Issue #199 acceptance. +See [About, licensing, IP boundaries, glossary and live-peer threat model](REMOTE-CA2A-PEER.md). ## Reproduce @@ -25,11 +27,10 @@ attestation, or completion of the full software milestone. python -m unittest discover -s tests -v ``` -The deterministic adapter records the package release targets that will be used -when protocol-specific adapters are wired: +The released component and bounded live-peer experiments use: -- `cmcp-runtime==0.5.0` -- `ca2a-runtime==0.2.0` +- `cmcp-runtime==0.7.0` +- `ca2a-runtime==0.4.0` Protocol/API changes remain in the owning repositories. Any scenario that needs an unreleased surface must carry `waiting_on_release`; a blocked required case diff --git a/integrations/agentrust-confidential-workflow-harness/RELEASED-API-PROBE.md b/integrations/agentrust-confidential-workflow-harness/RELEASED-API-PROBE.md new file mode 100644 index 00000000..5af1a0db --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/RELEASED-API-PROBE.md @@ -0,0 +1,33 @@ +# Experimental released-protocol interoperability and authenticated response + +This deterministic acceptance milestone executes the published `cmcp-runtime==0.7.0` +`MCPGateway.intercept_tool_call` and `ca2a-runtime==0.4.0` +`emit_dag` / `trace_record_hash` APIs, plus +`PendingResponse` / `ResponseProducer` authenticated response verification. +Positive and refusal tests are paired. All dependencies are transitively pinned +by the SHA-256 hash-locked requirements file. + +A local test-generated X25519 peer key is marked assurance `none`, rather than +hardware-verified. Signed TRACE DAG records use temporary Ed25519 keys and a +synthetic source. The actual dispatch count is zero. This is **not** a live +model, tool or network workflow. + +Reproduce from the repository root with Python 3.12: + +```sh +python -m pip install --require-hashes -r requirements/confidential-workflow-probe.txt +cd integrations/agentrust-confidential-workflow-harness +python -m unittest discover -s tests -v +``` + +The authenticated-response probe covers permitted execution, unauthorized tool, +MAC alteration, single-use replay, expiry, signed denial, request/response +context mismatch, and unobserved receipt remaining unknown. The valid twin is +executed independently for each adversarial case. It does **not** establish +independent issuer enrollment, externally operated peer receipt, a real execution +side effect, secure confinement or hardware-backed runtime measurement. + +Issue #199 must remain open until actual mediated tool and peer network transport, +independent boundary observations, composed mutation testing, and independently +operated live evidence are produced and externally reproduced. Component +interoperability may not be substituted for these requirements. diff --git a/integrations/agentrust-confidential-workflow-harness/REMOTE-CA2A-PEER.md b/integrations/agentrust-confidential-workflow-harness/REMOTE-CA2A-PEER.md new file mode 100644 index 00000000..1c237ec8 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/REMOTE-CA2A-PEER.md @@ -0,0 +1,144 @@ +# About: bounded cA2A + cMCP + TRACE software federation experiment + +This is a **public reference integration**, built for AgenTrust integrations +Issue #199. It combines the independently published +`cmcp-runtime==0.7.0`, `ca2a-runtime==0.4.0`, and +`agentrust-trace==0.11.0` APIs with Frequency Conduit's separately operated +*software process* on another host. It does not incorporate proprietary OPAQUE, +Anthropic, or other confidential-computing software, and does not claim +institutional endorsement by those organizations. + +The repository's root `LICENSE` is Apache-2.0. External runtime packages are +separate dependencies, not re-licensed by this submission: the installed +distribution metadata identifies `cmcp-runtime` and `ca2a-runtime` as MIT, +`agentrust-trace` as Apache-2.0, and `cryptography` as +Apache-2.0 OR BSD-3-Clause. Their own upstream source, copyright notices and +licenses remain authoritative. Frequency first-party private authority, +production deployment configuration, service keys, and any unpublished +software are not transferred or relicensed by the integration. + +## What is actually implemented + +1. The originating host calls the **published cMCP gateway** to authorize + `conduit.inspect` and creates one cA2A `PendingResponse` occurrence. +2. The remote VPS forced SSH command issues an expiring cA2A challenge and + publishes a *pinned software channel public key*. The caller uses signed + cA2A `DelegationCredential` and an Ed25519 holder-possession proof bound + to the remote audience, challenge, capability and **hash of the exact + authenticated request envelope**. +3. The remote peer independently verifies the chain against a + **pre-enrolled issuer key**, local capability scope and holder possession. + A persistent SQLite replay ledger consumes the challenge before dispatch. +4. Only the fixed, network-disabled Frequency Conduit `inspect` intent is + permitted. No arbitrary shell command is exposed by the peer. +5. The remote response is authenticated using published + `ResponseProducer`/`PendingResponse.verify` primitives and binds the + source transaction, request hash, nonce, reported Conduit receipt hashes, + commit and exit status. +6. The remote process signs a **TRACE v0.2 Level 0 software record** and an + independently Ed25519-signed companion manifest binding the exact request + and Conduit observations. The origin verifies the TRACE signature and + companion manifest with an **out-of-band pinned remote signing key**. The + manifest is separate so TRACE's `policy.bundle_hash` continues to describe + the actual static access policy rather than falsely representing a receipt. + +The remote endpoint is deployed in a *separate virtual environment* using a +SHA-256 hash-locked dependency set; it is reachable only as an SSH forced +command using a dedicated restricted key, not a new public TCP listener. + +## Evidence and claims NOT established + +- Hardware TEE/TPM attestation, confidential inference, protected model + weights, protected key release or confidential data disclosure. +- Independent organizational custody: the test's source host, remote host, + issuer enrolment and verifier signing key are all under one operator. +- Live signed revocation checking, real external delegated peers, and + authoritative validation of the claimed software image identity. +- A successful read-only `inspect` job is not proof of actual mediated + sensitive-data access or a confidential AI model computation. +- The TRACE record is Level 0 software evidence and uses the documented + software-mode placeholder URIs, not a hardware RIM or transparency proof. +- Approval, merger, or standards conformance across every scenario in Issue + #199. Those require Dinakar's independent matrix and authorized maintainer + review on the exact frozen commit. + +## Reproduction and deployment controls + +The upstream CI runs unit tests against hash-pinned package releases without +any external SSH key. For a live controlled laboratory, an operator must +separately provision **on the VPS** the channel X25519 private key, challenge +HMAC secret, issuer public key, TRACE Ed25519 signing key and replay database +in `~/.local/state/frequency-ca2a-peer`. Secrets must be mode 0600 and the +directory mode 0700. The matching channel and TRACE public keys must be +pinned independently **on the originating host**. The forced SSH command +executes `python -m harness.remote_peer_service` and has no PTY, port +forwarding or unrestricted shell. Do not commit any operator keys or +deployment configuration. Do not assume that generated test keys are +independent attestation authorities. + +A live test needs the separately deployed pinned remote peer, the local +operator identity, and a valid existing Conduit `inspect` repository. Use +`run_remote_ca2a_live.py` only in the recorded first-party lab environment. +**Never** retry an uncertain `execute` occurrence automatically: a lost +response can conceal a completed side effect. + +## Evidence-driven release gate + +The complete production gate remains **BLOCKED** until both protocol-specific +remote positive and negative tests and independent third-party replay pass, +the signature/issuer and revocation custody are independently controlled, +and the acceptance scope includes mediated tool calls, uncertain deliveries, +release/disclosure and valid control/mutation twins. Mark every evidence item +as synthetic, same-operator live software, or independently anchored hardware; +never promote a lower class because its checks are green. + +## Technical glossary + +| Project term | Standard equivalent | +|---|---| +| Frequency Conduit node | Authorized remote execution worker and RPC endpoint | +| EDRG | Evidence-driven release acceptance gate | +| Governance admission | cMCP policy decision / tool-call authorization | +| Delegation | Signed capability credential / delegated authorization | +| Holder proof | Proof of possession of an Ed25519 delegation key | +| cA2A channel | Per-request X25519-derived authenticated response channel | +| Peer appraisal | Verification of issuer, subject, scope and possession | +| Receipt binding | Cryptographic commitment to request and observed result | +| TRACE Level 0 | Software-signed provenance record without hardware attestation | +| Evidence manifest | Signed, canonicalized statement of observed execution facts | +| Receipt hash chain | Tamper-evident append-only log linkage, not independent custody | +| Replay ledger | Persistent single-use nonce/challenge consumption database | +| Unknown delivery | Indeterminate execution outcome after lost confirmation | +| Mutation twin | Positive control paired with one deliberately weakened safety guard | +| Independent verifier | Separately controlled party reproducing acceptance evidence | + +## Private lab live run and evidence export + +The operator supplies a local mode-0600 JSON config with SSH key **path**, +issuer and holder private key **paths**, pinned public keys, permitted repo, +and SSH hostname (never the private key contents). The following commands +create a fresh occurrence and an offline packet in an operator-controlled +private directory: + +```sh +python run_remote_ca2a_live.py --config /private/client.json --evidence-out /private/new-evidence.json +python run_remote_ca2a_matrix.py --config /private/client.json --output /private/new-matrix.json +``` + +The signed, non-sensitive example packet and verification instructions are +available in [evidence/](evidence/). The public fixture intentionally excludes +private keys, live SSH credentials, session challenge and raw authorization +payloads; the reviewer must enroll the public key through a distinct trust +channel. The exported packet is useful for *historical software signature +verification*, not live session-MAC replay or hardware assurance. + +## Expiry and revocation enforcement boundary + +The origin now issues transaction-specific signed cA2A credentials with a +**60-second default expiry** and a five-second clock-skew allowance. An +expired credential was refused by the remote VPS in the 11-case live matrix. +The released SDK unit/mutation suite also proves signed revocation and stale +revocation-snapshot refusal with valid twins. **No live independently supplied +revocation snapshot has been enrolled on the VPS**, because a fresh-looking +operator-authored snapshot must not be treated as independent revocation +authority. That remains a separate release gate. diff --git a/integrations/agentrust-confidential-workflow-harness/evidence/README.md b/integrations/agentrust-confidential-workflow-harness/evidence/README.md new file mode 100644 index 00000000..e2cbf037 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/evidence/README.md @@ -0,0 +1,52 @@ +# Independently replayable software-signature evidence + +The accompanying `live-software-20261016.json` is an **actual** Prometheus → +VPS software execution packet generated October 16, 2026. It contains a +TRACE v0.2 Level 0 record signed with the VPS's Ed25519 software key, a separate +signed companion manifest bound to the cA2A request hash, and hashes of the +Frequency Conduit start and completion receipts. It does **not** contain +private keys, raw cA2A holder proofs, decrypted confidential data or the VPS +network address. + +Packet file SHA-256: + +`402a8f0cc05bc517d2918e7a49b10051cb60122fcac8909f1a9ed308c12fdc13` + +## Offline verification + +Use the hash-locked released dependencies from the repository root. Then from +the harness directory: + +```sh +python verify_remote_peer_packet.py \ + --packet evidence/live-software-20261016.json \ + --trace-public 2c6ba06dde1a1a7dc8c9676a7c38de76c3f2df6268413cc27779bc6eb0c2d7f1 \ + --issuer-public 880a6aa8cd1976f69176cb1a095b5deb8449579d253b14003fc14ff9d983ed02 \ + --peer-public 69a7a6092973975edd92b2a836704a5c90c462825e69a08d20996e795a854d3d +``` + +**Trust warning:** The three public keys above are disclosed *by the same +operator that controls both hosts*. They allow anyone to independently +recompute and check the signatures, but do not establish externally enrolled +identity, independent key custody, or hardware attestation. Reviewers must +authenticate the keys through a separate trusted channel before using them +as externally trusted identities. + +Offline replay deliberately disables **current-age** enforcement to validate +a historical signed record. This cannot demonstrate *current* nonce freshness +or reproduce the cA2A session MAC: the official `PendingResponse` refuses +export or reuse of its ephemeral state by design. Live validation must instead +rerun the peer interaction, with a new challenge and nonce. Signatures prove +that the pinned software signer endorsed the recorded claims, **not** that an +external observer independently measured the job or confidential execution. +The underlying Conduit receipt log remains under the same operator. + +See [About, licensing, glossary and assurance boundaries](../REMOTE-CA2A-PEER.md). + +The packet's `peer_public_key` is unsigned export metadata. Comparing it to +`--peer-public` checks metadata consistency; the TRACE/companion signatures +do not cryptographically bind that channel key. The verifier reports +`peer_channel_binding: metadata-only-not-signed`. Relabelling that metadata +and supplying a different expected peer pin does not invalidate the software +signatures. Authenticate the live cA2A channel separately; offline signature +verification cannot establish which channel carried the recorded exchange. diff --git a/integrations/agentrust-confidential-workflow-harness/evidence/live-software-20261016.json b/integrations/agentrust-confidential-workflow-harness/evidence/live-software-20261016.json new file mode 100644 index 00000000..8f026592 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/evidence/live-software-20261016.json @@ -0,0 +1,75 @@ +{ + "evidence_class": "live-software-two-host-same-operator", + "execution": { + "commit_sha": "53c3399c1fa74a985cd74de3c40d48ca02e53bfb", + "exit_code": 0, + "finish_receipt_hash": "1d9569f7eeb5693faeed052511f89a0032361fb5b06a031d81a6a0ae19f3726c", + "session_id": "fe9c3918-8449-4a86-a722-0193ff1288f1", + "start_receipt_hash": "e3b1547af56264cdb790cbe86d7a313cb5d3d69dd28a9f2dd42e25dab898b63b" + }, + "nonce": "94594cfc2fdc4baca89bce376ddbbcaa", + "origin_ca2a_verification": "passed-in-process-not-exportable", + "peer_public_key": "69a7a6092973975edd92b2a836704a5c90c462825e69a08d20996e795a854d3d", + "repo": "/home/ubuntu/src/integrations", + "request_sha256": "4d20e95870afa4eda47776c9a92d43543522678e1c6f30aac98a52a6f39034f2", + "schema": "frequency-ca2a-trace-replay-packet/1", + "trace_bundle": { + "manifest": { + "assurance": "software-only-same-operator", + "capability": "conduit.inspect", + "execution": { + "commit_sha": "53c3399c1fa74a985cd74de3c40d48ca02e53bfb", + "exit_code": 0, + "finish_receipt_hash": "1d9569f7eeb5693faeed052511f89a0032361fb5b06a031d81a6a0ae19f3726c", + "session_id": "fe9c3918-8449-4a86-a722-0193ff1288f1", + "start_receipt_hash": "e3b1547af56264cdb790cbe86d7a313cb5d3d69dd28a9f2dd42e25dab898b63b" + }, + "nonce": "94594cfc2fdc4baca89bce376ddbbcaa", + "policy_bundle_hash": "sha256:edb1c936ac9e922da1ef8e6c382f14a7d65d4076472c6f8ec19d50bfb3be4956", + "repo": "/home/ubuntu/src/integrations", + "request_sha256": "4d20e95870afa4eda47776c9a92d43543522678e1c6f30aac98a52a6f39034f2", + "schema": "frequency-ca2a-software-manifest/1", + "trace_record_hash": "sha256:f830659f2af40ff74a42b48e04b1a6c544c41f25e9863c18aae56adc70ff77a5", + "transaction_id": "live-ca2a-a40f23585ad2451f9c738971ae64c050" + }, + "record": { + "appraisal": { + "status": "none", + "verifier": "https://appraisal.invalid/software-mode" + }, + "build_provenance": { + "digest": "sha256:ee038106752c12b17ed8384d8327b658173704a7ce1276a5a8c182ccb162e00f", + "slsa_level": 0 + }, + "cnf": { + "jwk": { + "crv": "Ed25519", + "kty": "OKP", + "x": "LGugbd4aGn3IyWdqfDjedsPy32JoQTzCd3m8brDC1_E" + } + }, + "data_class": "confidential", + "eat_profile": "tag:agentrust-io.com,2026:trace-v0.2", + "iat": 1792165120, + "model": { + "model_id": "conduit-inspect-no-model", + "provider": "frequency-software-only" + }, + "policy": { + "bundle_hash": "sha256:edb1c936ac9e922da1ef8e6c382f14a7d65d4076472c6f8ec19d50bfb3be4956", + "enforcement_mode": "enforce" + }, + "runtime": { + "measurement": "sha256:747428e46e6150aecb29100aec4eb8de7c343bbac0f3ea8b051457d58d6270e0", + "nonce": "94594cfc2fdc4baca89bce376ddbbcaa", + "platform": "software-only" + }, + "signature": "wVJeZkY1GP89VqSTUkNK-0wIkMvx6Djxt_MiT9ZuicnwZmSVEnc6eXE-FuHzwMWF3hWrzlZNOv2RsDTVgrlZAg", + "subject": "did:example:frequency-ca2a-vps-software", + "transparency": "https://transparency.invalid/software-mode" + }, + "signature": "d7ccc70413f9dbf17feedc59c30857329fafa5fb9000f9f3818fc7eaffe368d5d281c9ba6276effa0d6eb2e79df33a7c09e82e57f0df0b58e3561982b3b8fb01" + }, + "transaction_id": "live-ca2a-a40f23585ad2451f9c738971ae64c050", + "trusted_issuer": "880a6aa8cd1976f69176cb1a095b5deb8449579d253b14003fc14ff9d983ed02" +} diff --git a/integrations/agentrust-confidential-workflow-harness/harness/authenticated_exchange.py b/integrations/agentrust-confidential-workflow-harness/harness/authenticated_exchange.py new file mode 100644 index 00000000..f2461a4e --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/authenticated_exchange.py @@ -0,0 +1,67 @@ +"""Bounded, in-process cMCP admission and cA2A authenticated-response exercise. + +This is NOT network delivery, hardware attestation or independent verification. +The caller explicitly appraises a test-generated software key at assurance 'none'. +""" +from dataclasses import dataclass +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cmcp_runtime.runtime_gateway import MCPGateway, GovernancePolicy +from ca2a_runtime.attestation import VerifiedPeer +from ca2a_runtime.response import PendingResponse, ResponseProducer, decode, encode + +@dataclass(frozen=True) +class ExchangeResult: + outcome: str + request_sha256: str | None = None + observation: str = "synthetic-process-local" + actual_dispatches: int = 0 + +def exchange(*, transaction_id: str, nonce: str, allowed: bool = True, + tamper: bool = False, replay: bool = False, + expired: bool = False, refusal: bool = False, + binding_mismatch: bool = False, missing_receipt: bool = False) -> ExchangeResult: + if not transaction_id or not nonce: + return ExchangeResult("refused-missing-context") + gateway = MCPGateway(GovernancePolicy(allowed_tools=["test-tool"] if allowed else [])) + ok, _ = gateway.intercept_tool_call("test-agent", "test-tool", + {"transaction_id": transaction_id, "nonce": nonce}) + if not ok: + return ExchangeResult("refused-authorization") + key = X25519PrivateKey.generate() + peer = VerifiedPeer(key.public_key().public_bytes_raw().hex(), "none", "synthetic") + now = [10.0] + pending = PendingResponse(peer, {"transaction_id": transaction_id, "nonce": nonce}, + timeout=5.0, clock=lambda: now[0]) + producer = ResponseProducer(key, decode(pending.request_bytes)) + if missing_receipt: + return ExchangeResult("unknown-unobserved-delivery", pending.request_sha256) + if refusal: + raw = encode(producer.finish(403, {"error": {"code": "denied"}})) + try: + verified = pending.verify(403, raw) + return ExchangeResult("refused-authenticated", verified.request_sha256) + except Exception: + return ExchangeResult("unknown-verification-error", pending.request_sha256) + body = {"accepted": True, "transaction_id": transaction_id, "nonce": nonce} + if binding_mismatch: + body["nonce"] = "wrong-" + nonce + raw = encode(producer.finish(200, body)) + if tamper: + altered = decode(raw) + altered["body"]["nonce"] = "tampered" + raw = encode(altered) + if expired: + now[0] = 16.0 + try: + verified = pending.verify(200, raw) + if verified.body.get("transaction_id") != transaction_id or verified.body.get("nonce") != nonce: + return ExchangeResult("refused-response-binding", verified.request_sha256) + if replay: + try: + pending.verify(200, raw) + except Exception: + return ExchangeResult("refused-replay", verified.request_sha256) + return ExchangeResult("unsafe-replay-accepted", verified.request_sha256) + return ExchangeResult("authenticated-process-local", verified.request_sha256) + except Exception: + return ExchangeResult("refused-response-authentication", pending.request_sha256) diff --git a/integrations/agentrust-confidential-workflow-harness/harness/conduit_live.py b/integrations/agentrust-confidential-workflow-harness/harness/conduit_live.py new file mode 100644 index 00000000..f975acc1 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/conduit_live.py @@ -0,0 +1,92 @@ +"""Bounded live cMCP-to-Conduit experiment, not a cA2A peer acceptance claim. + +Uses the published cMCP admission API, then an existing locked-down Conduit +CLI SSH transport to run an approved, non-networked 'inspect' intent remotely. +The remote receipt is hash chained but NOT digitally signed or independent. +""" +import hashlib +import json +import subprocess +from dataclasses import dataclass +from pathlib import Path + +from cmcp_runtime.runtime_gateway import GovernancePolicy, MCPGateway + + +@dataclass(frozen=True) +class LiveResult: + outcome: str + transaction_id: str + start_hash: str | None = None + finish_hash: str | None = None + commit_sha: str | None = None + evidence_class: str = "live-two-host-same-operator" + assurance: str = "software-hash-chain-only" + + +def _call(cli: str, action: str, params: dict, timeout: int = 45) -> dict: + process = subprocess.run( + [cli, "call", "vps", action, "--params", json.dumps(params, sort_keys=True)], + stdin=subprocess.DEVNULL, capture_output=True, text=True, timeout=timeout, + check=False, + ) + if process.returncode: + raise RuntimeError("conduit-transport-failure") + response = json.loads(process.stdout) + if not isinstance(response, dict): + raise ValueError("non-object-conduit-response") + return response + + +def _receipt_hash(r: dict) -> bool: + if not isinstance(r, dict) or not isinstance(r.get("hash"), str): + return False + material = {k: v for k, v in r.items() if k != "hash"} + digest = hashlib.sha256(json.dumps(material, sort_keys=True, separators=(",", ":")).encode()).hexdigest() + return digest == r["hash"] + + +def run(*, transaction_id: str, repo: str, cli: str, + tool_allowed: bool = True, transport=_call) -> LiveResult: + if not transaction_id or not repo or not Path(cli).is_file(): + return LiveResult("invalid-request", transaction_id) + admitted, _ = MCPGateway(GovernancePolicy( + allowed_tools=["conduit.inspect"] if tool_allowed else [], + max_tool_calls=1, + )).intercept_tool_call("frequency-live-harness", "conduit.inspect", + {"transaction_id": transaction_id, "repo": repo}) + if not admitted: + return LiveResult("refused-cmcp", transaction_id) + try: + start = transport(cli, "job_start", {"intent": "inspect", "repo": repo}) + if not start.get("ok"): + return LiveResult("refused-conduit", transaction_id) + sr = start["receipt"] + job = start["result"] + session = job["session_id"] + if (not _receipt_hash(sr) or sr["status"] != "PASS" + or sr["action"] != "job_start" or sr["node"] != "vps-377a113a" + or sr.get("detail", {}).get("session_id") != session + or job.get("intent") != "inspect" + or job.get("network") is not False): + return LiveResult("untrusted-start", transaction_id) + poll = transport(cli, "job_poll", {"session_id": session}) + if not poll.get("ok"): + return LiveResult("unknown-unobserved-result", transaction_id, sr["hash"]) + fr = poll["receipt"] + finished = poll["result"] + if (not _receipt_hash(fr) or fr.get("action") != "job_poll" + or fr.get("node") != sr["node"] + or fr.get("detail", {}).get("session_id") != session + or fr.get("prev_hash") != sr["hash"] + or finished.get("session_id") != session + or finished.get("running") or finished.get("exit_code") != 0 + or finished.get("commit_sha") != job.get("commit_sha") + or finished.get("commit_sha_end") != job.get("commit_sha") + or finished.get("worktree_clean_start") is not True + or finished.get("worktree_clean_end") is not True): + return LiveResult("untrusted-or-unsuccessful-result", transaction_id, sr["hash"]) + return LiveResult("observed-live-conduit-inspect", transaction_id, + sr["hash"], fr["hash"], job["commit_sha"]) + except (ValueError, KeyError, TypeError, OSError, subprocess.TimeoutExpired, RuntimeError): + return LiveResult("unknown-transport-or-protocol", transaction_id) diff --git a/integrations/agentrust-confidential-workflow-harness/harness/delegated_conduit.py b/integrations/agentrust-confidential-workflow-harness/harness/delegated_conduit.py new file mode 100644 index 00000000..b1eec507 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/delegated_conduit.py @@ -0,0 +1,35 @@ +"""Compose released cA2A holder authorization and cMCP remote Conduit admission. + +Both authorization checks occur on the originating host before live dispatch. +This is NOT actual cA2A network transport or a remotely issued peer receipt. +""" +from dataclasses import dataclass +from harness.conduit_live import run as conduit_run +from harness.released_delegation import appraise + + +@dataclass(frozen=True) +class CompositionResult: + outcome: str + transaction_id: str + start_hash: str | None = None + finish_hash: str | None = None + evidence_class: str = "software-two-host-same-operator" + ca2a_peer_transport: bool = False + trace_verification: bool = False + + +def run(*, transaction_id: str, repo: str, cli: str, + credential, holder_private, trusted_issuer: str, + transport=None) -> CompositionResult: + decision = appraise( + credential=credential, holder_private=holder_private, + trusted_issuer=trusted_issuer, record_id=transaction_id) + if not decision.granted: + return CompositionResult("refused-ca2a-delegation", transaction_id) + args = {"transaction_id": transaction_id, "repo": repo, "cli": cli} + if transport is not None: + args["transport"] = transport + result = conduit_run(**args) + return CompositionResult(result.outcome, transaction_id, + result.start_hash, result.finish_hash) diff --git a/integrations/agentrust-confidential-workflow-harness/harness/released_delegation.py b/integrations/agentrust-confidential-workflow-harness/harness/released_delegation.py new file mode 100644 index 00000000..c20ea70a --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/released_delegation.py @@ -0,0 +1,61 @@ +"""Released cA2A 0.4.0 holder-bound delegation check. + +The verifier's root is explicitly supplied by the caller. It is NOT enrolled +with a remote independently controlled peer. The signed delegation and +holder proof are independently checked by the published runtime. +""" +from dataclasses import dataclass +from ca2a_runtime.delegation import build_holder_proof +from ca2a_runtime.delegation.credential import DelegationCredential +from ca2a_runtime.peer import PeerRequest, handle_peer_request +from ca2a_runtime.policy import LocalPolicy +from ca2a_runtime.challenge import generate_secret, issue_challenge +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey + + +@dataclass(frozen=True) +class DelegationDecision: + granted: bool + reason: str + record_id: str + + +def appraise(*, credential: DelegationCredential, holder_private, + trusted_issuer: str, record_id: str, + capability: str = "conduit.inspect", + local_capabilities=frozenset({"conduit.inspect"}), + challenge_secret=None, + holder_proof=None, revocations=None, + max_revocation_staleness=None) -> DelegationDecision: + if not record_id or not trusted_issuer: + return DelegationDecision(False, "missing-context", record_id) + # The challenge and audience are bound to a single local verifier occurrence. + # Supplying proof overrides is intended for negative tests; other callers + # must generate their proof for this verifier's challenge themselves. + if challenge_secret is None: + challenge_secret = generate_secret() + challenge = issue_challenge(challenge_secret) + channel = X25519PrivateKey.generate() + audience = channel.public_key().public_bytes_raw().hex() + try: + if holder_proof is None: + holder_proof = build_holder_proof( + holder_private, credential, audience=audience, + challenge=challenge, requested_capability=capability, + record_id=record_id) + except Exception as exc: + return DelegationDecision(False, type(exc).__name__, record_id) + request = PeerRequest([credential], capability, record_id, holder_proof=holder_proof) + try: + result = handle_peer_request( + request, policy=LocalPolicy(frozenset(local_capabilities)), + trusted_root_issuers={trusted_issuer}, + require_holder_proof=True, + challenge_secret=challenge_secret, audience=audience, + revocations=revocations, + max_revocation_staleness=max_revocation_staleness) + return DelegationDecision( + result.granted_capability == capability, + "released-ca2a-holder-and-delegation-verified", record_id) + except Exception as exc: + return DelegationDecision(False, type(exc).__name__, record_id) diff --git a/integrations/agentrust-confidential-workflow-harness/harness/released_protocol_probe.py b/integrations/agentrust-confidential-workflow-harness/harness/released_protocol_probe.py new file mode 100644 index 00000000..b369545d --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/released_protocol_probe.py @@ -0,0 +1,47 @@ +"""Synthetic interoperability probe of released cMCP and cA2A APIs. + +No tool is dispatched and no live or hardware assurance is claimed. +""" +from dataclasses import dataclass +from importlib.metadata import version +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from cmcp_runtime.runtime_gateway import GovernancePolicy, MCPGateway +from ca2a_runtime.trace_binding import HopContext, HopSpec, emit_dag, trace_record_hash + +@dataclass(frozen=True) +class ProbeResult: + admitted: bool + reason: str + versions: dict[str, str] + hashes: tuple[str, ...] + evidence_class: str = "synthetic" + actual_dispatches: int = 0 + +def probe(*, transaction_id: str, subject: str, tool_name: str, + allowed_tools: tuple[str, ...], policy_digest: str, nonce: str) -> ProbeResult: + versions = {"cmcp-runtime": version("cmcp-runtime"), + "ca2a-runtime": version("ca2a-runtime")} + if versions != {"cmcp-runtime":"0.7.0", "ca2a-runtime":"0.4.0"}: + return ProbeResult(False, "unpinned-version", versions, ()) + if not transaction_id or not subject or not nonce or len(policy_digest) != 71 or not policy_digest.startswith("sha256:") or any(c not in "0123456789abcdef" for c in policy_digest[7:]): + return ProbeResult(False, "invalid-context", versions, ()) + gateway = MCPGateway(GovernancePolicy(allowed_tools=list(allowed_tools), max_tool_calls=1)) + try: + allowed, reason = gateway.intercept_tool_call(subject, tool_name, {"transaction_id":transaction_id, "nonce":nonce, "policy_digest":policy_digest}) + except Exception: + return ProbeResult(False, "gateway-error", versions, ()) + if not allowed: + return ProbeResult(False, reason, versions, ()) + ctx = HopContext.software(model_provider="synthetic", model_id="no-model-run", + image_label="interoperability-probe", policy_bundle_hash=policy_digest, + runtime_nonce=nonce) + hops = [HopSpec(subject=f"{subject}:{transaction_id}", signing_key=Ed25519PrivateKey.generate(), context=ctx, iat=1), + HopSpec(subject=f"peer:{transaction_id}", signing_key=Ed25519PrivateKey.generate(), context=ctx, iat=2, credential_id=f"test:{transaction_id}")] + try: + records = emit_dag(hops) + hashes = tuple(trace_record_hash(record) for record in records) + except Exception: + return ProbeResult(False, "trace-api-error", versions, ()) + if len(hashes) != 2 or not all(hashes): + return ProbeResult(False, "missing-evidence", versions, ()) + return ProbeResult(True, "published-apis-executed-only", versions, hashes) diff --git a/integrations/agentrust-confidential-workflow-harness/harness/remote_peer_client.py b/integrations/agentrust-confidential-workflow-harness/harness/remote_peer_client.py new file mode 100644 index 00000000..46e9b6ad --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/remote_peer_client.py @@ -0,0 +1,165 @@ +"""Live SSH-constrained released-cA2A request/response with caller-side cMCP. + +The responder independently enforces delegation and holder binding. Transport +is an existing pinned-host-key SSH connection; the response is authenticated +by ca2a-runtime 0.4.0. This remains software-only, same-operator evidence. +""" +import hashlib +import json +import time +import subprocess +from dataclasses import dataclass + +from ca2a_runtime.attestation import VerifiedPeer +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey +from harness.trace_live_binding import verify_bundle +from harness.replay_export import make_packet +from ca2a_runtime.delegation import build_holder_proof +from ca2a_runtime.delegation.credential import DelegationCredential +from ca2a_runtime.response import PendingResponse, decode, encode +from ca2a_runtime.errors import CA2AError +from cmcp_runtime.runtime_gateway import GovernancePolicy, MCPGateway + +CAPABILITY = "conduit.inspect" +SCHEMA = "frequency-ca2a-peer/1" + + +@dataclass(frozen=True) +class LivePeerResult: + outcome: str + transaction_id: str + request_sha256: str | None = None + start_receipt_hash: str | None = None + finish_receipt_hash: str | None = None + evidence_class: str = "live-software-two-host-same-operator" + peer_assurance: str = "none" + remote_ca2a_verified: bool = False + trace_verified: bool = False + trace_record_hash: str | None = None + + +def ssh_sender(host: str, key_path: str, *, timeout=20): + if not host or not key_path: + raise ValueError("pinned SSH endpoint and key required") + + def send(request): + proc = subprocess.run([ + "ssh", "-F", "/dev/null", "-T", + "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", + "-o", "ConnectTimeout=6", "-o", "ClearAllForwardings=yes", + "-o", "IdentitiesOnly=yes", + "-i", key_path, "ubuntu@" + host, "frequency-ca2a-peer", + ], input=encode(request), stdout=subprocess.PIPE, + stderr=subprocess.PIPE, timeout=timeout, check=False) + if proc.returncode != 0 or len(proc.stdout) > 131072: + raise RuntimeError("ssh-peer-failed-or-too-large") + response = json.loads(proc.stdout) + if not isinstance(response, dict): + raise ValueError("invalid-peer-response") + return response + + return send + + +def run(*, transaction_id: str, nonce: str, repo: str, issuer_private, + holder_private, peer_public_key: str, send, + permitted: bool = True, trace_public_key: str | None = None, + evidence_sink=None, credential_not_after_offset: int = 60) -> LivePeerResult: + if not transaction_id or not nonce or not peer_public_key: + return LivePeerResult("invalid-context", transaction_id) + if not trace_public_key: + return LivePeerResult("missing-trace-trust-anchor", transaction_id) + gateway = MCPGateway(GovernancePolicy( + allowed_tools=[CAPABILITY] if permitted else [], max_tool_calls=1)) + allowed, _ = gateway.intercept_tool_call("frequency-peer-origin", + CAPABILITY, { + "transaction_id": transaction_id, + "nonce": nonce, "repo": repo}) + if not allowed: + return LivePeerResult("refused-cmcp", transaction_id) + pending = None + try: + hello = send({"schema": SCHEMA, "method": "challenge"}) + if (hello.get("status") != 200 or + hello.get("peer_public_key") != peer_public_key or + hello.get("assurance") != "none" or + hello.get("capability") != CAPABILITY): + return LivePeerResult("refused-peer-identity", transaction_id) + challenge = hello["challenge"] + pending = PendingResponse(VerifiedPeer(peer_public_key, "none", "software"), + {"transaction_id": transaction_id, "nonce": nonce, "repo": repo, + "capability": CAPABILITY}, timeout=20) + issuer_pub = issuer_private.public_key().public_bytes_raw().hex() + holder_pub = holder_private.public_key().public_bytes_raw().hex() + now=int(time.time()) + credential = DelegationCredential( + credential_id="transaction:" + transaction_id, issuer=issuer_pub, + subject=holder_pub, scope=frozenset({CAPABILITY}), depth=0, + not_before=now-5, not_after=now+credential_not_after_offset).sign(issuer_private) + envelope = decode(pending.request_bytes) + record_id = hashlib.sha256(encode(envelope)).hexdigest() + proof = build_holder_proof(holder_private, credential, + audience=peer_public_key, challenge=challenge, + requested_capability=CAPABILITY, record_id=record_id) + response = send({"schema": SCHEMA, "method": "execute", + "envelope": envelope, + "credential": {**credential.body(), "signature": credential.signature}, + "holder_proof": proof.to_dict()}) + status = response["status"] + verified = pending.verify(status, encode(response["envelope"])) + if status == 403: + return LivePeerResult("refused-authenticated-peer", transaction_id, + verified.request_sha256, remote_ca2a_verified=False) + if status != 200: + return LivePeerResult("unknown-authenticated-execution", transaction_id, + verified.request_sha256, remote_ca2a_verified=False) + body = verified.body + execution = body.get("execution") + if (body.get("transaction_id") != transaction_id or + body.get("nonce") != nonce or + body.get("repo") != repo or + body.get("capability") != CAPABILITY or + body.get("assurance") != "software-only" or + not isinstance(execution, dict) or + execution.get("exit_code") != 0 or + not isinstance(execution.get("start_receipt_hash"), str) or + not isinstance(execution.get("finish_receipt_hash"), str)): + return LivePeerResult("refused-output-binding", transaction_id, + verified.request_sha256) + trace_hash = None + if trace_public_key is not None: + try: + trace_hash = verify_bundle( + body.get("trace_bundle"), + public_key=Ed25519PublicKey.from_public_bytes( + bytes.fromhex(trace_public_key)), + transaction_id=transaction_id, nonce=nonce, + request_sha256=verified.request_sha256, + repo=repo, execution=execution, + trusted_issuer=issuer_pub) + except Exception: + return LivePeerResult("untrusted-trace-evidence", transaction_id, + verified.request_sha256, remote_ca2a_verified=True) + if evidence_sink is not None: + try: + evidence_sink(make_packet( + transaction_id=transaction_id, nonce=nonce, + request_sha256=verified.request_sha256, + repo=repo, peer_public_key=peer_public_key, + trusted_issuer=issuer_pub, + trace_bundle=body["trace_bundle"], execution=execution)) + except Exception: + return LivePeerResult("unavailable-evidence-export", transaction_id, + verified.request_sha256, remote_ca2a_verified=True, + trace_verified=True, trace_record_hash=trace_hash) + return LivePeerResult("authenticated-remote-ca2a-software", transaction_id, + verified.request_sha256, + execution["start_receipt_hash"], + execution["finish_receipt_hash"], + remote_ca2a_verified=True, + trace_verified=trace_hash is not None, + trace_record_hash=trace_hash) + except (CA2AError, ValueError, TypeError, KeyError, OSError, RuntimeError, + subprocess.TimeoutExpired): + return LivePeerResult("unknown-or-refused-transport", transaction_id, + pending.request_sha256 if pending else None) diff --git a/integrations/agentrust-confidential-workflow-harness/harness/remote_peer_service.py b/integrations/agentrust-confidential-workflow-harness/harness/remote_peer_service.py new file mode 100644 index 00000000..90de850d --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/remote_peer_service.py @@ -0,0 +1,204 @@ +"""Restricted CA2A 0.4.0 peer acceptance service for one non-networked Conduit intent. + +The service is intended ONLY behind a separately restricted SSH forced command. +It is a software trust boundary, not a TEE; its issuer root and channel public +key must be provisioned and pinned out of band. Never expose as a public API. +""" +import hashlib +import json +import os +import sqlite3 +import subprocess +import sys +import time +from pathlib import Path + +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from harness.trace_live_binding import sign_bundle +from ca2a_runtime.challenge import issue_challenge +from ca2a_runtime.delegation.credential import DelegationCredential +from ca2a_runtime.delegation import HolderProof +from ca2a_runtime.peer import PeerRequest, handle_peer_request +from ca2a_runtime.policy import LocalPolicy +from ca2a_runtime.response import ResponseProducer, encode + + +CAPABILITY = "conduit.inspect" +REPO = "/home/ubuntu/src/integrations" +MAX_REQUEST = 65536 + + +def _canon(value): + return json.dumps(value, sort_keys=True, separators=(",", ":")).encode() + + +def _digest(value): + return hashlib.sha256(_canon(value)).hexdigest() + + +def _consume(path: Path, occurrence: str) -> bool: + """Atomic persistent replay refusal; failure is denial, not cache reset.""" + path.parent.mkdir(mode=0o700, parents=True, exist_ok=True) + db = sqlite3.connect(path, timeout=5) + try: + db.execute("CREATE TABLE IF NOT EXISTS spent (id TEXT PRIMARY KEY, seen INTEGER NOT NULL)") + try: + db.execute("INSERT INTO spent (id,seen) VALUES (?,?)", (occurrence, int(time.time()))) + db.commit() + return True + except sqlite3.IntegrityError: + db.rollback() + return False + finally: + db.close() + + +def _receipt_ok(receipt, action, session): + if not isinstance(receipt, dict): + return False + digest = receipt.get("hash") + body = {key: value for key, value in receipt.items() if key != "hash"} + return (isinstance(digest, str) and _digest(body) == digest + and receipt.get("action") == action + and receipt.get("status") == "PASS" + and receipt.get("detail", {}).get("session_id") == session) + + +def _agent(agent_path: str, action: str, params: dict, *, timeout=12) -> dict: + proc = subprocess.run([agent_path], input=_canon({ + "request_id": os.urandom(16).hex(), "action": action, "params": params + }), stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, + timeout=timeout, check=False) + if proc.returncode != 0 or len(proc.stdout) > 262144: + raise RuntimeError("conduit-operation-failed") + data = json.loads(proc.stdout) + if not isinstance(data, dict): + raise ValueError("malformed-conduit-response") + return data + + +def execute_job(agent: str, repo: str) -> dict: + started = _agent(agent, "job_start", {"intent": "inspect", "repo": repo}) + if not started.get("ok"): + raise RuntimeError("conduit-refused-start") + start = started["receipt"] + job = started["result"] + sid = job["session_id"] + if not (_receipt_ok(start, "job_start", sid) + and job.get("intent") == "inspect" + and job.get("network") is False + and job.get("repo") == repo): + raise RuntimeError("untrusted-conduit-start") + # There is intentionally no retry of job_start on uncertain delivery. + for _ in range(16): + polled = _agent(agent, "job_poll", {"session_id": sid}) + if not polled.get("ok"): + raise RuntimeError("unobserved-conduit-completion") + finished = polled["result"] + if finished.get("running"): + time.sleep(0.3) + continue + finish = polled["receipt"] + if not (_receipt_ok(finish, "job_poll", sid) + and finish.get("prev_hash") == start["hash"] + and finished.get("session_id") == sid + and finished.get("exit_code") == 0 + and finished.get("commit_sha") == job.get("commit_sha") + and finished.get("commit_sha_end") == job.get("commit_sha") + and finished.get("worktree_clean_start") is True + and finished.get("worktree_clean_end") is True): + raise RuntimeError("invalid-conduit-outcome") + return {"session_id": sid, "start_receipt_hash": start["hash"], + "finish_receipt_hash": finish["hash"], + "commit_sha": job["commit_sha"], "exit_code": 0} + raise RuntimeError("unknown-conduit-timeout") + + +def serve(request: dict, *, channel_private, challenge_secret: bytes, + trusted_issuer: str, replay_db: Path, + agent: str = "", allowed_repo: str = REPO, dispatch=None, + trace_private=None) -> dict: + if not isinstance(request, dict) or request.get("schema") != "frequency-ca2a-peer/1": + return {"status": 400, "error": "invalid-request"} + public = channel_private.public_key().public_bytes_raw().hex() + if request.get("method") == "challenge": + return {"status": 200, "challenge": issue_challenge(challenge_secret), + "peer_public_key": public, "assurance": "none", + "capability": CAPABILITY} + if request.get("method") != "execute": + return {"status": 400, "error": "unsupported-method"} + try: + envelope = request["envelope"] + producer = ResponseProducer(channel_private, envelope) + message = producer.envelope["request"] + except (KeyError, ValueError, TypeError): + return {"status": 400, "error": "malformed-request-envelope"} + try: + if (not isinstance(message, dict) + or set(message) != {"transaction_id", "nonce", "repo", "capability"} + or not isinstance(message["transaction_id"], str) + or not 5 <= len(message["transaction_id"]) <= 128 + or not isinstance(message["nonce"], str) + or not 8 <= len(message["nonce"]) <= 128 + or message["repo"] != allowed_repo + or message["capability"] != CAPABILITY): + raise ValueError("bad-scope") + credential = DelegationCredential.from_dict(request["credential"]) + proof = HolderProof.from_dict(request["holder_proof"]) + record_id = hashlib.sha256(encode(producer.envelope)).hexdigest() + handle_peer_request( + PeerRequest([credential], CAPABILITY, record_id, holder_proof=proof), + policy=LocalPolicy(frozenset({CAPABILITY})), + trusted_root_issuers={trusted_issuer}, + challenge_secret=challenge_secret, audience=public, + require_holder_proof=True) + # Persist the one-time occurrence before any possible side effect. + unique = hashlib.sha256( + proof.challenge.encode() + ).hexdigest() + if not _consume(replay_db, unique): + raise PermissionError("already-consumed") + except Exception: + return {"status": 403, "envelope": producer.finish(403, { + "error": {"code": "delegation-or-context-refused"}})} + try: + observed = ((dispatch or execute_job)(agent, allowed_repo)) + body = {"accepted": True, + "transaction_id": message["transaction_id"], + "nonce": message["nonce"], "repo": allowed_repo, + "capability": CAPABILITY, "execution": observed, + "assurance": "software-only"} + if trace_private is not None: + body["trace_bundle"] = sign_bundle( + key=trace_private, transaction_id=message["transaction_id"], + nonce=message["nonce"], request_sha256=producer.request_sha256, + execution=observed, repo=allowed_repo, + trusted_issuer=trusted_issuer) + return {"status": 200, "envelope": producer.finish(200, body)} + except Exception: + return {"status": 503, "envelope": producer.finish(503, { + "error": {"code": "execution-unknown"}})} + + +def main(): + cfg_path = Path("/home/ubuntu/.local/state/frequency-ca2a-peer/config.json") + cfg = json.loads(cfg_path.read_text()) + private = X25519PrivateKey.from_private_bytes( + bytes.fromhex(Path(cfg["private_key_path"]).read_text().strip())) + secret = bytes.fromhex(Path(cfg["challenge_secret_path"]).read_text().strip()) + trace_private = Ed25519PrivateKey.from_private_bytes( + bytes.fromhex(Path(cfg["trace_private_key_path"]).read_text().strip())) + raw = sys.stdin.buffer.read(MAX_REQUEST + 1) + if len(raw) > MAX_REQUEST: + raise SystemExit(1) + response = serve(json.loads(raw), channel_private=private, + challenge_secret=secret, + trusted_issuer=cfg["trusted_issuer"], + replay_db=Path(cfg["replay_db"]), agent=cfg["agent"], + allowed_repo=cfg["allowed_repo"], trace_private=trace_private) + sys.stdout.buffer.write(_canon(response) + b"\n") + + +if __name__ == "__main__": + main() diff --git a/integrations/agentrust-confidential-workflow-harness/harness/replay_export.py b/integrations/agentrust-confidential-workflow-harness/harness/replay_export.py new file mode 100644 index 00000000..454ca632 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/replay_export.py @@ -0,0 +1,71 @@ +"""Offline verification of a remote peer's signed software evidence packet. + +The peer is identified only by keys enrolled OUTSIDE the packet. This validates +software signatures and claim binding, not that the operator is independent or +that confidential execution or hardware attestations occurred. +""" +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey +from harness.trace_live_binding import verify_bundle + +SCHEMA = "frequency-ca2a-trace-replay-packet/1" + + +def make_packet(*, transaction_id, nonce, request_sha256, repo, + peer_public_key, trusted_issuer, trace_bundle, execution): + return { + "schema": SCHEMA, + "transaction_id": transaction_id, + "nonce": nonce, + "request_sha256": request_sha256, + "repo": repo, + "peer_public_key": peer_public_key, + "trusted_issuer": trusted_issuer, + "trace_bundle": trace_bundle, + "execution": execution, + "origin_ca2a_verification": "passed-in-process-not-exportable", + "evidence_class": "live-software-two-host-same-operator", + } + + +def verify_packet(packet: dict, *, trace_public_key: str, + trusted_issuer: str, peer_public_key: str) -> dict: + if not isinstance(packet, dict) or set(packet) != { + "schema", "transaction_id", "nonce", "request_sha256", "repo", + "peer_public_key", "trusted_issuer", "trace_bundle", "execution", + "origin_ca2a_verification", "evidence_class"}: + raise ValueError("malformed-replay-packet") + if (packet["schema"] != SCHEMA or + packet["trusted_issuer"] != trusted_issuer or + packet["peer_public_key"] != peer_public_key or + packet["evidence_class"] != "live-software-two-host-same-operator" or + packet["origin_ca2a_verification"] != "passed-in-process-not-exportable"): + raise ValueError("replay-trust-or-evidence-class-mismatch") + if not isinstance(packet["execution"], dict): + raise ValueError("malformed-execution-evidence") + e=packet["execution"] + if (e.get("exit_code") != 0 or + not isinstance(e.get("session_id"), str) or + any(not isinstance(e.get(field),str) or len(e[field]) != 64 or + any(c not in "0123456789abcdef" for c in e[field]) + for field in ("start_receipt_hash","finish_receipt_hash"))): + raise ValueError("bad-execution-claim") + pk=Ed25519PublicKey.from_public_bytes(bytes.fromhex(trace_public_key)) + record_hash=verify_bundle( + packet["trace_bundle"], public_key=pk, + transaction_id=packet["transaction_id"], + nonce=packet["nonce"], + request_sha256=packet["request_sha256"], + repo=packet["repo"], execution=e, + trusted_issuer=trusted_issuer, max_age_seconds=None) + return { + "verified": True, + "record_hash": record_hash, + "manifest_binding": "valid", + "signed_by": trace_public_key, + "assurance": "software-only", + "independent_custody": False, + "hardware_attested": False, + "origin_response_authentication": "not-offline-replayable", + "peer_channel_binding": "metadata-only-not-signed", + "freshness": "historical-signature-only-not-current", + } diff --git a/integrations/agentrust-confidential-workflow-harness/harness/trace_live_binding.py b/integrations/agentrust-confidential-workflow-harness/harness/trace_live_binding.py new file mode 100644 index 00000000..a61d4ae6 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/harness/trace_live_binding.py @@ -0,0 +1,92 @@ +"""Software-only TRACE Level 0 record and separately signed execution manifest. + +TRACE policy.bundle_hash identifies the actual local acceptance policy, +NOT an execution receipt. A companion signed manifest binds the request and +Conduit outcome to the TRACE record's digest without abusing TRACE fields. +The signer is a VPS software key pinned by the origin, not independent custody. +""" +import hashlib +import time + +from cryptography.exceptions import InvalidSignature +from agentrust_trace import verify_record +from ca2a_runtime.response import encode +from ca2a_runtime.trace_binding import HopContext, HopSpec, emit_dag, trace_record_hash + +CAPABILITY = "conduit.inspect" +SUBJECT = "did:example:frequency-ca2a-vps-software" +PROFILE = "frequency-ca2a-software-manifest/1" + + +def policy_digest(*, repo: str, trusted_issuer: str) -> str: + policy = {"capability": CAPABILITY, "repo": repo, + "trusted_issuer": trusted_issuer, "network_allowed": False, + "peer_assurance": "none"} + return "sha256:" + hashlib.sha256(encode(policy)).hexdigest() + + +def sign_bundle(*, key, transaction_id: str, nonce: str, + request_sha256: str, execution: dict, repo: str, + trusted_issuer: str) -> dict: + policy_hash = policy_digest(repo=repo, trusted_issuer=trusted_issuer) + ctx = HopContext.software( + model_provider="frequency-software-only", + model_id="conduit-inspect-no-model", + image_label="unmeasured-software-peer-conduit-inspect", + policy_bundle_hash=policy_hash, + runtime_nonce=nonce) + record = emit_dag([HopSpec( + subject=SUBJECT, signing_key=key, + context=ctx, iat=int(time.time()))])[0] + manifest = { + "schema": PROFILE, + "trace_record_hash": trace_record_hash(record), + "policy_bundle_hash": policy_hash, + "transaction_id": transaction_id, + "nonce": nonce, + "request_sha256": request_sha256, + "repo": repo, + "capability": CAPABILITY, + "execution": execution, + "assurance": "software-only-same-operator", + } + signature = key.sign(encode(manifest)).hex() + return {"record": record, "manifest": manifest, "signature": signature} + + +def verify_bundle(bundle: dict, *, public_key, transaction_id: str, nonce: str, + request_sha256: str, repo: str, execution: dict, + trusted_issuer: str, + max_age_seconds: int | None = 120) -> str: + if not isinstance(bundle, dict) or set(bundle) != {"record","manifest","signature"}: + raise ValueError("trace-bundle-format") + record, manifest, signature = ( + bundle["record"], bundle["manifest"], bundle["signature"]) + if not isinstance(record, dict) or not isinstance(manifest, dict): + raise ValueError("trace-bundle-type") + expected_policy = policy_digest(repo=repo, trusted_issuer=trusted_issuer) + digest = trace_record_hash(record) + expected = { + "schema": PROFILE, + "trace_record_hash": digest, + "policy_bundle_hash": expected_policy, + "transaction_id": transaction_id, + "nonce": nonce, + "request_sha256": request_sha256, + "repo": repo, + "capability": CAPABILITY, + "execution": execution, + "assurance": "software-only-same-operator", + } + if manifest != expected or record.get("policy", {}).get("bundle_hash") != expected_policy: + raise ValueError("trace-manifest-binding-mismatch") + try: + public_key.verify(bytes.fromhex(signature), encode(manifest)) + except (ValueError, InvalidSignature) as exc: + raise ValueError("trace-manifest-signature-invalid") from exc + # Pin the remote signing key: embedded cnf.jwk is NOT a trust root. + verify_record(record, public_key, expected_nonce=nonce, + max_age_seconds=max_age_seconds) + if record.get("subject") != SUBJECT or record.get("runtime", {}).get("platform") != "software-only": + raise ValueError("unexpected-trace-claim") + return digest diff --git a/integrations/agentrust-confidential-workflow-harness/run_remote_ca2a_live.py b/integrations/agentrust-confidential-workflow-harness/run_remote_ca2a_live.py new file mode 100644 index 00000000..4bc4b66e --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/run_remote_ca2a_live.py @@ -0,0 +1,48 @@ +"""Run the restricted software cA2A peer proof from a private operator config. + +The config contains file paths and pinned PUBLIC keys, never private contents. +No implicit configuration, external discovery, or SSH host-key override. +""" +import argparse +import json +import os +import uuid +from pathlib import Path +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from harness.remote_peer_client import run, ssh_sender + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--config", type=Path, required=True) + parser.add_argument("--evidence-out", type=Path, required=True) + args = parser.parse_args() + cfg = json.loads(args.config.read_text()) + issuer = Ed25519PrivateKey.from_private_bytes( + bytes.fromhex(Path(cfg["issuer_key"]).read_text().strip())) + holder = Ed25519PrivateKey.from_private_bytes( + bytes.fromhex(Path(cfg["holder_key"]).read_text().strip())) + def write_packet(packet): + args.evidence_out.parent.mkdir(mode=0o700,parents=True,exist_ok=True) + fd=os.open(args.evidence_out,os.O_WRONLY|os.O_CREAT|os.O_EXCL,0o600) + with os.fdopen(fd,"w") as f: + json.dump(packet,f,sort_keys=True,indent=2) + f.write("\n") + + result = run( + transaction_id="live-ca2a-" + uuid.uuid4().hex, + nonce=uuid.uuid4().hex, + repo=cfg["repo"], issuer_private=issuer, holder_private=holder, + peer_public_key=cfg["peer_public_key"], + trace_public_key=cfg["trace_public_key"], + send=ssh_sender(cfg["host"], cfg["ssh_key"]), + evidence_sink=write_packet) + print(json.dumps(result.__dict__, sort_keys=True)) + if (result.outcome != "authenticated-remote-ca2a-software" + or not result.remote_ca2a_verified + or not result.trace_verified): + raise SystemExit(1) + + +if __name__ == "__main__": + main() diff --git a/integrations/agentrust-confidential-workflow-harness/run_remote_ca2a_matrix.py b/integrations/agentrust-confidential-workflow-harness/run_remote_ca2a_matrix.py new file mode 100644 index 00000000..685ac548 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/run_remote_ca2a_matrix.py @@ -0,0 +1,136 @@ +"""Bounded LIVE two-host negative matrix. No side-effect retry on unknown results. + +Requires a separately provisioned private operator config and remote forced +SSH peer. Never treats unobserved execution as proof of refusal. +""" +import argparse +import json +import uuid +from pathlib import Path + +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from ca2a_runtime.delegation import new_keypair +from harness.remote_peer_client import run, ssh_sender + + +def private(path): + return Ed25519PrivateKey.from_private_bytes( + bytes.fromhex(Path(path).read_text().strip())) + + + +def exact_replay_observation(response): + """Classify a transport status; consumed client state cannot verify its MAC.""" + refused = isinstance(response, dict) and response.get("status") == 403 + return { + "case": "one-time-challenge-replay", + "expected": "observed-status-403", + "observed": "observed-status-403" if refused else "unexpected", + "passed": refused, + "response_authentication": "not-verified", + "evidence_class": "live-software-two-host-same-operator", + } + + +def main(): + parser=argparse.ArgumentParser() + parser.add_argument("--config",type=Path,required=True) + parser.add_argument("--output",type=Path,required=True) + args=parser.parse_args() + cfg=json.loads(args.config.read_text()) + issuer=private(cfg["issuer_key"]) + holder=private(cfg["holder_key"]) + base_send=ssh_sender(cfg["host"],cfg["ssh_key"]) + results=[] + + def scenario(name, expected, *, send=None, issuer_private=None, + permitted=True, trace_public_key="default", + credential_not_after_offset=60): + key = cfg["trace_public_key"] if trace_public_key=="default" else trace_public_key + result=run(transaction_id="matrix-"+uuid.uuid4().hex, + nonce=uuid.uuid4().hex, + repo=cfg["repo"],issuer_private=issuer_private or issuer, + holder_private=holder,peer_public_key=cfg["peer_public_key"], + trace_public_key=key,permitted=permitted, + credential_not_after_offset=credential_not_after_offset, + send=send or base_send) + observed=result.outcome + passed=(observed==expected) + record={"case":name,"expected":expected,"observed":observed, + "passed":passed,"transaction_id":result.transaction_id, + "evidence_class":result.evidence_class, + "remote_ca2a_verified":result.remote_ca2a_verified, + "trace_verified":result.trace_verified} + if result.start_receipt_hash: + record["start_receipt_hash"]=result.start_receipt_hash + if result.finish_receipt_hash: + record["finish_receipt_hash"]=result.finish_receipt_hash + if result.trace_record_hash: + record["trace_record_hash"]=result.trace_record_hash + results.append(record) + print(json.dumps(record,sort_keys=True),flush=True) + return result + + valid="authenticated-remote-ca2a-software" + scenario("positive-twin",valid) + scenario("local-cmcp-authorization-refusal","refused-cmcp",permitted=False) + attacker,_=new_keypair() + scenario("untrusted-issuer","refused-authenticated-peer",issuer_private=attacker) + scenario("expired-signed-delegation","refused-authenticated-peer", + credential_not_after_offset=-2) + scenario("missing-trace-trust-root","missing-trace-trust-anchor",trace_public_key=None) + other,_=new_keypair() + scenario("wrong-trace-verifier-root","untrusted-trace-evidence", + trace_public_key=other.public_key().public_bytes_raw().hex()) + + def altered_credential(request): + if request.get("method")=="execute": + request["credential"]["scope"]=["conduit.delete"] + return base_send(request) + scenario("altered-delegation-scope","refused-authenticated-peer", + send=altered_credential) + + def tampered_mac(request): + ans=base_send(request) + if request.get("method")=="execute" and "envelope" in ans: + ans["envelope"]["mac"]="00"*32 + return ans + scenario("response-authentication-mutation","unknown-or-refused-transport", + send=tampered_mac) + + def lost_response(request): + ans=base_send(request) + if request.get("method")=="execute": + raise RuntimeError("delivery-uncertain-after-execution") + return ans + scenario("unobserved-result-remains-unknown","unknown-or-refused-transport", + send=lost_response) + + last=[None] + def record_submit(request): + if request.get("method")=="execute": + last[0]=json.loads(json.dumps(request)) + return base_send(request) + scenario("replay-valid-twin",valid,send=record_submit) + repeated=base_send(last[0]) + rr=exact_replay_observation(repeated) + results.append(rr) + print(json.dumps(rr,sort_keys=True),flush=True) + + passed=all(x["passed"] for x in results) + report={"schema":"frequency-ca2a-live-adversarial-matrix/1", + "evidence_class":"live-software-two-host-same-operator", + "operator_independent":False,"hardware_attested":False, + "tests":len(results),"passed":sum(x["passed"] for x in results), + "all_passed":passed, "results":results} + args.output.parent.mkdir(mode=0o700,parents=True,exist_ok=True) + args.output.write_text(json.dumps(report,indent=2,sort_keys=True)+"\n") + args.output.chmod(0o600) + print("MATRIX",json.dumps({"passed":report["passed"],"tests":report["tests"], + "all_passed":passed}),flush=True) + if not passed: + raise SystemExit(1) + + +if __name__=="__main__": + main() diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_authenticated_exchange.py b/integrations/agentrust-confidential-workflow-harness/tests/test_authenticated_exchange.py new file mode 100644 index 00000000..02c9da84 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_authenticated_exchange.py @@ -0,0 +1,29 @@ +import unittest +from harness.authenticated_exchange import exchange + +GOOD = {"transaction_id": "test-transaction", "nonce": "nonce-01"} +class AuthenticatedExchangeTests(unittest.TestCase): + def test_valid_authenticated_response_has_no_live_dispatch(self): + result = exchange(**GOOD) + self.assertEqual(result.outcome, "authenticated-process-local") + self.assertEqual(result.actual_dispatches, 0) + self.assertTrue(result.request_sha256) + def test_disallowed_tool_refused(self): + self.assertEqual(exchange(**GOOD,allowed=False).outcome,"refused-authorization") + def test_tamper_refused(self): + self.assertEqual(exchange(**GOOD,tamper=True).outcome,"refused-response-authentication") + def test_authenticated_refusal(self): + self.assertEqual(exchange(**GOOD,refusal=True).outcome,"refused-authenticated") + def test_replay_refused(self): + self.assertEqual(exchange(**GOOD,replay=True).outcome,"refused-replay") + def test_timeout_refused(self): + self.assertEqual(exchange(**GOOD,expired=True).outcome,"refused-response-authentication") + def test_missing_receipt_remains_unknown(self): + self.assertEqual(exchange(**GOOD,missing_receipt=True).outcome,"unknown-unobserved-delivery") + def test_response_binding_mismatch_refused(self): + self.assertEqual(exchange(**GOOD,binding_mismatch=True).outcome,"refused-response-binding") + def test_valid_twin_independent_of_each_negative(self): + for opt in ("tamper","replay","expired","refusal","binding_mismatch","missing_receipt"): + with self.subTest(opt=opt): + self.assertNotEqual(exchange(**GOOD, **{opt:True}).outcome, "authenticated-process-local") + self.assertEqual(exchange(**GOOD).outcome,"authenticated-process-local") diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_conduit_live.py b/integrations/agentrust-confidential-workflow-harness/tests/test_conduit_live.py new file mode 100644 index 00000000..b6d34e7b --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_conduit_live.py @@ -0,0 +1,65 @@ +import hashlib +import json +import tempfile +import unittest +from pathlib import Path +from harness.conduit_live import run + + +def receipt(action, session, previous="", **detail): + record = {"schema":"frequency-conduit-receipt/1", "node":"vps-377a113a", + "status":"PASS","action":action,"request_id":"test","ts":1, + "prev_hash":previous,"detail":{"session_id":session, **detail}} + record["hash"]=hashlib.sha256(json.dumps(record,sort_keys=True,separators=(",",":")).encode()).hexdigest() + return record + +class ConduitLiveTests(unittest.TestCase): + def setUp(self): + self.tmp=tempfile.TemporaryDirectory() + self.addCleanup(self.tmp.cleanup) + self.cli=str(Path(self.tmp.name)/"cli") + Path(self.cli).touch() + self.session="session-1" + self.started=receipt("job_start",self.session) + self.finished=receipt("job_poll",self.session,self.started["hash"]) + def transport(self,cli,action,params): + if action=="job_start": + return {"ok":True, "receipt":self.started, + "result":{"session_id":self.session,"intent":"inspect", + "commit_sha":"abc","network":False}} + return {"ok":True,"receipt":self.finished, + "result":{"session_id":self.session,"running":False,"exit_code":0, + "commit_sha":"abc","commit_sha_end":"abc", + "worktree_clean_start":True,"worktree_clean_end":True}} + def invoke(self,**opts): + return run(transaction_id="txn-1",repo="/home/ubuntu/src/integrations", + cli=self.cli,transport=self.transport,**opts) + def test_valid_receipts(self): + self.assertEqual(self.invoke().outcome,"observed-live-conduit-inspect") + def test_cmcp_denial(self): + self.assertEqual(self.invoke(tool_allowed=False).outcome,"refused-cmcp") + def test_receipt_tampering(self): + self.finished["detail"]["session_id"]="substituted" + self.assertEqual(self.invoke().outcome,"untrusted-or-unsuccessful-result") + def test_receipt_linkage(self): + self.finished["prev_hash"]="wrong" + data={k:v for k,v in self.finished.items() if k!="hash"} + self.finished["hash"]=hashlib.sha256(json.dumps(data,sort_keys=True,separators=(",",":")).encode()).hexdigest() + self.assertEqual(self.invoke().outcome,"untrusted-or-unsuccessful-result") + def test_unobserved_finish(self): + def transport(cli,action,params): + if action=="job_poll": + return {"ok":False} + return self.transport(cli,action,params) + out=run(transaction_id="txn-1",repo="/home/ubuntu/src/integrations", + cli=self.cli,transport=transport) + self.assertEqual(out.outcome,"unknown-unobserved-result") + def test_stale_commit(self): + original=self.transport + def transport(cli,action,params): + result=original(cli,action,params) + if action=="job_poll": + result["result"]["commit_sha_end"]="changed" + return result + self.transport=transport + self.assertEqual(self.invoke().outcome,"untrusted-or-unsuccessful-result") diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_delegated_conduit.py b/integrations/agentrust-confidential-workflow-harness/tests/test_delegated_conduit.py new file mode 100644 index 00000000..a822480f --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_delegated_conduit.py @@ -0,0 +1,71 @@ +import tempfile +import unittest +from pathlib import Path + +from ca2a_runtime.delegation import new_keypair +from ca2a_runtime.delegation.credential import DelegationCredential +from harness.delegated_conduit import run +from test_conduit_live import receipt + + +class DelegatedConduitTests(unittest.TestCase): + def setUp(self): + root, self.root_pub = new_keypair() + self.holder, pub = new_keypair() + self.credential = DelegationCredential( + "test-delegation", self.root_pub, pub, + frozenset({"conduit.inspect"}), 0).sign(root) + tmp = tempfile.TemporaryDirectory() + self.addCleanup(tmp.cleanup) + self.cli = str(Path(tmp.name) / "conduit") + Path(self.cli).touch() + self.calls = [] + self.start = receipt("job_start", "session") + self.finish = receipt("job_poll", "session", self.start["hash"]) + + def transport(self, cli, action, params): + self.calls.append(action) + if action == "job_start": + return {"ok": True, "receipt": self.start, + "result": {"session_id": "session", "intent": "inspect", + "network": False, "commit_sha": "abc"}} + return {"ok": True, "receipt": self.finish, + "result": {"session_id": "session", "running": False, + "exit_code": 0, "commit_sha": "abc", + "commit_sha_end": "abc", + "worktree_clean_start": True, + "worktree_clean_end": True}} + + def invoke(self, **override): + kw = dict(transaction_id="test-id", repo="/home/ubuntu/src/integrations", + cli=self.cli, credential=self.credential, holder_private=self.holder, + trusted_issuer=self.root_pub, transport=self.transport) + kw.update(override) + return run(**kw) + + def test_positive_composed_software(self): + result = self.invoke() + self.assertEqual(result.outcome, "observed-live-conduit-inspect") + self.assertEqual(self.calls, ["job_start", "job_poll"]) + self.assertFalse(result.ca2a_peer_transport) + self.assertFalse(result.trace_verification) + + def test_untrusted_root_never_dispatches(self): + _, other_root = new_keypair() + self.assertEqual(self.invoke(trusted_issuer=other_root).outcome, + "refused-ca2a-delegation") + self.assertEqual(self.calls, []) + + def test_wrong_holder_never_dispatches(self): + attacker, _ = new_keypair() + self.assertEqual(self.invoke(holder_private=attacker).outcome, + "refused-ca2a-delegation") + self.assertEqual(self.calls, []) + + def test_modified_scope_never_dispatches(self): + bad = DelegationCredential( + "test-delegation", self.root_pub, self.credential.subject, + frozenset({"conduit.delete"}), 0, signature=self.credential.signature) + self.assertEqual(self.invoke(credential=bad).outcome, + "refused-ca2a-delegation") + self.assertEqual(self.calls, []) diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_live_evidence_fixture.py b/integrations/agentrust-confidential-workflow-harness/tests/test_live_evidence_fixture.py new file mode 100644 index 00000000..25c93d33 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_live_evidence_fixture.py @@ -0,0 +1,40 @@ +"""Reproduce the historical public software signature fixture without SSH.""" +import copy +import hashlib +import json +import unittest +from pathlib import Path +from harness.replay_export import verify_packet + +FILE = Path(__file__).resolve().parents[1] / "evidence/live-software-20261016.json" +FILE_SHA256 = "402a8f0cc05bc517d2918e7a49b10051cb60122fcac8909f1a9ed308c12fdc13" +TRACE_PUB = "2c6ba06dde1a1a7dc8c9676a7c38de76c3f2df6268413cc27779bc6eb0c2d7f1" +ISSUER_PUB = "880a6aa8cd1976f69176cb1a095b5deb8449579d253b14003fc14ff9d983ed02" +PEER_PUB = "69a7a6092973975edd92b2a836704a5c90c462825e69a08d20996e795a854d3d" + + +class PublishedEvidenceFixture(unittest.TestCase): + def test_signed_packet_matches_pinned_digest(self): + blob=FILE.read_bytes() + self.assertEqual(hashlib.sha256(blob).hexdigest(), FILE_SHA256) + packet=json.loads(blob) + result=verify_packet( + packet,trace_public_key=TRACE_PUB, + trusted_issuer=ISSUER_PUB,peer_public_key=PEER_PUB) + self.assertTrue(result["verified"]) + self.assertFalse(result["hardware_attested"]) + self.assertFalse(result["independent_custody"]) + self.assertEqual(result["freshness"], + "historical-signature-only-not-current") + + def test_modified_manifest_refused(self): + packet=json.loads(FILE.read_bytes()) + mutated=copy.deepcopy(packet) + mutated["execution"]["finish_receipt_hash"]="f"*64 + with self.assertRaises(Exception): + verify_packet( + mutated,trace_public_key=TRACE_PUB, + trusted_issuer=ISSUER_PUB,peer_public_key=PEER_PUB) + self.assertTrue(verify_packet( + packet,trace_public_key=TRACE_PUB, + trusted_issuer=ISSUER_PUB,peer_public_key=PEER_PUB)["verified"]) diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_released_delegation.py b/integrations/agentrust-confidential-workflow-harness/tests/test_released_delegation.py new file mode 100644 index 00000000..cf0a5585 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_released_delegation.py @@ -0,0 +1,65 @@ +import unittest +import time +from ca2a_runtime.delegation import (new_keypair, credential_digest, + RevocationSnapshot, RevocationStatement) +from ca2a_runtime.delegation.credential import DelegationCredential +from harness.released_delegation import appraise + + +class ReleasedDelegationTests(unittest.TestCase): + def setUp(self): + self.root, self.root_pub = new_keypair() + self.holder, holder_pub = new_keypair() + self.credential = DelegationCredential( + "experimental", self.root_pub, holder_pub, + frozenset({"conduit.inspect"}), 0).sign(self.root) + + def check(self, **kw): + return appraise(credential=kw.pop("credential", self.credential), + holder_private=kw.pop("holder_private", self.holder), + trusted_issuer=kw.pop("trusted_issuer", self.root_pub), + record_id="live-test", **kw) + + def test_valid_delegation(self): + self.assertTrue(self.check().granted) + + def test_untrusted_root(self): + _, other_root = new_keypair() + self.assertFalse(self.check(trusted_issuer=other_root).granted) + self.assertTrue(self.check().granted) + + def test_holder_substitution(self): + other_holder, _ = new_keypair() + self.assertFalse(self.check(holder_private=other_holder).granted) + self.assertTrue(self.check().granted) + + def test_ungranted_capability(self): + self.assertFalse(self.check(capability="conduit.delete").granted) + self.assertTrue(self.check().granted) + + def test_policy_refusal(self): + self.assertFalse(self.check(local_capabilities=frozenset()).granted) + self.assertTrue(self.check().granted) + + def test_unsigned_credential(self): + c = DelegationCredential("experimental",self.root_pub, + self.credential.subject,frozenset({"conduit.inspect"}),0) + self.assertFalse(self.check(credential=c).granted) + self.assertTrue(self.check().granted) + + def test_signed_revocation_refuses_valid_delegation(self): + now=int(time.time()) + statement=RevocationStatement( + credential_digest(self.credential),self.root_pub,now).sign(self.root) + snapshot=RevocationSnapshot(now,(statement,)) + self.assertFalse(self.check(revocations=snapshot, + max_revocation_staleness=300).granted) + self.assertTrue(self.check(revocations=RevocationSnapshot(now), + max_revocation_staleness=300).granted) + + def test_stale_revocation_snapshot_fails_closed(self): + now=int(time.time()) + self.assertFalse(self.check(revocations=RevocationSnapshot(now-1000), + max_revocation_staleness=300).granted) + self.assertTrue(self.check(revocations=RevocationSnapshot(now), + max_revocation_staleness=300).granted) diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_released_protocol_probe.py b/integrations/agentrust-confidential-workflow-harness/tests/test_released_protocol_probe.py new file mode 100644 index 00000000..fb198ff0 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_released_protocol_probe.py @@ -0,0 +1,22 @@ +import unittest +from harness.released_protocol_probe import probe +GOOD = dict(transaction_id="test-txn", subject="test-subject", tool_name="inspect", + allowed_tools=("inspect",), policy_digest="sha256:"+"a"*64, nonce="test-nonce") +class ReleasedProtocolTests(unittest.TestCase): + def test_positive_uses_published_apis_and_does_not_dispatch(self): + result=probe(**GOOD) + self.assertTrue(result.admitted, result.reason) + self.assertEqual(len(result.hashes),2) + self.assertNotEqual(*result.hashes) + self.assertEqual(result.actual_dispatches,0) + self.assertEqual(result.evidence_class,"synthetic") + def test_disallowed_tool_refused(self): + result=probe(**{**GOOD,"allowed_tools":("different",)}) + self.assertFalse(result.admitted) + self.assertFalse(result.hashes) + def test_missing_or_corrupted_context_refused(self): + for overrides in ({"transaction_id":""},{"nonce":""},{"policy_digest":"invalid"},{"policy_digest":"sha256:"+"z"*64}): + with self.subTest(overrides=overrides): + result=probe(**{**GOOD,**overrides}) + self.assertFalse(result.admitted) + self.assertFalse(result.hashes) diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_remote_ca2a.py b/integrations/agentrust-confidential-workflow-harness/tests/test_remote_ca2a.py new file mode 100644 index 00000000..7606de9e --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_remote_ca2a.py @@ -0,0 +1,140 @@ +"""Adversarial published-cA2A client/server interoperability and replay tests.""" +import json +import tempfile +import unittest +from pathlib import Path + +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from ca2a_runtime.delegation import new_keypair + +from harness.remote_peer_client import run +from harness.remote_peer_service import serve + + +class RemoteCA2ATests(unittest.TestCase): + def setUp(self): + tmp = tempfile.TemporaryDirectory() + self.addCleanup(tmp.cleanup) + self.db = Path(tmp.name) / "replay.sqlite" + self.issuer, self.issuer_pub = new_keypair() + self.holder, self.holder_pub = new_keypair() + self.trace = Ed25519PrivateKey.generate() + self.peer = X25519PrivateKey.generate() + self.peer_pub = self.peer.public_key().public_bytes_raw().hex() + self.secret = b"secret-for-test-only-" + bytes(range(32)) + self.dispatch_count = 0 + self.calls = [] + self.last_submit = None + + def dispatch(self, agent, repo): + self.dispatch_count += 1 + return {"session_id":"session", "start_receipt_hash":"a"*64, + "finish_receipt_hash":"b"*64,"commit_sha":"abc","exit_code":0} + + def send(self, request): + self.calls.append(request["method"]) + if request["method"] == "execute": + self.last_submit = json.loads(json.dumps(request)) + return serve(request, channel_private=self.peer, + challenge_secret=self.secret, trusted_issuer=self.issuer_pub, + replay_db=self.db, dispatch=self.dispatch, + trace_private=self.trace) + + def invoke(self, **kw): + args = {"transaction_id": "transaction-1", "nonce": "0123456789abcdef", + "repo": "/home/ubuntu/src/integrations", + "issuer_private": self.issuer,"holder_private": self.holder, + "peer_public_key": self.peer_pub,"send": self.send, + "trace_public_key": self.trace.public_key().public_bytes_raw().hex()} + args.update(kw) + return run(**args) + + def test_real_library_roundtrip(self): + r=self.invoke() + self.assertEqual(r.outcome,"authenticated-remote-ca2a-software") + self.assertTrue(r.remote_ca2a_verified) + self.assertEqual(self.dispatch_count,1) + self.assertEqual(self.calls,["challenge","execute"]) + + def test_cmcp_refusal_before_network(self): + self.assertEqual(self.invoke(permitted=False).outcome,"refused-cmcp") + self.assertEqual(self.calls,[]) + self.assertEqual(self.dispatch_count,0) + + def test_untrusted_root_no_dispatch(self): + attacker,_=new_keypair() + self.assertEqual(self.invoke(issuer_private=attacker).outcome, + "refused-authenticated-peer") + self.assertEqual(self.dispatch_count,0) + + def test_authenticated_response_mutation(self): + def tamper(request): + result=self.send(request) + if request["method"]=="execute": + result["envelope"]["body"]["nonce"]="bad-nonce" + return result + self.assertNotEqual(self.invoke(send=tamper).outcome, + "authenticated-remote-ca2a-software") + + def test_substituted_credential_scope_no_dispatch(self): + def tamper(request): + if request["method"]=="execute": + request["credential"]["scope"]=["conduit.delete"] + return self.send(request) + self.assertEqual(self.invoke(send=tamper).outcome,"refused-authenticated-peer") + self.assertEqual(self.dispatch_count,0) + + def test_substituted_envelope_no_dispatch(self): + def tamper(request): + if request["method"]=="execute": + request["envelope"]["request"]["nonce"]="substituted" + return self.send(request) + self.assertNotEqual(self.invoke(send=tamper).outcome, + "authenticated-remote-ca2a-software") + self.assertEqual(self.dispatch_count,0) + + def test_stale_or_wrong_peer_identity(self): + wrong=X25519PrivateKey.generate().public_key().public_bytes_raw().hex() + self.assertEqual(self.invoke(peer_public_key=wrong).outcome, + "refused-peer-identity") + self.assertEqual(self.dispatch_count,0) + + def test_one_time_replay_is_refused(self): + self.assertEqual(self.invoke().outcome,"authenticated-remote-ca2a-software") + self.assertEqual(self.dispatch_count,1) + replay=self.send(self.last_submit) + self.assertEqual(replay["status"],403) + self.assertEqual(self.dispatch_count,1) + + def test_unobserved_delivery_remains_unknown(self): + def lose(request): + if request["method"]=="execute": + raise RuntimeError("transport-lost") + return self.send(request) + self.assertEqual(self.invoke(send=lose).outcome,"unknown-or-refused-transport") + self.assertEqual(self.dispatch_count,0) + + def test_real_trace_signed_record(self): + pub=self.trace.public_key().public_bytes_raw().hex() + result=self.invoke(trace_public_key=pub) + self.assertEqual(result.outcome,"authenticated-remote-ca2a-software") + self.assertTrue(result.trace_verified) + self.assertTrue(result.trace_record_hash.startswith("sha256:")) + + def test_untrusted_trace_issuer_refused(self): + wrong=Ed25519PrivateKey.generate().public_key().public_bytes_raw().hex() + result=self.invoke(trace_public_key=wrong) + self.assertEqual(result.outcome,"untrusted-trace-evidence") + self.assertTrue(result.remote_ca2a_verified) + self.assertFalse(result.trace_verified) + + def test_missing_trusted_trace_key_never_dispatches(self): + self.assertEqual(self.invoke(trace_public_key=None).outcome, + "missing-trace-trust-anchor") + self.assertEqual(self.dispatch_count,0) + + def test_expired_signed_credential_remote_refuses(self): + result=self.invoke(credential_not_after_offset=-2) + self.assertEqual(result.outcome,"refused-authenticated-peer") + self.assertEqual(self.dispatch_count,0) diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_replay_export.py b/integrations/agentrust-confidential-workflow-harness/tests/test_replay_export.py new file mode 100644 index 00000000..9a5ef989 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_replay_export.py @@ -0,0 +1,87 @@ +"""Offline TRACE signature/manifest acceptance and paired mutation twins.""" +import copy +import unittest +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from harness.replay_export import make_packet, verify_packet +from harness.trace_live_binding import sign_bundle + + +class ReplayExportTests(unittest.TestCase): + def setUp(self): + self.key=Ed25519PrivateKey.generate() + self.pub=self.key.public_key().public_bytes_raw().hex() + self.issuer="ab"*32 + self.peer="cd"*32 + self.execution={ + "session_id":"lab-session","start_receipt_hash":"1"*64, + "finish_receipt_hash":"2"*64,"commit_sha":"abc","exit_code":0} + bundle=sign_bundle( + key=self.key,transaction_id="test-transaction", + nonce="fixture-nonce",request_sha256="3"*64, + execution=self.execution,repo="/home/ubuntu/src/integrations", + trusted_issuer=self.issuer) + self.packet=make_packet( + transaction_id="test-transaction",nonce="fixture-nonce", + request_sha256="3"*64,repo="/home/ubuntu/src/integrations", + peer_public_key=self.peer,trusted_issuer=self.issuer, + trace_bundle=bundle,execution=self.execution) + + def verify(self, packet=None, **kwargs): + config={"trace_public_key":self.pub,"trusted_issuer":self.issuer, + "peer_public_key":self.peer} + config.update(kwargs) + return verify_packet(packet if packet is not None else self.packet,**config) + + def assert_refuses_with_twin(self, modified): + with self.assertRaises(Exception): + self.verify(modified) + self.assertTrue(self.verify()["verified"]) + + def test_valid_signed_packet(self): + result=self.verify() + self.assertTrue(result["verified"]) + self.assertFalse(result["hardware_attested"]) + self.assertFalse(result["independent_custody"]) + self.assertEqual(result["origin_response_authentication"], + "not-offline-replayable") + + def test_modified_result_digest(self): + p=copy.deepcopy(self.packet) + p["execution"]["finish_receipt_hash"]="4"*64 + self.assert_refuses_with_twin(p) + + def test_wrong_signer(self): + other=Ed25519PrivateKey.generate().public_key().public_bytes_raw().hex() + with self.assertRaises(Exception): + self.verify(trace_public_key=other) + self.assertTrue(self.verify()["verified"]) + + def test_wrong_issuer_pin(self): + with self.assertRaises(Exception): + self.verify(trusted_issuer="ee"*32) + self.assertTrue(self.verify()["verified"]) + + def test_wrong_peer_pin(self): + with self.assertRaises(Exception): + self.verify(peer_public_key="ee"*32) + self.assertTrue(self.verify()["verified"]) + + def test_modified_request_identity(self): + p=copy.deepcopy(self.packet) + p["request_sha256"]="9"*64 + self.assert_refuses_with_twin(p) + + def test_modified_trace_record(self): + p=copy.deepcopy(self.packet) + p["trace_bundle"]["record"]["model"]["model_id"]="injected" + self.assert_refuses_with_twin(p) + + def test_modified_trace_signature(self): + p=copy.deepcopy(self.packet) + p["trace_bundle"]["signature"]="00"*64 + self.assert_refuses_with_twin(p) + + def test_missing_field(self): + p=copy.deepcopy(self.packet) + del p["trace_bundle"] + self.assert_refuses_with_twin(p) diff --git a/integrations/agentrust-confidential-workflow-harness/tests/test_replay_reporting.py b/integrations/agentrust-confidential-workflow-harness/tests/test_replay_reporting.py new file mode 100644 index 00000000..21f03d4d --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/tests/test_replay_reporting.py @@ -0,0 +1,32 @@ +"""Keep status observations and signed channel attribution claims explicit.""" +import copy +import unittest + +import test_replay_export as replay_fixture +from run_remote_ca2a_matrix import exact_replay_observation + + +class ReplayReportingTests(unittest.TestCase): + def test_forged_mac_cannot_be_labelled_authenticated(self): + observation = exact_replay_observation({ + "status": 403, "envelope": {"mac": "forged"}}) + self.assertTrue(observation["passed"]) + self.assertEqual(observation["observed"], "observed-status-403") + self.assertEqual(observation["response_authentication"], "not-verified") + + def test_absent_or_other_status_is_not_a_denial_observation(self): + for response in (None, {}, {"status": 200}, {"status": "403"}): + with self.subTest(response=response): + self.assertFalse(exact_replay_observation(response)["passed"]) + + def test_relabelled_unsigned_peer_is_reported_as_metadata(self): + fixture = replay_fixture.ReplayExportTests() + fixture.setUp() + packet = copy.deepcopy(fixture.packet) + packet["peer_public_key"] = "ee" * 32 + result = fixture.verify(packet, peer_public_key="ee" * 32) + self.assertTrue(result["verified"]) + self.assertEqual(result["peer_channel_binding"], "metadata-only-not-signed") + with self.assertRaises(ValueError): + fixture.verify(packet) # Original pin still rejects inconsistent metadata. + self.assertTrue(fixture.verify()["verified"]) diff --git a/integrations/agentrust-confidential-workflow-harness/verify_remote_peer_packet.py b/integrations/agentrust-confidential-workflow-harness/verify_remote_peer_packet.py new file mode 100644 index 00000000..d5fab083 --- /dev/null +++ b/integrations/agentrust-confidential-workflow-harness/verify_remote_peer_packet.py @@ -0,0 +1,24 @@ +"""Verify the externally replayable TRACE software packet with independent pins.""" +import argparse +import json +from pathlib import Path +from harness.replay_export import verify_packet + + +def main(): + p=argparse.ArgumentParser() + p.add_argument("--packet",type=Path,required=True) + p.add_argument("--trace-public",required=True) + p.add_argument("--issuer-public",required=True) + p.add_argument("--peer-public",required=True) + a=p.parse_args() + packet=json.loads(a.packet.read_text()) + result=verify_packet( + packet, trace_public_key=a.trace_public, + trusted_issuer=a.issuer_public, + peer_public_key=a.peer_public) + print(json.dumps(result,sort_keys=True)) + + +if __name__=="__main__": + main() diff --git a/requirements/confidential-workflow-probe.in b/requirements/confidential-workflow-probe.in new file mode 100644 index 00000000..29808aa6 --- /dev/null +++ b/requirements/confidential-workflow-probe.in @@ -0,0 +1,2 @@ +cmcp-runtime==0.7.0 +ca2a-runtime==0.4.0 diff --git a/requirements/confidential-workflow-probe.txt b/requirements/confidential-workflow-probe.txt new file mode 100644 index 00000000..eac58fa9 --- /dev/null +++ b/requirements/confidential-workflow-probe.txt @@ -0,0 +1,743 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile requirements/confidential-workflow-probe.in --generate-hashes --output-file requirements/confidential-workflow-probe.txt +agent-manifest==0.15.0 \ + --hash=sha256:62b10c22c0a3b0888a91f944c703d13f567430dcb25c7e4f71568854e4299017 \ + --hash=sha256:e6f33bc7b4a1243fded44154df535c5055e09e9f1603d6e9297482eaa6cfef77 + # via + # ca2a-runtime + # cmcp-runtime +agentrust-trace==0.11.0 \ + --hash=sha256:7de621eaf795449e365d04967a82a551a18d75c99d248b4a0923f6d593bdb09e \ + --hash=sha256:8b76de58ec74fad57417093bf7977fe826ce6ade5859b4d5be8ce3938f9fcb35 + # via + # ca2a-runtime + # 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 +ca2a-runtime==0.4.0 \ + --hash=sha256:255928c353bdf423ec85b7c9f4e4102111982e8545b11c68f724a28ebd9c798b \ + --hash=sha256:f87a235c2fb31d2bf496e24223f5d95ee2efbca743e89c8ced22a6c87fd18bd5 + # via -r requirements/confidential-workflow-probe.in +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 + # ca2a-runtime + # 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/confidential-workflow-probe.in +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 + # ca2a-runtime + # 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 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 + # ca2a-runtime + # 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 + # ca2a-runtime + # 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 + # 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