Skip to content

feat: enforce AuthZ permissions in the Date Extensions tab endpoints - #327

Draft
efortish wants to merge 1 commit into
bav/instructor-authz-shared-infrafrom
ks/issue-491-date-extensions-authz
Draft

efortish wants to merge 1 commit into
bav/instructor-authz-shared-infrafrom
ks/issue-491-date-extensions-authz

Conversation

@efortish

Copy link
Copy Markdown

Description

Stacked on top of openedx#39255 (not mergeable until that one lands, since it carries that PR's full diff). Migrates the three endpoints behind the Date Extensions tab to the shared Instructor Dashboard AuthZ infrastructure from openedx-authz#486, following the README's migration guide (lms/djangoapps/instructor/authz/README.rst):

View HTTP method authz_permission Legacy fallback (unchanged)
GradedSubsectionsView GET courses.view_learner_extensions permissions.VIEW_DASHBOARD
UnitExtensionsView GET courses.view_learner_extensions permissions.VIEW_DASHBOARD
ChangeDueDateView POST courses.manage_learner_extensions permissions.GIVE_STUDENT_EXTENSION

Each view keeps its existing permission_name: LEGACY_PERMISSION_CHECKS in lms/djangoapps/instructor/authz/legacy.py already maps both COURSES_VIEW_LEARNER_EXTENSIONS/COURSES_MANAGE_LEARNER_EXTENSIONS to bridgekeeper_check(permissions.VIEW_DASHBOARD)/bridgekeeper_check(permissions.GIVE_STUDENT_EXTENSION) respectively (built as part of openedx#39255), so this is a "Single permission" migration per the README, no new legacy-check code needed. With authz.enable_course_authoring disabled for a course, behavior is byte-for-byte what it was before this PR.

The Date Extensions tab's own visibility logic (can_see("date_extensions", authz_legacy.has_instructor_access) in serializers_v2.py) was already wired up in openedx#39255, so this PR only touches the three endpoint views and their tests, nothing in the tab-visibility/serializer code.

Fixes openedx-authz#491.

Testing

Added DateExtensionsAuthzTest to test_api_v2_authz.py (next to the existing CourseMetadataViewAuthzTest from openedx#39255), covering all three endpoints:

  • Course Admin: granted.
  • Course Staff: granted.
  • A user with no AuthZ role in the course: denied (403).
  • AuthZ explicitly denying a legacy Instructor (flag on): denied, AuthZ wins over the legacy role.
  • A legacy Instructor with the flag off: granted, same as before this PR.
  • An enrolled learner with no staff role, flag off: denied (403), same as before this PR.
  • Flag off: AuthZ is never queried (is_user_allowed.assert_not_called()).

Also ran the existing (pre-this-PR) tests for these three views to confirm nothing regressed for the legacy path: GradedSubsectionsViewTest, UnitExtensionsViewTest (in test_api_v2.py), and TestChangeDueDateV2/TestDueDateExtensions (in test_api.py). All pass unchanged.

Full suite: lms/djangoapps/instructor/ (1045 passed). ruff, pylint, lint-imports clean.

Note for local testing: if you hit ImportErrors unrelated to this diff when running these tests (AccountActivationEmailContextGenerated from openedx_filters, or FullScopePolicy from edx_rest_framework_extensions), your devstack's LMS venv has openedx-filters/edx-drf-extensions older than what requirements/edx/base.txt pins. That's what I hit too; fixed locally with:

pip install --no-deps 'openedx-filters==3.16.0' 'edx-drf-extensions==10.9.0'

(or whatever those requirements currently pin). Unrelated to this PR's code, just a stale local environment.

Deadline

None

@BryanttV
BryanttV force-pushed the bav/instructor-authz-shared-infra branch 2 times, most recently from c7012a1 to 7d48414 Compare October 22, 2026 15:56
@BryanttV BryanttV linked an issue Oct 22, 2026 that may be closed by this pull request
1 task
@BryanttV
BryanttV force-pushed the bav/instructor-authz-shared-infra branch 2 times, most recently from e521b17 to df2efbe Compare October 26, 2026 21:46
@BryanttV
BryanttV force-pushed the ks/issue-491-date-extensions-authz branch 2 times, most recently from 8434e96 to 2b07cab Compare October 29, 2026 17:34
Migrate ChangeDueDateView, GradedSubsectionsView and UnitExtensionsView
to InstructorAuthzPermission, following the shared infrastructure from
openedx-authz#486. GET endpoints require courses.view_learner_extensions,
the POST endpoint requires courses.manage_learner_extensions. Both
already had a matching default legacy check registered in
LEGACY_PERMISSION_CHECKS, so the existing permission_name on each view
is reused unchanged as the fallback when the authz.enable_course_authoring
flag is disabled for the course.

Add DateExtensionsAuthzTest covering Course Admin, Course Staff, a user
with no permission, AuthZ denying a legacy instructor, and the legacy
path with the flag off, for all three endpoints.

Closes openedx-authz#491.
@BryanttV
BryanttV force-pushed the ks/issue-491-date-extensions-authz branch from 2b07cab to 114ad1c Compare October 29, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enforcement: Date Extensions tab

1 participant