Skip to content

Conversation

@d-gubert
Copy link
Member

@d-gubert d-gubert commented Jan 17, 2026

Proposed changes (including videos or screenshots)

  • Remove duplicated calls to parseBodyParams and parseQueryParams in RocketChatAPIRouter
  • Prevent logger middleware from consuming the request body and trying to parse it to JSON when the env var is not set
  • Redact the password field when logging requests
  • Fix schema definition for Livechat custom fields save request

Issue(s)

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • Security & Privacy

    • Passwords are now redacted from logged request payloads and logging is streamlined.
  • Bug Fixes & Improvements

    • Request body and query parameters are consistently populated for handlers; API action context now exposes route and incoming request info.
    • Form-urlencoded automatic payload override removed; payload parsing handles JSON and form data more robustly.
    • Livechat custom fields accept nullable IDs and enforce identifier patterns for consistency.

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

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Jan 17, 2026

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 targeting the wrong base branch. It should target 8.2.0, but it targets 8.1.0

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 Jan 17, 2026

⚠️ No Changeset found

Latest commit: 5ffad11

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 Jan 17, 2026

Caution

Review failed

The head commit changed during the review from 3ad9b41 to 5ffad11.

Walkthrough

Centralizes request parsing into Router, makes payload extraction asynchronous and request-centric, integrates password redaction in logging, removes runtime bodyParams-override population, and relaxes/aligns customFieldId handling across schema, types, and model to allow null and enforce pattern via types.

Changes

