Skip to content

fix: Cannot rerun courses - authz role assignment expects rerun to already exist#38840

Open
rodmgwgu wants to merge 1 commit into
openedx:masterfrom
WGU-Open-edX:fix/authzrerun
Open

fix: Cannot rerun courses - authz role assignment expects rerun to already exist#38840
rodmgwgu wants to merge 1 commit into
openedx:masterfrom
WGU-Open-edX:fix/authzrerun

Conversation

@rodmgwgu

@rodmgwgu rodmgwgu commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Fixes: #38826

Description

Fixes course rerun failure when the authz.enable_course_authoring flag is enabled.

When the flag is active, the add_instructor call in rerun_course fails because the openedx-authz module requires a CourseOverview instance to exist in order to create a Scope. At the point where add_instructor is called, the destination course hasn't been cloned yet, so no CourseOverview exists.

The original purpose of calling add_instructor before the Celery task was to grant the user immediate Studio access so they could monitor the rerun progress via CourseRerunState.

This PR addresses the issue with the following approach:

  • When authz.enable_course_authoring is enabled: Skip the pre-task add_instructor call entirely (since it would fail and legacy roles shouldn't exist when authz is enabled). Instead, grant visibility of the in-process rerun status by checking CourseRerunState.created_user — the user who initiated the rerun can always see its status. The proper authz-compatible permissions are established inside the Celery task after clone_course completes (at which point CourseOverview can be generated).

  • When authz.enable_course_authoring is disabled: The existing behavior is preserved — add_instructor is called pre-task using the legacy path (CourseAccessRole.objects.get_or_create), which is idempotent.

The add_instructor call added inside the rerun task runs after clone_course, where the course exists in the modulestore and CourseOverview can be resolved. This works correctly for both flag states since add_users routes to the appropriate implementation based on the flag.

Impacted roles: Course Admin, Superuser.

Supporting information

Related issue: #38826

Relevant Traceback:

File "/openedx/edx-platform/cms/djangoapps/contentstore/views/course.py", line 1198, in _create_or_rerun_course
    destination_course_key = rerun_course(request.user, source_course_key, org, course, run, fields)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/cms/djangoapps/contentstore/views/course.py", line 1328, in rerun_course
    add_instructor(destination_course_key, user, user)
  File "/openedx/edx-platform/cms/djangoapps/contentstore/utils.py", line 115, in add_instructor
    CourseInstructorRole(course_key).add_users(new_instructor)
  File "/openedx/edx-platform/common/djangoapps/student/roles.py", line 524, in add_users
    self._authz_add_users(users)
  File "/openedx/edx-platform/common/djangoapps/student/roles.py", line 493, in _authz_add_users
    authz_add_role(
  File "/openedx/edx-platform/common/djangoapps/student/roles.py", line 69, in authz_add_role
    authz_api.assign_role_to_user_in_scope(
  File "/mnt/openedx-authz/openedx_authz/api/users.py", line 84, in assign_role_to_user_in_scope
    return assign_role_to_subject_in_scope(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/openedx-authz/openedx_authz/api/roles.py", line 232, in assign_role_to_subject_in_scope
    extended_rule = ExtendedCasbinRule.create_based_on_policy(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/openedx-authz/openedx_authz/models/core.py", line 229, in create_based_on_policy
    "scope": Scope.objects.get_or_create_for_external_key(scope),
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/openedx-authz/openedx_authz/models/core.py", line 77, in get_or_create_for_external_key
    return scope_class.get_or_create_for_external_key(scope_data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/openedx-authz/openedx_authz/models/scopes.py", line 140, in get_or_create_for_external_key
    course_overview = CourseOverview.get_from_id(course_key)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/lib/cache_utils.py", line 73, in decorator
    result = wrapped(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/content/course_overviews/models.py", line 431, in get_from_id
    return course_overview or cls.load_from_module_store(course_id)
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/content/course_overviews/models.py", line 373, in load_from_module_store
    raise cls.DoesNotExist()
openedx.core.djangoapps.content.course_overviews.models.CourseOverview.DoesNotExist

Files changed:

  • cms/djangoapps/contentstore/views/course.py — Conditional add_instructor skip + created_user visibility check
  • cms/djangoapps/contentstore/tasks.pyadd_instructor call after clone_course

Testing instructions

Note: To observe the in-process rerun status in Studio, you must test in a non-dev environment (e.g., one running with tutor local launch or a prod-like setup). In dev mode, Celery tasks run synchronously, so the in-progress status is never visible.

  1. Enable the authz.enable_course_authoring flag globally.
  2. Trigger a course rerun from Studio.
  3. Verify the rerun initiates without a CourseOverview.DoesNotExist error.
  4. Verify the in-process rerun status is visible on the Studio home page for the user who initiated it.
  5. Verify the rerun completes successfully and the user has proper access to the new course.
  6. Disable authz.enable_course_authoring and repeat steps 2–5 to confirm the legacy path still works correctly.

Deadline

Verawood release

Other information

  • Coauthored by Kiro using Claude Opus 4.6 - Issue was replicated and researched manually, possible solutions were discussed with the agent and implemented by the agent. This description was partially generated by the agent and manually amended.
  • No changes to openedx-authz are required.
  • The _legacy_add_users path uses get_or_create, so calling add_instructor both pre-task and in-task (when the flag is disabled) does not produce duplicate CourseAccessRole records.
  • The created_user check in get_in_process_course_actions is a minimal, safe addition — CourseRerunState already stores the initiating user, and this simply allows them to see their own rerun's status without requiring course-level permissions that can't yet exist.

@openedx-webhooks

openedx-webhooks commented Jul 1, 2026

Copy link
Copy Markdown

Thanks for the pull request, @rodmgwgu!

This repository is currently maintained by @openedx/wg-maintenance-openedx-platform.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

Details
Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@openedx-webhooks openedx-webhooks added open-source-contribution PR author is not from Axim or 2U core contributor PR author is a Core Contributor (who may or may not have write access to this repo). labels Jul 1, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Jul 1, 2026
@rodmgwgu rodmgwgu marked this pull request as ready for review July 1, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core contributor PR author is a Core Contributor (who may or may not have write access to this repo). open-source-contribution PR author is not from Axim or 2U

Projects

Status: Needs Triage

Development

Successfully merging this pull request may close these issues.

Cannot rerun courses - authz role assignment expects rerun to already exist

2 participants