Skip to content

Conversation

@carlos-r-l-rodrigues
Copy link
Contributor

@carlos-r-l-rodrigues carlos-r-l-rodrigues commented Dec 15, 2025

What

  • Initial RBAC module, workflow and endpoint implementation

Note

Introduce RBAC module with roles, policies, role-policies, and inheritance, exposing workflows and Admin API CRUD, plus integration tests and wiring across types/utils/config.

  • Backend Module (@medusajs/rbac):
    • Add models: rbac_role, rbac_policy, rbac_role_policy, rbac_role_inheritance with indexes and migrations.
    • Implement RbacModuleService and RbacRepository (policy listing with inheritance; augment role listings to include policies).
    • Register module in configs and Modules constants; add IRbacModuleService and RBAC DTOs/types.
  • Core Flows:
    • Steps and workflows to create/update/delete rbac_roles, rbac_policies, rbac_role_policies; manage role inheritance (set-role-inheritance); expose via core-flows.
  • Admin API:
    • New routes: GET/POST /admin/rbac/roles, GET/POST/DELETE /admin/rbac/roles/:id.
    • New routes: GET/POST /admin/rbac/policies, GET/POST/DELETE /admin/rbac/policies/:id.
    • New routes: GET/POST /admin/rbac/role-policies, GET/POST/DELETE /admin/rbac/role-policies/:id.
    • Add validators, query-config, and middleware registration.
  • Types/Utils:
    • Export RBAC types (common, mutations, service), extend container typings; add Modules.RBAC mappings.
  • Tests:
    • Integration tests for Admin API CRUD and filtering; workflow tests for role inheritance and policy aggregation.
  • Config:
    • Enable RBAC module in test configs and API middleware aggregation.

Written by Cursor Bugbot for commit 3d63ef0. This will update automatically on new commits. Configure here.

@changeset-bot
Copy link

changeset-bot bot commented Dec 15, 2025

⚠️ No Changeset found

Latest commit: 3d63ef0

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

@vercel
Copy link

vercel bot commented Dec 15, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

8 Skipped Deployments
Project Deployment Review Updated (UTC)
api-reference Ignored Ignored Dec 22, 2025 11:44am
api-reference-v2 Ignored Ignored Preview Dec 22, 2025 11:44am
cloud-docs Ignored Ignored Preview Dec 22, 2025 11:44am
docs-ui Ignored Ignored Preview Dec 22, 2025 11:44am
docs-v2 Ignored Ignored Preview Dec 22, 2025 11:44am
medusa-docs Ignored Ignored Preview Dec 22, 2025 11:44am
resources-docs Ignored Ignored Preview Dec 22, 2025 11:44am
user-guide Ignored Ignored Preview Dec 22, 2025 11:44am

@carlos-r-l-rodrigues carlos-r-l-rodrigues changed the title Feat/rbac module feat(rbac): Role-based access control module Dec 15, 2025
@carlos-r-l-rodrigues carlos-r-l-rodrigues changed the title feat(rbac): Role-based access control module feat(rbac): role-based access control module Dec 15, 2025
Copy link
Contributor

@olivermrbl olivermrbl left a comment

Choose a reason for hiding this comment

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

Overall LGTM, a few suggestions and comments

.define("rbac_role_policy", {
id: model.id({ prefix: "rlpl" }).primaryKey(),
role: model.belongsTo(() => RbacRole),
scope: model.belongsTo(() => RbacPolicy),
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: wouldn't it make more sense to call this policy?

Suggested change
scope: model.belongsTo(() => RbacPolicy),
policy: model.belongsTo(() => RbacPolicy),

Copy link
Contributor

Choose a reason for hiding this comment

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

resurfacing this one

.define("rbac_role_inheritance", {
id: model.id({ prefix: "rlin" }).primaryKey(),
role: model.belongsTo(() => RbacRole, { mappedBy: "inherited_roles" }),
inherited_role: model.belongsTo(() => RbacRole, {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: we have historically used parent_ for inheritance relationships; would it make sense to use it here too? not a strong opinion, so also fine to keep as is

@carlos-r-l-rodrigues carlos-r-l-rodrigues marked this pull request as ready for review December 22, 2025 11:39
@carlos-r-l-rodrigues carlos-r-l-rodrigues requested a review from a team as a code owner December 22, 2025 11:39
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on January 17

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

}
)

createRbacRolePoliciesStep(policiesUpdateData)
Copy link

Choose a reason for hiding this comment

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

Update workflow only adds policies, never removes existing

The updateRbacRolesWorkflow handles policy_ids inconsistently with inherited_role_ids. For inheritance, setRoleInheritanceStep properly syncs by fetching existing records, comparing, removing old ones, and adding new ones. However, for policies, it uses createRbacRolePoliciesStep which only creates new associations without removing existing ones. When a user updates a role with policy_ids, they expect it to replace all policies, but instead it only appends new ones. This means clearing policies with an empty array won't work, and updating with a subset of policies will accumulate rather than replace.

Fix in Cursor Fix in Web

q: z.string().optional(),
id: z.union([z.string(), z.array(z.string())]).optional(),
name: z.union([z.string(), z.array(z.string())]).optional(),
parent_id: z.union([z.string(), z.array(z.string())]).optional(),
Copy link

Choose a reason for hiding this comment

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

Validators reference nonexistent parent_id model field

The API validators (AdminGetRbacRolesParamsFields, AdminCreateRbacRole, AdminUpdateRbacRole) and defaultAdminRbacRoleFields query config all reference a parent_id field that doesn't exist in the RbacRole model. The model only defines id, name, description, and metadata. Role inheritance is handled through the separate RbacRoleInheritance table, not a parent_id column. This will cause failures when filtering by parent_id, creating/updating with parent_id, or when the default query fields are requested.

Additional Locations (2)

Fix in Cursor Fix in Web

Copy link
Contributor

@olivermrbl olivermrbl left a comment

Choose a reason for hiding this comment

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

Overall LGTM, few comments and suggestions

Comment on lines +18 to +19
role_id: string
previousInheritedRoleIds: string[]
Copy link
Contributor

Choose a reason for hiding this comment

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

super-nit: think we should align casing 😅

import { adminRbacRolePolicyRoutesMiddlewares } from "./role-policies/middlewares"
import { adminRbacRoleRoutesMiddlewares } from "./roles/middlewares"

export const adminRbacRoutesMiddlewares: MiddlewareRoute[] = [
Copy link
Contributor

Choose a reason for hiding this comment

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

q: should we omit this file if the feature flag is not enabled?

AdminUpdateRbacPolicy,
} from "./validators"

export const adminRbacPolicyRoutesMiddlewares: MiddlewareRoute[] = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as other comment

Copy link
Contributor

Choose a reason for hiding this comment

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

separately: I am leaning toward removing the rbac resource from the API; I think this goes against our general conventions, and I doubt we will have other features needing the routes without it

AdminUpdateRbacPolicy,
} from "./validators"

export const adminRbacPolicyRoutesMiddlewares: MiddlewareRoute[] = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as other comment

AdminUpdateRbacRolePolicy,
} from "./validators"

export const adminRbacRolePolicyRoutesMiddlewares: MiddlewareRoute[] = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as other comment

.define("rbac_role_policy", {
id: model.id({ prefix: "rlpl" }).primaryKey(),
role: model.belongsTo(() => RbacRole),
scope: model.belongsTo(() => RbacPolicy),
Copy link
Contributor

Choose a reason for hiding this comment

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

resurfacing this one

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