Cohort / File(s) Summary
Router & Request Context
packages/http-router/src/Router.ts, apps/meteor/app/api/server/router.ts
Introduced InnerRouter type and initialize innerRouter = new Hono(); parseBodyParams is now async and returns parsed body (JSON/form), Router stores bodyParams/queryParams on Hono context; APIActionContext types expanded to include route and incoming, and param types changed to Record<string, unknown>.
Logging / Payload Extraction
apps/meteor/app/api/server/middlewares/logger.ts, apps/meteor/server/lib/logger/logPayloads.ts
Replaced synchronous payload extraction with async getRestPayload(request) (handles multipart/form-data by returning a placeholder); logger now awaits payload inline and uses redact to hide passwords when building child logger.
Integrations & Middleware
apps/meteor/app/integrations/server/api/api.ts
Removed runtime population of bodyParams-override for form-urlencoded payloads; no override c.set calls remain.
Livechat Custom Fields (API, Types, Model)
apps/meteor/app/livechat/server/api/v1/customField.ts, packages/rest-typings/src/v1/omnichannel.ts, packages/model-typings/src/models/ILivechatCustomFieldModel.ts, packages/models/src/models/LivechatCustomField.ts
Removed endpoint-level regex precheck for customFieldId; schema allows `customFieldId: string

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Router
  participant LoggerMiddleware as Logger
  participant PayloadSvc as getRestPayload
  participant Handler

  Client->>Router: HTTP request
  Router->>Router: async parse query + body → c.set('queryParams','bodyParams')
  Router->>Logger: invoke logger middleware
  Logger->>PayloadSvc: await getRestPayload(request)
  PayloadSvc-->>Logger: payload | "{ payload: '[multipart/form-data]' }" | null
  Logger->>Handler: call handler (context includes body/query and logs with redacted payload)
  Handler-->>Client: response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • sampaiodiego
  • tassoevan

Poem

🐇
I hopped through routes and parsed the stream,
I nudged the logger to hide the cream,
Async payloads now rest in place,
Fields aligned and patterns trace,
A little rabbit twitches, pleased—hop, scheme! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'chore: api http router improvements' is vague and generic, using non-descriptive terms that don't convey meaningful information about the specific changes in the changeset. Consider a more descriptive title that captures the main change, such as 'refactor: consolidate payload parsing and add password redaction in API router' or 'refactor: dedup body/query parsing and redact logs in HTTP router'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ 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 chore/router-improvements

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.

@d-gubert d-gubert force-pushed the chore/router-improvements branch from 12a4f8f to b1b33d3 Compare January 17, 2026 00:19
@codecov
Copy link

codecov bot commented Jan 17, 2026

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.84%. Comparing base (c107092) to head (5ffad11).
⚠️ Report is 3 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #38227      +/-   ##
===========================================
+ Coverage    70.73%   70.84%   +0.10%     
===========================================
  Files         3158     3159       +1     
  Lines       109359   109383      +24     
  Branches     19695    19703       +8     
===========================================
+ Hits         77358    77489     +131     
+ Misses       29966    29869      -97     
+ Partials      2035     2025      -10     
Flag Coverage Δ
e2e 60.39% <ø> (+0.10%) ⬆️
e2e-api 49.15% <20.00%> (+1.09%) ⬆️
unit 71.96% <100.00%> (+0.08%) ⬆️

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.

@d-gubert d-gubert added this to the 8.1.0 milestone Jan 17, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 17, 2026

📦 Docker Image Size Report

➡️ Changes

Service Current Baseline Change Percent
sum of all images 0B 0B 0B
account-service 0B 0B 0B
authorization-service 0B 0B 0B
ddp-streamer-service 0B 0B 0B
omnichannel-transcript-service 0B 0B 0B
presence-service 0B 0B 0B
queue-worker-service 0B 0B 0B
rocketchat 0B 0B 0B

📊 Historical Trend

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

Statistics (last 30 days):

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

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

  • Tag: pr-38227
  • Baseline: develop
  • Timestamp: 2026-01-23 21:51:48 UTC
  • Historical data points: 30

Updated: Fri, 23 Jan 2026 21:51:49 GMT

if (options.query) {
const validatorFn = options.query;
if (typeof options.query === 'function' && !validatorFn(queryParams)) {
if (typeof options.query === 'function' && !validatorFn(structuredClone(queryParams))) {
Copy link
Member Author

Choose a reason for hiding this comment

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

validatorFn mutates its input, which causes some weird behaviors that break tests. Cloning the input "solves" the issues, but defeats the purpose of removing the second calls to parseBodyParams and parseQueryParams.

I think it is valuable to actually take a look at the breaking tests and make the system adapt to the mutatons that happen in those validatorFn calls

@d-gubert d-gubert force-pushed the chore/router-improvements branch from dd78dad to 536fd45 Compare January 20, 2026 23:28
@d-gubert
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

✅ 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

@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

Caution

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

⚠️ Outside diff range comments (1)
packages/rest-typings/src/v1/omnichannel.ts (1)

4502-4505: Type guard does not match schema nullability for customFieldId.

The schema defines customFieldId with nullable: true and no required array (making it optional), but the type guard narrows to customFieldId: string. After validation, customFieldId could be null or omitted (undefined), violating the type guard. Align the generic type to customFieldId?: string | null to match the schema.

Suggested fix
 export const isPOSTLivechatSaveCustomFieldsParams = ajv.compile<{
-	customFieldId: string;
+	customFieldId?: string | null;
 	customFieldData: Omit<ILivechatCustomField, '_id' | '_updatedAt'> & { field: string };
 }>(POSTLivechatSaveCustomFieldsSchema);
🤖 Fix all issues with AI agents
In `@packages/rest-typings/src/v1/omnichannel.ts`:
- Around line 4446-4457: Update the regex character classes to move the hyphen
to the end so they read `[0-9a-zA-Z_-]` for both customFieldId and
customFieldData.field to avoid creating an unintended range; also reconcile the
nullable mismatch by either removing `nullable: true` from the `customFieldId`
schema or updating the type guard that references `customFieldId` (the check
near the type guard around line ~4502) to accept `string | null` so schema and
runtime types match.
🧹 Nitpick comments (1)
packages/http-router/src/Router.ts (1)

157-175: Align bodyParams typing with possible JSON shapes.
request.raw.clone().json() can return arrays or primitives, but the context types are Record<string, unknown>. Consider normalizing non‑object bodies to {} or widening the type so downstream code doesn’t rely on an incorrect shape.

@d-gubert d-gubert force-pushed the chore/router-improvements branch from 536fd45 to 2186968 Compare January 21, 2026 00:39
@d-gubert d-gubert marked this pull request as ready for review January 21, 2026 11:59
@d-gubert d-gubert requested review from a team as code owners January 21, 2026 11:59
Copy link
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.

No issues found across 9 files

@ggazzo ggazzo modified the milestones: 8.1.0, 8.2.0 Jan 21, 2026
@ricardogarim
Copy link
Contributor

ricardogarim commented Jan 21, 2026

While reviewing the bodyParams-override removal, which looks correct since parseBodyParams never used the extra parameter, I noticed that incoming webhooks receiving application/x-www-form-urlencoded with payload={...json...} (Slack/GitHub format) have been broken for a while. The JSON is never unwrapped from the payload field.

Created CORE-1741 to track this separately.

@sampaiodiego
Copy link
Member

@ricardogarim are they really broken? I've found this test to validate it (should) be working:

it('should send a message if the payload is a application/x-www-form-urlencoded JSON', async () => {
const payload = { msg: `Message as x-www-form-urlencoded JSON sent successfully at #${Date.now()}` };
await request
.post(`/hooks/${integration._id}/${integration.token}`)
.set('Content-Type', 'application/x-www-form-urlencoded')
.send(`payload=${JSON.stringify(payload)}`)
.expect(200)
.expect(async () => {
return request
.get(api('channels.messages'))
.set(credentials)
.query({
roomId: 'GENERAL',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages').and.to.be.an('array');
expect(!!(res.body.messages as IMessage[]).find((m) => m.msg === payload.msg)).to.be.true;
});
});
});

