a2aproject / a2aproject/a2a-js
[Bug]: Timestamp fields are unvalidated strings and are never normalized to UTC
- Langage dominant
- TypeScript
- Étoiles
- 613
- Forks
- 169
- Merge moyen
- 1 j 6 h
- PR mergées (30 j)
- 21
Description
### What happened?
`google.protobuf.Timestamp` fields are passed straight through as strings. The generated
code is:
```ts
timestamp: isSet(object.timestamp) ? globalThis.String(object.timestamp) : undefined,
```
and `toJSON` copies it back out unchanged. Nothing parses it and nothing checks it, which
causes two separate problems.
**Malformed timestamps are accepted and forwarded.** Every one of these is stored and
re-emitted verbatim:
```js
import { TaskStatus } from '@a2a-js/sdk';
const ts = (t) => TaskStatus.toJSON(TaskStatus.fromJSON({ state: 'TASK_STATE_WORKING', timestamp: t }));
ts('not-a-timestamp'); // { state: 'TASK_STATE_WORKING', timestamp: 'not-a-timestamp' }
ts(''); // { ..., timestamp: '' }
ts(12345); // { ..., timestamp: '12345' } a JSON number becomes a string
```
`a2a-python` rejects all of them. So a JS server accepts a `Task` whose
`status.timestamp` is arbitrary text, hands it downstream, and the Python peer is the one
that throws. The component that let the bad data in isn't the component that reports it,
which makes this annoying to track down in a mixed deployment.
**Offsets are never normalized.** proto3 JSON output is always Z-normalized.
`a2a-python` does that; this SDK keeps whatever offset arrived:
```
input "2026-01-01T05:30:00+05:30"
python "2026-01-01T00:00:00Z"
js "2026-01-01T05:30:00+05:30"
```
Same instant, different bytes. That's fine until something compares bytes rather than
instants, which is what canonicalization does. `src/signature.ts:188` canonicalizes via
`AgentCard.toJSON(AgentCard.fromJSON(card))`, so this codec sits on the signing path.
Storing the field unparsed also means any timestamp comparison or ordering inside the SDK
is operating on a string whose format isn't guaranteed.
### What I'd expect
`fromJSON` parses and validates RFC 3339, rejecting input that isn't a timestamp, and
`toJSON` emits the Z-normalized form.
### How this was found
Round-tripping a shared corpus through this SDK and `a2a-python` and diffing the JSON.
Both generate from the same `.proto`.
Reproduced on `@a2a-js/sdk` 1.0.1 from npm and on `main` at `1c6eb32`, against
`a2a-python` at `cff6727`.
Same question as the other codec issues I'm filing: this is in the generated
`src/types/pb/a2a.ts`, so tell me where you'd like the fix and I'll send it.
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.