a2aproject / a2aproject/a2a-python

[Feat]: Add a runnable sample for Agent Card signing and verification

Đang mở
#1,197 1 bình luận 0 reaction 1 người được giao Được @rohityan nhận Xem trên GitHub
component: core
Ngôn ngữ chính
Python
Star
2.1k
Fork
496
Merge trung bình
4 ngày 17 giờ
Pull request đã merge (30 ngày)
12

Mô tả

### Is your feature request related to a problem? Please describe.

The SDK ships Agent Card signing support in `a2a.utils.signing`
(`create_agent_card_signer` / `create_signature_verifier`), and both
`A2ACardResolver.get_agent_card` and `ClientFactory.create_from_url` accept a
`signature_verifier`. But `samples/` only contains `hello_world_agent.py` and
`cli.py`, so there is no end-to-end example showing how the two halves fit
together.

That leaves a few things easy to get wrong, and all of them fail in ways that
are hard to diagnose:

- **The verifier is a synchronous callable.** The natural implementation of a
`key_provider` — fetch the JWKS from the signature's `jku` with a sync HTTP
client — does blocking I/O inside async code. Against an in-process server it
deadlocks, and the symptom is a bare `InvalidSignaturesError: No valid
signature found`, which points at the crypto rather than at the I/O.
- **`create_agent_card_signer` mutates the card it signs** (it appends to
`card.signatures`). Wiring it directly into
`create_agent_card_routes(card_modifier=...)` means the served card
accumulates a new signature on every request.
- **`key_provider` failures need to be `PyJWTError` subclasses.** The verifier
only catches `PyJWTError` while iterating signatures, so a provider raising
`ValueError` aborts the whole card instead of moving on to the next
signature.
- **Trusting the card's own `jku` defeats the purpose.** The `jku` header lives
in the untrusted card, so a verifier that fetches keys from whatever URL the
card names will happily verify a forged card against the attacker's own key.
The key source has to be pinned out of band, and nothing in the API signature
makes that obvious.

### Describe the solution you'd like

A runnable sample under `samples/` covering both halves of card signing:

- **Server**: sign the Agent Card with an ES256 key via
`create_agent_card_signer`, serve it through
`create_agent_card_routes(card_modifier=...)`, and publish the matching
public key as a JWKS document at `/.well-known/jwks.json` — the URL the
signature's `jku` points to.
- **Client**: verify the fetched card with `create_signature_verifier` passed
to `A2ACardResolver.get_agent_card(signature_verifier=...)`, resolving keys
by `kid` from an allowlist of pinned JWKS URLs, with the accepted algorithms
pinned too.
- **Negative cases**, so the security property is visible rather than asserted:
a card whose transport URL was rewritten in transit, a card with its
signature stripped, and a genuine card whose `jku` the client does not trust.

Plus a smoke test in the style of `tests/integration/test_samples_smoke.py` and
a `samples/README.md` section.

### Describe alternatives you've considered

Documenting the flow in prose only (e.g. in the SDK docs). The unit tests in
`tests/utils/test_signing.py` already cover the crypto, but they use symmetric
keys and an inline `key_provider`, so they do not surface the async, mutation
or key-pinning pitfalls above — those only show up once a real server and
client are wired together.

### Additional context

_No response_

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.