Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ Changed
========

* Static roles may declare an empty permission list when ``role_extensions`` contribute their permissions. Permission lists used by extension edits remain non-empty.
* Built-in Content Library and course authorization definitions now live in capability applets. The compiled authorization schema, the permission constants, and the role keys remain unchanged.

Removed
=======

* Removed the role permission lists from ``openedx_authz.constants.roles``, such as ``COURSE_ADMIN_PERMISSIONS`` and ``LIBRARY_ADMIN_PERMISSIONS``. Role constants now identify a role and have an empty ``permissions`` list. Use ``openedx_authz.api.get_permissions_for_single_role`` or the compiled schema to read a role's permissions.
* Removed ``COURSES_CREATE_COURSE`` (``courses.create_course``) from ``openedx_authz.constants.permissions``. No schema file defined it, so no role could include it.

Fixed
=====
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: clean clean_tox compile_translations coverage diff_cover docs dummy_translations \
extract_translations fake_translations help pii_check pull_translations paragon_icons \
extract_translations fake_translations help pii_check pull_translations paragon_icons compiled_schema \
paragon_icons_check quality requirements selfcheck test test-all upgrade validate \
install_transifex_client

Expand Down Expand Up @@ -43,6 +43,9 @@ paragon_icons: ## regenerate the vendored @openedx/paragon icon-name allow-list
paragon_icons_check: ## fail if the vendored Paragon icon list is out of date (CI)
python scripts/generate_paragon_icons.py --check

compiled_schema: ## regenerate the compiled schema snapshot in docs/references/compiled-schema.yaml
python scripts/generate_compiled_schema.py

quality: ## check coding style with pycodestyle and pylint
tox -e quality

Expand Down
2 changes: 0 additions & 2 deletions docs/concepts/core_roles_and_permissions/course_roles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ The following permissions are associated with the course roles:
Course Access & Content
=========================
- **View course** (``courses.view_course``): Allows users to view the course and access the course outline in read-only mode.
- **Create course** (``courses.create_course``): Allows users to create a new course in Studio.
- **Edit course content** (``courses.edit_course_content``): Allows users to edit course content, outline, units, and components.
- **Publish course content** (``courses.publish_course_content``): Allows users to publish course content.

Expand Down Expand Up @@ -132,7 +131,6 @@ Roles and Permissions Summary Table
**Access & Content**
--------------------------------------------- -------------- -------------- --------------------- --------------
courses.view_course ✅ ✅ ✅ ✅
courses.create_course ❌ ❌ ❌ ❌
courses.publish_course_content ✅ ✅ ❌ ❌
courses.edit_course_content ✅ ✅ ✅ ❌
**Files**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,21 @@ Roles such as ``course_editor`` have no permissions of their own, so schema vers

REST endpoints continue to follow the ownership rules in `ADR 0026`_, and applets now give those rules a package boundary. The Admin Console endpoints therefore move to ``role_management``, since they support the same role-management workflow, although this placement does not settle the ownership of the organization data returned by ``AdminConsoleOrgsAPIView``, and ``WaffleFlagStatesAPIView`` moves to ``course_authoring``. In both cases, the existing URLs and route names remain unchanged.

5. Imports
==========
5. YAML definitions and Python constants
========================================

YAML is the source of truth for static definitions. It defines every permission, role, and role extension together with their metadata, and it is the only place that lists a role's permissions, so the schema pipeline composes each role's complete permission list from the ``role_extensions`` contributed by the applets.

Python constants give clients stable identifiers to reference in code, since permission constants name the actions that clients check through the public API and role constants name the roles that clients assign. Role constants do not list permissions, because listing them in Python would repeat the schema composition and make each capability applet import and extend roles owned by ``course_team_roles``, so code that needs a role's permissions reads them through the public API or the compiled schema.

Although applets are internal packages, ``openedx_authz.constants.permissions`` and ``openedx_authz.constants.roles`` continue to export every existing constant, while ``COURSE_ADMIN`` and ``COURSE_STAFF`` continue to contain their complete permission lists, so existing import paths remain valid when code moves into an applet.
Every permission constant names a permission defined in YAML, and every permission defined in YAML has a constant. Each applet maintains its permission constants manually for now, tests compare them with the compiled schema, and generating them from YAML may replace this process in later work.

6. Imports
==========

YAML remains the source of truth for static definitions, although each applet will maintain its Python constants manually for now, so tests compare those constants with the applet's YAML definitions, and generating them from YAML may replace this process in later work.
Applets are internal packages, so clients import the permission and role constants from ``openedx_authz.constants.permissions`` and ``openedx_authz.constants.roles``, which re-export each applet's constants and keep existing import paths valid when code moves into an applet.

6. Future extraction
7. Future extraction
====================

The applets remain inside ``openedx-authz`` for this work, so implementing the ownership model and the permissions from `Issue #484`_ does not require coordinated changes across the services that use the library, and since their definitions describe the underlying actions and data rather than one user interface, another client can reuse the same permissions when it exposes the same responsibility.
Expand All @@ -143,11 +150,12 @@ Consequences

1. Each built-in definition has an explicit owner based on the capability it protects.
2. Adding a capability does not require adding its definitions to shared course permission and role files.
3. The complete permission list for a course role is assembled from several schema contributions, so readers use the compiled schema or the public role constants to inspect that list.
3. The complete permission list for a course role is assembled from several schema contributions, so readers use the compiled schema or the public API to inspect that list.
4. Each permission identifier appears in YAML and Python until generated constants replace the manually maintained files.
5. The Admin Console and course-authoring endpoints move again after `ADR 0026`_, although their public URLs, route names, request and response contracts, and import paths remain stable.
6. Reviewers must identify unwanted dependencies between applets because this decision does not add automated import-boundary checks.
7. Applets create boundaries that can support later extraction, although moving one to another service requires a separate decision about dependencies and compatibility.
5. Role constants no longer list permissions, so code that read a role's permissions from its constant uses the public API instead.
6. The Admin Console and course-authoring endpoints move again after `ADR 0026`_, although their public URLs, route names, request and response contracts, and import paths remain stable.
7. Reviewers must identify unwanted dependencies between applets because this decision does not add automated import-boundary checks.
8. Applets create boundaries that can support later extraction, although moving one to another service requires a separate decision about dependencies and compatibility.

Rejected Alternatives
*********************
Expand Down
11 changes: 11 additions & 0 deletions docs/references/compiled-schema.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.. _Compiled Authorization Schema:

Compiled Authorization Schema
#############################

The built-in applets each contribute part of the authorization schema, so a role's complete permission list only exists after the schema pipeline composes the base definitions with the ``role_extensions`` from every applet. This page shows that compiled result for the built-in applets, where each role lists its permissions grouped by the applet that adds them, and each permission and category names the applet that defines it. Installations may add more definitions through their own schema contributions, which this snapshot does not include.

The snapshot is generated from the applet schemas with ``make compiled_schema``, and a test fails when it no longer matches the compiled schema, so any change to an applet schema also shows its effect on the compiled roles in the same diff. You can also :download:`download the snapshot <compiled-schema.yaml>`.

.. literalinclude:: compiled-schema.yaml
:language: yaml
Loading
Loading