Skip to content

Conversation

@ricardogarim
Copy link
Contributor

@ricardogarim ricardogarim commented Sep 25, 2025

As per FDR-159, this PR introduces two new middlewares for federation routes:

  • isAuthenticatedMiddleware — ensures request signature validation.
  • canAccessResourceMiddleware — enforces resource-based authorization and internally calls isAuthenticatedMiddleware.
Method Route RC - sign RC - resource HS - sign HS - resource MP - sign MP - resource
GET /_matrix/federation/v1/event_auth/{roomId}/{eventId} YES YES YES YES YES YES
GET /_matrix/federation/v1/backfill/{roomId} YES YES YES YES YES YES
POST /_matrix/federation/v1/get_missing_events/{roomId} YES YES YES YES YES YES
GET /_matrix/federation/v1/event/{eventId} YES YES YES YES YES NO
GET /_matrix/federation/v1/make_join/{roomId}/{stateKey} YES YES YES YES YES YES
PUT /_matrix/federation/v1/send_join/{roomId}/{stateKey} YES YES YES YES YES YES
PUT /_matrix/federation/v2/invite/{roomId}/{eventId} YES NO YES NO YES YES***
GET /_matrix/federation/v1/publicRooms YES NO YES NO YES NO
POST /_matrix/federation/v1/publicRooms YES NO YES NO YES NO
GET /_matrix/federation/v1/query/profile YES NO YES NO YES NO
GET /_matrix/federation/v1/user/devices/{userId} YES NO YES NO YES NO
POST /_matrix/federation/v1/user/keys/query YES NO YES NO YES NO
GET /_matrix/federation/v1/media/download/{mediaId} YES YES YES YES YES NO*
PUT /_matrix/federation/v1/send/{txnId} YES NO YES NO YES NO**
GET /.well-known/matrix/server NO NO NO NO NO NO
GET /_matrix/federation/v1/version NO NO NO NO NO NO

* Note: The Server Access Control Lists (ACLs) section doesn’t explicitly mention enforcing ACLs on media, but we understand it as necessary and are applying it accordingly.

** Note: MP suggests handling ACLs and resource access per PDU/EDU internally rather than through middleware. We're delegating this responsibility to state resolution. TODO: Verify that all scenarios are properly covered.

*** Note: We're dealing with ACL on the state instead of a middleware. TODO: Verify that all scenarios are properly covered.

RC = Rocket.Chat; HS = Homeserver; MP = Matrix Protocol.

Relates to RocketChat/homeserver#224.

Summary by CodeRabbit

  • New Features

    • Federation endpoints now require authenticated federation requests; verified server context is passed to invite and room flows.
    • Route-level access checks added across room, event, and media endpoints.
  • Bug Fixes

    • Clearer 401/403/404/500 responses for unauthorized, missing, or errored federation requests.
    • Media downloads return proper multipart responses and headers; thumbnails report not implemented.
    • Invite join path returns a clearer error when joining is not possible.
    • Devices endpoint returns 501 Not Implemented.
  • Refactor

    • Consolidated resource-level access checks into a single middleware.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Sep 25, 2025

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

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Sep 25, 2025

⚠️ No Changeset found

Latest commit: 2e4a6fe

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
Contributor

coderabbitai bot commented Sep 25, 2025

Walkthrough

Adds request signature verification and a unified resource-access middleware, removes legacy per-entity middlewares, wires authentication and ACL into federation Matrix routes (invite, media, profiles, send-join, transactions, rooms), passes authenticatedServer into invite processing, and bumps @rocket.chat/federation-sdk to 0.1.25.

Changes

Cohort / File(s) Summary
New middlewares
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts, ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts
Add isAuthenticatedMiddleware (verifies request signature, stores authenticatedServer) and canAccessResourceMiddleware (extracts entity id and enforces resource-level authorization for room/event/media).
Removed legacy middlewares
ee/packages/federation-matrix/src/api/middlewares.ts
Remove exported canAccessMedia and canAccessEvent implementations and related imports.
Invite route
ee/packages/federation-matrix/src/api/_matrix/invite.ts
Destructure federationAuth; apply isAuthenticatedMiddleware(federationAuth); obtain authenticatedServer from context and pass it to invite.processInvite; shorten join-room error message.
Media routes
ee/packages/federation-matrix/src/api/_matrix/media.ts
Replace prior middleware with canAccessResourceMiddleware(federationAuth, 'media'); inline Router return; add tags; implement explicit 200 multipart responses and 404/500 error handling; thumbnail returns M_UNRECOGNIZED.
Profiles & devices
ee/packages/federation-matrix/src/api/_matrix/profiles.ts
Apply isAuthenticatedMiddleware(federationAuth) at router level; protect room-related endpoints with canAccessResourceMiddleware(federationAuth, 'room'); change /v1/user/devices/:userId to return 501 Not Implemented.
Send-join route
ee/packages/federation-matrix/src/api/_matrix/send-join.ts
Destructure federationAuth and add canAccessResourceMiddleware(federationAuth, 'room') to route middleware chain; handler unchanged.
Transactions routes
ee/packages/federation-matrix/src/api/_matrix/transactions.ts
Add isAuthenticatedMiddleware(federationAuth) for PUT /v1/send/:txnId; apply canAccessResourceMiddleware for room routes (state_ids, state, backfill) and for event on GET /v1/event/:eventId.
Rooms router
ee/packages/federation-matrix/src/api/_matrix/rooms.ts
Apply isAuthenticatedMiddleware(federationAuth) at router level; no handler logic changes.
Deps bumped
ee/packages/federation-matrix/package.json, packages/core-services/package.json
Bump @rocket.chat/federation-sdk from 0.1.23 to 0.1.25.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client as Federation Client
  participant Router as Matrix Router
  participant Auth as isAuthenticatedMiddleware
  participant ACL as canAccessResourceMiddleware
  participant Handler as Route Handler

  Client->>Router: HTTP request (/_matrix/federation/v1/...)
  Router->>Auth: verifyRequestSignature(Authorization, method, path, body)
  alt verification failed
    Auth-->>Client: 401 M_UNAUTHORIZED
  else verification success
    Auth-->>Router: store authenticatedServer
    Router->>ACL: canAccessResource(entityType, resourceId, authenticatedServer)
    alt invalid params or access denied
      ACL-->>Client: 400 M_INVALID_PARAM or 403 M_FORBIDDEN
    else access granted
      Router->>Handler: execute handler (invite/media/transactions/...)
      Handler-->>Client: 2xx / 4xx / 5xx
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • rodrigok
  • sampaiodiego

Poem