@sampaiodiego
Copy link
Member

@d-gubert maybe the Livechat changes could be in another PR? they look like regular changes not necessarily related to "api http router improments"

@d-gubert
Copy link
Member Author

d-gubert commented Jan 21, 2026

@d-gubert maybe the Livechat changes could be in another PR? they look like regular changes not necessarily related to "api http router improments"

We need to modify that endpoint, otherwise tests fail because of this #38227 (comment) (there was an example of CI run with the tests failing, but I rebased... 😬 ) (actually, found the run https://github.com/RocketChat/Rocket.Chat/actions/runs/21084954407/job/60650568531?pr=38227)

I can make a much more contrived change just to make sure the tests are passing, then open a new PR with the appropriate changes to schemas and all. But the endpoint can't go unscathed 😛

@d-gubert
Copy link
Member Author

Forgot to mention @sampaiodiego #38227 (comment) 😬

@d-gubert d-gubert force-pushed the chore/router-improvements branch from 2186968 to 5ffad11 Compare January 23, 2026 15:55
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

Caution

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

⚠️ Outside diff range comments (1)
packages/models/src/models/LivechatCustomField.ts (1)

52-75: Return value missing _id in update path.

When updating an existing record (_id is truthy), the returned record object lacks the _id property, which violates the ILivechatCustomField return type. The insert path correctly assigns record._id = field, but the update path does not preserve the ID on the returned object.

🐛 Proposed fix
 	async createOrUpdateCustomField(
 		_id: string | null,
 		field: string,
 		label: ILivechatCustomField['label'],
 		scope: ILivechatCustomField['scope'],
 		visibility: ILivechatCustomField['visibility'],
 		extraData: any,
 	) {
 		const record = {
 			label,
 			scope,
 			visibility,
 			...extraData,
 		};

 		if (_id) {
 			await this.updateOne({ _id }, { $set: record });
+			record._id = _id;
 		} else {
 			record._id = field;
 			await this.insertOne(record);
 		}

 		return record;
 	}
🤖 Fix all issues with AI agents
In `@apps/meteor/app/api/server/router.ts`:
- Around line 44-49: The APIActionContext construction should defensively
default potentially-undefined context entries; update the code that builds
APIActionContext (the object with requestIp, urlParams, queryParams, bodyParams,
request) to use c.get('bodyParams') ?? {} and c.get('queryParams') ?? {} so
bodyParams and queryParams are always objects even if c.get(...) returns
undefined, keeping the existing fields (e.g., requestIp: c.get('remoteAddress')
and urlParams: req.param()) unchanged.

@ricardogarim ricardogarim force-pushed the chore/router-improvements branch 2 times, most recently from 3ad9b41 to 5ffad11 Compare January 23, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants