Skip to content

Conversation

@ricardogarim
Copy link
Contributor

@ricardogarim ricardogarim commented Nov 25, 2025

Summary by CodeRabbit

  • Improvements
    • Standardized user identifier validation across federation member events to ensure consistent and reliable data integrity throughout federated server operations.
    • Enhanced verification of user state information in room operations, improving the robustness of member state management when interacting across federated servers.
    • Strengthened consistency checks for user identification in federation communications.

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

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 53.33333% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.79%. Comparing base (c3605da) to head (965ac0b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ckages/federation-sdk/src/services/room.service.ts 54.54% 5 Missing ⚠️
...ages/federation-sdk/src/services/invite.service.ts 0.00% 1 Missing ⚠️
...es/federation-sdk/src/services/profiles.service.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #308   +/-   ##
=======================================
  Coverage   52.79%   52.79%           
=======================================
  Files          96       96           
  Lines       12589    12590    +1     
=======================================
+ Hits         6646     6647    +1     
  Misses       5943     5943           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 25, 2025

Walkthrough

This pull request introduces and applies stateIdSchema validation across federation services and controllers. It exports the schema from the room package and systematically replaces raw user IDs with parsed state IDs in membership event construction and authorization checks across invite, profile, and room service layers.

Changes

Cohort / File(s) Summary
Type definitions & schema exports
packages/room/src/types/_common.ts, packages/room/src/types/v3-11.ts
Exports stateIdSchema and StateID type as public; updates PduNoContentStateEventSchema to use stateIdSchema for state_key validation
Federation SDK service layer
packages/federation-sdk/src/services/invite.service.ts, packages/federation-sdk/src/services/profiles.service.ts, packages/federation-sdk/src/services/room.service.ts
Systematically replaces raw user IDs with stateIdSchema.parse(<id>) when populating state_key fields in membership events and equality checks across invite, profile, and room operations
Homeserver controller layer
packages/homeserver/src/controllers/internal/invite.controller.ts, packages/homeserver/src/controllers/internal/room.controller.ts
Applies stateIdSchema.parse() to username and user IDs when constructing m.room.member invite and ban events

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • room.service.ts requires extra attention due to changes across multiple methods (createRoom, leaveRoom, kickUser, updateMemberProfile, power levels, joinUser) with numerous ID validation conversions
  • Verify schema parsing doesn't introduce unexpected validation failures in edge cases (empty strings, special characters)
  • Confirm equality checks comparing parsed IDs against existing event state_keys work correctly across all code paths

Possibly related PRs

Suggested reviewers

  • sampaiodiego

Poem

🐰 With schemas now parsing each ID string with care,
State keys are branded, normalized fair—
From services to controllers, consistency shines,
No raw IDs left in federation's lines! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing a StateID branded type for the state_key field in m.room.member events across multiple service files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/room-member-branded-stateid

📜 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 06f4fd1 and 965ac0b.

📒 Files selected for processing (7)
  • packages/federation-sdk/src/services/invite.service.ts (2 hunks)
  • packages/federation-sdk/src/services/profiles.service.ts (2 hunks)
  • packages/federation-sdk/src/services/room.service.ts (11 hunks)
  • packages/homeserver/src/controllers/internal/invite.controller.ts (2 hunks)
  • packages/homeserver/src/controllers/internal/room.controller.ts (2 hunks)
  • packages/room/src/types/_common.ts (1 hunks)
  • packages/room/src/types/v3-11.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/homeserver/src/controllers/internal/invite.controller.ts
  • packages/homeserver/src/controllers/internal/room.controller.ts
  • packages/federation-sdk/src/services/invite.service.ts
  • packages/federation-sdk/src/services/room.service.ts
  • packages/federation-sdk/src/services/profiles.service.ts
  • packages/room/src/types/_common.ts
  • packages/room/src/types/v3-11.ts
📚 Learning: 2025-09-14T13:34:12.448Z
Learnt from: ricardogarim
Repo: RocketChat/homeserver PR: 184
File: packages/federation-sdk/src/services/event-authorization.service.ts:213-223
Timestamp: 2025-09-14T13:34:12.448Z
Learning: ACL events (m.room.server_acl) are not yet implemented in the homeserver codebase, so ACL-related code currently handles the simpler case where no ACL events exist in room state.

Applied to files:

  • packages/homeserver/src/controllers/internal/room.controller.ts
🧬 Code graph analysis (6)
packages/homeserver/src/controllers/internal/invite.controller.ts (1)
packages/room/src/types/_common.ts (1)
  • stateIdSchema (18-18)
packages/homeserver/src/controllers/internal/room.controller.ts (1)
packages/room/src/types/_common.ts (1)
  • stateIdSchema (18-18)
packages/federation-sdk/src/services/invite.service.ts (1)
packages/room/src/types/_common.ts (1)
  • stateIdSchema (18-18)
packages/federation-sdk/src/services/room.service.ts (1)
packages/room/src/types/_common.ts (1)
  • stateIdSchema (18-18)
packages/federation-sdk/src/services/profiles.service.ts (1)
packages/room/src/types/_common.ts (1)
  • stateIdSchema (18-18)
packages/room/src/types/v3-11.ts (1)
packages/room/src/types/_common.ts (1)
  • stateIdSchema (18-18)
🔇 Additional comments (16)
packages/room/src/types/_common.ts (1)

18-20: LGTM!

The stateIdSchema and StateID type follow the same pattern as the existing eventIdSchema, roomIdSchema, and userIdSchema definitions, providing consistent branded type safety across all ID types.

packages/room/src/types/v3-11.ts (1)

642-647: LGTM!

Using stateIdSchema for state_key is semantically more accurate than userIdSchema, as state_key can contain user IDs (for member events), empty strings (for room-level state), or other identifiers depending on the event type.

packages/homeserver/src/controllers/internal/room.controller.ts (1)

358-358: LGTM!

The stateIdSchema.parse(userIdToBan) correctly brands the user ID for the state_key field. Since userIdToBan comes from URL path parameters, it will always be a string, so the parse won't throw.

packages/homeserver/src/controllers/internal/invite.controller.ts (1)

44-44: LGTM!

Consistent application of stateIdSchema.parse() for the invite event's state_key, matching the pattern used in other controllers.

packages/federation-sdk/src/services/profiles.service.ts (1)

94-94: LGTM!

The stateIdSchema.parse(userId) correctly converts the UserID branded type to StateID for the state_key field in the join membership event.

packages/federation-sdk/src/services/invite.service.ts (1)

86-86: LGTM!

Correctly applies stateIdSchema.parse(userId) to brand the user ID as a StateID for the invite event's state_key.

packages/federation-sdk/src/services/room.service.ts (10)

265-265: LGTM!

Correctly brands the creator's user ID as a StateID for the initial membership event's state_key.


490-490: LGTM!

The comparison correctly uses stateIdSchema.parse(senderId) to ensure type-safe matching against the event's state_key when finding the sender's membership auth event.


620-620: LGTM!

Consistent usage of stateIdSchema.parse() for the leave event's state_key.


701-701: LGTM!

Correctly uses stateIdSchema.parse(kickedUserId) for the kick event, where the state_key identifies the kicked user.


744-744: LGTM!

Properly brands the user ID for the profile update membership event's state_key.


827-827: LGTM!

Correctly applies stateIdSchema.parse(bannedUserId) for the ban event's state_key.


877-877: LGTM!

Consistent application for the join membership event in joinUser.


1427-1427: LGTM!

Correctly brands the creator's user ID for the DM room creator membership event.


1544-1544: LGTM!

Correctly brands the target user ID for the local DM room target membership event.


1602-1603: LGTM!

The includes() checks correctly compare parsed StateID values against the existing state_key values from membership events when searching for existing DM rooms.


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
Copy link
Member

ggazzo commented Nov 26, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

@ggazzo: I'll review the changes in this PR.


🧠 Learnings used
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the codebase to introduce a StateID branded type for the state_key field in state events, replacing the previous use of UserID. This change improves type safety by distinguishing between user identifiers and state keys, which can represent different types of values depending on the event type.

Key Changes:

  • Moved and reorganized the stateIdSchema and StateID type definition in _common.ts for better code organization
  • Updated PduNoContentStateEventSchema to use stateIdSchema instead of userIdSchema for the state_key field
  • Updated all event creation and comparison logic across controllers and services to properly parse user IDs to state IDs using stateIdSchema.parse()

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/room/src/types/_common.ts Reorganized type definitions by moving stateIdSchema and StateID type after userIdSchema
packages/room/src/types/v3-11.ts Updated PduNoContentStateEventSchema to use stateIdSchema for state_key, added import for stateIdSchema
packages/homeserver/src/controllers/internal/room.controller.ts Added stateIdSchema import and updated ban event creation to parse user ID to state ID
packages/homeserver/src/controllers/internal/invite.controller.ts Added stateIdSchema import and updated invite event creation to parse user ID to state ID
packages/federation-sdk/src/services/room.service.ts Added stateIdSchema import and updated multiple membership event creations and comparisons to parse user IDs to state IDs
packages/federation-sdk/src/services/profiles.service.ts Added stateIdSchema import and updated profile join event creation to parse user ID to state ID
packages/federation-sdk/src/services/invite.service.ts Added stateIdSchema import and updated invite event creation to parse user ID to state ID

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

Comment on lines +1602 to +1603
currentUserIds.includes(stateIdSchema.parse(userId1)) &&
currentUserIds.includes(stateIdSchema.parse(userId2))
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Calling stateIdSchema.parse() inside the includes() check adds unnecessary parsing overhead for each comparison. Consider parsing userId1 and userId2 to StateID once before the comparison:

const stateId1 = stateIdSchema.parse(userId1);
const stateId2 = stateIdSchema.parse(userId2);
if (
  currentUserIds.length === 2 &&
  currentUserIds.includes(stateId1) &&
  currentUserIds.includes(stateId2)
) {
  return roomId;
}

Copilot uses AI. Check for mistakes.
authEventIds,
'm.room.member',
(e) => e.event.state_key === senderId,
(e) => e.event.state_key === stateIdSchema.parse(senderId),
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Calling stateIdSchema.parse(senderId) inside the filter callback causes the parsing to be executed for each event during the search, which is inefficient. Consider parsing once before the callback:

const senderStateId = stateIdSchema.parse(senderId);
const memberAuthResult = this.getEventByType(
  authEventIds,
  'm.room.member',
  (e) => e.event.state_key === senderStateId,
);

Copilot uses AI. Check for mistakes.
@ggazzo ggazzo closed this Nov 27, 2025
@ggazzo ggazzo deleted the refactor/room-member-branded-stateid branch November 27, 2025 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants