Skip to content

fix(a2a): wire AgentRegistry into --connect and fix JWS canonicalization - #6209

Merged
bug-ops merged 2 commits into
mainfrom
fix/6200-a2a-agentregistry-wiring
Jul 13, 2026
Merged

fix(a2a): wire AgentRegistry into --connect and fix JWS canonicalization#6209
bug-ops merged 2 commits into
mainfrom
fix/6200-a2a-agentregistry-wiring

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Two follow-up fixes to the A2A Agent Card JWS signature verification + trust policy feature (#5928, PR #6202):

  • AgentRegistry had no runtime construction site anywhere outside crates/zeph-a2a's own tests, so [a2a_client].card_trust_policy enforced nothing on a running agent. Wired AgentRegistry::discover into zeph --connect <URL> (src/tui_remote.rs) — the only outbound A2A client path in the codebase — using an explicit non-wildcard conversion between zeph-config and zeph-a2a's CardTrustPolicy/key types, and hardening the discovery fetch with the same TLS/SSRF posture already applied to the A2aClient connection. Also fixes a real bug where the discovery URL was built from the full --connect target (including its RPC path) instead of the origin root where /.well-known/agent.json is served.
  • card_signing::canonical_payload canonicalized the raw received card JSON verbatim, which would reject a genuinely valid card from a signer that strips proto3-default-valued fields before signing, per the A2A spec text. Fixed by stripping the same proto3-default fields recursively before JCS canonicalization, covered by a synthetic regression test (real a2a-sdk interop is still unvalidated; card_trust_policy remains "ignore" by default pending a real signed-card vector).

An adversarial critique round caught a real backward-compat regression in the initial wiring (discovery-fetch failure was unconditionally fatal to --connect, breaking card-less peers under the default ignore policy) — fixed by gating fatality on the trust policy so only require hard-fails on a fetch/parse failure; trust-check rejections (untrusted signature, URL-origin mismatch) remain fatal under every policy.

Closes #6200
Closes #6201

Test plan

  • cargo +nightly fmt --check
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins (13357 passed, 0 failed)
  • RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler"
  • cargo test --doc -p zeph-a2a -p zeph-config --all-features
  • Updated CHANGELOG.md, specs/014-a2a/spec.md, .local/testing/playbooks/a2a.md, .local/testing/coverage-status.md
  • Live-session verification of the wired --connect path against a real signed/unsigned peer (flagged in the playbook as the next live-tester cycle's priority target)

AgentRegistry had no runtime construction site anywhere outside
crates/zeph-a2a's own tests, so card_trust_policy enforced nothing on a
running agent. Wire AgentRegistry::discover into `zeph --connect <URL>`,
the only outbound A2A client path in the codebase, converting
zeph-config's CardTrustPolicy/TrustedAgentKey to zeph-a2a's types via an
explicit non-wildcard mapping and hardening the discovery fetch with the
same TLS/SSRF posture already applied to the A2aClient connection.
Discovery-fetch failure only aborts the connection under the "require"
policy; under "ignore"/"prefer" it is tolerated so card-less peers keep
connecting as before.

Also fix canonical_payload to strip proto3-default-valued fields before
JCS canonicalization, matching the A2A spec text, so a signature computed
by a signer that strips defaults still verifies against a card
transmitted with defaults present.

Closes #6200
Closes #6201
@github-actions github-actions Bot added bug Something isn't working size/XL Extra large PR (500+ lines) documentation Improvements or additions to documentation rust Rust code changes labels Jul 13, 2026
@bug-ops
bug-ops enabled auto-merge (squash) July 13, 2026 03:46
The doc comment referenced CardTrustPolicy::Require without the
zeph_a2a:: qualifier the type needs to resolve outside its defining
crate, since the bare name isn't imported into this module's scope.
Add the missing reference-style link, matching the two link definitions
already used for A2aError's variants right below it.
@bug-ops
bug-ops merged commit 9b98f90 into main Jul 13, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6200-a2a-agentregistry-wiring branch July 13, 2026 04:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation rust Rust code changes size/XL Extra large PR (500+ lines)

Projects

None yet

1 participant