Skip to content

Conversation

@ggazzo
Copy link
Member

@ggazzo ggazzo commented Dec 12, 2025

https://rocketchat.atlassian.net/browse/FB-144

Proposed changes (including videos or screenshots)

Issue(s)

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where canceled, revoked, or disinvited federation invitations were not processed, causing stale subscriptions.
    • Improved invitation rejection handling to ensure subscriptions are cleaned up and membership state updates (e.g., leave) are applied correctly.

✏️ Tip: You can customize this high-level summary in your review settings.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Dec 12, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Dec 12, 2025

🦋 Changeset detected

Latest commit: 266f381

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/core-services Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/ui-voip Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/models Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

Walkthrough

This PR bumps the federation SDK across packages, adds 403-handling when rejecting Matrix invites (removing the local subscription on forbidden responses), and adds end-to-end tests covering revoked-invitation flows.

Changes

Cohort / File(s) Summary
Dependency bumps
.changeset/dull-tips-look.md, apps/meteor/package.json, ee/packages/federation-matrix/package.json, packages/core-services/package.json
Bump @rocket.chat/federation-sdk from 0.3.3 to 0.3.5 and add a changeset documenting the invite-handling bug fix.
Federation invite error handling
ee/packages/federation-matrix/src/FederationMatrix.ts
Import FederationRequestError and wrap rejectInvite with try/catch: on a FederationRequestError with status 403, call Room.performUserRemoval(room, user) and return; otherwise log and rethrow.
Federation tests
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
Add "Revoked invitation flow from Synapse" end-to-end test and update reject-invite tests to assert that rejection/removal cleans up the subscription and updates membership state.

Sequence Diagram(s)

sequenceDiagram
  participant RC as Rocket.Chat (FederationMatrix)
  participant SDK as `@rocket.chat/federation-sdk`
  participant Room as Room subsystem / DB
  RC->>SDK: rejectInvite(invite)
  alt SDK returns success
    SDK-->>RC: success
    RC->>Room: (no-op / keep subscription removed by normal flow)
  else SDK throws FederationRequestError (403)
    SDK-->>RC: throw FederationRequestError(403)
    RC->>Room: performUserRemoval(room, user)
    Room-->>RC: removal confirmed
  else SDK throws other error
    SDK-->>RC: throw Error
    RC->>RC: log error and rethrow
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay special attention to ee/packages/federation-matrix/src/FederationMatrix.ts for correct error-type detection and that Room.performUserRemoval is invoked only for 403 cases.
  • Review ee/packages/federation-matrix/tests/end-to-end/room.spec.ts for reliable setup/teardown and assertions reflecting subscription state transitions.
  • Verify dependency version consistency across the four manifest files.

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • sampaiodiego
  • rodrigok

Poem

🐇 I hopped through code with eager paws,
A 403 blocked invitation's cause.
I nibbled bugs and cleared the thread,
Now revoked invites are gently shed —
Hooray — subscriptions rest instead! ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main fix: handling federation 'disinvite' scenarios and duplicated messages, which aligns with the changeset and code modifications for invite revocation handling.
Linked Issues check ✅ Passed The PR addresses FB-144 by implementing error handling for 403 responses when accepting/rejecting revoked invitations, with proper user removal and subscription cleanup via updated federation-sdk dependency.
Out of Scope Changes check ✅ Passed All changes directly support the objectives: dependency updates for federation-sdk fix, error handling in FederationMatrix.ts for 403 responses, and test coverage for revoked invitation scenarios.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/feration-disinvite

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 01f9f99 and 266f381.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • apps/meteor/package.json (1 hunks)
  • ee/packages/federation-matrix/package.json (1 hunks)
  • packages/core-services/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/meteor/package.json
  • packages/core-services/package.json
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • ee/packages/federation-matrix/package.json
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/package.json
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (1)
ee/packages/federation-matrix/package.json (1)

25-25: @rocket.chat/federation-sdk version 0.3.5 does not exist on the public npm registry.

The dependency version specified (0.3.5) cannot be resolved from the public npm registry—only versions in the 0.1.x series are published. This will cause build failures unless:

  • Version 0.3.5 is available through a private Rocket.Chat npm registry
  • The version constraint should be updated to an existing published version
  • This PR is not intended for merge until after 0.3.5 is publicly released

Confirm registry access or update the version constraint before merging.

⛔ Skipped due to learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ggazzo ggazzo added this to the 7.14.0 milestone Dec 12, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 12, 2025

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.2GiB 1.2GiB +12MiB
rocketchat 358MiB 347MiB +12MiB
omnichannel-transcript-service 132MiB 132MiB -324B
queue-worker-service 132MiB 132MiB -714B
ddp-streamer-service 126MiB 126MiB +341B
account-service 113MiB 113MiB -259B
stream-hub-service 110MiB 110MiB -445B
presence-service 110MiB 110MiB +911B
authorization-service 110MiB 110MiB +644B

📊 Historical Trend

---
config:
  theme: "dark"
  xyChart:
    width: 900
    height: 400
---
xychart
  title "Image Size Evolution by Service (Last 30 Days + This PR)"
  x-axis ["11/15 22:28", "11/16 01:28", "11/17 23:50", "11/18 22:53", "11/19 23:02", "11/21 16:49", "11/24 17:34", "11/27 22:32", "11/28 19:05", "12/01 23:01", "12/02 21:57", "12/03 21:00", "12/04 18:17", "12/05 21:56", "12/08 20:15", "12/09 22:17", "12/10 23:26", "12/11 21:56", "12/12 22:45", "12/13 01:34", "12/15 16:51", "12/15 17:14 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12]
  line "omnichannel-transcript-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "queue-worker-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.35, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.35]
  line "stream-hub-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
Loading

Statistics (last 21 days):

  • 📊 Average: 1.5GiB
  • ⬇️ Minimum: 1.2GiB
  • ⬆️ Maximum: 1.6GiB
  • 🎯 Current PR: 1.2GiB
ℹ️ About this report

This report compares Docker image sizes from this build against the develop baseline.

  • Tag: pr-37791
  • Baseline: develop
  • Timestamp: 2025-12-15 17:14:01 UTC
  • Historical data points: 21

Updated: Mon, 15 Dec 2025 17:14:01 GMT

@codecov
Copy link

codecov bot commented Dec 12, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.72%. Comparing base (d3538e7) to head (266f381).
⚠️ Report is 8 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37791      +/-   ##
===========================================
- Coverage    67.80%   67.72%   -0.09%     
===========================================
  Files         3458     3458              
  Lines       113955   113953       -2     
  Branches     20927    20926       -1     
===========================================
- Hits         77271    77175      -96     
- Misses       34553    34648      +95     
+ Partials      2131     2130       -1     
Flag Coverage Δ
e2e 57.37% <ø> (ø)
e2e-api 42.29% <ø> (-0.99%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ggazzo ggazzo marked this pull request as ready for review December 12, 2025 23:23
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)

897-936: Handle revoked invite on accept path too (currently only clears on reject).

The original FB-144 repro scenario is "accept after disinvite". A 403 from the accept path currently propagates as an error without any subscription cleanup, leaving the INVITED subscription dangling. The reject path already handles this correctly by calling performUserRemoval on 403. Apply the same logic to accept: catch the 403, remove the stale subscription, then throw an error for the user.

 async handleInvite(roomId: IRoom['_id'], userId: IUser['_id'], action: 'accept' | 'reject'): Promise<void> {
@@
 		if (action === 'accept') {
+			try {
+				await federationSDK.acceptInvite(room.federation.mrid, matrixUserId);
+			} catch (error) {
+				if (error instanceof FederationRequestError && error.response?.status === 403) {
+					await Room.performUserRemoval(room, user);
+					throw new Error('Invitation was revoked');
+				}
+				throw error;
+			}
 
 			await Room.performAcceptRoomInvite(room, subscription, user);
+			return;
 		}
 		if (action === 'reject') {
 			try {
 				await federationSDK.rejectInvite(room.federation.mrid, matrixUserId);
 			} catch (error) {
-				if (error instanceof FederationRequestError && error.response.status === 403) {
+				if (error instanceof FederationRequestError && error.response?.status === 403) {
 					return Room.performUserRemoval(room, user);
 				}
 				this.logger.error(error, 'Failed to reject invite in Matrix');
 				throw error;
 			}
 		}
 	}

Also add optional chaining (error.response?.status) for defensive access to the response object.

🧹 Nitpick comments (2)
.changeset/dull-tips-look.md (1)

1-7: Changeset looks correct; consider making the description more specific (revoked invite → stale INVITED subscription / 403).
Current wording is fine, but a slightly more explicit summary will make release notes clearer.

ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)

