Skip to content

fix: apply historyLength trimming on tasks/resubscribe snapshot - #628

Open
ez-lbz wants to merge 4 commits into
a2aproject:mainfrom
ez-lbz:fix/resubscribe-history-trim
Open

fix: apply historyLength trimming on tasks/resubscribe snapshot#628
ez-lbz wants to merge 4 commits into
a2aproject:mainfrom
ez-lbz:fix/resubscribe-history-trim

Conversation

@ez-lbz

@ez-lbz ez-lbz commented Aug 10, 2026

Copy link
Copy Markdown

What changed

1. Apply historyLength trimming on tasks/resubscribe snapshot

Problem: resubscribe yielded the full stored task without applying _applyHistoryLengthSemantics, unlike getTask and listTasks. A client that reconnects with historyLength expecting a trimmed snapshot receives the entire task history, defeating the historyLength information-disclosure protection (CWE-200). The canonical SubscribeToTaskRequest wire type has no historyLength field, and the src/types/pb/a2a.ts / src/grpc/pb/a2a.ts files are generated from the upstream A2A proto (via buf generate), so the field is carried at the handler/transport layer instead of editing the generated files.

Fix (src/server/request_handler/default_request_handler.ts):

  • resubscribe now accepts SubscribeToTaskRequest & { historyLength?: number } and applies _applyHistoryLengthSemantics to the initial Task snapshot before yielding it.
  • Validates historyLength (non-negative integer) and throws RequestMalformedError for NaN/negative values — a NaN would previously bypass the <= 0 check and slice(-NaN)slice(0) would return the full history.

Fix (src/server/request_handler/a2a_request_handler.ts):

  • A2ARequestHandler.resubscribe signature widened to SubscribeToTaskRequest & { historyLength?: number } (optional field, backward-compatible for all existing call sites).

Fix (src/server/transports/rest/rest_transport_handler.ts):

  • resubscribe(taskId, context, tenant?, historyLength?) parses the optional query value with the existing parseHistoryLength and forwards it to the handler.

Fix (src/server/express/rest_handler.ts):

  • GET/POST /tasks/:taskId:subscribe passes req.query.historyLength through to the transport.

Fix (src/server/transports/jsonrpc/jsonrpc_transport_handler.ts):

  • SubscribeToTask extracts params.historyLength from the raw JSON-RPC params (dropped by SubscribeToTaskRequest.fromJSON) and attaches it to the request passed to resubscribe.

Note: the gRPC transport cannot carry historyLength — the gRPC SubscribeToTaskRequest proto message has no history_length field (field 3 is unset in src/grpc/pb/a2a.ts), so the trimming is applied only for REST/JSON-RPC, matching the field's absence on the wire.

Testing

  • npx vitest run test/server/request_handler/resubscribe.spec.ts test/server/rest_transport_handler.spec.ts test/server/jsonrpc_transport_handler.spec.ts — all pass.
  • New regression tests (6): snapshot trimming, historyLength=0 omits history entirely, non-integer rejection, negative rejection (resubscribe.spec.ts); REST passthrough and REST validation of the parsed value (rest_transport_handler.spec.ts).
  • npx tsc --noEmit passes.

Behavior change: tasks/resubscribe now honors an optional historyLength query param (REST) / params.historyLength (JSON-RPC); invalid values are rejected with -32602/400. When historyLength is absent, behavior is unchanged.

@ez-lbz
ez-lbz requested a review from a team as a code owner August 10, 2026 16:25
@ez-lbz
ez-lbz force-pushed the fix/resubscribe-history-trim branch from 040d533 to 6daa921 Compare August 10, 2026 16:43
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🧪 Code Coverage

⬇️ Download Full Report

Base PR Delta
src/server/express/rest_handler.ts 87.78% 87.82% 🟢 +0.04%
src/server/request_handler/default_request_handler.ts 87.83% 87.93% 🟢 +0.10%
src/server/store.ts 68.47% 66.3% 🔴 -2.17%
src/server/transports/jsonrpc/jsonrpc_transport_handler.ts 83.58% 81.13% 🔴 -2.45%
src/server/transports/rest/rest_transport_handler.ts 98.69% 98.75% 🟢 +0.06%
Total 91.21% 91.14% 🔴 -0.07%

Generated by coverage-comment.yml

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