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.
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/CHANGELOG.rst +12 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/Makefile +4 -1
- {openedx_authz-2.4.0/src/openedx_authz.egg-info → openedx_authz-3.0.0}/PKG-INFO +1 -1
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/core_roles_and_permissions/course_roles.rst +0 -2
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0026-rest-api-domain-ownership-boundary.rst +7 -0
- openedx_authz-3.0.0/docs/decisions/0032-applets-for-built-in-authorization-capabilities.rst +202 -0
- openedx_authz-3.0.0/docs/decisions/0033-shared-applet-for-course-team-roles.rst +43 -0
- openedx_authz-3.0.0/docs/how-tos/index.rst +7 -0
- openedx_authz-3.0.0/docs/how-tos/use-built-in-constants.rst +25 -0
- openedx_authz-3.0.0/docs/references/built-in-constants.rst +13 -0
- openedx_authz-3.0.0/docs/references/compiled-schema.rst +11 -0
- openedx_authz-3.0.0/docs/references/compiled-schema.yaml +803 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/references/index.rst +2 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/pyproject.toml +2 -1
- openedx_authz-3.0.0/scripts/generate_compiled_schema.py +41 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/scripts/generate_paragon_icons.py +3 -1
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/data.py +2 -66
- openedx_authz-3.0.0/src/openedx_authz/applets/__init__.py +1 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/README.rst +6 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/__init__.py +1 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/content_libraries/constants.py +63 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/README.rst +6 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/course_authoring/__init__.py +1 -0
- 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
- 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
- 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
- openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/README.rst +8 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/__init__.py +1 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/constants.py +59 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/schema/legacy_permissions.yaml +50 -0
- openedx_authz-3.0.0/src/openedx_authz/applets/course_team_roles/schema/roles.yaml +60 -0
- openedx_authz-3.0.0/src/openedx_authz/authz/__init__.py +52 -0
- openedx_authz-3.0.0/src/openedx_authz/constants/permissions.py +7 -0
- openedx_authz-3.0.0/src/openedx_authz/constants/roles.py +35 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/data.py +33 -2
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/authz-schema-v1.json +11 -3
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/discovery.py +8 -7
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/parsing.py +1 -1
- openedx_authz-3.0.0/src/openedx_authz/engine/schema/snapshot.py +79 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/translation.py +1 -1
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/loading.py +1 -1
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/validation.py +16 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/load_authz_schema.py +3 -2
- openedx_authz-3.0.0/src/openedx_authz/migrations/0012_move_builtin_schema_sources_to_applets.py +123 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_roles.py +38 -63
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_users.py +3 -13
- openedx_authz-3.0.0/src/openedx_authz/tests/applets/__init__.py +1 -0
- openedx_authz-3.0.0/src/openedx_authz/tests/applets/test_builtin_definitions.py +78 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/authz/test_resources.py +7 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/test_views.py +2 -1
- openedx_authz-3.0.0/src/openedx_authz/tests/role_permissions.py +107 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_discovery.py +33 -16
- openedx_authz-3.0.0/src/openedx_authz/tests/schema/test_json_schema.py +48 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_loading.py +6 -3
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_renderer.py +25 -1
- openedx_authz-3.0.0/src/openedx_authz/tests/schema/test_snapshot.py +136 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_syntax.py +1 -1
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_translation.py +7 -9
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_validation.py +10 -0
- openedx_authz-3.0.0/src/openedx_authz/tests/test_imports.py +114 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_migrations.py +120 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_utils.py +1 -3
- {openedx_authz-2.4.0 → openedx_authz-3.0.0/src/openedx_authz.egg-info}/PKG-INFO +1 -1
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/SOURCES.txt +30 -4
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/scm_file_list.json +30 -4
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tox.ini +3 -3
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/uv.lock +10 -0
- openedx_authz-2.4.0/docs/how-tos/index.rst +0 -2
- openedx_authz-2.4.0/src/openedx_authz/authz/__init__.py +0 -33
- openedx_authz-2.4.0/src/openedx_authz/constants/roles.py +0 -216
- openedx_authz-2.4.0/src/openedx_authz/tests/test_imports.py +0 -37
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.annotation_safe_list.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.editorconfig +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/dependabot.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/add-depr-ticket-to-depr-board.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/add-remove-label-on-comment.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/ci.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/commitlint.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/release.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/self-assign-issue.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.github/workflows/upgrade-python-requirements.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.gitignore +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.pii_annotations.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/.readthedocs.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/LICENSE +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/MANIFEST.in +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/README.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/catalog-info.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/codecov.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/Makefile +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/_images/architecture-overview.png +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/_static/theme_overrides.css +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/changelog.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/core_roles_and_permissions/content_library_roles.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/core_roles_and_permissions/index.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/concepts/index.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/conf.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0001-purpose-of-this-repo.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0002-authorization-model-foundation.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0003-jwt-usage.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0004-technology-selection.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0005-architecture-and-data-modeling.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0007-enforcement-mechanisms-mfe.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0008-compatibility-scheme.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0009-authz-for-course-authoring.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0010-course-authoring-flag.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0011-course-authoring-migration-process.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0012-auditability.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0012-glob-support-for-role-assignments.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0013-course-authoring-automatic-migration.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0014-bulk-assignment-queries-without-casbin-enforce.rst +0 -0
- {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
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0016-static-and-dynamic-roles.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0017-static-authorization-schema.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0018-authorization-schema-lifecycle.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0019-authorization-schema-discovery.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0020-authorization-schema-internationalization.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0021-authorization-definition-api.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0022-defer-authorization-implications.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0023-extend-static-roles.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0024-api-contract-for-user-grouped-role-assignments.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0025-authorization-schema-source-tracking.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0027-cross-domain-filtering-via-openedx-filters.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0028-api-contract-for-role-catalog.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0029-paragon-icon-list-maintenance.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0030-tutor-implementation-authz-schema-discovery.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/0031-priority-applies-to-role-extensions-only.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions/README.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/decisions.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/getting_started.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/index.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/internationalization.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/make.bat +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/quickstarts/index.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/readme.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/references/authorization-schema-json.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/references/authorization-schema.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/docs/testing.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/manage.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/pylintrc +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/pylintrc_tweaks +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/ruff.toml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/setup.cfg +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/admin.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/catalog.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/permissions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/roles.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/users.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/api/utils.py +0 -0
- /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
- /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
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/apps.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/conf/locale/config.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/constants/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/constants/schema.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/adapter.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/apps.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/config/model.conf +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/enforcer.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/filter.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/matcher.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/policy.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/renderer.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/compilation.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/exceptions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/issues.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/loading.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/paragon_icons.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/pipeline.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/syntax.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/compilation.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/schema/types/definitions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/engine/utils.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/filters.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/handlers.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/authz_migrate_course_authoring.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/authz_rollback_course_authoring.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/enforcement.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/extract_schema_translations.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/management/commands/load_policies.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0001_add_casbin_dependency.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0002_initial.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0003_usersubject.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0004_contentlibraryscope.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0005_policycachecontrol.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0006_migrate_legacy_permissions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0007_coursescope.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0008_authzcourseauthoringmigrationrun.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0009_roleassignmentaudit.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0010_scope_external_key.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/0011_authz_schema_definitions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/migrations/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/authz_migration.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/base.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/core.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/engine.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/schema.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/scopes.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/models/subjects.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/data.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/decorators.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/urls.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/utils.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/filters.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/serializers.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/admin_console/views.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/course_authoring/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/course_authoring/pipeline.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/course_authoring/views.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/fields.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/paginators.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/permissions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/serializers.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/urls.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/rest_api/v1/views.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/common.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/production.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/settings/test.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/templates/openedx_authz/base.html +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_catalog.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/api/test_data.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/authz/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/conftest.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/categories.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/extensions.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/permissions.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_compiled/roles.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_parse/malformed.yaml +0 -0
- {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
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_structure/items.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/invalid_structure/priority.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/categories.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/extensions.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/permissions.yml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/fixtures/schema_pipeline/valid/roles.yaml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_handlers.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_models.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_schema_apply.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_schema_pipeline.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/integration/test_views.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/admin_console/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/admin_console/test_views.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/course_authoring/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/course_authoring/test_pipeline.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/course_authoring/test_views.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/mixins.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/test_permissions.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/rest_api/test_utils.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/factories.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_apply.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_compilation.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_load_authz_schema_command.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_parsing.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_pipeline.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_schema_models.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_source_storage.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/schema/test_types.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/apps.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/migrations/0001_initial.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/migrations/0002_learningpackage_contentlibrary_learning_package.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/migrations/0002_userprofile.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/stubs/models.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_commands.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_enforcement.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_enforcer.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_engine_utils.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_filter.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_handlers.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_models.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/tests/test_policy.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/urls.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz/utils.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/dependency_links.txt +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/entry_points.txt +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/requires.txt +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/src/openedx_authz.egg-info/top_level.txt +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/.gitignore +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/LICENSE.txt +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/MANIFEST.in +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/Makefile +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/README.rst +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/pyproject.toml +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/__about__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/__init__.py +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/patches/openedx-common-settings +0 -0
- {openedx_authz-2.4.0 → openedx_authz-3.0.0}/tutor/tutor-contrib-authz/tutor_authz/plugin.py +0 -0
- {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:
|
|
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,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
|