openedx-authz 2.4.0__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/CHANGELOG.rst +12 -0
  2. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/Makefile +4 -1
  3. {openedx_authz-2.4.0/src/openedx_authz.egg-info → openedx_authz-3.0.0}/PKG-INFO +1 -1
  4. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/core_roles_and_permissions/course_roles.rst +0 -2
  5. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0026-rest-api-domain-ownership-boundary.rst +7 -0
  6. openedx_authz-3.0.0/docs/decisions/0032-applets-for-built-in-authorization-capabilities.rst +202 -0
  7. openedx_authz-3.0.0/docs/decisions/0033-shared-applet-for-course-team-roles.rst +43 -0
  8. openedx_authz-3.0.0/docs/how-tos/index.rst +7 -0
  9. openedx_authz-3.0.0/docs/how-tos/use-built-in-constants.rst +25 -0
  10. openedx_authz-3.0.0/docs/references/built-in-constants.rst +13 -0
  11. openedx_authz-3.0.0/docs/references/compiled-schema.rst +11 -0
  12. openedx_authz-3.0.0/docs/references/compiled-schema.yaml +803 -0
  13. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/references/index.rst +2 -0
  14. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/pyproject.toml +2 -1
  15. openedx_authz-3.0.0/scripts/generate_compiled_schema.py +41 -0
  16. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/scripts/generate_paragon_icons.py +3 -1
  17. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/data.py +2 -66
  18. openedx_authz-3.0.0/src/openedx_authz/applets/__init__.py +1 -0
  19. openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/README.rst +6 -0
  20. openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/__init__.py +1 -0
  21. openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/constants.py +63 -0
  22. openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/README.rst +6 -0
  23. openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/__init__.py +1 -0
  24. openedx_authz-2.4.0/src/openedx_authz/constants/permissions.py → openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/constants.py +43 -96
  25. openedx_authz-2.4.0/src/openedx_authz/authz/schema/course_permissions.yaml → openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/schema/permissions.yaml +0 -53
  26. openedx_authz-2.4.0/src/openedx_authz/authz/schema/course_roles.yaml → openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/schema/role_extensions.yaml +9 -61
  27. openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/README.rst +8 -0
  28. openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/__init__.py +1 -0
  29. openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/constants.py +59 -0
  30. openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/schema/legacy_permissions.yaml +50 -0
  31. openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/schema/roles.yaml +60 -0
  32. openedx_authz-3.0.0/src/openedx_authz/authz/__init__.py +52 -0
  33. openedx_authz-3.0.0/src/openedx_authz/constants/permissions.py +7 -0
  34. openedx_authz-3.0.0/src/openedx_authz/constants/roles.py +35 -0
  35. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/data.py +33 -2
  36. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/authz-schema-v1.json +11 -3
  37. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/discovery.py +8 -7
  38. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/parsing.py +1 -1
  39. openedx_authz-3.0.0/src/openedx_authz/engine/schema/snapshot.py +79 -0
  40. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/translation.py +1 -1
  41. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/loading.py +1 -1
  42. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/validation.py +16 -0
  43. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/load_authz_schema.py +3 -2
  44. openedx_authz-3.0.0/src/openedx_authz/migrations/0012_move_builtin_schema_sources_to_applets.py +123 -0
  45. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_roles.py +38 -63
  46. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_users.py +3 -13
  47. openedx_authz-3.0.0/src/openedx_authz/tests/applets/__init__.py +1 -0
  48. openedx_authz-3.0.0/src/openedx_authz/tests/applets/test_builtin_definitions.py +78 -0
  49. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/authz/test_resources.py +7 -0
  50. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/test_views.py +2 -1
  51. openedx_authz-3.0.0/src/openedx_authz/tests/role_permissions.py +107 -0
  52. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_discovery.py +33 -16
  53. openedx_authz-3.0.0/src/openedx_authz/tests/schema/test_json_schema.py +48 -0
  54. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_loading.py +6 -3
  55. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_renderer.py +25 -1
  56. openedx_authz-3.0.0/src/openedx_authz/tests/schema/test_snapshot.py +136 -0
  57. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_syntax.py +1 -1
  58. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_translation.py +7 -9
  59. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_validation.py +10 -0
  60. openedx_authz-3.0.0/src/openedx_authz/tests/test_imports.py +114 -0
  61. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_migrations.py +120 -0
  62. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_utils.py +1 -3
  63. {openedx_authz-2.4.0 → openedx_authz-3.0.0/src/openedx_authz.egg-info}/PKG-INFO +1 -1
  64. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/SOURCES.txt +30 -4
  65. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/scm_file_list.json +30 -4
  66. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tox.ini +3 -3
  67. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/uv.lock +10 -0
  68. openedx_authz-2.4.0/docs/how-tos/index.rst +0 -2
  69. openedx_authz-2.4.0/src/openedx_authz/authz/__init__.py +0 -33
  70. openedx_authz-2.4.0/src/openedx_authz/constants/roles.py +0 -216
  71. openedx_authz-2.4.0/src/openedx_authz/tests/test_imports.py +0 -37
  72. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.annotation_safe_list.yml +0 -0
  73. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.editorconfig +0 -0
  74. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  75. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/dependabot.yml +0 -0
  76. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/add-depr-ticket-to-depr-board.yml +0 -0
  77. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/add-remove-label-on-comment.yml +0 -0
  78. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/ci.yml +0 -0
  79. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/commitlint.yml +0 -0
  80. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/release.yml +0 -0
  81. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/self-assign-issue.yml +0 -0
  82. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/upgrade-python-requirements.yml +0 -0
  83. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.gitignore +0 -0
  84. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.pii_annotations.yml +0 -0
  85. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.readthedocs.yaml +0 -0
  86. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/LICENSE +0 -0
  87. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/MANIFEST.in +0 -0
  88. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/README.rst +0 -0
  89. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/catalog-info.yaml +0 -0
  90. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/codecov.yml +0 -0
  91. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/Makefile +0 -0
  92. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/_images/architecture-overview.png +0 -0
  93. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/_static/theme_overrides.css +0 -0
  94. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/changelog.rst +0 -0
  95. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/core_roles_and_permissions/content_library_roles.rst +0 -0
  96. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/core_roles_and_permissions/index.rst +0 -0
  97. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/index.rst +0 -0
  98. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/conf.py +0 -0
  99. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0001-purpose-of-this-repo.rst +0 -0
  100. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0002-authorization-model-foundation.rst +0 -0
  101. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0003-jwt-usage.rst +0 -0
  102. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0004-technology-selection.rst +0 -0
  103. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0005-architecture-and-data-modeling.rst +0 -0
  104. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0007-enforcement-mechanisms-mfe.rst +0 -0
  105. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0008-compatibility-scheme.rst +0 -0
  106. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0009-authz-for-course-authoring.rst +0 -0
  107. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0010-course-authoring-flag.rst +0 -0
  108. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0011-course-authoring-migration-process.rst +0 -0
  109. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0012-auditability.rst +0 -0
  110. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0012-glob-support-for-role-assignments.rst +0 -0
  111. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0013-course-authoring-automatic-migration.rst +0 -0
  112. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0014-bulk-assignment-queries-without-casbin-enforce.rst +0 -0
  113. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0015-expose-course-authoring-waffle-flag-state-via-rest-api.rst +0 -0
  114. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0016-static-and-dynamic-roles.rst +0 -0
  115. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0017-static-authorization-schema.rst +0 -0
  116. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0018-authorization-schema-lifecycle.rst +0 -0
  117. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0019-authorization-schema-discovery.rst +0 -0
  118. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0020-authorization-schema-internationalization.rst +0 -0
  119. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0021-authorization-definition-api.rst +0 -0
  120. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0022-defer-authorization-implications.rst +0 -0
  121. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0023-extend-static-roles.rst +0 -0
  122. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0024-api-contract-for-user-grouped-role-assignments.rst +0 -0
  123. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0025-authorization-schema-source-tracking.rst +0 -0
  124. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0027-cross-domain-filtering-via-openedx-filters.rst +0 -0
  125. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0028-api-contract-for-role-catalog.rst +0 -0
  126. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0029-paragon-icon-list-maintenance.rst +0 -0
  127. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0030-tutor-implementation-authz-schema-discovery.rst +0 -0
  128. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0031-priority-applies-to-role-extensions-only.rst +0 -0
  129. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/README.rst +0 -0
  130. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions.rst +0 -0
  131. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/getting_started.rst +0 -0
  132. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/index.rst +0 -0
  133. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/internationalization.rst +0 -0
  134. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/make.bat +0 -0
  135. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/quickstarts/index.rst +0 -0
  136. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/readme.rst +0 -0
  137. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/references/authorization-schema-json.rst +0 -0
  138. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/references/authorization-schema.rst +0 -0
  139. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/testing.rst +0 -0
  140. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/manage.py +0 -0
  141. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/pylintrc +0 -0
  142. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/pylintrc_tweaks +0 -0
  143. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/ruff.toml +0 -0
  144. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/setup.cfg +0 -0
  145. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/__init__.py +0 -0
  146. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/admin.py +0 -0
  147. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/__init__.py +0 -0
  148. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/catalog.py +0 -0
  149. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/permissions.py +0 -0
  150. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/roles.py +0 -0
  151. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/users.py +0 -0
  152. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/utils.py +0 -0
  153. /openedx_authz-2.4.0/src/openedx_authz/authz/schema/library_permissions.yaml → /openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/schema/permissions.yaml +0 -0
  154. /openedx_authz-2.4.0/src/openedx_authz/authz/schema/library_roles.yaml → /openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/schema/roles.yaml +0 -0
  155. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/apps.py +0 -0
  156. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/conf/locale/config.yaml +0 -0
  157. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/constants/__init__.py +0 -0
  158. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/constants/schema.py +0 -0
  159. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/__init__.py +0 -0
  160. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/adapter.py +0 -0
  161. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/apps.py +0 -0
  162. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/config/model.conf +0 -0
  163. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/enforcer.py +0 -0
  164. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/filter.py +0 -0
  165. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/matcher.py +0 -0
  166. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/policy.py +0 -0
  167. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/renderer.py +0 -0
  168. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/__init__.py +0 -0
  169. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/compilation.py +0 -0
  170. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/exceptions.py +0 -0
  171. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/issues.py +0 -0
  172. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/loading.py +0 -0
  173. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/paragon_icons.py +0 -0
  174. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/pipeline.py +0 -0
  175. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/syntax.py +0 -0
  176. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/__init__.py +0 -0
  177. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/compilation.py +0 -0
  178. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/definitions.py +0 -0
  179. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/utils.py +0 -0
  180. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/filters.py +0 -0
  181. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/handlers.py +0 -0
  182. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/__init__.py +0 -0
  183. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/__init__.py +0 -0
  184. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/authz_migrate_course_authoring.py +0 -0
  185. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/authz_rollback_course_authoring.py +0 -0
  186. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/enforcement.py +0 -0
  187. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/extract_schema_translations.py +0 -0
  188. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/load_policies.py +0 -0
  189. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0001_add_casbin_dependency.py +0 -0
  190. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0002_initial.py +0 -0
  191. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0003_usersubject.py +0 -0
  192. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0004_contentlibraryscope.py +0 -0
  193. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0005_policycachecontrol.py +0 -0
  194. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0006_migrate_legacy_permissions.py +0 -0
  195. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0007_coursescope.py +0 -0
  196. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0008_authzcourseauthoringmigrationrun.py +0 -0
  197. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0009_roleassignmentaudit.py +0 -0
  198. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0010_scope_external_key.py +0 -0
  199. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0011_authz_schema_definitions.py +0 -0
  200. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/__init__.py +0 -0
  201. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/__init__.py +0 -0
  202. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/authz_migration.py +0 -0
  203. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/base.py +0 -0
  204. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/core.py +0 -0
  205. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/engine.py +0 -0
  206. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/schema.py +0 -0
  207. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/scopes.py +0 -0
  208. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/subjects.py +0 -0
  209. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/__init__.py +0 -0
  210. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/data.py +0 -0
  211. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/decorators.py +0 -0
  212. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/urls.py +0 -0
  213. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/utils.py +0 -0
  214. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/__init__.py +0 -0
  215. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/__init__.py +0 -0
  216. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/filters.py +0 -0
  217. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/serializers.py +0 -0
  218. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/views.py +0 -0
  219. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/course_authoring/__init__.py +0 -0
  220. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/course_authoring/pipeline.py +0 -0
  221. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/course_authoring/views.py +0 -0
  222. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/fields.py +0 -0
  223. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/paginators.py +0 -0
  224. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/permissions.py +0 -0
  225. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/serializers.py +0 -0
  226. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/urls.py +0 -0
  227. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/views.py +0 -0
  228. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/__init__.py +0 -0
  229. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/common.py +0 -0
  230. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/production.py +0 -0
  231. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/test.py +0 -0
  232. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/templates/openedx_authz/base.html +0 -0
  233. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/__init__.py +0 -0
  234. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/__init__.py +0 -0
  235. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_catalog.py +0 -0
  236. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_data.py +0 -0
  237. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/authz/__init__.py +0 -0
  238. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/__init__.py +0 -0
  239. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/conftest.py +0 -0
  240. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/categories.yaml +0 -0
  241. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/extensions.yaml +0 -0
  242. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/permissions.yaml +0 -0
  243. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/roles.yaml +0 -0
  244. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_parse/malformed.yaml +0 -0
  245. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_semantics/unknown_category.yaml +0 -0
  246. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_structure/items.yml +0 -0
  247. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_structure/priority.yaml +0 -0
  248. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/categories.yaml +0 -0
  249. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/extensions.yaml +0 -0
  250. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/permissions.yml +0 -0
  251. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/roles.yaml +0 -0
  252. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_handlers.py +0 -0
  253. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_models.py +0 -0
  254. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_schema_apply.py +0 -0
  255. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_schema_pipeline.py +0 -0
  256. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_views.py +0 -0
  257. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/__init__.py +0 -0
  258. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/admin_console/__init__.py +0 -0
  259. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/admin_console/test_views.py +0 -0
  260. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/course_authoring/__init__.py +0 -0
  261. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/course_authoring/test_pipeline.py +0 -0
  262. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/course_authoring/test_views.py +0 -0
  263. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/mixins.py +0 -0
  264. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/test_permissions.py +0 -0
  265. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/test_utils.py +0 -0
  266. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/__init__.py +0 -0
  267. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/factories.py +0 -0
  268. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_apply.py +0 -0
  269. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_compilation.py +0 -0
  270. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_load_authz_schema_command.py +0 -0
  271. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_parsing.py +0 -0
  272. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_pipeline.py +0 -0
  273. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_schema_models.py +0 -0
  274. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_source_storage.py +0 -0
  275. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_types.py +0 -0
  276. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/__init__.py +0 -0
  277. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/apps.py +0 -0
  278. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/migrations/0001_initial.py +0 -0
  279. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/migrations/0002_learningpackage_contentlibrary_learning_package.py +0 -0
  280. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/migrations/0002_userprofile.py +0 -0
  281. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/models.py +0 -0
  282. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_commands.py +0 -0
  283. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_enforcement.py +0 -0
  284. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_enforcer.py +0 -0
  285. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_engine_utils.py +0 -0
  286. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_filter.py +0 -0
  287. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_handlers.py +0 -0
  288. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_models.py +0 -0
  289. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_policy.py +0 -0
  290. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/urls.py +0 -0
  291. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/utils.py +0 -0
  292. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/dependency_links.txt +0 -0
  293. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/entry_points.txt +0 -0
  294. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/requires.txt +0 -0
  295. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/top_level.txt +0 -0
  296. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/.gitignore +0 -0
  297. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/LICENSE.txt +0 -0
  298. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/MANIFEST.in +0 -0
  299. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/Makefile +0 -0
  300. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/README.rst +0 -0
  301. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/pyproject.toml +0 -0
  302. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/__about__.py +0 -0
  303. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/__init__.py +0 -0
  304. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/patches/openedx-common-settings +0 -0
  305. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/plugin.py +0 -0
  306. {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/templates/apps/openedx/config/authz-schema.yml +0 -0
@@ -52,6 +52,18 @@ Added
52
52
  ``openedx_authz/engine/schema/paragon_icons.py`` and regenerated with
53
53
  ``make paragon_icons`` (ADR 0029).
54
54
 
55
+ Changed
56
+ ========
57
+
58
+ * Static roles may declare an empty permission list when ``role_extensions`` contribute their permissions. Permission lists used by extension edits remain non-empty.
59
+ * 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.
60
+
61
+ Removed
62
+ =======
63
+
64
+ * 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.
65
+ * Removed ``COURSES_CREATE_COURSE`` (``courses.create_course``) from ``openedx_authz.constants.permissions``. No schema file defined it, so no role could include it.
66
+
55
67
  Fixed
56
68
  =====
57
69
 
@@ -1,5 +1,5 @@
1
1
  .PHONY: clean clean_tox compile_translations coverage diff_cover docs dummy_translations \
2
- extract_translations fake_translations help pii_check pull_translations paragon_icons \
2
+ extract_translations fake_translations help pii_check pull_translations paragon_icons compiled_schema \
3
3
  paragon_icons_check quality requirements selfcheck test test-all upgrade validate \
4
4
  install_transifex_client
5
5
 
@@ -43,6 +43,9 @@ paragon_icons: ## regenerate the vendored @openedx/paragon icon-name allow-list
43
43
  paragon_icons_check: ## fail if the vendored Paragon icon list is out of date (CI)
44
44
  python scripts/generate_paragon_icons.py --check
45
45
 
46
+ compiled_schema: ## regenerate the compiled schema snapshot in docs/references/compiled-schema.yaml
47
+ python scripts/generate_compiled_schema.py
48
+
46
49
  quality: ## check coding style with pycodestyle and pylint
47
50
  tox -e quality
48
51
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openedx-authz
3
- Version: 2.4.0
3
+ Version: 3.0.0
4
4
  Summary: Open edX AuthZ provides the architecture and foundations of the authorization framework.
5
5
  Author-email: Open edX Project <oscm@openedx.org>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -36,7 +36,6 @@ The following permissions are associated with the course roles:
36
36
  Course Access & Content
37
37
  =========================
38
38
  - **View course** (``courses.view_course``): Allows users to view the course and access the course outline in read-only mode.
39
- - **Create course** (``courses.create_course``): Allows users to create a new course in Studio.
40
39
  - **Edit course content** (``courses.edit_course_content``): Allows users to edit course content, outline, units, and components.
41
40
  - **Publish course content** (``courses.publish_course_content``): Allows users to publish course content.
42
41
 
@@ -132,7 +131,6 @@ Roles and Permissions Summary Table
132
131
  **Access & Content**
133
132
  --------------------------------------------- -------------- -------------- --------------------- --------------
134
133
  courses.view_course ✅ ✅ ✅ ✅
135
- courses.create_course ❌ ❌ ❌ ❌
136
134
  courses.publish_course_content ✅ ✅ ❌ ❌
137
135
  courses.edit_course_content ✅ ✅ ✅ ❌
138
136
  **Files**
@@ -105,6 +105,11 @@ Rejected Alternatives
105
105
  **Adding application-specific visibility rules to reusable endpoint code**
106
106
  This would make reusable authorization code interpret data that authorization does not own. A general hook keeps the rule in a separate implementation, and `openedx_catalog`_ follows a related approach for installation-specific visibility rules.
107
107
 
108
+ Addendum 2026-10-20
109
+ *******************
110
+
111
+ `ADR 0032`_ replaces the package layout in decisions 4, 6, and 8, so client-specific and cross-domain endpoints now belong in the applet for the capability they serve, while the ownership rules in this ADR still apply.
112
+
108
113
  References
109
114
  **********
110
115
 
@@ -115,6 +120,7 @@ References
115
120
  * `Issue #377`_
116
121
  * `PR #361`_
117
122
  * `openedx_catalog`_
123
+ * `ADR 0032`_
118
124
 
119
125
  .. _edX DDD Bounded Contexts: https://openedx.atlassian.net/wiki/spaces/AC/pages/663224968/edX+DDD+Bounded+Contexts
120
126
  .. _ADR 0018 in openedx-events: https://github.com/openedx/openedx-events/blob/main/docs/decisions/0018-supporting-subdomain-modules.rst
@@ -123,3 +129,4 @@ References
123
129
  .. _Issue #377: https://github.com/openedx/openedx-authz/issues/377
124
130
  .. _PR #361: https://github.com/openedx/openedx-authz/pull/361
125
131
  .. _openedx_catalog: https://github.com/openedx/openedx-core/blob/main/src/openedx_catalog/api.py
132
+ .. _ADR 0032: 0032-applets-for-built-in-authorization-capabilities.rst
@@ -0,0 +1,202 @@
1
+ 0032: Applets for Built-In Authorization Capabilities
2
+ #####################################################
3
+
4
+ Status
5
+ ******
6
+
7
+ **Draft**
8
+
9
+ Context
10
+ *******
11
+
12
+ `ADR 0005`_ defines ``openedx_authz.api`` as the public API for the reusable authorization framework, although the package also ships the Open edX-specific roles and permissions that the platform uses, as YAML schema files and Python constants. These definitions are grouped by type, so ``authz/schema/course_permissions.yaml`` defines every course permission and ``authz/schema/course_roles.yaml`` lists the complete permissions for each course role.
13
+
14
+ Grouping by type keeps roles apart from permissions, but it also puts definitions from unrelated responsibilities into the same course-level files, so a reader can see that a permission applies to a course without being able to tell whether enrollments, grading, or another area owns it.
15
+
16
+ `Issue #484`_ defines permissions for the Instructor Dashboard, which brings together several areas of course administration, including enrollments, the gradebook, learner extensions, and cohorts. The `edX DDD Bounded Contexts`_ map places those areas in different parts of the platform, so adding their permissions to the shared files would mix definitions from several bounded contexts and make those files the place where every new contribution has to be added.
17
+
18
+ The existing decisions do not say where these definitions belong, because `ADR 0026`_ defines ownership and placement rules only for REST endpoints, while `PR #421`_ raised the same ownership question for constants and schema definitions.
19
+
20
+ `ADR 0010 in openedx-core`_ answers a similar question for a single Django app by giving each bounded responsibility its own internal package, which it calls an applet. The authorization schema can already support that structure, since `ADR 0019`_ allows a package to load several schema directories and `ADR 0023`_ allows one schema contribution to extend a role defined by another.
21
+
22
+ Decision
23
+ ********
24
+
25
+ We will organize built-in Open edX authorization capabilities as applets under ``openedx_authz.applets``, while the existing public API and import paths remain stable, since ``openedx_authz.constants`` re-exports each applet's constants and the ``authz.schema`` provider lists each applet's schema directory.
26
+
27
+ 1. Applet boundaries
28
+ ====================
29
+
30
+ An applet is an internal Python package that gives one bounded responsibility a concrete place inside the existing ``openedx_authz`` Django app and keeps the related YAML definitions, Python constants, REST endpoints, filters, and tests together when those elements exist:
31
+
32
+ .. code-block:: text
33
+
34
+ openedx_authz/applets/
35
+ course_team_roles/
36
+ constants.py
37
+ schema/
38
+ enrollments/
39
+ constants.py
40
+ schema/
41
+ course_authoring/
42
+ constants.py
43
+ schema/
44
+ rest_api/
45
+ ...
46
+
47
+ The `edX DDD Bounded Contexts`_ map says where each responsibility belongs, but it does not prescribe a package layout inside one Django app, so applets turn those boundaries into Python packages that keep the code and definitions for each responsibility together. Reusable schema handling, enforcement, persistence, and public APIs stay in their existing top-level packages, since every applet depends on them.
48
+
49
+ Dependencies point in one direction, from clients to the public modules, from those modules to the applets, and from the applets to the shared packages:
50
+
51
+ .. code-block:: text
52
+
53
+ clients, such as openedx-platform
54
+ └── openedx_authz.api, openedx_authz.constants
55
+ └── openedx_authz.applets.<applet>
56
+ └── openedx_authz.api.data, openedx_authz.data
57
+
58
+ Applets do not import each other, since role extensions in YAML already connect their definitions. Applets are internal, so clients import constants from ``openedx_authz.constants``, and an applet can change or move without changing client code.
59
+
60
+ 2. Definition ownership
61
+ =======================
62
+
63
+ A permission belongs to the applet responsible for the action or data that the permission controls. For example, the ``enrollments`` applet defines the permissions for viewing or changing enrollments, along with their metadata, constants, and contributions to shared roles, so code elsewhere may check those permissions through the public API while their definitions remain in ``enrollments``.
64
+
65
+ A role belongs to the applet for the bounded context where it is assigned, as with the library roles, and other applets add the permissions they own through ``role_extensions``. Roles that cut across several contexts need a specific decision about where they live, which `ADR 0033`_ makes for the course-team roles.
66
+
67
+ Both rules rely on the `edX DDD Bounded Contexts`_ map, which shows the context that owns each action or data even when a user interface combines several capabilities. To place a new permission, we find the bounded context that owns its action or data in the map and add the permission to that context's applet, or create an applet when the context has none yet. Applet names describe the definitions they hold, so the following table records which bounded context each one stands for:
68
+
69
+ .. list-table::
70
+ :header-rows: 1
71
+
72
+ * - Applet
73
+ - Bounded context
74
+ - Definitions
75
+ * - ``course_authoring``
76
+ - Course Run Authoring and Learning Content Authoring
77
+ - Course authoring and course-team permissions
78
+ * - ``content_libraries``
79
+ - Learning Content Authoring and Learning Content Repository
80
+ - Library roles and permissions
81
+ * - ``enrollments``
82
+ - Content Access / Enrollments
83
+ - Viewing and changing course enrollments
84
+ * - ``learner_grading``
85
+ - Consuming Learning Content
86
+ - The gradebook and grading tools for individual learners
87
+ * - ``learner_administration``
88
+ - Support Learning
89
+ - Course information, learner extensions, and cohorts
90
+ * - ``course_team_roles``
91
+ - Shared by several bounded contexts
92
+ - Roles held by members of a course team
93
+ * - ``role_management``
94
+ - Authorization
95
+ - Admin Console role assignment workflows
96
+
97
+ 3. Course roles
98
+ ===============
99
+
100
+ Following `ADR 0033`_, ``course_team_roles`` defines the identifiers and metadata for the course-team roles, and their base definitions list only the permissions that ``course_team_roles`` owns, such as the legacy compatibility permissions, while each capability applet adds the permissions it owns through ``role_extensions``:
101
+
102
+ .. code-block:: yaml
103
+
104
+ # course_team_roles/schema/roles.yaml
105
+ roles:
106
+ - id: course_admin
107
+ display_name: Course Admin
108
+ description: Can manage the course team and all course settings.
109
+ scopes:
110
+ - course-v1
111
+ permissions:
112
+ - courses.legacy_instructor_role_permissions
113
+
114
+ # enrollments/schema/role_extensions.yaml
115
+ role_extensions:
116
+ - role_id: course_admin
117
+ add_permissions:
118
+ - courses.view_enrollments
119
+ - courses.enroll_learners
120
+
121
+ Roles such as ``course_editor`` have no permissions of their own, so schema version 1 will accept an empty permission list, while the compiled roles will still contain the complete permission lists contributed by the applets.
122
+
123
+ 4. REST endpoints
124
+ =================
125
+
126
+ 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.
127
+
128
+ 5. Imports
129
+ ==========
130
+
131
+ 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.
132
+
133
+ 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.
134
+
135
+ 6. Future extraction
136
+ ====================
137
+
138
+ 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.
139
+
140
+ An applet may later move to the service that owns its responsibility and contribute its definitions through the existing ``authz.schema`` entry point, although this decision does not include that extraction because the service boundary, package dependency, and compatibility path for the Python constants would need to be agreed first.
141
+
142
+ Consequences
143
+ ************
144
+
145
+ 1. Each built-in definition has an explicit owner based on the capability it protects.
146
+ 2. Adding a capability does not require adding its definitions to shared course permission and role files.
147
+ 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.
148
+ 4. Each permission identifier appears in YAML and Python until generated constants replace the manually maintained files.
149
+ 5. The schema accepts an empty base permission list for applets that define roles whose permissions come from other applets. Validation logs a warning so contributors can confirm that the empty list is intentional and that ``role_extensions`` provide the role's permissions.
150
+ 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.
151
+ 7. Reviewers must identify unwanted dependencies between applets because this decision does not add automated import-boundary checks.
152
+ 8. Applets create boundaries that can support later extraction, although moving one to another service requires a separate decision about dependencies and compatibility.
153
+
154
+ Rejected Alternatives
155
+ *********************
156
+
157
+ **Keeping all definitions in the shared files**
158
+ Definitions would remain grouped by type, leaving ownership implicit and continuing the growth of the shared course files.
159
+
160
+ **One applet for each screen, such as the Instructor Dashboard**
161
+ A permission that Studio and the dashboard both use would have two possible owners.
162
+
163
+ **A separate Django app for each feature**
164
+ Each feature would gain a separate app label and installation boundary, which the definitions and integrations covered by this decision do not require.
165
+
166
+ **Moving the definitions to their owning services now**
167
+ This would place the definitions at their eventual service boundary, but it would also require coordinating package dependencies and compatibility imports before implementing the permissions in `Issue #484`_, while the existing schema contribution mechanism leaves that move available after those boundaries are agreed.
168
+
169
+ References
170
+ **********
171
+
172
+ * `Issue #484`_
173
+ * `PR #421`_
174
+ * `ADR 0005`_
175
+ * `ADR 0010 in openedx-core`_
176
+ * `edX DDD Bounded Contexts`_
177
+ * `ADR 0019`_
178
+ * `ADR 0023`_
179
+ * `ADR 0026`_
180
+ * `ADR 0033`_
181
+
182
+ Addendum: 2026-11-04
183
+ ********************
184
+
185
+ Each applet keeps the permission and role constants it owns in one ``constants.py`` file. Clients import these constants from ``openedx_authz.authz``, while ``openedx_authz.constants.permissions`` and ``openedx_authz.constants.roles`` remain compatibility exports.
186
+
187
+ ``ActionData``, ``PermissionData``, and ``RoleData`` live in ``openedx_authz.data``. This keeps the dependency direction from ``openedx_authz.api.data`` to ``openedx_authz.authz``, then to the applet constants, and finally to the low-level data classes. It also avoids the circular import that previously required action and permission data classes to move below the public API layer in `commit 2b732c3`_.
188
+
189
+ YAML remains the source of truth for role composition. Role constants identify roles without listing their permissions, so callers use the public API or the compiled schema to read a role's complete permission list.
190
+
191
+ This addendum replaces the import paths, dependency direction, and role constant behavior described earlier in this decision. The :doc:`Built-In Python Constants <../references/built-in-constants>` reference documents the public imports.
192
+
193
+ .. _Issue #484: https://github.com/openedx/openedx-authz/issues/484
194
+ .. _PR #421: https://github.com/openedx/openedx-authz/pull/421
195
+ .. _ADR 0005: 0005-architecture-and-data-modeling.rst
196
+ .. _ADR 0010 in openedx-core: https://github.com/openedx/openedx-core/blob/6a26b3a4181815a44e9d724c16857b61b484b0ea/docs/openedx_content/decisions/0010-merge-authoring-apps-into-openedx-content.rst
197
+ .. _edX DDD Bounded Contexts: https://openedx.atlassian.net/wiki/spaces/AC/pages/663224968/edX+DDD+Bounded+Contexts
198
+ .. _ADR 0019: 0019-authorization-schema-discovery.rst
199
+ .. _ADR 0023: 0023-extend-static-roles.rst
200
+ .. _ADR 0026: 0026-rest-api-domain-ownership-boundary.rst
201
+ .. _ADR 0033: 0033-shared-applet-for-course-team-roles.rst
202
+ .. _commit 2b732c3: https://github.com/openedx/openedx-authz/commit/2b732c3560b6392b82a5f835e2bf254eefe70d7c
@@ -0,0 +1,43 @@
1
+ 0033: Shared Applet for Course-Team Roles
2
+ #########################################
3
+
4
+ Status
5
+ ******
6
+
7
+ **Draft**
8
+
9
+ Context
10
+ *******
11
+
12
+ `ADR 0032`_ places a role in the applet for the bounded context where it is assigned, while roles that cut across several contexts need a specific decision about where they live. The course-team roles are the first case, since they are assigned to members of a course team and combine permissions from course authoring, enrollments, grading, and learner administration.
13
+
14
+ These roles do not all combine permissions in the same way today. ``course_admin`` and ``course_staff`` receive permissions from several applets, ``course_editor`` and ``course_auditor`` receive every permission from ``course_authoring``, and the legacy roles such as ``course_limited_staff`` only list their legacy compatibility permission. However, the `Instructor Dashboard Permissions`_ proposal allows more restricted roles to receive a subset of the dashboard permissions, so the roles that rely on one applet today may combine several later.
15
+
16
+ Decision
17
+ ********
18
+
19
+ The course-team roles are cross-cutting, so they live in the shared ``course_team_roles`` applet regardless of which applets currently provide their permissions. Their base definitions list only the permissions that ``course_team_roles`` owns, such as the legacy compatibility permissions, while every other applet adds the permissions it owns through ``role_extensions``.
20
+
21
+ Any other group of cross-cutting roles needs its own decision about where it lives.
22
+
23
+ Consequences
24
+ ************
25
+
26
+ 1. A course-team role keeps its owner when another applet starts adding permissions to it.
27
+ 2. Every role that a course team can assign is defined in one place, next to the legacy role equivalences.
28
+ 3. Base definitions such as ``course_editor`` may list no permissions, so the schema has to accept an empty permission list.
29
+
30
+ Rejected Alternatives
31
+ *********************
32
+
33
+ **Placing each course-team role in the applet that provides its permissions**
34
+ ``course_editor`` and ``course_auditor`` would move to ``course_authoring``, splitting one group of roles across applets, and each role would have to move again once another applet added permissions to it.
35
+
36
+ References
37
+ **********
38
+
39
+ * `ADR 0032`_
40
+ * `Instructor Dashboard Permissions`_
41
+
42
+ .. _ADR 0032: 0032-applets-for-built-in-authorization-capabilities.rst
43
+ .. _Instructor Dashboard Permissions: https://openedx.atlassian.net/wiki/spaces/OEPM/pages/6789234689/Instructor+Dashboard+Permissions
@@ -0,0 +1,7 @@
1
+ How-tos
2
+ #######
3
+
4
+ .. toctree::
5
+ :maxdepth: 1
6
+
7
+ use-built-in-constants
@@ -0,0 +1,25 @@
1
+ Use Built-In Permission and Role Constants
2
+ ##########################################
3
+
4
+ Import built-in permissions and roles from ``openedx_authz.authz``. Pass their external keys to the convenience functions in ``openedx_authz.api``:
5
+
6
+ .. code-block:: python
7
+
8
+ from openedx_authz.api import assign_role_to_user_in_scope, is_user_allowed
9
+ from openedx_authz.authz import COURSE_ADMIN, COURSES_VIEW_COURSE
10
+
11
+ can_view_course = is_user_allowed(
12
+ user_external_key="alice",
13
+ action_external_key=COURSES_VIEW_COURSE.identifier,
14
+ scope_external_key="course-v1:edX+DemoX+2026",
15
+ )
16
+
17
+ assign_role_to_user_in_scope(
18
+ user_external_key="alice",
19
+ role_external_key=COURSE_ADMIN.external_key,
20
+ scope_external_key="course-v1:edX+DemoX+2026",
21
+ )
22
+
23
+ Role constants identify roles without containing their complete permission lists. Use ``get_permissions_for_single_role`` or the compiled schema when a client needs to inspect the permissions assigned to a role.
24
+
25
+ See :doc:`Built-In Python Constants <../references/built-in-constants>` for the import and compatibility paths.
@@ -0,0 +1,13 @@
1
+ Built-In Python Constants
2
+ #########################
3
+
4
+ Applications import built-in permission and role constants from ``openedx_authz.authz``:
5
+
6
+ .. code-block:: python
7
+
8
+ from openedx_authz.authz import COURSE_ADMIN, COURSES_VIEW_COURSE
9
+
10
+ Each applet keeps the permission and role constants it owns in one ``constants.py`` file. The YAML schema remains the source of truth for role composition, so role constants identify roles without copying their complete permission lists.
11
+
12
+ ``openedx_authz.constants.permissions`` and ``openedx_authz.constants.roles`` remain available as compatibility imports. New code should use ``openedx_authz.authz``.
13
+
@@ -0,0 +1,11 @@
1
+ .. _Compiled Authorization Schema:
2
+
3
+ Compiled Authorization Schema
4
+ #############################
5
+
6
+ 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.
7
+
8
+ 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>`.
9
+
10
+ .. literalinclude:: compiled-schema.yaml
11
+ :language: yaml