1660-1705: Strengthen revoked-invite assertions (and add retries for eventual consistency).
Two improvements that will make this scenario more robust and more clearly tied to FB-144:

  • Poll for subscription removal (same reason as above).
  • When accept fails, assert the error message contains something like “revoked” (once implemented), and consider asserting the stale invitation is cleared (either on accept-403 cleanup or after reject).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d3538e7 and 01f9f99.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • .changeset/dull-tips-look.md (1 hunks)
  • apps/meteor/package.json (1 hunks)
  • ee/packages/federation-matrix/package.json (1 hunks)
  • ee/packages/federation-matrix/src/FederationMatrix.ts (2 hunks)
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1 hunks)
  • packages/core-services/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • packages/core-services/package.json
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • packages/core-services/package.json
  • .changeset/dull-tips-look.md
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • .changeset/dull-tips-look.md
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: When reviewing federation invite handling in Rocket.Chat (specifically under ee/packages/federation-matrix), understand that rejecting an invite via federationSDK.rejectInvite() triggers an event-driven cleanup: a leave event is emitted and handled by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, which calls Room.performUserRemoval() to remove the subscription. Do not add explicit cleanup in the reject branch of handleInvite(); rely on the existing leave-event flow for cleanup. If making changes, ensure this invariant remains and that any related paths still funnel cleanup through the leave event to avoid duplicate or missing removals.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-12-09T20:01:07.355Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • .changeset/dull-tips-look.md
🧬 Code graph analysis (1)
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (3)
apps/meteor/tests/data/rooms.helper.ts (3)
  • rejectRoomInvite (492-508)
  • getSubscriptions (467-479)
  • acceptRoomInvite (439-455)
ee/packages/federation-matrix/tests/helper/config.ts (1)
  • federationConfig (113-113)
ee/packages/federation-matrix/src/events/member.ts (1)
  • member (238-261)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (3)
packages/core-services/package.json (1)

18-22: Version alignment is correct.
All internal packages (core-services, federation-matrix, apps/meteor) consistently pin @rocket.chat/federation-sdk to 0.3.4, and yarn.lock resolves to a single version. No risk of duplicate installations or instanceof mismatches.

ee/packages/federation-matrix/package.json (1)

21-27: SDK bump to v0.3.4 is compatible with current code usage.

The @rocket.chat/federation-sdk v0.3.4 dependency is properly integrated. FederationRequestError is successfully imported and used throughout the codebase for error handling (e.g., checking error instanceof FederationRequestError && error.response.status === 403). The acceptInvite and rejectInvite methods are called consistently without issues. No breaking changes are evident from the working code patterns across the federation-matrix package.

apps/meteor/package.json (1)

101-101: federation-sdk version 0.3.4 is correctly applied across all workspace packages.

Version 0.3.4 is available on npm and all related package.json files (apps/meteor, ee/packages/federation-matrix, and packages/core-services) are consistently updated. The patch-level version bump is properly coordinated across the monorepo.

} from '@rocket.chat/core-typings';
import type { MessageQuoteAttachment, IMessage, IRoom, IUser, IRoomNativeFederated } from '@rocket.chat/core-typings';
import { eventIdSchema, roomIdSchema, userIdSchema, federationSDK } from '@rocket.chat/federation-sdk';
import { eventIdSchema, roomIdSchema, userIdSchema, federationSDK, FederationRequestError } from '@rocket.chat/federation-sdk';
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

@rocket.chat/federation-sdk v0.3.4 FederationRequestError export response status

💡 Result:

I don’t see the v0.3.4 source online right now. In practice, FederationRequestError objects usually expose the HTTP status in one of these places — try checking in this order:

  • err.response?.status
  • err.statusCode
  • err.status

If that doesn’t work, log the error keys (console.log(Object.keys(err)) or console.dir(err, { depth: null })) and share the output and/or the thrown error stack and I’ll look up the SDK source (or fetch v0.3.4 on npm/GitHub) and give exact accessors.


🏁 Script executed:

# First, check the actual error handling in FederationMatrix.ts around lines 925-934
fd FederationMatrix.ts | head -5

Repository: RocketChat/Rocket.Chat

Length of output: 119


🏁 Script executed:

# Search for FederationRequestError usage in the codebase
rg "FederationRequestError" --type ts --type tsx -B 2 -A 5

Repository: RocketChat/Rocket.Chat

Length of output: 93


🏁 Script executed:

# Check package.json for federation-sdk version
rg "@rocket.chat/federation-sdk" package.json

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Find the FederationMatrix.ts file and check lines around 925-934
fd FederationMatrix.ts -x cat -n {} | sed -n '920,940p'

Repository: RocketChat/Rocket.Chat

Length of output: 733


🏁 Script executed:

# Find package.json files that contain federation-sdk
fd package.json | xargs grep -l "federation-sdk"

Repository: RocketChat/Rocket.Chat

Length of output: 169


🏁 Script executed:

# Search for FederationRequestError with broader approach
rg "FederationRequestError" -A 5 -B 2

Repository: RocketChat/Rocket.Chat

Length of output: 1805


🏁 Script executed:

# Check the imports in FederationMatrix.ts
head -30 ee/packages/federation-matrix/src/FederationMatrix.ts

Repository: RocketChat/Rocket.Chat

Length of output: 1321


🏁 Script executed:

# Check federation-sdk version in ee/packages/federation-matrix/package.json
cat ee/packages/federation-matrix/package.json | grep -A 2 "federation-sdk"

Repository: RocketChat/Rocket.Chat

Length of output: 193


🏁 Script executed:

