Skip to content

fix: use $ne operator in findCustomRoles to prevent false negatives#41031

Open
aegisforensicsmonk wants to merge 4 commits into
RocketChat:developfrom
aegisforensicsmonk:fix/findCustomRoles-false-negative
Open

fix: use $ne operator in findCustomRoles to prevent false negatives#41031
aegisforensicsmonk wants to merge 4 commits into
RocketChat:developfrom
aegisforensicsmonk:fix/findCustomRoles-false-negative

Conversation

@aegisforensicsmonk

@aegisforensicsmonk aegisforensicsmonk commented Jun 21, 2026

Copy link
Copy Markdown

Proposed changes

Fixed an issue where custom roles with a missing protected field were incorrectly excluded from query results.
fix: include roles with missing protected field in custom role queries
Previously, the query used:

{ protected: false }

This only matched documents where protected was explicitly set to false, causing a false negative for legacy roles where the field was absent.

The query has been updated to:

{ protected: { $ne: true } }

This correctly includes both:

  • Roles with protected: false
  • Roles where the protected field is missing

The same fix was applied to countCustomRoles to ensure consistency between role retrieval and counting operations.

Issue(s)

Fixes incorrect custom role filtering when the protected field is absent.

Steps to test or reproduce

  1. Create a custom role without the protected field in the database.
  2. Navigate to the Roles management page or invoke the affected API.
  3. Observe that the role is not returned when using the previous query (protected: false).
  4. Apply this change.
  5. Verify that the role is now returned correctly.
  6. Confirm that roles with protected: true remain excluded.
  7. Verify that countCustomRoles returns the correct count.

Further comments

This change preserves the intended behavior of excluding protected roles while maintaining compatibility with legacy documents that do not contain the protected field.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Fixed custom roles not appearing when their protected status is unspecified.
    • Updated custom role searches and counts to consistently exclude only protected roles.

The query protected:false missed roles where the protected field was absent, causing a false negative. Changed to protected:{$ne:true} which correctly matches both protected:false and missing protected field. Applied the same fix to countCustomRoles.
@aegisforensicsmonk
aegisforensicsmonk requested a review from a team as a code owner June 21, 2026 14:49
@changeset-bot

changeset-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 58dbc6c

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

This PR includes changesets to release 4 packages
Name Type
@rocket.chat/models Patch
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch

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

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

@dionisio-bot

dionisio-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

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

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d26ae2a8-d5d8-4674-8bb3-ce185da95a91

📥 Commits

Reviewing files that changed from the base of the PR and between 7db02e6 and 58dbc6c.

📒 Files selected for processing (1)
  • .changeset/fix-missing-protected-roles.md
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: cubic · AI code reviewer
⚠️ CI failures not shown inline (1)

GitHub Check: Dionisio QA: Some checks did not pass

Conclusion: failure

View job details

**Conclusion:** failure
### Steps
- ✅ **No merge conflicts**
- ❌ **QA assured** — This PR is missing the 'stat: QA assured' label
- ✅ **Mergeable**
- ❌ **Has milestone or project** — This PR is missing the required milestone or project
- ✅ **Valid PR title**
- ✅ **Correct target version**
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-16T21:50:37.589Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39676
File: .changeset/migrate-users-register-openapi.md:3-3
Timestamp: 2026-03-16T21:50:37.589Z
Learning: For changes related to OpenAPI migrations in Rocket.Chat/OpenAPI, when removing endpoint types and validators from rocket.chat/rest-typings (e.g., UserRegisterParamsPOST, /v1/users.register) document this as a minor changeset (not breaking) per RocketChat/Rocket.Chat-Open-API#150 Rule 7. Note that the endpoint type is re-exposed via a module augmentation .d.ts in the consuming package (e.g., packages/web-ui-registration/src/users-register.d.ts). In reviews, ensure the changeset clearly states: this is a non-breaking change, the major version should not be bumped, and the changeset reflects a minor version bump. Do not treat this as a breaking change during OpenAPI migrations.

Applied to files:

  • .changeset/fix-missing-protected-roles.md
🔇 Additional comments (1)
.changeset/fix-missing-protected-roles.md (1)

1-6: LGTM!


Walkthrough

Custom role lookup and counting now include roles without a protected field, while continuing to exclude explicitly protected roles. A changeset records patch releases for @rocket.chat/models and @rocket.chat/meteor.

Changes

Protected Role Field Handling

Layer / File(s) Summary
Custom roles query filter update
packages/models/src/models/Roles.ts, .changeset/fix-missing-protected-roles.md
findCustomRoles and countCustomRoles now use protected: { $ne: true }; a changeset documents the fix and patch releases.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue #40798 — Directly addresses custom roles not being found when the protected field is missing.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the core fix to custom role queries using $ne to avoid missing roles.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 1 file

Re-trigger cubic

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f6f86080df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

findCustomRoles(options?: FindOptions<IRole>): FindCursor<IRole> {
const query: Filter<IRole> = {
protected: false,
protected: { $ne: true },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Don't classify unmarked default roles as custom

On upgraded workspaces where default roles were created before protected existed, those roles can still be missing the field: startup runs createOrUpdateProtectedRoleAsync, but its existing-role path only calls Roles.updateById(...) and never writes protected: true. This predicate therefore makes built-in roles like admin, moderator, and user match findCustomRoles/countCustomRoles, so Apps-Engine custom-role reads and custom-role statistics include protected default roles instead of only real custom roles. The fix should distinguish known protected roles or migrate/default their protected flag, rather than treating every missing value as custom.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for pointing this out. My intention was to include custom roles where the protected field is missing, since the previous query only matched roles with protected: false.

However, I see the issue with legacy workspaces where built-in roles such as admin, moderator, and user may also be missing the protected field. In those cases, using protected: { $ne: true } would incorrectly classify those default roles as custom roles.

I'll revisit the approach and look into a solution that correctly handles legacy protected roles, either by ensuring their protected flag is properly set through a migration or by explicitly distinguishing them from custom roles.

Since legacy workspaces might have built-in roles missing the protected flag, this ensures that the protected flag is added to them on startup.

@Shevilll Shevilll left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The core fix ({ protected: false }{ protected: { $ne: true } }) is correct — equality on false skips documents where protected is missing, so legacy custom roles get dropped.

A few things before it's mergeable:

  1. This duplicates #41033, which makes the same change to Roles.ts, links the tracking issue (#40798), and includes a changeset — worth coordinating so the fix isn't reviewed twice.
  2. No .changeset/ entry, but this touches @rocket.chat/models (and apps/meteor), so the changeset check will fail — needs a yarn changeset.
  3. The added Roles.updateOne(...) in createOrUpdateProtectedRole.ts isn't in the description and is a separate concern — it backfills protected: true onto legacy system roles (extra DB write per protected role). Might be reasonable, but it deserves its own PR + rationale rather than riding along with the query fix.
  4. Mind linking #40798 in the description for traceability?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants