0019: Discover and Load Authorization Schemas During Deployment#
Status#
Draft
Context#
Applications, such as Django apps or IDAs, need a standard way to provide their static authz schema files. Because Open edX supports several deployment methods, discovery must work with Tutor, native deployments and local development.
Decision#
1. Python entry point and package resources#
Applications can register schema resources through a Python entry point defined by openedx-authz, following the pattern used to register LMS and CMS Django apps. For example, the course_authoring package can add an authz.schema entry point in setup.py:
entry_points={
"authz.schema": [
"course_authoring = course_authoring.authz:get_schema_resources",
],
}
The registered function returns the package directories that contain its schema files:
...
def get_schema_resources():
return ["course_authoring/authz/schema"]
The compiler loads the authz.schema entry-point group, calls each registered function, and uses importlib.resources or a similar mechanism to find the directories. It loads every .yaml file in those directories, then validates the schemas, compiles them into Casbin rows, and applies them to the database.
If a registered function raises an exception, discovery stops and reports which application failed. This prevents deployment from continuing with an incomplete set of static definitions.
Site operators can contribute a schema through a Python Tutor plugin that uses the openedx-authz-schema patch:
from tutor import hooks
hooks.Filters.ENV_PATCHES.add_item((
"openedx-authz-schema",
"""
schema_version: "1.0"
priority: 200
role_extensions:
- role: course_editor
add_permissions:
- courses.export_course
""",
))
The compiler combines schemas from application entry points and Tutor patches in a defined order because discovery order may vary.
2. Static source information#
For every contribution, the compiler records:
the installed distribution name and version;
the Python module that owns the resource;
the resource path inside that module; and
the schema version and content digest.
Together, these values identify the same source across deployment layouts. The loader reads them from the package and uses them as the source record.
The compiler records this information for each definition and role-permission assignment. For example, openedx-authz:openedx_authz/authz/schema/roles.yaml may assign courses.view_course to course_admin, while course-authoring:course_authoring/authz/schema/roles.yaml assigns courses.edit_schedule to the same role. Because both resources contributed to the compiled role, it keeps both source records.
3. Deployment command#
openedx-authz exposes one non-interactive command that discovers, validates, compiles, reports, and applies the static schema. For CI and local development, the same command can accept explicit resources or directories.
Tutor calls the command via for example a plugin initialization task, while other deployment systems call it before their application processes begin serving traffic. Each integration chooses the appropriate hook, but all of them use the same compiler.
4. Removed applications#
When an application is disabled or removed, the next deployment removes the static definitions that came only from that application. If users are assigned to one of its roles, deployment stops and reports those assignments so that an operator can remove them or move the users to another role. Shared definitions remain available when another application still provides them.
Deployment also stops if a remaining schema refers to a role, permission, or category that would be removed with the application. An operator may allow the removal through explicit deployment configuration. Without that configuration, the stored definitions remain unchanged.
Consequences#
An application can ship authorization definitions with its code.
Tutor and other deployment systems use the same mechanism to discover and load the definitions.
Source information remains consistent across containers.
Authorization changes after the deployment command runs successfully.
Packaging checks must verify that schema resources are included in wheels and source distributions.
Deployment integrations need to pass database settings and run the command at a point where all contributing packages are installed.