feat: add platform-level glob scope#289
Conversation
|
Thanks for the pull request, @BryanttV! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
4c6afcd to
f4eebe1
Compare
e7f2a69 to
7c34a40
Compare
|
Hi everyone! This PR is ready for review, however, I have a few questions related to this PR that I'd like to resolve. @mariajgrimaldi @MaferMazu @rodmgwgu @bmtcril
|
|
Hello @BryanttV, thanks for this PR. Regarding your questions:
As a cold answer, I'll say yes, probably we would need that. But it could be out of scope of this PR. I'll open an issue about it.
I think it is better to maintain the wildcard to be consistent when someone has permissions across the platform (for example, global staff), and it is easier to handle (because leaving it blank could mean other things). Notes from my first review: When I try to assign a user as a course_user on the platform, I get a bad request. Request: {
"users": [
"course_user"
],
"role": "course_user", // The role to add users to
"scope": "course-v1:*" // The scope to add users to
}Answer {
"role": [
"Role 'course_user' does not exist in scope 'course-v1:*'"
]
}We should be able to apply all course roles over this platform course's global scope, right? Another thing I found is that it is better to use |
|
Thanks for the review! @MaferMazu
Thanks! I agree that we should address this in another PR
Yes, I also agree with returning
Yes! This applies to all roles, but the
I followed your suggestion and added IS_GLOB as a property here: 1168bee |
🙈 Yes, you are right, it works as expected! |
MaferMazu
left a comment
There was a problem hiding this comment.
Thanks for addressing my feedback. This looks good to me.
* refactor: rename glob_cls to org_glob_cls and add platform access check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…se overview glob scope check
1168bee to
4aeb6d6
Compare
bmtcril
left a comment
There was a problem hiding this comment.
Looks good, just a couple of nits because I'm paranoid
| super().__init__(name, bases, attrs) | ||
| if not hasattr(cls, "scope_registry"): | ||
| cls.scope_registry = {} | ||
| if not hasattr(cls, "glob_registry"): |
There was a problem hiding this comment.
I don't think these checks / assignments make sense since these are all ClassVars? They should always be assigned. If we are clearing them for testing or something it might make more sense to create a method just for that purpose.
There was a problem hiding this comment.
I'm really not sure why this was done in the first place, however, removing the code doesn't seem to affect anything anywhere.
@mariajgrimaldi, you implemented this. Do you see any concerns we should take into account? Or can we remove it? For now, I made this commit: f142a26
| if mcs._is_platform_glob(external_key, namespace): | ||
| return mcs.platform_glob_registry.get(namespace, ScopeData) | ||
| # If not a platform glob, check if it's an org glob | ||
| return mcs.org_glob_registry.get(namespace, ScopeData) |
There was a problem hiding this comment.
Same comment as above regarding unknown scopes. Can we also create an _is_org_glob to specifically check that format and tighten this up to check for that?
There was a problem hiding this comment.
Yes, agreed. I created a new _is_org_glob method to perform the explicit check.
|
|
||
| if not glob_subclass.validate_external_key(external_key): | ||
| raise ValueError(f"Invalid external_key format for glob scope: {external_key}") | ||
| org_subclass = mcs.org_glob_registry.get(namespace) |
There was a problem hiding this comment.
Same as above, I'd just like to be explicit in our checks of the org globs too.
| case api.SuperAdminAssignmentData(): | ||
| return "*" | ||
| case api.RoleAssignmentData(): | ||
| if isinstance(obj.scope, api.PlatformCourseOverviewGlobData): |
There was a problem hiding this comment.
Can we tighten up this check too?
|
I've actually found something testing locally. I think we're in a weird place with global permissions where we're actually using is_staff / superuser, but allow When a user is created with this scope it breaks |
|
|
||
| Examples: | ||
| >>> ScopeMeta.get_all_platform_glob_namespaces() | ||
| {'course-v1': PlatformCourseOverviewGlobData, 'lib': PlatformContentLibraryGlobData} |
There was a problem hiding this comment.
I know this is an example, but PlatformContentLibraryGlobData doesn't exist?
There was a problem hiding this comment.
Yes, it's just an example. At the moment, that scope doesn't exist. I'll remove it.
|
|
||
| # Fall back to standard scope class | ||
| # If not a glob, return the standard scope class | ||
| return mcs.scope_registry.get(namespace, ScopeData) |
There was a problem hiding this comment.
Not in your changes, but a 3rd place where we could stop defaulting and raise an error on unknown scopes.
There was a problem hiding this comment.
Yes, I agree. I added those changes in this commit: b9dd29b
…lidation error messages
…tion error handling
|
Thanks for the review, @bmtcril!
I took your suggestions into account and restricted the use of |
|
I had to add a new commit to fix some tests that weren't using a valid namespace: 8d7c87f |
| "Use a specific scope key or a namespaced wildcard." | ||
| ) | ||
|
|
||
| return ScopeData |
There was a problem hiding this comment.
Should we return this here, or raise? I'm not sure what the success case would be for something that got here.
There was a problem hiding this comment.
ScopeData was being returned for the lib^* and course-v1^* cases. However, I added new changes to specifically handle those cases, and to raise an exception for any other case: 3590a75
bmtcril
left a comment
There was a problem hiding this comment.
This seems good to me, pending Maria's input on the open question in data.py and a decision on my last comment about returning a ScopeData or raising a ValueError.
Restrict ScopeMeta fallback to ScopeData to external_key '*' when the namespace is registered (e.g. lib, course-v1). Invalid glob shapes now raise ValueError instead of being silently accepted.

Resolves: #268
Description
This PR adds platform-level glob scopes so role assignments can target all resources of a type across the entire platform, not just within a single organization or specific scope.
Problem
Org-level globs (
course-v1:OpenedX+*,lib:DemoX:*) grant access within one org. Some use cases need platform-wide coverage (e.g., a role on all courses everywhere) without assigning per-org globs.Solution
PlatformGlobDataandPlatformCourseOverviewGlobDatafor thecourse-v1:*pattern (all courses on the platform).ScopeMeta:org_glob_registry: org-wide patterns (renamed fromglob_registry)platform_glob_registry: platform-wide patternsIS_ORG_GLOB/IS_PLATFORM_GLOBflags whereIS_GLOBis derived from both.Additional changes
get_all_org_glob_namespaces,get_all_platform_glob_namespaces,get_all_registered_scopes)PlatformCourseOverviewGlobDataincluded inSCOPES_WITH_ADMIN_OR_SUPERUSER_CHECK|Related Pull Requests
Testing Instructions
To test these changes, you can check the REST API.
Use the
/api/authz/v1/roles/users/endpoint to add platform-level permissions:{ "users": [ "john" ], "role": "course_admin", "scopes": [ "course-v1:*" ] }Validate the permissions
/api/authz/v1/permissions/validate/me[ { "action": "courses.view_course_team", "scope": "course-v1:OpenedX+DemoX+DemoCourse" }, { "action": "courses.manage_course_updates", "scope": "course-v1:edunext+RBAC+2026" }, { "action": "courses.manage_advanced_settings", "scope": "course-v1:any-org+any-course+any-run" } ]Response
[ { "action": "courses.view_course_team", "scope": "course-v1:OpenedX+DemoX+DemoCourse", "allowed": true }, { "action": "courses.view_course_team", "scope": "course-v1:edunext+RBAC+2026", "allowed": true }, { "action": "courses.view_course_team", "scope": "course-v1:any-org+any-course+any-run", "allowed": true } ]Example scope keys
course-v1:*course-v1:OpenedX+*OpenedXcourse-v1:OpenedX+Demo+2026Merge checklist
Check off if complete or not applicable: