diff --git a/.claude/skills/mendix/write-lint-rules/SKILL.md b/.claude/skills/mendix/write-lint-rules/SKILL.md index 4f2457759..2f8d51d4b 100644 --- a/.claude/skills/mendix/write-lint-rules/SKILL.md +++ b/.claude/skills/mendix/write-lint-rules/SKILL.md @@ -497,6 +497,10 @@ Returned by `permissions()` (all types) or `permissions_for()` (entity-specific) | `name` | string | `"Administrator"` | | `is_anonymous` | bool | True if this is the anonymous/guest role | | `module_roles` | list of string | `["Sales.Admin", "HR.Viewer"]` | +| `check_security` | bool | Studio Pro's per-role "Check security" flag | +| `manage_all_roles` | bool | The role may hand out every user role | +| `manage_users_without_roles` | bool | The role may manage users that have no role | +| `manageable_roles` | list of string | The user roles this role may hand out, when not all | ### module_role | Property | Type | Example | diff --git a/mdl/linter/context.go b/mdl/linter/context.go index e27ef4fbf..41b8f986e 100644 --- a/mdl/linter/context.go +++ b/mdl/linter/context.go @@ -485,6 +485,16 @@ type UserRoleInfo struct { Name string IsAnonymous bool ModuleRoles []string + // CheckSecurity is Studio Pro's per-role "Check security" flag. With it on, + // the Modeler verifies that the role's access rules actually grant what its + // pages and microflows need — the setting a rule of the form "security + // should be checked for each project role" asserts. + CheckSecurity bool + // ManageAllRoles, ManageUsersWithoutRoles and ManageableRoles are the + // user-management grants: which other roles this role may hand out. + ManageAllRoles bool + ManageUsersWithoutRoles bool + ManageableRoles []string } // UserRoles returns the user roles from project security. @@ -501,9 +511,13 @@ func (ctx *LintContext) UserRoles() []UserRoleInfo { var roles []UserRoleInfo for _, ur := range ps.UserRoles { roles = append(roles, UserRoleInfo{ - Name: ur.Name, - IsAnonymous: ur.Name == ps.GuestUserRole, - ModuleRoles: ur.ModuleRoles, + Name: ur.Name, + IsAnonymous: ur.Name == ps.GuestUserRole, + ModuleRoles: ur.ModuleRoles, + CheckSecurity: ur.CheckSecurity, + ManageAllRoles: ur.ManageAllRoles, + ManageUsersWithoutRoles: ur.ManageUsersWithoutRoles, + ManageableRoles: ur.ManageableRoles, }) } return roles diff --git a/mdl/linter/starlark.go b/mdl/linter/starlark.go index a854bfa0c..50e827512 100644 --- a/mdl/linter/starlark.go +++ b/mdl/linter/starlark.go @@ -1045,10 +1045,18 @@ func userRoleToStarlark(ur UserRoleInfo) starlark.Value { for _, mr := range ur.ModuleRoles { moduleRoles = append(moduleRoles, starlark.String(mr)) } + var manageableRoles []starlark.Value + for _, mr := range ur.ManageableRoles { + manageableRoles = append(manageableRoles, starlark.String(mr)) + } return starlarkstruct.FromStringDict(starlark.String("user_role"), starlark.StringDict{ - "name": starlark.String(ur.Name), - "is_anonymous": starlark.Bool(ur.IsAnonymous), - "module_roles": starlark.NewList(moduleRoles), + "name": starlark.String(ur.Name), + "is_anonymous": starlark.Bool(ur.IsAnonymous), + "module_roles": starlark.NewList(moduleRoles), + "check_security": starlark.Bool(ur.CheckSecurity), + "manage_all_roles": starlark.Bool(ur.ManageAllRoles), + "manage_users_without_roles": starlark.Bool(ur.ManageUsersWithoutRoles), + "manageable_roles": starlark.NewList(manageableRoles), }) }