Skip to content

feat: make can_tag_object's course check authorization-service aware - #39112

Open
alezconsultant wants to merge 1 commit into
openedx:masterfrom
alezconsultant:alezconsultant/795-add--can-change-tag-authz-branch
Open

alezconsultant wants to merge 1 commit into
openedx:masterfrom
alezconsultant:alezconsultant/795-add--can-change-tag-authz-branch

Conversation

@alezconsultant

@alezconsultant alezconsultant commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Description

Makes oel_tagging.can_tag_object's course check authorization-service aware
(openedx/openedx-core#795). can_change_object_tag_objectid in
content_tagging/rules.py — the predicate every direct has_perm('oel_tagging.can_tag_object', ...) caller resolves through — already checked the new openedx-authz service for Content
Library objects, but for course objects it only ever checked the legacy has_studio_write_access
role, regardless of whether that course had been switched to the new authorization service.
ObjectTagOrgView already had the correct, toggle-aware
behavior, but only inside that one view class — every other caller, including the CBE
create-criterion endpoint (openedx-core#665), silently got the wrong (legacy-only) answer for
switched-over courses. This closes that gap by giving the shared predicate the same
toggle-aware branch ObjectTagOrgView already had, then removing the view's own now-duplicate
override so the toggle check lives in one place.

Changes

  • content_tagging/rules.py: can_change_object_tag_objectid gets a new branch, checked
    after the existing Content Library case and before the legacy has_studio_write_access
    fallback. It calls should_use_course_authz_for_object(object_id) (already used by
    ObjectTagOrgView, from content_tagging/auth.py); when the course has been switched, it
    returns authz_api.is_user_allowed(user.username, COURSES_MANAGE_TAGS.identifier, str(course_key)) directly, with no fallback to legacy roles or org-admin access — an
    exclusive switch, matching ObjectTagOrgView's existing behavior exactly. Docstring updated
    to describe the new branch.
  • content_tagging/rest_api/v1/views.py: ObjectTagOrgView.ensure_user_has_can_tag_object_permissions
    deleted. Verified the parent ObjectTagView.ensure_user_has_can_tag_object_permissions
    (openedx-core) already resolves through user.has_perm("oel_tagging.can_tag_object", ...),
    so this override became pure duplication of the same logic now living in rules.py.
    get_permissions and _authz_check are unchanged — _authz_check's docstring now
    explains why: ensure_has_view_object_tag_permission (the separate, untouched view
    permission) and ObjectTagTaxonomyOrgFilterBackend.filter_queryset both still read it
    directly, so only the tagging-permission override became redundant, not this.
  • content_tagging/tests/test_rules.py: new TestRulesCourseAuthzPermissions, covering the
    ticket's acceptance criteria directly against the predicate: a course switched to authz
    grants access via authz_api.is_user_allowed alone; a course not yet switched keeps resolving through the
    legacy check unaffected; Content Library objects are
    unaffected.

Tests

  • Course switched, user holds the permission only via authz (no legacy role) → allowed,
    is_user_allowed called with the right identifier/scope.
  • Course switched, user has a real legacy CourseStaffRole but authz denies → denied; proves
    the switch is exclusive, not an OR with a legacy course-level role.
  • Course switched, user has org-level admin access but authz denies → denied; proves the
    exclusivity holds against org-admin fallback too, not just the course-level role.
  • Course not switched, user has a legacy role → allowed, unchanged from today, and
    is_user_allowed is never even called.
  • Content Library object, course-authz flag on → unchanged, still resolves through
    MANAGE_LIBRARY_TAGS (regression guard on the untouched branch).

Verification

  • pytest openedx/core/djangoapps/content_tagging/tests/test_rules.py openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py --no-cov:
    575 passed, 0 failed.
  • pylint on both changed source files and the changed test file: clean.

Manual testing

Since #665 not merged I've walked current tagging flow. Walked both paths live in Studio: added a fresh user via Course Team with the course's authz
waffle override off (routes through a real legacy CourseAccessRole) and again with it on — tagging succeeded both ways.

Related to openedx/openedx-core#795 and openedx/openedx-core#665

🤖 Generated with Claude Code

can_change_object_tag_objectid in content_tagging/rules.py -- the predicate every direct
has_perm('oel_tagging.can_tag_object', ...) caller resolves through -- already checked the
new openedx-authz service for Content Library objects, but for course objects it only ever
checked the legacy has_studio_write_access role, regardless of whether that course had been
switched to the new authorization service. ObjectTagOrgView (Studio's own tag-editing
endpoint) already had the correct, toggle-aware behavior, but only inside that one view
class, so every other caller (including the CBE create-criterion endpoint, openedx-core#665)
silently got the wrong, legacy-only answer for switched-over courses.

Add a branch to can_change_object_tag_objectid, checked after the Content Library case and
before the legacy fallback: when should_use_course_authz_for_object says the course has been
switched, return authz_api.is_user_allowed directly, with no
fallback to legacy roles or org-admin access -- an exclusive switch, matching
ObjectTagOrgView's existing behavior exactly.

Delete ObjectTagOrgView.ensure_user_has_can_tag_object_permissions: the parent
ObjectTagView's own version (openedx-core) already resolves through
has_perm(oel_tagging.can_tag_object, ...), so this override had become pure duplication of
logic that now lives in rules.py. get_permissions and _authz_check stay, since
ensure_has_view_object_tag_permission (the separate, untouched view permission) and
ObjectTagTaxonomyOrgFilterBackend.filter_queryset both still read them directly.

Related to openedx/openedx-core#795

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Sep 16, 2026
@openedx-webhooks

Copy link
Copy Markdown

Thanks for the pull request, @alezconsultant!

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

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.

@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Sep 16, 2026
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Ready for Review in Contributions Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

open-source-contribution PR author is not from Axim or 2U

Projects

Status: Ready for Review

Development

Successfully merging this pull request may close these issues.

3 participants