# Search for FederationRequestError class/interface definition in the codebase
rg "class FederationRequestError|interface FederationRequestError|type FederationRequestError" -A 10

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if there's a node_modules or type definitions for federation-sdk
fd "FederationRequestError" --type f

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Look for federation-sdk in node_modules or dist if available
find . -name "@rocket.chat" -type d 2>/dev/null | head -5

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Search for any imports or usage of error.response in the codebase to see patterns
rg "error\.response" -A 2 -B 2 | head -40

Repository: RocketChat/Rocket.Chat

Length of output: 3444


🏁 Script executed:

# Check if there are other places where FederationRequestError is caught and used
rg "instanceof FederationRequestError" -B 5 -A 5

Repository: RocketChat/Rocket.Chat

Length of output: 1024


Use defensive chaining for error.response.status to match codebase patterns: Line 929 accesses error.response.status directly without a null/undefined check, while similar error handling elsewhere in the codebase (webdav, webdavClientAdapter) uses optional chaining (error.response?.statusText). Add a guard (error.response?.status === 403) or validate that error.response exists before accessing status.

🤖 Prompt for AI Agents
In ee/packages/federation-matrix/src/FederationMatrix.ts around line 11 and
specifically where error.response.status is accessed (line ~929), the code
accesses error.response.status directly; change this to use defensive chaining
or a null check (e.g. error.response?.status === 403 or check that
error.response exists before reading status) to avoid runtime errors when
response is undefined, and mirror the existing pattern used elsewhere
(error.response?.statusText) so the conditional safely handles missing response
objects.

Comment on lines +1650 to 1657
it('should allow RC user to reject the invite and remove the subscription', async () => {
const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig);
expect(rejectResponse.success).toBe(true);
});

it('It should remove the subscription after rejection', async () => {
const subscriptions = await getSubscriptions(rc1AdminRequestConfig);

const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));

expect(invitedSub).toBeFalsy();
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid flakiness: wait/poll for subscription removal instead of asserting immediately.
If subscription cleanup is driven by async Matrix membership events, this can race. Prefer polling subscriptions.get until the INVITED sub disappears (or a timeout).

 it('should allow RC user to reject the invite and remove the subscription', async () => {
 	const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig);
 	expect(rejectResponse.success).toBe(true);
 
-	const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
-	const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
-	expect(invitedSub).toBeFalsy();
+	const deadline = Date.now() + 10_000;
+	while (true) {
+		const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
+		const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
+		if (!invitedSub) break;
+		if (Date.now() > deadline) throw new Error('Timed out waiting for invited subscription removal');
+		await new Promise((r) => setTimeout(r, 250));
+	}
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should allow RC user to reject the invite and remove the subscription', async () => {
const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig);
expect(rejectResponse.success).toBe(true);
});
it('It should remove the subscription after rejection', async () => {
const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
expect(invitedSub).toBeFalsy();
});
it('should allow RC user to reject the invite and remove the subscription', async () => {
const rejectResponse = await rejectRoomInvite(rid, rc1AdminRequestConfig);
expect(rejectResponse.success).toBe(true);
const deadline = Date.now() + 10_000;
while (true) {
const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
if (!invitedSub) break;
if (Date.now() > deadline) throw new Error('Timed out waiting for invited subscription removal');
await new Promise((r) => setTimeout(r, 250));
}
});
🤖 Prompt for AI Agents
In ee/packages/federation-matrix/tests/end-to-end/room.spec.ts around lines 1650
to 1657, the test asserts immediately that the invited subscription is removed
which can be flaky due to async Matrix membership events; replace the immediate
check with a polling/wait loop that repeatedly calls getSubscriptions (e.g.,
every 100–500ms) until the invited subscription is no longer present or a
sensible timeout (e.g., 5–10s) elapses, then assert that the invited
subscription is falsy; ensure the polling rejects/fails the test on timeout to
preserve test correctness.

@ggazzo ggazzo changed the title fix(federation): handle "disinvite" fix(federation): handle "disinvite" and duplicate messages Dec 15, 2025
@ggazzo ggazzo changed the title fix(federation): handle "disinvite" and duplicate messages fix(federation): handle "disinvite" and duplicated messages Dec 15, 2025
@sampaiodiego sampaiodiego added the stat: QA assured Means it has been tested and approved by a company insider label Dec 15, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Dec 15, 2025
@ggazzo ggazzo merged commit 1baa03c into develop Dec 15, 2025
51 of 53 checks passed
@ggazzo ggazzo deleted the feat/feration-disinvite branch December 15, 2025 21:17
gaolin1 pushed a commit to gaolin1/medsense.webchat that referenced this pull request Jan 6, 2026
…at#37791)

Co-authored-by: Jéssica Souza <jessica_schelly@hotmail.com>
@dougfabris dougfabris modified the milestones: 7.14.0, 8.0.0 Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants