-
Notifications
You must be signed in to change notification settings - Fork 4.3k
fix: platform-wide glob role assignments crash get_orgs_for_user/has_org_for_user #38980
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
65b57d9
526ea04
8b92fc6
ace8a06
d32aa52
795de56
fbb2726
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,13 +14,15 @@ | |||||
| ContentLibraryData, | ||||||
| CourseOverviewData, | ||||||
| OrgCourseOverviewGlobData, | ||||||
| PlatformCourseOverviewGlobData, | ||||||
| RoleAssignmentData, | ||||||
| RoleData, | ||||||
| ScopeData, | ||||||
| UserData, | ||||||
| ) | ||||||
| from openedx_authz.constants.roles import COURSE_ADMIN, COURSE_STAFF | ||||||
| from openedx_authz.engine.enforcer import AuthzEnforcer | ||||||
| from organizations.api import add_organization | ||||||
|
|
||||||
| from common.djangoapps.student.admin import CourseAccessRoleHistoryAdmin | ||||||
| from common.djangoapps.student.models import CourseAccessRoleHistory, User | ||||||
|
|
@@ -313,6 +315,33 @@ def test_get_orgs_for_user_authz(self): | |||||
| result = role.get_orgs_for_user(self.student) | ||||||
| self.assertCountEqual(result, [self.course_key.org, other_org]) # noqa: PT009 | ||||||
|
|
||||||
| @override_waffle_flag(AUTHZ_COURSE_AUTHORING_FLAG, active=True) | ||||||
| def test_get_orgs_for_user_authz_platform_glob(self): | ||||||
| """ | ||||||
| A platform-wide glob assignment (course-v1:*) has no `.org` attribute, unlike | ||||||
| course/org-glob scopes. get_orgs_for_user must special-case it and return every | ||||||
| registered org instead of crashing with an AttributeError. | ||||||
| """ | ||||||
| role = CourseStaffRole(self.course_key) | ||||||
|
|
||||||
| for org in self.orgs: | ||||||
| add_organization({"name": org, "short_name": org, "description": ""}) | ||||||
|
|
||||||
| staff_authz_role = RoleData(external_key=COURSE_STAFF) | ||||||
| assignments = [ | ||||||
| RoleAssignmentData( | ||||||
| subject=UserData(external_key=self.student.username), | ||||||
| roles=[staff_authz_role], | ||||||
| scope=PlatformCourseOverviewGlobData(external_key="course-v1:*"), | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
And could we please update
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied — wrapped it in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you're right. Now that I'm taking a closer look at the test, instead of mocking the assignments, could we use the assign_role_to_user_in_scope(
self.student.username,
COURSE_STAFF.external_key,
PlatformCourseOverviewGlobData.build_external_key(),
)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea — this is actually stronger, since it exercises the real Casbin assignment + policy load instead of mocking get_user_role_assignments_filtered. It also caught a latent bug in my mock: I had |
||||||
| ), | ||||||
| ] | ||||||
|
|
||||||
| with patch("openedx_authz.api.users.get_user_role_assignments_filtered", return_value=assignments): | ||||||
| result = role.get_orgs_for_user(self.student) | ||||||
| self.assertCountEqual(result, self.orgs) # noqa: PT009 | ||||||
| assert role.has_org_for_user(self.student) | ||||||
| assert role.has_org_for_user(self.student, org=self.orgs[0]) | ||||||
|
|
||||||
| def test_get_authz_compat_course_access_roles_for_user(self): | ||||||
| """ | ||||||
| Test that get_authz_compat_course_access_roles_for_user doesn't crash when the user | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for being late to this review. Does this return the same structure as in L641? Can we make sure of this with a test - like a test case that for a user returns a subset and for another all orgs? Not sure if we're doing that already. Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries about the timing! Yes — both branches return the same shape, a plain list[str] of org short names (L640 is a list comprehension over get_organizations(), L641 is list(a set) of assignment.scope.org values). Added test_get_orgs_for_user_authz_platform_glob_vs_org_scoped: it registers a third org that's never assigned to anyone, then asserts an org-scoped grant returns only its own org while a platform-wide grant returns all three, against that same shared pool of orgs — so the two branches are actually distinguished instead of just coincidentally returning the same numbers (which is what my original platform_glob test alone couldn't rule out, since it only ever registered exactly the orgs it expected back). Verified locally against a real devstack. Fixed in fbb2726.