Skip to content

fix(federation): revoke invite when banning a user who has not yet accepted#39839

Merged
sampaiodiego merged 9 commits intorelease-8.3.0from
fix/ban-invited-user-federation
Mar 30, 2026
Merged

fix(federation): revoke invite when banning a user who has not yet accepted#39839
sampaiodiego merged 9 commits intorelease-8.3.0from
fix/ban-invited-user-federation

Conversation

@ggazzo
Copy link
Copy Markdown
Member

@ggazzo ggazzo commented Mar 24, 2026

Summary

When a federated user is banned while still in INVITED state, the remote homeserver cannot process the ban event (no room state exists). The homeserver SDK now emits a membership.rejected event for this case.

This PR listens for the rejected event, resolves the local room and user, and calls a new Room.revokeInvite() method that removes the INVITED subscription and notifies the client so the invite disappears from the UI.

Changes

  • IRoomService / RoomService: new revokeInvite(room, user) method that removes an INVITED subscription and sends a removed notification to the client
  • federation-matrix/events/member.ts: new handleMembershipRejected handler that listens for homeserver.matrix.membership.rejected and cleans up the invite
  • docs/features/ban-user.md: documents the current ban/unban behavior

Depends on: RocketChat/homeserver#384 for the membership.rejected event and the getServerSetInRoom fix

Summary by CodeRabbit

  • New Features

    • Users can now revoke pending room invitations sent to other users for improved invitation management.
  • Improvements

    • Enhanced federation support for handling rejected membership events from federated systems.
  • Documentation

    • Added comprehensive documentation for user ban and unban features, including permission requirements, subscription behavior, system messages, UI interactions, REST API endpoints, and federation integration.

@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Mar 24, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 24, 2026

⚠️ No Changeset found

Latest commit: f57fc24

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

Walkthrough

This PR introduces invite revocation functionality by updating the federation-sdk dependency to v0.6.2 across multiple packages, adding a revokeInvite method to RoomService, integrating Matrix membership rejection event handling, and providing comprehensive ban/unban user documentation.

Changes

Cohort / File(s) Summary
Dependency Updates
apps/meteor/package.json, ee/packages/federation-matrix/package.json, packages/core-services/package.json
Updated @rocket.chat/federation-sdk from 0.6.0 to 0.6.2 across three package.json files.
Room Service Implementation
apps/meteor/server/services/room/service.ts, packages/core-services/src/types/IRoomService.ts
Added revokeInvite(room: IRoom, user: IUser) method to RoomService that removes user subscriptions with INVITED status and emits subscription removal notifications. Extended IRoomService interface with the new method signature.
Federation Matrix Integration
ee/packages/federation-matrix/src/events/member.ts
Added handleMembershipRejected() event handler for Matrix membership rejections that locates the local room and user, then calls Room.revokeInvite() to remove the invite.
Documentation
docs/features/ban-user.md
Added comprehensive specification of ban and unban user behavior across UI, REST, and slash commands, including federation propagation, access control, and related system messages.
Test Updates
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
Standardized test case titles to lowercase format and replaced explicit rejection test with subscription presence verification.

Sequence Diagram

sequenceDiagram
    participant Matrix as Matrix Homeserver
    participant SDK as Federation SDK
    participant Handler as Event Handler
    participant Service as RoomService
    participant Subs as Subscriptions

    Matrix->>SDK: Emit membership.rejected event
    SDK->>Handler: Route to handleMembershipRejected()
    Handler->>Handler: Locate local room & user
    Handler->>Service: revokeInvite(room, user)
    Service->>Subs: Fetch subscription (status='INVITED')
    Subs-->>Service: Return subscription
    Service->>Subs: removeById(subscription)
    Subs-->>Service: Confirmed
    Service->>Handler: Emit subscription 'removed' notification
    Handler-->>Matrix: Process complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

type: bug

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: implementing invite revocation for banned users in federation scenarios.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 changed the base branch from develop to release-8.3.0 March 27, 2026 21:35
@ggazzo ggazzo force-pushed the fix/ban-invited-user-federation branch from 3ff21de to 75ac572 Compare March 27, 2026 21:38
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 0% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.56%. Comparing base (df94285) to head (f57fc24).
⚠️ Report is 3 commits behind head on release-8.3.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                @@
##           release-8.3.0   #39839      +/-   ##
=================================================
- Coverage          70.61%   70.56%   -0.05%     
=================================================
  Files               3256     3258       +2     
  Lines             115790   115859      +69     
  Branches           21057    21038      -19     
=================================================
- Hits               81767    81760       -7     
- Misses             31961    32038      +77     
+ Partials            2062     2061       -1     
Flag Coverage Δ
e2e 60.59% <ø> (-0.10%) ⬇️
e2e-api 48.13% <0.00%> (+0.05%) ⬆️
unit 71.08% <ø> (-0.05%) ⬇️

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 added this to the 8.3.0 milestone Mar 30, 2026
@ggazzo ggazzo marked this pull request as ready for review March 30, 2026 13:54
@ggazzo ggazzo requested review from a team as code owners March 30, 2026 13:54
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docs/features/ban-user.md">

<violation number="1" location="docs/features/ban-user.md:80">
P3: The “Key Files” section uses incorrect repository paths for Meteor files (missing `apps/meteor/`), so several documented file references do not exist at the stated locations.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@coderabbitai coderabbitai bot added the type: feature Pull requests that introduces new feature label Mar 30, 2026
Copy link
Copy Markdown
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)
apps/meteor/app/lib/server/lib/notifyListener.ts (1)

487-497: ⚠️ Potential issue | 🔴 Critical

Notification broadcast fails silently when clientAction is 'removed'.

In revokeInvite (room/service.ts:156–157), the subscription is deleted via removeById before the notification function is called. Since removeById returns only a DeleteResult (not the deleted document), the subsequent query on line 492 (findByUserIdAndRoomIds) executes against a live collection with the subscription already removed, causing the cursor to be empty and the broadcast to never occur.

Compare with removeByRoomIdAndUserId (Subscriptions.ts:1932), which uses findOneAndDelete to retrieve the deleted document and allows callers to pass it directly to notifyOnSubscriptionChanged. Other models like LivechatInquiry and Settings use trashFind/trashFindOneById to handle the same scenario.

Suggested fix: Either call notifyOnSubscriptionChanged(subscription, 'removed') before deletion, or refactor revokeInvite to use removeByRoomIdAndUserId instead of removeById to obtain the deleted document.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/lib/server/lib/notifyListener.ts` around lines 487 - 497,
notifyOnSubscriptionChangedByRoomIdAndUserId is called after revokeInvite uses
removeById, so the subscription has already been deleted and the subsequent
findByUserIdAndRoomIds returns an empty cursor; fix by obtaining the deleted
document and passing it to the notifier (or notifying before deletion): either
change revokeInvite to call notifyOnSubscriptionChanged(subscription, 'removed')
before calling removeById, or refactor revokeInvite to use
Subscriptions.removeByRoomIdAndUserId / Subscriptions.findOneAndDelete (or the
model method that returns the deleted document) and then call
notifyOnSubscriptionChanged with that deleted subscription; update references to
revokeInvite, removeById, removeByRoomIdAndUserId,
notifyOnSubscriptionChangedByRoomIdAndUserId/notifyOnSubscriptionChanged
accordingly.
🧹 Nitpick comments (2)
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)

1799-1803: Consider adding a retry for async event processing.

The subscription cleanup depends on the membership.rejected event propagating and being processed asynchronously. Without a retry/wait, this test could be flaky if event processing takes longer than expected.

Consider wrapping the assertion in a retry helper (already used elsewhere in this file, e.g., line 1715-1728):

🔧 Suggested approach
 it('should not have the subscription on the RC side after revoked invitation', async () => {
+  await retry(
+    'waiting for subscription to be removed after revocation',
+    async () => {
       const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
       const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
       expect(invitedSub).toBeFalsy();
+    },
+    { retries: 10, delayMs: 500 },
+  );
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/packages/federation-matrix/tests/end-to-end/room.spec.ts` around lines
1799 - 1803, The assertion that the invited subscription is removed should be
made resilient to async event propagation by wrapping it in the existing retry
helper used earlier in this file; call retry and inside its callback call
getSubscriptions(rc1AdminRequestConfig), find invitedSub via
subscriptions.update.find((sub) => sub.fname?.includes(channelName)) and assert
invitedSub is falsy, retrying until success or timeout to account for the
asynchronous processing of the membership.rejected event.
docs/features/ban-user.md (1)

11-16: Improve repeated sentence starts in validation bullets

Lines 11–16 repeatedly start with “Checks/Rejects,” which makes the section read mechanically. Rewording a couple of bullets would improve readability.

Suggested wording tweak
-  - Checks if the banning user has access to the room.
-  - Checks if the target user exists and is in the room.
+  - Ensures the banning user has access to the room.
+  - Verifies the target user exists and is in the room.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/ban-user.md` around lines 11 - 16, The validation bullet list
for the "ban-user" feature reads repetitively because several lines start with
"Checks" or "Rejects"; edit the bullets to vary sentence starters and improve
flow—for example, change "Checks `ban-user` permission scoped to the room" to
"Verify the user has the `ban-user` permission for the room", change "Checks if
the room type allows the action (via `roomDirectives.allowMemberAction`)" to
"Ensure the room type permits this action (`roomDirectives.allowMemberAction`)",
change "Checks if the banning user has access to the room" to "Confirm the
banning user can access the room", and rephrase the two "Rejects" lines to "Do
not allow banning a user who is already banned" and "Prevent banning the last
owner"; update the file's bullet list accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/server/services/room/service.ts`:
- Around line 151-159: In revokeInvite, the subscription is removed with
Subscriptions.removeById which doesn't decrement Rooms.usersCount and the notify
call happens after deletion so no broadcast occurs; change the flow to call
notifyOnSubscriptionChangedByRoomIdAndUserId(room._id, user._id, 'removed')
before deleting, and replace Subscriptions.removeById(subscription._id) with
Subscriptions.removeByRoomIdAndUserId(room._id, user._id) so the rooms
usersCount is decremented (matching createWithRoomAndUser behavior) and the
notification can read the subscription before it's deleted.

In `@docs/features/ban-user.md`:
- Line 84: The docs line mixes a full path and a shorthand filename; update the
Key Files entry so both filenames use fully-qualified paths—change `unban.ts` to
`app/slashcommands-ban/server/unban.ts` to match
`app/slashcommands-ban/server/ban.ts` so readers can reliably locate both files.

---

Outside diff comments:
In `@apps/meteor/app/lib/server/lib/notifyListener.ts`:
- Around line 487-497: notifyOnSubscriptionChangedByRoomIdAndUserId is called
after revokeInvite uses removeById, so the subscription has already been deleted
and the subsequent findByUserIdAndRoomIds returns an empty cursor; fix by
obtaining the deleted document and passing it to the notifier (or notifying
before deletion): either change revokeInvite to call
notifyOnSubscriptionChanged(subscription, 'removed') before calling removeById,
or refactor revokeInvite to use Subscriptions.removeByRoomIdAndUserId /
Subscriptions.findOneAndDelete (or the model method that returns the deleted
document) and then call notifyOnSubscriptionChanged with that deleted
subscription; update references to revokeInvite, removeById,
removeByRoomIdAndUserId,
notifyOnSubscriptionChangedByRoomIdAndUserId/notifyOnSubscriptionChanged
accordingly.

---

Nitpick comments:
In `@docs/features/ban-user.md`:
- Around line 11-16: The validation bullet list for the "ban-user" feature reads
repetitively because several lines start with "Checks" or "Rejects"; edit the
bullets to vary sentence starters and improve flow—for example, change "Checks
`ban-user` permission scoped to the room" to "Verify the user has the `ban-user`
permission for the room", change "Checks if the room type allows the action (via
`roomDirectives.allowMemberAction`)" to "Ensure the room type permits this
action (`roomDirectives.allowMemberAction`)", change "Checks if the banning user
has access to the room" to "Confirm the banning user can access the room", and
rephrase the two "Rejects" lines to "Do not allow banning a user who is already
banned" and "Prevent banning the last owner"; update the file's bullet list
accordingly.

In `@ee/packages/federation-matrix/tests/end-to-end/room.spec.ts`:
- Around line 1799-1803: The assertion that the invited subscription is removed
should be made resilient to async event propagation by wrapping it in the
existing retry helper used earlier in this file; call retry and inside its
callback call getSubscriptions(rc1AdminRequestConfig), find invitedSub via
subscriptions.update.find((sub) => sub.fname?.includes(channelName)) and assert
invitedSub is falsy, retrying until success or timeout to account for the
asynchronous processing of the membership.rejected event.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 76cb8f86-3219-4d52-b591-5bf3eda236cd

📥 Commits

Reviewing files that changed from the base of the PR and between 9d42d28 and e82a4ce.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • apps/meteor/app/lib/server/lib/notifyListener.ts
  • apps/meteor/package.json
  • apps/meteor/server/services/room/service.ts
  • docs/features/ban-user.md
  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • packages/core-services/package.json
  • packages/core-services/src/types/IRoomService.ts
📜 Review details
⏰ 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). (1)
  • GitHub Check: 📦 Build Packages
🧰 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:

  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • apps/meteor/app/lib/server/lib/notifyListener.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 (30)
📓 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.
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.

Applied to files:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/package.json
  • packages/core-services/package.json
📚 Learning: 2026-02-24T19:09:09.561Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.

Applied to files:

  • apps/meteor/package.json
📚 Learning: 2026-02-24T19:05:56.710Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 0
File: :0-0
Timestamp: 2026-02-24T19:05:56.710Z
Learning: Rocket.Chat repo context: When a workspace manifest on develop already pins a dependency version (e.g., packages/web-ui-registration → "rocket.chat/ui-contexts": "27.0.1"), a lockfile change in a feature PR that upgrades only that dependency’s resolution is considered a manifest-driven sync and can be kept, preferably as a small "chore: sync yarn.lock with manifests" commit.

Applied to files:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/package.json
  • 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
  • packages/core-services/package.json
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2026-02-24T19:05:56.710Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 0
File: :0-0
Timestamp: 2026-02-24T19:05:56.710Z
Learning: In Rocket.Chat PRs, keep feature PRs free of unrelated lockfile-only dependency bumps; prefer reverting lockfile drift or isolating such bumps into a separate "chore" commit/PR, and always use yarn install --immutable with the Yarn version pinned in package.json via Corepack.

Applied to files:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/package.json
  • packages/core-services/package.json
📚 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
  • packages/core-services/package.json
  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2026-03-14T14:58:58.834Z
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.

Applied to files:

  • apps/meteor/package.json
📚 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/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 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:

  • apps/meteor/package.json
  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.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:

  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • apps/meteor/app/lib/server/lib/notifyListener.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • apps/meteor/app/lib/server/lib/notifyListener.ts
📚 Learning: 2026-03-09T18:39:21.178Z
Learnt from: Harxhit
Repo: RocketChat/Rocket.Chat PR: 39476
File: apps/meteor/server/methods/addAllUserToRoom.ts:0-0
Timestamp: 2026-03-09T18:39:21.178Z
Learning: In apps/meteor/server/methods/addAllUserToRoom.ts, the implementation uses a single cursor pass (Users.find(userFilter).batchSize(100)) that collects both the full user objects (collectedUsers: IUser[]) and their usernames (usernames: string[]) in one iteration. `beforeAddUserToRoom` is then called once with the full usernames batch (preserving batch-validation semantics), and the subsequent subscription/message processing loop iterates over the same stable `collectedUsers` array — no second DB query is made. This avoids any race condition between validation and processing while preserving the original batch-validation behavior.

Applied to files:

  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • docs/features/ban-user.md
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/room/service.ts
  • apps/meteor/app/lib/server/lib/notifyListener.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/room/service.ts
  • apps/meteor/app/lib/server/lib/notifyListener.ts
📚 Learning: 2026-03-11T22:04:20.529Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 39545
File: apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts:59-61
Timestamp: 2026-03-11T22:04:20.529Z
Learning: In `apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts`, the `msg.u._id === uid` early-return in the `streamNewMessage` handler is intentional: the "New messages" indicator is designed to notify about messages from other users only. Self-sent messages — including those sent from a different session/device — are always skipped, by design. Do not flag this as a multi-session regression.

