fix: validate A2A version and extensions on all gRPC handler methods - #1042
Conversation
kabir
left a comment
There was a problem hiding this comment.
Hi @ez-lbz thanks it looks good! Just a small suggestion to centralize the code.
The main question there is whether installForkedContextWrapper() can happen after doing the validation for the streaming calls which is what will happen if we go with my suggestion. sendStreamingMessage() currently creates this wrapper before its validation.
If the wrapper needs to be created before validation we can probably massage createCallContext() a bit to conditionally install the wrapper before validation
| try { | ||
| ServerCallContext context = createCallContext(responseObserver); | ||
| A2AVersionValidator.validateProtocolVersion(getAgentCardInternal(), context); | ||
| A2AExtensions.validateRequiredExtensions(getAgentCardInternal(), context); |
There was a problem hiding this comment.
I wonder if we could just put these two lines inside createCallContext()?
…ntext Move validateProtocolVersion + validateRequiredExtensions into createCallContext() so every gRPC handler method validates through one path, per review suggestion. The streaming methods still install the forked context wrapper after createCallContext() returns; the wrapper is independent of the validation (it only attaches a forked gRPC Context around agent-executor runnables), so validating first is safe — and a failed validation now skips the fork entirely.
|
Good suggestion — done. Regarding your question on ordering: |
What changed
1. Enforce A2A version and extension validation on all gRPC handler methods
Problem: In
GrpcHandler, onlysendMessageandsendStreamingMessagecalledA2AVersionValidator.validateProtocolVersion+A2AExtensions.validateRequiredExtensions. The remaining methods —getTask,listTasks,cancelTask,createTaskPushNotificationConfig,getTaskPushNotificationConfig,listTaskPushNotificationConfigs,subscribeToTask,deleteTaskPushNotificationConfig,getExtendedAgentCard— skipped validation entirely, so clients using an incompatible protocol version (or missing required extensions) were served instead of being rejected.Fix (transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandler.java):
A2AVersionValidator.validateProtocolVersion(getAgentCardInternal(), context)andA2AExtensions.validateRequiredExtensions(getAgentCardInternal(), context)immediately aftercreateCallContext(...)in all nine previously-unvalidated methods, mirroring the existingsendMessage/sendStreamingMessagepattern. ForsubscribeToTaskthe checks are placed afterinstallForkedContextWrapper, matchingsendStreamingMessage.Fix (transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandlerTest.java):
testVersionNotSupportedErrorOnGetTask: a handler with an incompatible requested protocol version ("2.0" vs the card's "1.0") now failsgetTaskwith gRPCUNIMPLEMENTED(mapped fromVersionNotSupportedError). PreviouslygetTaskskipped validation and would have returned the task.Behavior change: gRPC requests with an incompatible
A2A-Versionheader or missing required extensions are now rejected on all methods instead of only the two streaming/unary message methods. Requests carrying no version header are unaffected (they default to "0.3" compatibility per spec, and validation passes when the card supports a compatible version).Testing
mvn -pl transport/grpc test— 41 tests run, 0 failures, 0 errors, 0 skipped (BUILD SUCCESS), including the new regression testtestVersionNotSupportedErrorOnGetTask.