I'm a rabbit in the headers, ears tuned to each sign,
I check the signature, stash the server that's mine.
Rooms and media guarded, events get a nod,
401 or 403 — I hop so the world stays odd. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning In addition to ACL refactoring, the PR introduces a 501 stub for the user-devices endpoint and updates @rocket.chat/federation-sdk versions in package.json, neither of which relate to applying access controls as mandated by FDR-159. These functional and dependency changes extend beyond the scope of the linked issue. Please isolate the user-devices stub and SDK version bump into a separate commit or PR so that this change remains focused solely on applying ACL middlewares.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely summarizes the primary change introduced by this PR—adding both authentication and resource authorization middlewares to the federation codebase—and aligns directly with the refactor scope.
Linked Issues Check ✅ Passed This PR implements signature validation via isAuthenticatedMiddleware and enforces ACLs with canAccessResourceMiddleware across all specified federation routes, replacing legacy media and event authorization handlers and aligning with the objectives of FDR-159.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/federation-middlewares

📜 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 b43e6fe and 2e4a6fe.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • 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)
  • packages/core-services/package.json
  • 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

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.

@ricardogarim ricardogarim changed the title refactor: add federation isAuthenticated and canAccessResource middlewares refactor(federation): add isAuthenticated and canAccessResource middlewares Sep 25, 2025
Base automatically changed from chore/federation-backup to develop September 25, 2025 23:25
@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch 2 times, most recently from a9908ec to 05982a0 Compare September 27, 2025 13:25
@ricardogarim ricardogarim marked this pull request as ready for review September 29, 2025 10:42
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 (3)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (2)

311-317: Validation mismatch: “event_id” is a query param, not a path param.

Both state_ids and state routes declare event_id under params, but you read it from the query. This can cause validation failures or lack of validation where needed.

Minimal fix in route options:

-{
-  params: isGetStateIdsParamsProps,
+{
+  // params: roomId schema (optional to add)
+  query: isGetStateIdsParamsProps,
   response: { … }
}
…
-{
-  params: isGetStateParamsProps,
+{
+  // params: roomId schema (optional to add)
+  query: isGetStateParamsProps,
   response: { … }
}

Optionally add a dedicated RoomIdParamsSchema and use it in params for both routes.

Also applies to: 341-347


283-289: Typo in error payload key (“errorcode” → “errcode”).

Matrix errors use “errcode”. This response currently returns “errorcode”.

- errorcode: 'M_UNKNOWN',
+ errcode: 'M_UNKNOWN',
ee/packages/federation-matrix/src/api/_matrix/invite.ts (1)

139-152: Backoff bug: seconds vs milliseconds mix-up (retries trigger too early and escalate incorrectly).

You compute delay in “seconds” but pass ms to the next cycle and seconds to setTimeout. Fix to keep units consistent and cap properly.

 async function runWithBackoff(fn: () => Promise<void>, delaySec = 5) {
   try {
     await fn();
   } catch (e) {
-    const delay = delaySec === 625 ? 625 : delaySec ** 2;
-    console.log(`error occurred, retrying in ${delay}ms`, e);
-    setTimeout(() => {
-      runWithBackoff(fn, delay * 1000);
-    }, delay);
+    const nextDelaySec = delaySec === 625 ? 625 : delaySec ** 2; // 5 -> 25 -> 625 -> 625 ...
+    console.log(`error occurred, retrying in ${nextDelaySec}s`, e);
+    setTimeout(() => {
+      void runWithBackoff(fn, nextDelaySec);
+    }, nextDelaySec * 1000);
   }
 }
🧹 Nitpick comments (11)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (2)

10-13: Confirm body format used for signature verification; handle bad JSON as 400.

You parse JSON from a cloned body and pass the object to verifyRequestSignature. If the verifier expects canonical bytes, object reserialization may break signatures; if it expects parsed JSON, this is fine. Also, a JSON parse error currently becomes a 500 (M_UNKNOWN). Consider mapping SyntaxError to 400 (M_BAD_JSON) and passing raw text to the verifier if required.

Example adjustment:

- const body = c.req.raw.body ? await c.req.raw.clone().json() : undefined;
+ let body: unknown = undefined;
+ if (c.req.raw.body) {
+   try {
+     // If verifier expects raw, prefer: await c.req.text()
+     body = await c.req.raw.clone().json();
+   } catch (e) {
+     return c.json({ errcode: 'M_BAD_JSON', error: 'Invalid JSON' }, 400);
+   }
+ }

Please confirm what verifyRequestSignature expects and adjust accordingly.

Also applies to: 24-33


35-36: Type the context variable for safer downstream usage.

Set a typed variable on Context to avoid any-typed c.get('authenticatedServer') consumers.

-export const isAuthenticatedMiddleware = (federationAuth: EventAuthorizationService) =>
-  createMiddleware(async (c: Context, next) => {
+type Vars = { authenticatedServer: { serverName: string; keyId: string } }; // shape per verifier result
+export const isAuthenticatedMiddleware = (federationAuth: EventAuthorizationService) =>
+  createMiddleware<{ Variables: Vars }>(async (c: Context, next) => {-    c.set('authenticatedServer', verificationResult);
+    c.set('authenticatedServer', verificationResult);
     return next();
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)

31-36: Skip-on-missing-entity is fine; consider explicit allowlist of routes.

Skipping when no entity param exists is convenient but can mask missing checks on new routes. Consider an allowlist or a per-route opt-in to make intent explicit.

ee/packages/federation-matrix/src/api/_matrix/media.ts (3)

100-115: Stream large media instead of buffering in memory.

Buffering entire files risks high memory usage and GC pressure. Prefer a streaming response (Readable stream) with proper headers; multipart boundaries can be written chunked.

Example (illustrative):

- // TODO: Add file streaming support
- const result = await getMediaFile(mediaId, serverName);
+ // Stream file to avoid buffering large payloads
+ const result = await MatrixMediaService.getLocalFileForMatrixNode(mediaId, serverName);
  if (!result) {
    return {
      statusCode: 404,
      body: { errcode: 'M_NOT_FOUND', error: 'Media not found' },
    };
  }
- const { file, buffer } = result;
+ const file = result;
+ const fileStream = await MatrixMediaService.getLocalFileReadStream(file); // or equivalent API

  const mimeType = file.type || 'application/octet-stream';
- const fileName = file.name || mediaId;
+ const fileName = sanitizeFilename(file.name || mediaId);

- const multipartResponse = createMultipartResponse(buffer, mimeType, fileName);
+ const { stream, contentType } = createMultipartStream(fileStream, mimeType, fileName);

  return {
    statusCode: 200,
    headers: {
      ...SECURITY_HEADERS,
-     'content-type': multipartResponse.contentType,
-     'content-length': String(multipartResponse.body.length),
+     'content-type': contentType,
+     // omit content-length to allow chunked transfer when streaming
    },
-   body: multipartResponse.body,
+   body: stream,
  };

Additional helper signatures (outside diff scope):

function sanitizeFilename(name: string): string { return name.replace(/[\r\n"]/g, '_'); }
function createMultipartStream(fileStream: NodeJS.ReadableStream, mime: string, name: string) { /* write preamble and boundary, pipe stream, write closing boundary */ }

103-107: Include security headers on error responses for consistency.

Return SECURITY_HEADERS on 404/500 as well.

  if (!result) {
    return {
      statusCode: 404,
+     headers: SECURITY_HEADERS,
      body: { errcode: 'M_NOT_FOUND', error: 'Media not found' },
    };
  }

} catch (error) {
  return {
    statusCode: 500,
+   headers: SECURITY_HEADERS,
    body: { errcode: 'M_UNKNOWN', error: 'Internal server error' },
  };
}

Also applies to: 126-129


86-93: Response schema for 200 doesn’t match a binary/multipart body.

Using an Ajv “object” schema for a Buffer/multipart is misleading and brittle. Either drop validation for 200 here or model as string with contentEncoding=binary if your tooling supports it.

- 200: isBufferResponseProps,
+ // 200 is binary/multipart; skip Ajv validation to avoid false positives
+ // 200: isBinaryResponseProps,
ee/packages/federation-matrix/src/api/_matrix/invite.ts (3)

306-313: Validate invite body with a concrete schema and expose 401/403 in spec.

Replace the TODO with a schema that matches the handler’s { event, room_version } and include 401/403 produced by middlewares.

- body: ajv.compile({ type: 'object' }), // TODO: add schema from room package.
+ body: ajv.compile({
+   type: 'object',
+   properties: {
+     event: RoomMemberEventSchema,
+     room_version: { type: 'string' },
+   },
+   required: ['event', 'room_version'],
+ }),
   params: isProcessInviteParamsProps,
   response: {
-   200: isProcessInviteResponseProps,
+   200: isProcessInviteResponseProps,
+   401: ajv.compile({ type: 'object', properties: { errcode: { type: 'string' }, error: { type: 'string' } }, required: ['errcode','error'] }),
+   403: ajv.compile({ type: 'object', properties: { errcode: { type: 'string' }, error: { type: 'string' } }, required: ['errcode','error'] }),
   },

314-355: Wrap handler in try/catch and return Matrix error shape on failures.

Current throws will bubble as generic 500s. Align with media route and middleware error style.

- async (c) => {
-   const { roomId, eventId } = c.req.param();
-   const { event, room_version: roomVersion } = await c.req.json();
-   ...
-   return { body: { event: inviteEvent.event }, statusCode: 200 };
- }
+ async (c) => {
+   try {
+     const { roomId, eventId } = c.req.param();
+     const { event, room_version: roomVersion } = await c.req.json();
+     ...
+     return { body: { event: inviteEvent.event }, statusCode: 200 };
+   } catch (e) {
+     return { statusCode: 500, body: { errcode: 'M_UNKNOWN', error: 'Internal server error' } };
+   }
+ }

324-329: Harden Matrix ID parsing
Avoid brittle split(':') and slice(1) — explicitly parse and validate the full @user:domain format. Extract or implement a shared parseMatrixUserId helper that returns validated { localpart, domain }, then use it here.

ee/packages/federation-matrix/src/api/_matrix/send-join.ts (2)

235-242: Expose 401/403 in route response spec.

Middlewares can return 401/403; reflect that in the schema.

 response: {
-  200: isSendJoinResponseProps,
+  200: isSendJoinResponseProps,
+  401: ajv.compile({ type: 'object', properties: { errcode: { type: 'string' }, error: { type: 'string' } }, required: ['errcode','error'] }),
+  403: ajv.compile({ type: 'object', properties: { errcode: { type: 'string' }, error: { type: 'string' } }, required: ['errcode','error'] }),
 },

243-253: Add try/catch to map unexpected errors to Matrix error response.

Keep handler consistent with other routes.

- async (c) => {
-   const { roomId, stateKey } = c.req.param();
-   const body = await c.req.json();
-   const response = await sendJoin.sendJoin(roomId, stateKey as EventID, body);
-   return { body: response, statusCode: 200 };
- }
+ async (c) => {
+   try {
+     const { roomId, stateKey } = c.req.param();
+     const body = await c.req.json();
+     const response = await sendJoin.sendJoin(roomId, stateKey as EventID, body);
+     return { body: response, statusCode: 200 };
+   } catch (e) {
+     return { statusCode: 500, body: { errcode: 'M_UNKNOWN', error: 'Internal server error' } };
+   }
+ }
📜 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 dca0b3a and 05982a0.

📒 Files selected for processing (9)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/media.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/profiles.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/send-join.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/middlewares.ts (0 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/index.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • ee/packages/federation-matrix/src/api/middlewares.ts
🧰 Additional context used
🧬 Code graph analysis (7)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
ee/packages/federation-matrix/src/api/middlewares/index.ts (1)
  • canAccessResourceMiddleware (5-5)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (23-53)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (3)
ee/packages/federation-matrix/src/api/middlewares/index.ts (2)
  • isAuthenticatedMiddleware (4-4)
  • canAccessResourceMiddleware (5-5)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (23-53)
ee/packages/federation-matrix/src/api/_matrix/media.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (23-53)
ee/packages/federation-matrix/src/api/_matrix/send-join.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (23-53)
ee/packages/federation-matrix/src/api/_matrix/invite.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (23-53)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
ee/packages/federation-matrix/src/api/middlewares/index.ts (1)
  • isAuthenticatedMiddleware (4-4)
🪛 GitHub Actions: CI
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts

[error] 38-38: TS2339: Property 'canAccessResource' does not exist on type 'EventAuthorizationService'.

🔇 Additional comments (5)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (1)

349-352: Good middleware order; verify intended coverage for routes without entity params.

Auth runs before resource access, which is correct. Note that routes like /v1/query/profile and /v1/user/devices/:userId have no eventId/roomId/mediaId, so canAccessResource will skip checks and only authentication applies. Confirm this matches your security model for these endpoints.

ee/packages/federation-matrix/src/api/_matrix/transactions.ts (1)

261-263: Auth + resource middleware applied correctly at router level.

Order is correct. Be aware /v1/send/:txnId has no recognized entity param, so only authentication will run there; resource check will skip.

ee/packages/federation-matrix/src/api/middlewares/index.ts (1)

1-5: Re-export barrel looks good.

Centralizing the middleware exports simplifies imports across routes.

ee/packages/federation-matrix/src/api/_matrix/send-join.ts (1)

229-232: LGTM: middlewares applied at router level.

AuthN/AuthZ gating is correctly wired ahead of the handler.

ee/packages/federation-matrix/src/api/_matrix/media.ts (1)

79-94: Incorrect resource-authorization concern: mediaId is already handled.
The canAccessResourceMiddleware maps mediaId to type "media" and enforces ACL checks, so no additional media‐specific guard is needed.

Likely an incorrect or invalid review comment.

@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch from 05ee026 to f533048 Compare September 30, 2025 20:33
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: 1

♻️ Duplicate comments (1)
ee/packages/federation-matrix/src/api/_matrix/media.ts (1)

110-114: Sanitize filename to prevent header injection.

The filename from file.name can contain quotes or CR/LF characters that could corrupt MIME headers in the multipart response. This was previously flagged and remains unaddressed.

Apply this diff to add sanitization:

+function sanitizeFilename(input: string): string {
+  return input.replace(/[\r\n"]/g, '_').slice(0, 200);
+}
+
 async function getMediaFile(mediaId: string, serverName: string): Promise<{ file: IUpload; buffer: Buffer } | null> {

Then update line 111:

 const mimeType = file.type || 'application/octet-stream';
-const fileName = file.name || mediaId;
+const fileName = sanitizeFilename(file.name || mediaId);
🧹 Nitpick comments (3)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (1)

351-351: Review layered authentication approach.

The base router applies isAuthenticatedMiddleware(federationAuth) (line 351), and specific routes also apply canAccessResourceMiddleware(federationAuth, 'room') (lines 426, 454, 478). Since canAccessResourceMiddleware internally composes isAuthenticatedMiddleware (per relevant code snippets), routes with canAccessResourceMiddleware will run authentication twice. This is redundant but not harmful.

Consider either:

  1. Remove base-level isAuthenticatedMiddleware and apply canAccessResourceMiddleware to all routes that need it
  2. Apply only resource-specific checks to individual routes if base auth is sufficient
ee/packages/federation-matrix/src/api/_matrix/media.ts (2)

124-129: Consider logging errors before returning generic error response.

The catch block returns a generic M_UNKNOWN error without logging the original error. This makes debugging difficult in production. Consider logging the error before returning the response.

Apply this diff to add error logging:

 } catch (error) {
+  console.error('Media download error:', error);
   return {
     statusCode: 500,
     body: { errcode: 'M_UNKNOWN', error: 'Internal server error' },
   };
 }

132-149: Consider using 501 Not Implemented for consistency.

The thumbnail endpoint returns 404 to indicate it's not implemented, but 501 (Not Implemented) would be more semantically correct and consistent with the /v1/user/devices/:userId endpoint in profiles.ts (line 419).

Apply this diff:

 async () => ({
-  statusCode: 404,
+  statusCode: 501,
   body: {
     errcode: 'M_UNRECOGNIZED',
     error: 'This endpoint is not implemented on the homeserver side',
   },
 }),
📜 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 05ee026 and f533048.

📒 Files selected for processing (8)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/media.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/profiles.ts (5 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/send-join.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts (5 hunks)
  • ee/packages/federation-matrix/src/api/middlewares.ts (0 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • ee/packages/federation-matrix/src/api/middlewares.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • ee/packages/federation-matrix/src/api/_matrix/send-join.ts
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts
  • ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts
🧰 Additional context used
🧬 Code graph analysis (3)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/_matrix/media.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/_matrix/invite.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
⏰ 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: ✅ Tests Done
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (8)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (2)

24-33: LGTM!

Signature verification is correctly implemented with proper error handling and Matrix-compliant error responses.


38-38: Manual verification required: confirm errCodes.M_UNKNOWN shape
Ensure that errCodes.M_UNKNOWN provides both errcode and error properties as expected by the JSON response schema; adjust the middleware to wrap or supplement those fields if it does not.

ee/packages/federation-matrix/src/api/_matrix/invite.ts (2)

15-15: LGTM!

The import and service extraction correctly integrate the new middleware infrastructure.

Also applies to: 298-298


303-303: Verify 'room' entity type for invite validation.

The middleware uses 'room' as the entity type for access validation. Ensure that canAccessResource properly validates room access in the invite context. Based on a previous review comment on profiles.ts asking about resource validation, confirm that the authenticated server has permission to invite users to the specified room.

ee/packages/federation-matrix/src/api/_matrix/profiles.ts (2)

413-421: LGTM!

Returning 501 Not Implemented with M_UNRECOGNIZED is appropriate for endpoints that are not yet supported by the homeserver.


426-426: Verify 'room' entity type validation for these endpoints.

All three routes use canAccessResourceMiddleware(federationAuth, 'room'). Confirm that:

  1. make_join - validates the requesting server can participate in the room join flow
  2. get_missing_events - validates the requesting server has access to the room's event history
  3. event_auth - validates the requesting server can query the room's authorization chain

This addresses the previous review comment asking "what resource is being validated here?"

Based on learnings (previous review comment on this file).

Also applies to: 454-454, 478-478

ee/packages/federation-matrix/src/api/_matrix/media.ts (2)

9-9: LGTM!

Import and service extraction follow the established pattern for middleware integration.

Also applies to: 77-78


79-93: LGTM!

Route configuration correctly applies media-specific access control and defines comprehensive response schemas.

@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch from f533048 to 3c66363 Compare September 30, 2025 20:38
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: 1

♻️ Duplicate comments (1)
ee/packages/federation-matrix/src/api/_matrix/media.ts (1)

110-113: Sanitize filename to prevent header injection.

The file.name value is used directly in the Content-Disposition header within the multipart response (line 55 in createMultipartResponse). An attacker-controlled filename containing CR/LF (\r\n) or double quotes can inject additional headers or corrupt the MIME structure, potentially leading to security vulnerabilities such as header injection attacks.

Apply this diff to sanitize the filename:

-					const fileName = file.name || mediaId;
+					const fileName = sanitizeFilename(file.name || mediaId);

Add a helper function at the module level (after imports, before route definitions):

function sanitizeFilename(input: string): string {
	// Remove CR/LF and dangerous quotes; clamp length
	return input.replace(/[\r\n"]/g, '_').slice(0, 200);
}
🧹 Nitpick comments (1)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (1)

262-381: Avoid double signature verification in federation transactions

canAccessResourceMiddleware already wraps isAuthenticatedMiddleware, so adding a router-level .use(isAuthenticatedMiddleware(federationAuth)) causes every state/event request to verify the Matrix signature twice. That doubles the crypto work on hot paths and adds latency without strengthening security. Consider limiting isAuthenticatedMiddleware to the /v1/send/:txnId route (or introducing a version of canAccessResourceMiddleware that skips the auth wrapper) so other handlers don't incur the redundant verification.

📜 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 f533048 and 9c49c78.

📒 Files selected for processing (6)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (3 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/media.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/profiles.ts (6 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/send-join.ts (3 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts (5 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts
🧰 Additional context used
🧬 Code graph analysis (5)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/_matrix/media.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/_matrix/invite.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/_matrix/send-join.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
⏰ 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 (9)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (4)

5-6: LGTM!

The new middleware imports are correctly placed and will be used throughout the file.


348-351: LGTM! Router-level authentication applied correctly.

The isAuthenticatedMiddleware at the router level ensures all federation endpoints require signature verification before proceeding to handlers. This centralizes authentication and eliminates per-route duplication.


413-420: LGTM! Correct Matrix error format for unimplemented endpoint.

The 501 response with M_UNRECOGNIZED and a descriptive error message follows Matrix spec conventions for unsupported endpoints.


434-434: LGTM! Room resource access control correctly applied.

The canAccessResourceMiddleware(federationAuth, 'room') middleware correctly validates that the authenticated server has permission to access the specified room resource before executing the handler. This addresses the previous review question about what resource is being validated—the roomId parameter extracted from the route is checked against the server's access rights.

Each of these three endpoints (make_join, get_missing_events, event_auth) operates on room-scoped data, so the 'room' resource type is appropriate.

Also applies to: 462-462, 485-485

ee/packages/federation-matrix/src/api/_matrix/media.ts (5)

9-9: LGTM!

The middleware import is correctly placed and used later in the file.


78-93: LGTM! Media download route properly secured.

The route definition correctly applies canAccessResourceMiddleware(federationAuth, 'media') to ensure the authenticated server has permission to access the requested media resource. The schema validation and response type definitions are comprehensive.


95-106: LGTM! Proper 404 handling for missing media.

The error response correctly returns a 404 status with the Matrix-spec-compliant M_NOT_FOUND error code when media is not found.


115-123: LGTM! Appropriate security headers for media responses.

The response includes comprehensive security headers (X-Content-Type-Options, X-Frame-Options, CSP, HSTS) to mitigate common web vulnerabilities when serving user-uploaded media.


124-129: LGTM! Proper error handling with Matrix-compliant response.

The catch block returns a 500 status with the Matrix M_UNKNOWN error code, maintaining consistency with the Matrix specification.

Comment on lines +132 to +149
.get(
'/v1/media/thumbnail/:mediaId',
{
params: isMediaDownloadParamsProps,
response: {
404: isErrorResponseProps,
},
tags: ['Federation', 'Media'],
},
}),
);

return router;
canAccessResourceMiddleware(federationAuth, 'media'),
async (_c) => ({
statusCode: 404,
body: {
errcode: 'M_UNRECOGNIZED',
error: 'This endpoint is not implemented on the homeserver side',
},
}),
);
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

Status code mismatch: use 501 for unimplemented endpoints.

The endpoint returns a 404 status code with an error message stating "This endpoint is not implemented on the homeserver side." This is semantically incorrect—404 indicates "resource not found," while 501 indicates "not implemented."

Apply this diff to use the correct status code:

 		.get(
 			'/v1/media/thumbnail/:mediaId',
 			{
 				params: isMediaDownloadParamsProps,
 				response: {
-					404: isErrorResponseProps,
+					501: isErrorResponseProps,
 				},
 				tags: ['Federation', 'Media'],
 			},
 			canAccessResourceMiddleware(federationAuth, 'media'),
 			async (_c) => ({
-				statusCode: 404,
+				statusCode: 501,
 				body: {
 					errcode: 'M_UNRECOGNIZED',
 					error: 'This endpoint is not implemented on the homeserver side',
 				},
 			}),
 		);
📝 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
.get(
'/v1/media/thumbnail/:mediaId',
{
params: isMediaDownloadParamsProps,
response: {
404: isErrorResponseProps,
},
tags: ['Federation', 'Media'],
},
}),
);
return router;
canAccessResourceMiddleware(federationAuth, 'media'),
async (_c) => ({
statusCode: 404,
body: {
errcode: 'M_UNRECOGNIZED',
error: 'This endpoint is not implemented on the homeserver side',
},
}),
);
.get(
'/v1/media/thumbnail/:mediaId',
{
params: isMediaDownloadParamsProps,
response: {
501: isErrorResponseProps,
},
tags: ['Federation', 'Media'],
},
canAccessResourceMiddleware(federationAuth, 'media'),
async (_c) => ({
statusCode: 501,
body: {
errcode: 'M_UNRECOGNIZED',
error: 'This endpoint is not implemented on the homeserver side',
},
}),
);
🤖 Prompt for AI Agents
In ee/packages/federation-matrix/src/api/_matrix/media.ts around lines 132 to
149, the thumbnail route returns a 404 while the handler message says the
endpoint is not implemented; change the response statusCode to 501 and ensure
the returned body remains the same so the HTTP status semantically matches "Not
Implemented" (501) instead of "Not Found" (404).

@ricardogarim ricardogarim changed the base branch from develop to chore/fed-branded October 6, 2025 13:42
@ricardogarim ricardogarim requested review from a team as code owners October 6, 2025 13:42
@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch 2 times, most recently from cc1bbf8 to 3d413f6 Compare October 6, 2025 14:31
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: 0

♻️ Duplicate comments (4)
apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts (1)

2-2: LGTM! Migration matches the HeaderV2 version.

The migration is correct and identical to the one in apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts. Both hooks now use the REST endpoint /v1/livechat/inquiries.returnAsInquiry with the proper payload structure.

Also applies to: 11-11, 17-17

ee/packages/federation-matrix/src/api/_matrix/media.ts (2)

132-149: Use 501 Not Implemented for thumbnail endpoint.

Returning 404 with “not implemented” message is semantically wrong. Use 501.

Apply:

-				response: {
-					404: isErrorResponseProps,
+				response: {
+					501: isErrorResponseProps,
 				},
...
-			async (_c) => ({
-				statusCode: 404,
+			async (_c) => ({
+				statusCode: 501,
 				body: {
 					errcode: 'M_UNRECOGNIZED',
 					error: 'This endpoint is not implemented on the homeserver side',
 				},
 			}),

110-114: Sanitize filename to prevent header injection in multipart.

file.name can contain quotes or CR/LF. Sanitize or RFC5987-encode before embedding in Content-Disposition.

Apply:

-					const fileName = file.name || mediaId;
+					const fileName = sanitizeFilename(file.name || mediaId);

Add helper (outside selected range):

function sanitizeFilename(input: string): string {
  return input.replace(/[\r\n"]/g, '_').slice(0, 200);
}
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)

2-72: Fix auth compat, robust ID extraction, and deny-by-default on missing ID.

  • EventAuthorizationService may not expose canAccessResource (TS2339). Add runtime fallback to canAccessEvent/Room/Media, deny-by-default.
  • In our router, params can be empty in middlewares. Add fallbacks: use body.room_id for 'room' and parse mediaId from URL for 'media'.
  • If no ID is determinable, return 400 instead of 500 to avoid accidental allow/deny drift.

Apply:

 import { errCodes } from '@rocket.chat/federation-sdk';
-import type { EventAuthorizationService } from '@rocket.chat/federation-sdk';
+import type { EventAuthorizationService } from '@rocket.chat/federation-sdk';
 import { every } from 'hono/combine';
 import { createMiddleware } from 'hono/factory';
 
 import { isAuthenticatedMiddleware } from './isAuthenticated';
 
+// Runtime-compatible auth surface (older SDKs may lack canAccessResource)
+type ResourceAuth = EventAuthorizationService & {
+	canAccessResource?: (type: 'event' | 'media' | 'room', id: string, server: unknown) => Promise<boolean>;
+	canAccessEvent?: (id: string, server: unknown) => Promise<boolean>;
+	canAccessRoom?: (id: string, server: unknown) => Promise<boolean>;
+	canAccessMedia?: (id: string, server: unknown) => Promise<boolean>;
+};
+
 function extractEntityId(params: { eventId?: string; mediaId?: string; roomId?: string }, entityType: 'event' | 'media' | 'room'): string {
   if (entityType === 'room') {
     const { roomId } = params;
     if (!roomId) {
       throw new Error('Room ID is required');
     }
 
     return roomId;
   }
 
   if (entityType === 'media') {
     const { mediaId } = params;
     if (!mediaId) {
       throw new Error('Media ID is required');
     }
 
     return mediaId;
   }
 
   if (entityType === 'event') {
     const { eventId } = params;
     if (!eventId) {
       throw new Error('Event ID is required');
     }
 
     return eventId;
   }
 
   throw new Error('Invalid entity type');
 }
 
-const canAccessResource = (federationAuth: EventAuthorizationService, entityType: 'event' | 'media' | 'room') =>
+const canAccessResource = (federationAuth: ResourceAuth, entityType: 'event' | 'media' | 'room') =>
 	createMiddleware(async (c, next) => {
 		try {
 			const authenticatedServer = c.get('authenticatedServer');
 			if (!authenticatedServer) {
 				return c.json({ errcode: 'M_UNAUTHORIZED', error: 'Missing Authorization header' }, 401);
 			}
 
-			const mediaId = c.req.param('mediaId');
-			const eventId = c.req.param('eventId');
-			const roomId = c.req.param('roomId');
-
-			const resourceAccess = await federationAuth.canAccessResource(
-				entityType,
-				extractEntityId({ mediaId, eventId, roomId }, entityType),
-				authenticatedServer,
-			);
+			// Params may be empty inside middlewares on this router; add robust extraction.
+			const paramsAll = (typeof (c.req as any).param === 'function' ? (c.req as any).param() : {}) as
+				| { mediaId?: string; eventId?: string; roomId?: string; stateKey?: string }
+				| undefined;
+			let mediaId = paramsAll?.mediaId;
+			let eventId = paramsAll?.eventId;
+			let roomId = paramsAll?.roomId;
+
+			// Fallback to body where applicable
+			let body: any | undefined;
+			try {
+				body = c.req.raw.body ? await c.req.raw.clone().json() : undefined;
+			} catch {
+				// ignore body parse errors here
+			}
+			if (!roomId) {
+				roomId = body?.room_id || body?.roomId || body?.event?.room_id;
+			}
+			// Fallback for media: parse from URL if missing
+			if (!mediaId) {
+				const pathname = new URL(c.req.url).pathname;
+				const m = pathname.match(/\/media\/(?:download|thumbnail)\/([^/]+)/);
+				if (m) {
+					try {
+						mediaId = decodeURIComponent(m[1]);
+					} catch {
+						mediaId = m[1];
+					}
+				}
+			}
+
+			// Determine resource id based on the entityType
+			let resourceId: string | undefined;
+			if (entityType === 'room') resourceId = roomId;
+			else if (entityType === 'event') resourceId = eventId;
+			else if (entityType === 'media') resourceId = mediaId;
+
+			if (!resourceId) {
+				return c.json(
+					{
+						errcode: 'M_BAD_JSON',
+						error: 'Missing resource identifier',
+					},
+					400,
+				);
+			}
+
+			// Compatibility: prefer canAccessResource, fallback to per-entity methods, deny-by-default
+			let allowed = false;
+			if (typeof federationAuth.canAccessResource === 'function') {
+				allowed = await federationAuth.canAccessResource(entityType, resourceId, authenticatedServer);
+			} else if (entityType === 'event' && typeof federationAuth.canAccessEvent === 'function') {
+				allowed = await federationAuth.canAccessEvent(resourceId, authenticatedServer);
+			} else if (entityType === 'room' && typeof federationAuth.canAccessRoom === 'function') {
+				allowed = await federationAuth.canAccessRoom(resourceId, authenticatedServer);
+			} else if (entityType === 'media' && typeof federationAuth.canAccessMedia === 'function') {
+				allowed = await federationAuth.canAccessMedia(resourceId, authenticatedServer);
+			} else {
+				allowed = false;
+			}
+			const resourceAccess = allowed;
 			if (!resourceAccess) {
 				return c.json(
 					{
 						errcode: 'M_FORBIDDEN',
 						error: 'Access denied to resource',
 					},
 					403,
 				);
 			}
 
 			return next();
 		} catch (error) {
 			return c.json(errCodes.M_UNKNOWN, 500);
 		}
 	});
 
-export const canAccessResourceMiddleware = (federationAuth: EventAuthorizationService, entityType: 'event' | 'media' | 'room') =>
+export const canAccessResourceMiddleware = (federationAuth: ResourceAuth, entityType: 'event' | 'media' | 'room') =>
 	every(isAuthenticatedMiddleware(federationAuth), canAccessResource(federationAuth, entityType));

This also satisfies the suggestion to fail closed when we cannot determine the resource. Based on prior CI failure and reviewer notes.

🧹 Nitpick comments (7)
apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts (1)

2-2: LGTM! Clean migration from deprecated method to REST endpoint.

The changes correctly migrate from the deprecated livechat:returnAsInquiry method to the REST endpoint /v1/livechat/inquiries.returnAsInquiry. The payload structure change from rid to { roomId: rid } aligns with REST API conventions.

Note: This hook is duplicated in apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts. Consider consolidating both into a shared location (e.g., apps/meteor/client/lib/omnichannel/hooks/) to reduce maintenance burden.

Also applies to: 11-11, 17-17

apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx (1)

125-135: Excellent accessibility improvements, but refine list item display.

The addition of semantic HTML (<ul>/<li>) and ARIA attributes (aria-labelledby) significantly improves screen reader support. However, using display='inline' on list items can degrade accessibility because some screen readers may not properly announce list semantics when items are inline-styled.

Apply this diff to use inline-block for better screen reader compatibility:

-							<ul aria-labelledby={`${roomId}-tags`}>
+							<ul aria-labelledby={`${roomId}-tags`} style={{ display: 'flex', flexWrap: 'wrap', gap: '4px', listStyle: 'none', padding: 0 }}>
 								{tags.map((tag) => (
-									<Box is='li' key={tag} mie={4} display='inline'>
-										<Tag style={{ display: 'inline' }} disabled>
+									<Box is='li' key={tag}>
+										<Tag disabled>
 											{tag}
 										</Tag>
 									</Box>

This preserves the inline layout while maintaining list semantics for assistive technologies.

apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts (1)

56-66: Scope selectors to the Edit Room dialog and harden selectTag against closed dropdowns

Current selectors search the whole page and can match unrelated elements. Also, selectTag assumes the dropdown is open. Scope to dialog and ensure the listbox is visible before clicking.

Apply:

 get inputTags(): Locator {
-  return this.page.getByRole('textbox', { name: 'Select an option' });
+  return this.dialogEditRoom.getByRole('textbox', { name: 'Select an option' });
 }

 optionTags(name: string): Locator {
-  return this.page.getByRole('option', { name, exact: true });
+  return this.page.getByRole('listbox').getByRole('option', { name, exact: true });
 }

 async selectTag(name: string): Promise<void> {
-  await this.optionTags(name).click();
+  const listbox = this.page.getByRole('listbox');
+  if (!(await listbox.isVisible())) {
+    await this.inputTags.click();
+    await listbox.waitFor();
+  }
+  await this.optionTags(name).click();
 }

If the control uses role="combobox" with a different accessible name (e.g., “Tags”), prefer getByRole('combobox', { name: 'Tags' }) for inputTags. As per coding guidelines.

apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (3)

84-89: Wait for the tag listbox after opening to reduce flakiness

After clicking the input, wait for the options container to be visible before asserting option visibility.

       await poOmnichannel.roomInfo.inputTags.click();
+      await expect(poOmnichannel.page.getByRole('listbox')).toBeVisible();

As per coding guidelines.


106-110: Ensure multi-select stability and confirm dialog close after Save

If the dropdown closes after the first selection, the second click may fail. Either re-open before the second selection or rely on a hardened selectTag (see page-object suggestion). Also assert the Edit dialog closes after Save.

       await poOmnichannel.roomInfo.selectTag('TagA');
+      // If the dropdown closes on selection, re-open:
+      // await poOmnichannel.roomInfo.inputTags.click();
       await poOmnichannel.roomInfo.selectTag('GlobalTag');
       await poOmnichannel.roomInfo.btnSaveEditRoom.click();
+      await expect(poOmnichannel.roomInfo.dialogEditRoom).not.toBeVisible();

119-125: Repeat the listbox visibility wait for the second scenario

Mirror the wait to keep both scenarios equally robust.

       await poOmnichannel.roomInfo.inputTags.click();
+      await expect(poOmnichannel.page.getByRole('listbox')).toBeVisible();

As per coding guidelines.

ee/packages/federation-matrix/src/api/_matrix/media.ts (1)

99-114: Consider streaming to reduce memory pressure.

Building a single Buffer for large media doubles memory usage. Prefer streaming multipart to the response.

📜 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 9c49c78 and 3d413f6.

📒 Files selected for processing (19)
  • .changeset/calm-hounds-look.md (1 hunks)
  • apps/meteor/app/livechat/imports/server/rest/inquiries.ts (2 hunks)
  • apps/meteor/app/livechat/server/lib/rooms.ts (2 hunks)
  • apps/meteor/app/livechat/server/methods/returnAsInquiry.ts (2 hunks)
  • apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx (2 hunks)
  • apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts (2 hunks)
  • apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts (2 hunks)
  • apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (1 hunks)
  • apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts (1 hunks)
  • apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts (7 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (3 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/media.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/profiles.ts (6 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/send-join.ts (3 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts (5 hunks)
  • ee/packages/federation-matrix/src/api/middlewares.ts (0 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1 hunks)
  • packages/rest-typings/src/v1/omnichannel.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • ee/packages/federation-matrix/src/api/middlewares.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts
  • ee/packages/federation-matrix/src/api/_matrix/profiles.ts
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts
🧰 Additional context used
📓 Path-based instructions (4)
apps/meteor/tests/e2e/page-objects/**/*.ts

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

Utilize and place Page Object implementations under apps/meteor/tests/e2e/page-objects/

Files:

  • apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts
apps/meteor/tests/e2e/**/*.{ts,tsx,js,jsx}

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

apps/meteor/tests/e2e/**/*.{ts,tsx,js,jsx}: Write concise, technical TypeScript/JavaScript with accurate typing
Follow DRY by extracting reusable logic into helper functions or page objects
Avoid code comments in the implementation

Files:

  • apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts
  • apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
apps/meteor/tests/e2e/**/*.{ts,tsx}

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

apps/meteor/tests/e2e/**/*.{ts,tsx}: Avoid using page.locator(); prefer semantic locators like page.getByRole, page.getByLabel, page.getByText, and page.getByTitle
Store commonly used locators in variables/constants for reuse
Use page.waitFor() with specific conditions and avoid hardcoded timeouts
Implement proper wait strategies for dynamic content
Follow the Page Object Model pattern consistently

Files:

  • apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts
  • apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
apps/meteor/tests/e2e/**/*.spec.ts

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

apps/meteor/tests/e2e/**/*.spec.ts: All Playwright test files must be located under apps/meteor/tests/e2e/ and use the .spec.ts extension (e.g., login.spec.ts)
Use descriptive test names that clearly communicate expected behavior
Use test.beforeAll() and test.afterAll() for setup and teardown
Use test.step() to organize complex test scenarios
Group related tests in the same file
Utilize Playwright fixtures (test, page, expect) consistently
Prefer web-first assertions (e.g., toBeVisible, toHaveText)
Use expect matchers (toEqual, toContain, toBeTruthy, toHaveLength, etc.) instead of assert statements
Maintain test isolation between test cases
Ensure a clean state for each test execution
Ensure tests run reliably in parallel without shared state conflicts

Files:

  • apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
🧬 Code graph analysis (10)
apps/meteor/app/livechat/server/lib/rooms.ts (1)
packages/core-services/src/index.ts (1)
  • Omnichannel (189-189)
ee/packages/federation-matrix/src/api/_matrix/media.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (3)
apps/meteor/tests/mocks/data.ts (1)
  • createFakeVisitor (310-315)
apps/meteor/tests/e2e/page-objects/home-omnichannel.ts (1)
  • HomeOmnichannel (14-67)
apps/meteor/tests/data/livechat/department.ts (1)
  • createDepartment (20-33)
ee/packages/federation-matrix/src/api/_matrix/invite.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts (1)
apps/meteor/tests/data/api-data.ts (2)
  • credentials (39-42)
  • request (10-10)
ee/packages/federation-matrix/src/api/_matrix/send-join.ts (1)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (72-73)
apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts (2)
packages/ui-contexts/src/index.ts (1)
  • useEndpoint (32-32)
apps/meteor/app/livechat/server/methods/returnAsInquiry.ts (1)
  • rid (18-35)
apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts (2)
packages/ui-contexts/src/index.ts (1)
  • useEndpoint (32-32)
apps/meteor/app/livechat/server/methods/returnAsInquiry.ts (1)
  • rid (18-35)
apps/meteor/app/livechat/imports/server/rest/inquiries.ts (5)
packages/rest-typings/src/v1/omnichannel.ts (2)
  • POSTLivechatInquiriesReturnAsInquirySuccessResponse (3508-3510)
  • isPOSTLivechatInquiriesReturnAsInquiry (3490-3492)
packages/rest-typings/src/v1/Ajv.ts (3)
  • validateBadRequestErrorResponse (46-46)
  • validateUnauthorizedErrorResponse (69-69)
  • validateForbiddenErrorResponse (92-92)
packages/models/src/index.ts (1)
  • LivechatRooms (176-176)
apps/meteor/app/livechat/server/lib/rooms.ts (1)
  • returnRoomAsInquiry (212-260)
apps/meteor/app/api/server/ApiClass.ts (1)
  • ExtractRoutesFromAPI (73-77)
⏰ 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 (8)
apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx (1)

56-56: LGTM!

Destructuring _id as roomId improves code clarity.

apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts (3)

7-7: LGTM: Import updates align with REST migration.

The removal of parseMethodResponse and addition of request and credentials correctly reflect the shift from methodCall-based testing to REST endpoint testing.

Also applies to: 22-22


327-452: LGTM: REST endpoint migration is complete and consistent.

The test suite has been properly migrated from methodCall-based API to REST endpoint usage. All tests maintain their logical intent while using the new API structure:

  • Correct HTTP method (POST) and endpoint path (livechat/inquiries.returnAsInquiry)
  • Simplified payload structure ({ roomId } instead of nested RPC-style)
  • Appropriate HTTP status codes (403 for unauthorized, 400 for validation errors, 200 for success)
  • Proper assertions for REST response format
  • Consistent error handling across all test cases

The business logic is preserved: returning success: true, result: false when no agent is serving (line 413-414) and success: true, result: true when successfully moved to queue (line 435-436).


510-528: LGTM: Last message verification updated correctly.

The test for verifying the correct last message when a room is returned to the queue has been properly updated to use the REST endpoint while maintaining the same validation logic.

apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts (1)

68-70: LGTM for tag assertions

Good use of role scoping to the Room Information dialog and exact text matching.

Confirm the list has accessible name “Tags” in the DOM to keep this selector stable across themes.

apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (1)

1-135: Solid coverage and structure

Good POM usage, web-first assertions, setup/teardown, and EE-only gating. Naming and steps are clear.

ee/packages/federation-matrix/src/api/_matrix/send-join.ts (1)

227-241: Verify middleware can read route params in this context.

Known issue: in our router, c.req.param() may be empty inside middlewares, causing canAccessResource to fail extracting roomId and return 500/skip checks. Ensure canAccessResource.ts falls back to body.room_id or URL parsing, or set the resource id into c context before this middleware.

ee/packages/federation-matrix/src/api/_matrix/invite.ts (1)

320-336: Confirm param extraction and target entity.

  • Ensure canAccessResource can read roomId inside middleware; otherwise it should fall back to body.event.room_id.
  • This route has both roomId and eventId; you’re checking entityType 'room'. Please confirm that is the intended resource for authorization here.

@ggazzo ggazzo force-pushed the chore/fed-branded branch from c1f33ff to ae1e270 Compare October 6, 2025 20:09
@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch from 381548e to 18de66e Compare October 7, 2025 15:32
@ricardogarim ricardogarim requested a review from a team as a code owner October 7, 2025 15:32
@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch 2 times, most recently from f3e8b32 to db60d28 Compare October 7, 2025 15:36
@ggazzo ggazzo force-pushed the chore/fed-branded branch 2 times, most recently from c699bbf to bc0ad58 Compare October 7, 2025 19:30
@ggazzo ggazzo force-pushed the chore/fed-branded branch 8 times, most recently from 89ebe54 to 94445d8 Compare October 8, 2025 02:47
Base automatically changed from chore/fed-branded to release-7.11.0 October 8, 2025 03:42
@ggazzo ggazzo force-pushed the refactor/federation-middlewares branch from e55889f to 00f58d9 Compare October 8, 2025 03:45
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: 0

🧹 Nitpick comments (1)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (1)

323-323: Redundant authentication on routes with resource-level checks.

The router-level isAuthenticatedMiddleware (line 323) combined with route-level canAccessResourceMiddleware (lines 378, 409, 441, 476) causes duplicate authentication. According to the middleware implementation, canAccessResourceMiddleware internally includes isAuthenticatedMiddleware, so authentication runs twice for these routes—once at the router level and once within the resource middleware.

Consider refactoring to avoid duplicate verification:

Option 1 (Recommended): Remove router-level middleware, apply explicitly per route

 	return (
 		new Router('/federation')
-			.use(isAuthenticatedMiddleware(federationAuth))
 			.put(
 				'/v1/send/:txnId',
 				{
 					params: isSendTransactionParamsProps,
 					body: isSendTransactionBodyProps,
 					response: {
 					},
 					tags: ['Federation'],
 					license: ['federation'],
 				},
+				isAuthenticatedMiddleware(federationAuth),
 				async (c) => {

This ensures each route has authentication applied exactly once.

Option 2: Keep router-level middleware if a separate canAccessResource middleware exists

If the codebase provides a canAccessResource middleware (without embedded authentication), use that on GET routes instead of canAccessResourceMiddleware. However, this option requires changes outside the current file.

Also applies to: 378-378, 409-409, 441-441, 476-476

📜 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 00f58d9 and bf74936.

📒 Files selected for processing (3)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (4 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/rooms.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
🧰 Additional context used
🧬 Code graph analysis (2)
ee/packages/federation-matrix/src/api/_matrix/rooms.ts (1)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (61-62)
⏰ 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/src/api/_matrix/rooms.ts (1)

5-6: LGTM! Clean middleware integration.

The authentication middleware is correctly applied at the router level, ensuring all public room endpoints require valid request signatures.

Also applies to: 127-130

@ricardogarim ricardogarim force-pushed the refactor/federation-middlewares branch 2 times, most recently from a4d77a4 to 89df936 Compare October 8, 2025 21:38
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: 1

📜 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 a4d77a4 and 89df936.

📒 Files selected for processing (3)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (5 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/rooms.ts (2 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/transactions.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • ee/packages/federation-matrix/src/api/_matrix/rooms.ts
🧰 Additional context used
🧬 Code graph analysis (1)
ee/packages/federation-matrix/src/api/_matrix/transactions.ts (2)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (6-40)
ee/packages/federation-matrix/src/api/middlewares/canAccessResource.ts (1)
  • canAccessResourceMiddleware (61-62)
⏰ 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

@sampaiodiego sampaiodiego force-pushed the refactor/federation-middlewares branch from 89df936 to 165f855 Compare October 9, 2025 19:10
@sampaiodiego sampaiodiego force-pushed the refactor/federation-middlewares branch from 165f855 to b00fa81 Compare October 10, 2025 21:55
@codecov
Copy link

codecov bot commented Oct 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.36%. Comparing base (4bd409d) to head (2e4a6fe).
⚠️ Report is 4 commits behind head on release-7.11.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-7.11.0   #37067      +/-   ##
==================================================
- Coverage           66.37%   66.36%   -0.02%     
==================================================
  Files                3386     3386              
  Lines              115619   115619              
  Branches            21351    21357       +6     
==================================================
- Hits                76739    76725      -14     
- Misses              36275    36285      +10     
- Partials             2605     2609       +4     
Flag Coverage Δ
e2e 57.26% <ø> (-0.03%) ⬇️
unit 71.21% <ø> (-0.02%) ⬇️

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 merged commit f44030f into release-7.11.0 Oct 11, 2025
41 checks passed
@ggazzo ggazzo deleted the refactor/federation-middlewares branch October 11, 2025 12:43
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