Applied to files:

  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • apps/meteor/app/lib/server/lib/notifyListener.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/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-12-10T21:00:54.909Z
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.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to **/*.spec.ts : Use descriptive test names that clearly communicate expected behavior in Playwright tests

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2026-03-04T14:16:49.202Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39304
File: packages/ui-contexts/src/ActionManagerContext.ts:26-26
Timestamp: 2026-03-04T14:16:49.202Z
Learning: In `packages/ui-contexts/src/ActionManagerContext.ts` (TypeScript, RocketChat/Rocket.Chat), the `disposeView` method in `IActionManager` uses an intentionally explicit union `UiKit.ModalView['id'] | UiKit.BannerView['viewId'] | UiKit.ContextualBarView['id']` to document which view types are accepted, even though all constituents resolve to the same primitive. The inline `// eslint-disable-next-line typescript-eslint/no-duplicate-type-constituents` comment is intentional and should not be flagged or removed.

Applied to files:

  • apps/meteor/app/lib/server/lib/notifyListener.ts
📚 Learning: 2026-03-11T18:15:53.272Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/app/api/server/v1/rooms.ts:294-296
Timestamp: 2026-03-11T18:15:53.272Z
Learning: In Rocket.Chat's `rooms.mediaConfirm/:rid/:fileId` endpoint (apps/meteor/app/api/server/v1/rooms.ts), updating `file.name` from `bodyParams.fileName` without updating `file.path` is intentionally safe. The file path is keyed by `_id` (not by filename), so the stored path remains valid regardless of a rename. `file.name` only affects the display name in the message attachment; do not flag this as a path-divergence issue.

Applied to files:

  • docs/features/ban-user.md
🪛 LanguageTool
docs/features/ban-user.md

[style] ~14-~14: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...nning user has access to the room. - Checks if the target user exists and is in the...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (7)
packages/core-services/package.json (1)

21-21: LGTM!

Dependency bump aligns with the PR requirement for the new homeserver.matrix.membership.rejected event support.

apps/meteor/package.json (1)

106-106: LGTM!

Consistent dependency bump across the monorepo packages.

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

25-25: LGTM!

Required dependency bump for the federation-matrix package to access the new homeserver.matrix.membership.rejected event.

packages/core-services/src/types/IRoomService.ts (1)

43-43: LGTM!

Well-placed interface addition alongside related invite handling methods. The signature follows existing patterns.

ee/packages/federation-matrix/src/events/member.ts (2)

398-426: LGTM!

The handleMembershipRejected handler follows existing patterns in the file:

  • Silent early returns for missing room/user align with the federation pattern of silently skipping remote-initiated events when local state doesn't match.
  • Proper logging for debugging revocation flow.
  • Correct usage of getUsernameServername consistent with other handlers like handleLeave and handleBan.

455-462: LGTM!

Event listener registration follows the established error-handling pattern used by the homeserver.matrix.membership handler above.

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

98-98: LGTM!

Test description rewording improves readability while maintaining descriptive test names per coding guidelines.

Also applies to: 115-115, 135-135, 157-157, 179-179, 229-229, 261-261, 350-350, 361-361, 391-391, 450-450, 465-465, 508-508, 533-533, 599-599, 616-616, 678-678, 862-862, 873-873, 903-903, 968-968, 983-983, 1030-1030, 1104-1104, 1121-1121, 1183-1183, 1273-1273, 1284-1284, 1314-1314, 1379-1379, 1394-1394, 1441-1441, 1514-1514, 1531-1531, 1593-1593, 1664-1664, 1673-1673, 1714-1714

ggazzo and others added 8 commits March 30, 2026 15:20
…cepted

When a federated user is banned while still in INVITED state, the remote
homeserver cannot validate the ban event (no room state exists locally).
The federation SDK now emits a membership.rejected event for this case.

Listen for the rejected event and clean up the INVITED subscription via
a new Room.revokeInvite() method, so the invite disappears from the UI.

Includes ban-user feature documentation.
@sampaiodiego sampaiodiego force-pushed the fix/ban-invited-user-federation branch from e82a4ce to 0baf143 Compare March 30, 2026 20:27
@coderabbitai coderabbitai bot added type: bug and removed type: feature Pull requests that introduces new feature labels Mar 30, 2026
Copy link
Copy Markdown
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: 1

♻️ Duplicate comments (2)
docs/features/ban-user.md (1)

84-84: ⚠️ Potential issue | 🟡 Minor

Use a fully-qualified path for unban.ts in the Key Files table.

This row mixes one fully-qualified path with one shorthand filename, which hurts scanability in docs navigation.

Suggested docs fix
-| Slash commands | `app/slashcommands-ban/server/ban.ts`, `unban.ts` |
+| Slash commands | `app/slashcommands-ban/server/ban.ts`, `app/slashcommands-ban/server/unban.ts` |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/ban-user.md` at line 84, The Key Files table entry currently
mixes a fully-qualified path with a shorthand filename; update the table row to
use fully-qualified paths for both files by replacing `unban.ts` with its full
path `app/slashcommands-ban/server/unban.ts` so the row reads
`app/slashcommands-ban/server/ban.ts, app/slashcommands-ban/server/unban.ts`,
ensuring consistent, scannable docs (edit the Key Files table in
docs/features/ban-user.md where the slash commands row is defined).
apps/meteor/server/services/room/service.ts (1)

161-161: ⚠️ Potential issue | 🟠 Major

Use counter-aware deletion when revoking invites.

At Line 161, Subscriptions.removeById(subscription._id) can leave room membership counters inconsistent. Prefer the room/user removal path that also updates usersCount.

Suggested fix
-		await Subscriptions.removeById(subscription._id);
+		await Subscriptions.removeByRoomIdAndUserId(room._id, user._id);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/server/services/room/service.ts` at line 161, Replace the direct
call to Subscriptions.removeById(subscription._id) with the room/user removal
path that updates membership counters (e.g., call the existing
removeUserFromRoom or Rooms.removeUserById-style helper used elsewhere) so that
usersCount on the Room is decremented correctly; locate the call to
Subscriptions.removeById(subscription._id) and swap it for the project’s
counter-aware removal function that accepts the room and user/subscription
identifiers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/server/services/room/service.ts`:
- Around line 156-161: The two-step check-then-delete on subscription is racy:
instead of calling Subscriptions.findOneByRoomIdAndUserId(...) and then
Subscriptions.removeById(subscription._id), perform a single conditional delete
that includes status: 'INVITED' (e.g. call a remove method that accepts a filter
{_id: subscription._id, status: 'INVITED'} or add a new
Subscriptions.removeByIdAndStatus/_removeWithFilter helper) so the deletion only
succeeds if the row is still INVITED atomically.

---

Duplicate comments:
In `@apps/meteor/server/services/room/service.ts`:
- Line 161: Replace the direct call to
Subscriptions.removeById(subscription._id) with the room/user removal path that
updates membership counters (e.g., call the existing removeUserFromRoom or
Rooms.removeUserById-style helper used elsewhere) so that usersCount on the Room
is decremented correctly; locate the call to
Subscriptions.removeById(subscription._id) and swap it for the project’s
counter-aware removal function that accepts the room and user/subscription
identifiers.

In `@docs/features/ban-user.md`:
- Line 84: The Key Files table entry currently mixes a fully-qualified path with
a shorthand filename; update the table row to use fully-qualified paths for both
files by replacing `unban.ts` with its full path
`app/slashcommands-ban/server/unban.ts` so the row reads
`app/slashcommands-ban/server/ban.ts, app/slashcommands-ban/server/unban.ts`,
ensuring consistent, scannable docs (edit the Key Files table in
docs/features/ban-user.md where the slash commands row is defined).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6057453-b85d-4912-997a-749ec5c270fc

📥 Commits

Reviewing files that changed from the base of the PR and between e82a4ce and f57fc24.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (8)
  • apps/meteor/package.json
  • apps/meteor/server/services/room/service.ts
  • docs/features/ban-user.md
  • ee/packages/federation-matrix/package.json
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • packages/core-services/package.json
  • packages/core-services/src/types/IRoomService.ts
✅ Files skipped from review due to trivial changes (4)
  • ee/packages/federation-matrix/package.json
  • apps/meteor/package.json
  • packages/core-services/package.json
  • packages/core-services/src/types/IRoomService.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/member.ts
📜 Review details
⏰ 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). (1)
  • GitHub Check: 📦 Build Packages
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{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:

  • apps/meteor/server/services/room/service.ts
🧠 Learnings (19)
📓 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.
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.
📚 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:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-03-09T18:39:21.178Z
Learnt from: Harxhit
Repo: RocketChat/Rocket.Chat PR: 39476
File: apps/meteor/server/methods/addAllUserToRoom.ts:0-0
Timestamp: 2026-03-09T18:39:21.178Z
Learning: In apps/meteor/server/methods/addAllUserToRoom.ts, the implementation uses a single cursor pass (Users.find(userFilter).batchSize(100)) that collects both the full user objects (collectedUsers: IUser[]) and their usernames (usernames: string[]) in one iteration. `beforeAddUserToRoom` is then called once with the full usernames batch (preserving batch-validation semantics), and the subsequent subscription/message processing loop iterates over the same stable `collectedUsers` array — no second DB query is made. This avoids any race condition between validation and processing while preserving the original batch-validation behavior.

Applied to files:

  • apps/meteor/server/services/room/service.ts
  • docs/features/ban-user.md
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-03-11T22:04:20.529Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 39545
File: apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts:59-61
Timestamp: 2026-03-11T22:04:20.529Z
Learning: In `apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts`, the `msg.u._id === uid` early-return in the `streamNewMessage` handler is intentional: the "New messages" indicator is designed to notify about messages from other users only. Self-sent messages — including those sent from a different session/device — are always skipped, by design. Do not flag this as a multi-session regression.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 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/server/services/room/service.ts
📚 Learning: 2026-03-12T10:26:26.697Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39340
File: apps/meteor/app/api/server/v1/im.ts:1349-1398
Timestamp: 2026-03-12T10:26:26.697Z
Learning: In `apps/meteor/app/api/server/v1/im.ts` (PR `#39340`), the `DmEndpoints` type intentionally includes temporary stub entries for `/v1/im.kick`, `/v1/dm.kick`, `/v1/im.leave`, and `/v1/dm.leave` (using `DmKickProps` and `DmLeaveProps`) even though no route handlers exist for them yet. These stubs were added to preserve type compatibility after removing the original `DmLeaveProps` and related files. They are planned for cleanup in a follow-up PR. Do not flag these as missing implementations when reviewing this file until the follow-up is merged.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/server/services/room/service.ts
  • docs/features/ban-user.md
📚 Learning: 2026-03-14T14:58:58.834Z
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-03-11T16:46:55.955Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 39535
File: apps/meteor/app/apps/server/bridges/livechat.ts:249-249
Timestamp: 2026-03-11T16:46:55.955Z
Learning: In `apps/meteor/app/apps/server/bridges/livechat.ts`, `createVisitor()` intentionally does not propagate `externalIds` to `registerData`. This is by design: the method is deprecated (JSDoc: `deprecated Use createAndReturnVisitor instead. Note: This method does not support externalIds.`) to push callers toward `createAndReturnVisitor()`, which does support `externalIds`. Do not flag the missing `externalIds` field in `createVisitor()` as a bug.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/server/services/room/service.ts
📚 Learning: 2026-03-11T18:15:53.272Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/app/api/server/v1/rooms.ts:294-296
Timestamp: 2026-03-11T18:15:53.272Z
Learning: In Rocket.Chat's `rooms.mediaConfirm/:rid/:fileId` endpoint (apps/meteor/app/api/server/v1/rooms.ts), updating `file.name` from `bodyParams.fileName` without updating `file.path` is intentionally safe. The file path is keyed by `_id` (not by filename), so the stored path remains valid regardless of a rename. `file.name` only affects the display name in the message attachment; do not flag this as a path-divergence issue.

Applied to files:

  • docs/features/ban-user.md
📚 Learning: 2025-11-19T12:32:29.696Z
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.

Applied to files:

  • docs/features/ban-user.md
📚 Learning: 2026-03-15T14:31:28.969Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39647
File: apps/meteor/app/api/server/v1/users.ts:710-757
Timestamp: 2026-03-15T14:31:28.969Z
Learning: In RocketChat/Rocket.Chat, the `UserCreateParamsPOST` type in `apps/meteor/app/api/server/v1/users.ts` (migrated from `packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts`) intentionally has `fields: string` (non-optional) and `settings?: IUserSettings` without a corresponding AJV schema entry. This is a pre-existing divergence carried over verbatim from the original rest-typings source (PR `#39647`). Do not flag this type/schema misalignment during the OpenAPI migration review — it is tracked as a separate follow-up fix.

Applied to files:

  • docs/features/ban-user.md
📚 Learning: 2026-03-12T17:12:49.121Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:28-33
Timestamp: 2026-03-12T17:12:49.121Z
Learning: Rocket.Chat — apps/meteor/client/lib/chats/flows/uploadFiles.ts: When E2E_Enable_Encrypt_Files is disabled, plaintext file uploads are allowed in E2E rooms; this fallback is expected and should not be flagged as a security regression.

Applied to files:

  • docs/features/ban-user.md
📚 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:

  • docs/features/ban-user.md
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • docs/features/ban-user.md
🪛 LanguageTool
docs/features/ban-user.md

[style] ~14-~14: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...nning user has access to the room. - Checks if the target user exists and is in the...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (2)
docs/features/ban-user.md (1)

1-91: Good coverage and structure for ban/unban behavior docs.

The flow breakdown, callback notes, and endpoint/system-message mapping are clear and actionable for both product and engineering readers.

apps/meteor/server/services/room/service.ts (1)

25-29: Import update looks fine.

@sampaiodiego sampaiodiego merged commit 2b7ee36 into release-8.3.0 Mar 30, 2026
45 of 46 checks passed
@sampaiodiego sampaiodiego deleted the fix/ban-invited-user-federation branch March 30, 2026 21:23
@sampaiodiego sampaiodiego added the stat: QA assured Means it has been tested and approved by a company insider label Mar 30, 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 type: bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants