Repository navigation
refactor!: centralize server validation - #1213
Conversation
bb224c9 to
6d43ff6
Compare
ehsavoie
left a comment
There was a problem hiding this comment.
Medium Severity
-
AgentCardOperation.java:12-16 — Latent NPE from nullable capabilityFailure
capabilityFailure is @nullable but AgentCardRequestPolicy.validateCapability calls Objects.requireNonNull() on it. Any caller constructing new AgentCardOperation(predicate, null) will NPE at runtime. Only safe today because AgentCardOperation.none() pairs null with an always-true predicate. Add constructor validation or a typed factory. -
DefaultRequestHandler.java:1273 — isBlank() vs isNullOrEmpty() inconsistency
validateRequiredId uses id.isBlank() while authorizeTaskAccess uses Assert.isNullOrEmpty() (which accepts whitespace). A whitespace-only ID passes one guard but fails the other — inconsistent behavior within the same class. Unify on one check. -
RestHandler_v0_3.java (8+ sites) — Redundant isNullOrEmpty + checkNotNullParam pattern
Since isNullOrEmpty returning false already guarantees non-null, the follow-up checkNotNullParam call is only there for NullAway. Extract a requireNonEmpty helper or use @SuppressWarnings. -
JSONRPCHandler.java:729 — Dead TenantNotFoundException catch block
preflight() at line 745-751 already catches TenantNotFoundException and wraps it as InvalidParamsError. resolveExtendedDiscoveryCard returns null, never throws it. Branch is unreachable and misleading.
Low Severity
-
RestHandler_v0_3.java:228-237 — Negative historyLength returns 500 instead of 422
Integer.parseInt("-1") succeeds with no bounds check — negative historyLength escapes format parsing and causes a 500 InternalError downstream instead of a 422 InvalidParamsError. Add historyLength < 0 → InvalidParamsError_v0_3. -
GrpcHandler.java:743,750 — Per-request allocation of policy objects
AgentCardResolver and AgentCardRequestPolicy are allocated on every request via createAgentCardResolver(). JSONRPCHandler and RestHandler create them once in @PostConstruct. Cache in a field or use lazy init. -
AgentCardResolver.java:31-32 — Tenant normalized twice
AgentCardRequestPolicy.normalizeTenant() normalizes before calling resolveEffectiveCard(), which internally calls normalizeTenantForResolution() again. Idempotent today, maintenance trap tomorrow. -
JSONRPCRequestDecoder_v0_3.java:109-111 — Null body relies on undocumented Gson behavior
Null body rejection relies on JsonParser.parseString(null) throwing rather than an explicit null check. Fragile across Gson version upgrades. -
A2AServerRoutesTest.java — Missing blank line before @test
Missing blank line before testEmptyMessageIdDecodeErrorRetainsId — formatting inconsistency with the rest of the file.
23dd672 to
072e123
Compare
ehsavoie
left a comment
There was a problem hiding this comment.
Breaking API change: Confirmed. RestHandler.getTask, listTasks, and listTaskPushNotificationConfigurations all changed from typed params (Integer, Boolean, int) to raw String. These are public methods, so any external subclass or caller breaks silently. The commit is labeled feat: instead of feat!: — that's a real oversight.
taskId validation repeated 7× in RestHandler and GrpcHandler canonicalTenant repeated ~10×
|
|
||
| private static final Logger LOGGER = Logger.getLogger(JSONRPCHandler.class.getName()); | ||
|
|
||
| private static final AgentCardOperation STREAMING = new AgentCardOperation( |
There was a problem hiding this comment.
Duplicated in RestHandler and GrpcHandler
| private static final AgentCardOperation STREAMING = new AgentCardOperation( | ||
| card -> card.capabilities().streaming(), | ||
| () -> new UnsupportedOperationError(null, "Streaming is not supported by the agent", null)); | ||
| private static final AgentCardOperation PUSH_NOTIFICATIONS = new AgentCardOperation( |
There was a problem hiding this comment.
Duplicated in RestHandler and GrpcHandler with PUSH
| } catch (JsonSyntaxException e) { | ||
| return new DecodeFailure(requestId, methodName, new JSONParseError_v0_3(e.getMessage())); | ||
| } catch (Throwable t) { | ||
| return new DecodeFailure(requestId, methodName, new InternalError_v0_3(t.getMessage())); |
There was a problem hiding this comment.
Should n't this be sanitized ?
072e123 to
be20ca2
Compare
be20ca2 to
2f0013f
Compare
This fixes #1093
BREAKING CHANGE
It changes how integrations interact with the transport/* handlers.
The public user API remains the same