test(signing): add cross-SDK signature vectors - #1286
ogasurfproject-jpg wants to merge 1 commit into
Conversation
Pins what a change to _canonicalize_agent_card (a2aproject#1278) has to keep: a card signed by another SDK still verifies here. signing_interop_vectors.json carries the five s0-control vectors of the language-neutral a2a-card-sign-v01 corpus, each lifted verbatim: one card with every REQUIRED field and no field at its default value, signed by this SDK, @a2a-js/sdk 1.3.0, a2a-go (main 534a60fc) and a reference signer, plus the card edited after signing. These hold however a2aproject/A2A#2122 is settled. The frozen JS-signed production card from a2aproject/a2a-go#445 is checked against the anchors used in a2aproject#1278. It carries a nested empty value, so that test pins today's bytes and needs updating if #2122 settles the other way. Test only; no library code changes. Signed-off-by: Horizon <horizon@example.com>
🧪 Code Coverage (vs
|
|
I ran the 11 tests from this PR (at The frozen JS-signed card also canonicalizes to 6410 bytes / |
|
Thanks for running them against both commits. That is the result this PR is built for: the five s0 vectors and the frozen card carry every REQUIRED field, so they hold under every reading of §8.4.1 and should stay green whichever way A2A#2122 is settled. The reading-dependent cases stay out of this PR on purpose. The s2 group added to a2a-tck#246 (a REQUIRED field absent from the served JSON) is where the Rule 1 commit |
Adds tests that pin what a change to
_canonicalize_agent_card(#1278) has to keep: a card signed by another SDK still verifies here. Test only; no library code changes.tests/utils/signing_interop_vectors.json: the fives0-controlvectors of thea2a-card-sign-v01corpus (test(conformance): add Agent Card signature vectors (a2a-card-sign-v01) a2a-tck#246), each lifted verbatim, the same wayjcs_vectors.jsonwas lifted from Add RFC 8785 canonicalization conformance vectors (a2a-jcs-v01, Layer A) a2a-tck#228. One card with every REQUIRED field and no field at its default value, signed by this SDK, @a2a-js/sdk 1.3.0, a2a-go (main 534a60fc) and a reference signer, plus the reference signature on the card edited after signing. These expectations hold however [Bug]: §8.4.1 canonicalization is under-determined - two SDKs produce different bytes for the same card, and neither reproduces the section's own worked example A2A#2122 is settled.tests/utils/test_signing_interop.py:InvalidSignaturesError;c5d5384a…, the anchors @kuangmi-bit set out in Signing/verification canonicalization drops REQUIRED fields at their default value, breaks cross-SDK Agent Card signature verification #1278. Its file hashes are asserted too, so the fixture cannot drift.One caveat on that last test: the frozen card carries
securityRequirements: [{}], a nested empty value whose canonical form is part of #2122. So it pins today's bytes, the ones this SDK and @a2a-js/sdk agree on, as agreed in #1278, and it needs updating if #2122 settles the other way. The docstring says so.The reading-dependent group (
s1-default-valued:description: "",skills: [],tags: [],extensions: []) is deliberately not lifted. Its expectations depend on #2122, and adding them now would lock in one answer before the spec does.All 11 tests pass on main (fad0482).
ruff check,ruff format --checkandty checkare clean.The production card is ours (HORIZON SHIELD publishes it). If you would rather not carry it in the repo,
test_frozen_js_signed_production_cardand its two files drop out cleanly.cc @aeoess @kuangmi-bit