Skip to content

Drop an unrecognised inReplyTo instead of the message - #40

Merged
juicycleff merged 1 commit into
mainfrom
fix/a2a-inreplyto-interop
Sep 3, 2026
Merged

juicycleff merged 1 commit into
mainfrom
fix/a2a-inreplyto-interop

Conversation

@juicycleff

Copy link
Copy Markdown
Contributor

This revisits the Copilot autofix in 01f9e49. That commit made an inbound A2A message fail outright when its inReplyTo is not one of our TypeIDs, and I think the rejection is the wrong half of it.

Why refusing is wrong

A peer's message ids are the peer's business. Ours are TypeIDs; a conformant A2A implementation might use UUIDs, or a sequence, or anything else. A message quoting one of those in inReplyTo is still a valid message, and it simply cannot match a token we issued.

The bus was already built for that case. TestUnmatchedReplyIsJustAMessage in a2a/bus_reply_test.go pins it: an in-reply-to matching no pending ask is delivered as ordinary mail and resumes nothing. Refusing the request instead turns a message we can read into an error the peer cannot act on, and it means cortex cannot hold a conversation with any peer whose ids are not shaped like ours.

So the token is still validated, which is what the alert was pointing at. What changes is what happens when validation fails: the correlation is dropped, the message is delivered.

Why the alert was a false positive

The value reaches ClaimPendingAsk, and the sinks are:

Where("reply_with = ?", replyWith)   // sqlite and postgres
bson.M{"_id": replyWith}             // mongo

A bound parameter and a bson value. There was no injection to fix. Validating the shape is still cheap and worth keeping as defence in depth, so I kept it. Refusing conformant peers is the part worth undoing.

The alert can be dismissed as a false positive once this lands, or left resolved by the validation that is still there.

Tests

Two, and the first is the regression:

  • an inReplyTo carrying a UUID is accepted, with the correlation dropped
  • an inReplyTo carrying one of our own tokens still correlates

The existing suite passes unchanged, golangci-lint is clean, and no test covered the non-TypeID case before, which is how the autofix passed CI while changing behaviour.

The CodeQL autofix made an inbound message fail outright when its
inReplyTo is not one of our TypeIDs. A peer's message ids are the peer's
business: a UUID there is perfectly conformant A2A, it simply cannot
match a token we issued. The bus already treats an in-reply-to matching
no pending ask as ordinary mail, so refusing the request turned a
message we can read into an error the peer cannot act on.

The token is still validated before it travels any further, which is
what the alert was pointing at, so what changes is only what happens
when validation fails.

Worth saying about the alert itself: the sink is
Where("reply_with = ?", replyWith) on sqlite and postgres and a bson
value on mongo, so there was no injection to fix. Validating is cheap
and worth keeping regardless; refusing conformant peers was the part to
undo.
@juicycleff
juicycleff merged commit fb70f26 into main Sep 3, 2026
13 of 17 checks passed
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