Skip to content

feat: AgentCardSignature#448

Draft
bartek-gralewicz wants to merge 4 commits intoepic/1.0_breaking_changesfrom
bgralewicz/agent_card_signature
Draft

feat: AgentCardSignature#448
bartek-gralewicz wants to merge 4 commits intoepic/1.0_breaking_changesfrom
bgralewicz/agent_card_signature

Conversation

@bartek-gralewicz
Copy link
Copy Markdown
Contributor

@bartek-gralewicz bartek-gralewicz commented May 5, 2026

Description

Implementing the feature of AgentCardSignature. The PR is based on #290.

Important note

Most changes are ported 1-1. The main difference between the implementation here and the one on the #290 is that in the initial PR, the agentCard had root signatures incremented. This resulted in constantly growing agentCard object.

In the #290 there were also unit tests to confirm that behavior but it seems like an undesired outcome. In this PR, using generateAgentCardSignature will return a new agentCard with incremented signatures instead of incrementing the original object.

Fixes #289 🦕

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

🧪 Code Coverage

⬇️ Download Full Report

Base PR Delta
src/client/multitransport-client.ts 97.24% 96.62% 🔴 -0.62%
src/server/request_handler/default_request_handler.ts 81.88% 81.45% 🔴 -0.43%
src/signature.ts (new) 94.05%
Total 87.76% 87.79% 🟢 +0.03%

Generated by coverage-comment.yml

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Agent Card signature support using JWS and JCS canonicalization, adding the jose library as a dependency. Key changes include new signature generation and verification utilities, updates to the client and server request handlers to support signed cards, and comprehensive tests. Feedback focuses on avoiding object mutation in the signer, improving the type safety of object cloning by using destructuring instead of JSON serialization, and refining the canonicalization logic to preserve array semantics and handle Date objects correctly.

Comment thread src/signature.ts Outdated
Comment thread src/signature.ts Outdated
Comment thread src/signature.ts Outdated
Comment thread src/signature.ts Outdated
Comment thread src/signature.ts Outdated
Comment thread src/signature.ts
@bartek-gralewicz
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Agent Card signing and verification capabilities using JWS (JSON Web Signature) and JCS (JSON Canonicalization Scheme). It adds the jose library as a dependency, updates the Node.js engine requirement to version 20, and integrates signature generation and verification into the client and server request handlers. The review feedback identifies a critical issue where the signature generator mutates the internal state of the agent card, leading to an ever-growing list of signatures on the server. Additionally, it is recommended to remove diagnostic logging from the verification loop to avoid cluttering consumer logs and to update the test suite to verify immutability.

Comment thread src/signature.ts
Comment thread src/signature.ts Outdated
Comment thread test/signature.spec.ts
@bartek-gralewicz
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Agent Card signature support using JWS and JCS canonicalization, integrating signing and verification utilities into both the client and server request handlers. Feedback focuses on ensuring the canonicalization logic correctly handles empty array elements and Date objects, avoiding the use of console logging in library code, and reconsidering the minimum Node.js version bump to maintain compatibility.

Comment thread src/signature.ts
Comment on lines +151 to +154
if (Array.isArray(d)) {
const cleanedList = d.map((v) => cleanEmpty(v));
return cleanedList.length > 0 ? cleanedList : null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The cleanEmpty function uses map on arrays, which preserves the array length even if elements are "cleaned" to null. This results in arrays like [null, null] if the original contained empty strings. This is likely not the intended behavior for canonicalization. If the goal is to remove empty elements, you should also filter the results. However, please verify if the A2A specification allows changing array indices during canonicalization.

Suggested change
if (Array.isArray(d)) {
const cleanedList = d.map((v) => cleanEmpty(v));
return cleanedList.length > 0 ? cleanedList : null;
}
if (Array.isArray(d)) {
const cleanedList = d.map((v) => cleanEmpty(v)).filter((v) => v !== null);
return cleanedList.length > 0 ? cleanedList : null;
}

Comment thread package-lock.json
},
"engines": {
"node": ">=18"
"node": ">=20"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Bumping the minimum Node.js version to 20 is a breaking change for users on Node 18. While breaking changes are permissible if documented in the PR description, consider maintaining compatibility with Node 18 since the jose dependency (v6) supports it, unless Node 20 features are specifically required.

References
  1. Breaking changes to public interfaces are permissible if they are expected and explicitly documented in the pull request description.

Comment thread src/signature.ts
await jose.flattenedVerify(jws, publicKey);
return; // At least one valid signature found
} catch (error) {
console.debug('Signature verification on entry was not successful:', signatureEntry, error);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Avoid using console.debug in library code. It can be intrusive for consumers and doesn't provide a way to suppress or redirect the output. It's better to let the caller handle verification failures or provide a configurable logging mechanism.

Comment thread src/signature.ts
}

if (typeof d === 'object') {
if (d instanceof Date) return d;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The cleanEmpty function explicitly preserves Date objects, but jcsStringify (line 175) does not handle them specifically. Since Date objects have no enumerable properties, jcsStringify will serialize them as {}. If Date objects are expected in the AgentCard, they should be converted to ISO strings during the cleaning process to ensure correct canonicalization.

Suggested change
if (d instanceof Date) return d;
if (d instanceof Date) return d.toISOString();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant