Skip to content

Update MSC4311 tests to conform to the spec and better coverage - #796

Merged
MadLittleMods merged 34 commits into
mainfrom
travis/msc4311-v2
Sep 22, 2026
Merged

MadLittleMods merged 34 commits into
mainfrom
travis/msc4311-v2

Conversation

@turt2live

@turt2live turt2live commented Aug 15, 2025 •

Copy link
Copy Markdown
Member

Update MSC4311 tests to conform to the spec. MSC4311 states that the client API should still use the stripped state event format. For the federation API, it should use full PDU's. MSC4311 also requires the m.room.create event be included in the list of stripped state.

"Stripped state" is a generic term that refers to simplified slice of state shared in invite_room_state/knock_room_state (invite_state/knock_state with /sync) before someone is joined to a room and can see the full room state.

This PR was originally authored by @turt2live taking a stab at fixing single the flawed test (self-reported: "I have no idea what I'm doing" disclaimer goes here) but has since been taken over by @MadLittleMods. And has naturally evolved some new better test coverage as I've worked on a full solution.

Synapse PR: element-hq/synapse#18822 element-hq/synapse#19723

The previous tests passed because of a flawed implementation in Synapse which is being removed in element-hq/synapse#19723 as well.

Dev notes

Running the tests with Synapse:

COMPLEMENT_DIR=../complement ./scripts-dev/complement.sh -run TestMSC4311StrippedStateClientAPI

COMPLEMENT_DIR=../complement ./scripts-dev/complement.sh -run TestMSC4311FullEventsOnStrippedStateFederation

COMPLEMENT_DIR=../complement ./scripts-dev/complement.sh -run TestMSC4311RejectInvalidStrippedStateFederation
go test ./match -v -count=1 -run TestJSONArraySome

Comment thread tests/v12_test.go Outdated
must.MatchGJSON(t, ev,
match.JSONKeyPresent("origin_server_ts"),
)
srv.Mux().HandleFunc("/_matrix/federation/v2/invite/{roomID}/{eventID}", srv.ValidFederationRequest(t, func(fr *fclient.FederationRequest, pathParams map[string]string) util.JSONResponse {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to alternatively use:

	srv := federation.NewServer(t, deployment,
		federation.HandleInviteRequests(func(p gomatrixserverlib.PDU) {
			// checks here
		}),
		federation.HandleKeyRequests(),
		federation.HandleMakeSendJoinRequests(),
		federation.HandleTransactionRequests(nil, nil),
	)

@MadLittleMods MadLittleMods May 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went down this route but the problem is that federation.HandleInviteRequests(...) doesn't allow you to inspect the invite_room_state yet. It would have to be updated to pass in the full invite request to the callback.

And gomatrixserverlib needs to be updated to handle the new world where invite_room_state can be stripped state or full PDUs.

We could have an infallible InviteV2Request.StrippedInviteRoomState() that would give a view of stripped state regardless of whether we were passed stripped or full PDU's (we can derive stripped state from the full PDU's). And then a fallible InviteV2Request.FullInviteRoomState() that would return an error if the homeserver didn't pass us full PDUs.

We would also need to update IRoomVersion to add new fields like CreateEventRequiredInInviteRoomState and FullPDUInviteRoomState (full PDU's can happen in any room version) so we can conditionally apply this behavior. Or maybe the flags could be combined as MSC4311InviteRoomState

If any of the events are not a PDU, not for the room ID specified, or fail signature checks, or the m.room.create event is missing, the receiving server MAY respond to invites with a 400 M_MISSING_PARAM standard Matrix error (new to the endpoint). For invites to room version 12+ rooms, servers SHOULD rather than MAY respond to such requests with 400 M_MISSING_PARAM.

-- matrix-org/matrix-spec-proposals#4311

Comment thread tests/v12_test.go Outdated
Comment thread tests/v12_test.go Outdated
Comment thread tests/v12_test.go Outdated
Comment thread tests/v12_test.go
Comment thread tests/v12_test.go Outdated
// > error (new to the endpoint). For invites to room version 12+ rooms, servers
// > SHOULD rather than MAY respond to such requests with `400 M_MISSING_PARAM`.
func TestMSC4311RejectInvalidStrippedStateFederation(t *testing.T) {
runtime.SkipIf(t, runtime.Synapse) // FIXME: Run these tests after 2027-06-01

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also cross-linked this in the Synapse codebase (see element-hq/synapse#19723)

@MadLittleMods MadLittleMods changed the title Try to modify MSC4311 test to meet new proposal Update MSC4311 tests to conform to the spec May 27, 2026
@MadLittleMods MadLittleMods changed the title Update MSC4311 tests to conform to the spec Update MSC4311 tests to conform to the spec and better coverage May 27, 2026
@MadLittleMods
MadLittleMods marked this pull request as ready for review May 27, 2026 21:04
@MadLittleMods
MadLittleMods requested review from a team as code owners May 27, 2026 21:04
@anoadragon453
anoadragon453 requested a review from Copilot May 28, 2026 15:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates MSC4311 coverage for room version 12 by replacing an incorrect stripped-state test with client-server, federation, and rejection coverage, plus helper support for knock flows.

Changes:

  • Adds MSC4311 tests for client /sync stripped state and federation invite/knock stripped state.
  • Adds JSONArraySome matcher for asserting that at least one JSON array element matches.
  • Adds client and federation knock helpers used by the new tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
tests/v12_test.go Replaces the old MSC4311 test with expanded client, federation, and invalid-state rejection tests.
match/json.go Adds JSONArraySome matcher for “any element matches” assertions.
federation/server.go Adds federation knock helper and strict knock_room_state validation option.
client/client.go Adds client knock helper and fixes invite helper comments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread match/json.go Outdated
Comment thread match/json.go
Comment thread client/client.go

@anoadragon453 anoadragon453 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only nits below. Otherwise this LGTM!

Comment thread client/client.go Outdated
Comment thread tests/v12_test.go Outdated
Comment thread tests/v12_test.go Outdated
Comment thread tests/v12_test.go
Comment on lines +1534 to +1541
match.JSONArraySome("invite_room_state", func(event gjson.Result) error {
// MSC4311 also mandates that `m.room.create` event is required
return should.MatchGJSON(event, match.JSONKeyEqual("type", "m.room.create"))
}),
match.JSONArrayEach("invite_room_state", func(event gjson.Result) error {
// Each event should have extra fields `origin_server_ts` that indicate we're
// seeing a full PDU and not just a "stripped state event"
return should.MatchGJSON(event, match.JSONKeyPresent("origin_server_ts"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it'd make sense to extract this to a helper function at this point, given I've seen it about 4 times now.

@MadLittleMods MadLittleMods Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not (not totally convinced yet). They're all dealing with different field names which of course could be a function arg but the abstraction is just going to make things less clear what we care about.

Comment thread tests/v12_test.go Outdated
MadLittleMods added a commit to element-hq/synapse that referenced this pull request Sep 22, 2026
…over federation and always include `m.room.create` event (#19723)

### Background

This PR was originally just trying to remove the flawed [MSC4311](matrix-org/matrix-spec-proposals#4311) partial implementation as client side API's like `/sync` should still use stripped events. But it turns out we were just re-using the client logic for the federation side and things might break if we didn't include the full `m.room.create` event so this PR now introduces MSC4311 support to use full PDU's in the `invite_room_state`/`knock_room_state` in the federation API's.

The flawed implementation was originally introduced in 0eb7252 (no PR I assume because part of Hydra security fix) which was part of [Synapse v1.136.0](https://github.com/element-hq/synapse/blob/7530874a1250d6ad975b39582a784c594d29a505/CHANGES.md#synapse-11360-2025-08-12).

Spawning from reviewing #19722 and noticing that we have [`TestMSC4311FullCreateEventOnStrippedState`](https://github.com/matrix-org/complement/blob/1e2e12eebc1edb27bbf12108ec849a8254b6ddcd/tests/v12_test.go#L1341-L1376) in Complement which already passes even though that test looks [flawed](matrix-org/complement#791 (comment)):

> I think this test is mixing up what [MSC4311](matrix-org/matrix-spec-proposals#4311) proposes. Perhaps these were changes to the MSC that came after?
> 
> For the client API's like `/sync`, it only proposes that `m.room.create` is a required *stripped* state event.
> 
> For the federation API's, alongside requiring `m.room.create`, it also mandates using the full event PDU format for all events in the `invite_room_state`/`knock_room_state` on `m.room.member` events (in `unsigned`)

### What does this PR do?

 1. Always use stripped state for client API's
    1. Remove flawed [MSC4311](matrix-org/matrix-spec-proposals#4311) partial implementation (as explained above)
    1. Sanitize stripped state when we receive events over federation
 1. Use full PDU's when sending `invite_room_state`/`knock_room_state` over federation
 1. Validate PDU's and warn when receiving `invite_room_state`/`knock_room_state` over federation
     1. In the future, we will strictly validate and reject

Complement tests: matrix-org/complement#796

---

Part of #19414
@MadLittleMods
MadLittleMods merged commit c5c17f6 into main Sep 22, 2026
8 of 10 checks passed
@MadLittleMods
MadLittleMods deleted the travis/msc4311-v2 branch September 22, 2026 17:13
@MadLittleMods

Copy link
Copy Markdown
Contributor

Thanks for the review @anoadragon453 🐏

Kudos to @turt2live for starting this a year ago 🐃

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.

5 participants