Spike - RBAC AuthZ - Authoring Waffle Flag Implementation
Overview
There is a desire to implement the new RBAC functionality for course authoring behind a Waffle flag as a beta feature for a few reasons:
Allow development to happen incrementally without breaking existing functionality
Allow large sites to test performance and functionality at small volumes before flipping the switch for all users
Hedge against the time crunch of finishing entire feature before the Verawood cut
Development Goals
Due to the nature of the permissions model, we will need to be cognizant of a few things:
Waffle flag can be set via the Django admin UI (for Orgs or Courses) or via management command (for orgs, courses, or the whole instance)
Keep permissions in sync when moving between the old and new systems
Remove permissions from the system that the user is moving away from, so that if they move back at a later point they will not potentially inherit permissions that they should no longer have
We should enforce that the flag cannot be set at a per-user level to prevent the difficulties of having users of the same course get differing permissions experiences
Specifically this prevents the situation of course staff trying to set permissions on one system for users who are flagged to the other system, which would have no effect
We will need to document the differences between the systems carefully, in an easy to find and user friendly way. Permissions between the systems will not line up exactly.
If a course switches between the new and old implementations a course admin may need to review and potentially manually fix some users' permissions. It should be easy for them to find what to look for.
Ideally there will be links or instructions directly in the UI for this
The focus will be on maintaining similar roles between systems, not managing the individual user permissions
The management command created for this should be able to:
Set the waffle flag for a course, org, or the whole instance
Not use Django bulk updates for this, as it will skip the on_save handlers needed to run our custom code to keep the roles in sync
Implementation Details
WaffleFlagOrgOverrideModel and WaffleFlagCourseOverrideModel in conjunction with a site-wide default flag are designed to achieve the following:
Site setting can be overridden by an Org setting
Org setting can be overridden by a Course setting
This allows for the following use cases:
“We only want to test on this course”
“We want this feature on for everyone, but there are performance regressions for certain large courses so it is turned off for them”
“This particular org has a fine grained permissions need, so it is only on for them”
There is no existing higher level API to hook into changes on the Waffle flag models, this means we would need to implement Django signal handlers for pre_save signals for the models we care about.
WaffleFlagOrgOverrideModel:
If the flag is the one we care about, update permissions for every permission-granted user for every course in the org
WaffleFlagCourseOverrideModel:
If the flag is the one we care about, update permissions for every permission-granted user in the course
Flag:
If the flag is the one we care about, probably throw an error? Need to investigate more to understand how this works with the global default, we may only need to throw errors here if it is trying to update specific sets of users (ie not “everyone”). This should prevent the flag from being set.
In all cases we must ensure that the permissions copy executes in the same database transaction as setting the waffle flag to ensure all-or-nothing permissions consistency.
We will also need to document the flag so that it can be reported on and the expected state / removal timeline understood.
Open Questions
Need more details on how the global flag state is stored and what to do when that changes
Will we use the new UI to change permissions in both systems?
If not, how will the frontend know which UI to show?
How will the UI gracefully handle various state changes of the toggle being flipped?
Ex: If you’re on the new UI but get changed to the old permissions, can it forward you back to the old UI?
Specific Role Mappings and Migration Steps
TBD as we map permissions: openedx-authz permission list
Resources
An earlier attempt to move all of the toggle functionality to a separate package was not entirely completed, as such the things we will need to touch are spread around a few different places:
The main OEP around all of this: https://open-edx-proposals.readthedocs.io/en/latest/best-practices/oep-0017-bp-feature-toggles.html
All of this functionality is based on https://waffle.readthedocs.io/en/stable/index.html
openedx-platform has
waffle_utils, which handles caching and implements custom Course and Org override modelshttps://docs.openedx.org/projects/edx-toggles/en/latest/index.html wraps a lot of Waffle and has a lot of documentation around how toggles should be used / documented / and lifecyle
Specifically this: Implementing the toggle