fix(rbac): resolve product-scoped users for the engagement Testing Lead selector#15063
Draft
valentijnscholten wants to merge 4 commits into
Draft
fix(rbac): resolve product-scoped users for the engagement Testing Lead selector#15063valentijnscholten wants to merge 4 commits into
valentijnscholten wants to merge 4 commits into
Conversation
…efectDojo#15062) The OS auth-filter impls _get_authorized_users_for_product_type and _get_authorized_users_for_product_and_product_type ignored their product_type/product argument and returned users.none() for any non-staff/non-superuser caller. This emptied the (mandatory) engagement 'Testing Lead' selector for users granted access to a product via the 'authorized users' section, blocking engagement creation (DefectDojo#15062). Resolve the users authorized on the given product/product type via the authorized_users M2M (the inverse of _authorized_product_ids), mirroring the rest of the OS authorization layer. Superuser/staff still bypass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…8.4 parity) 2.58.4's get_authorized_users_for_product_and_product_type always included is_superuser users (and global-role users) as candidates. Mirror the OS- applicable part here so admins remain pickable as a Testing Lead for a product-scoped caller. Global-role resolution stays a Pro concern (roles are inert in OS). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
….58.4 parity) The OS _get_authorized_users returned only the calling user (pk=user.pk) for any non-staff/non-superuser caller, vs 2.58.4 which returned co-members of the caller's authorized products/types plus global-role users and superusers. This collapsed the engagement/test 'users' lists and the audit-log actor/user filters to self-only for scoped users. Resolve collaborators via the authorized_users M2M (users sharing the caller's authorized products/product types) plus superusers, mirroring the OS-applicable part of 2.58.4. Updated the carrier-table 'legacy' tests accordingly (carrier roles remain inert in OS; superusers now surface) and added a collaborator test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…solution The get_authorized_users_for_product_and_product_type / _for_product_type resolution now executes the authorized_users subqueries (the DefectDojo#15062 fix), adding a small fixed overhead (+1 async / +3 sync) to the import notification path. Recalibrate both the V2 (TestDojoImporterPerformanceSmall) and V3 (TestDojoImporterPerformanceSmallLocations) expected query counts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Maffooch
approved these changes
Jun 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #15062
The engagement Testing Lead selector (a required field) is empty for any user who was granted access to a product via the product's authorized users section, which blocks them from creating an engagement.
Root cause
dojo/forms.pypopulates the lead field fromget_authorized_users_for_product_and_product_type(None, product, "view"). In the v3 OS authorization layer (dojo/authorization/query_registrations.py) the two impls are incomplete:They ignore the
product/product_typeargument and returnusers.none()for every non-staff/non-superuser caller, so a product-scoped user gets an empty lead list. (Granting full/global access "fixes" it only because that flips the user into the_is_unrestrictedbranch — which is why an admin never sees the bug.)Behaviour in 2.58.4 (what this restores)
In 2.58.4 the same function was a real query and was not gated on the calling user — any caller, including a non-staff product member, received the users authorized on that product/type:
The v3 rewrite introduced two behaviours that weren't in 2.58.4: it now branches on the calling user, and for any non-staff caller it returns nothing — ignoring
productentirely. That is the regression.Fix
Resolve the users authorized on the given product / product type via the
authorized_usersM2M — the inverse of the existing_authorized_product_idshelper, consistent with the rest of the OS layer. Superuser/staff still bypass; anonymous andNoneobject still return none._get_authorized_users_for_product_type→ users inproduct_type.authorized_usersplus superusers_get_authorized_users_for_product_and_product_type→ users inproduct.authorized_usersorproduct.prod_type.authorized_usersplus superusersThis is the OS-layer equivalent of the 2.58.4 query: v3 split the model so that the RBAC carrier tables (
Product_Member,Product_Type_Group,Global_Role, …) moved to Pro, while OS membership is theauthorized_usersM2M. Theis_superuserclause is carried over from 2.58.4 (which always surfaced superusers as candidates). Pro layers the member/group/global-role resolution back on via its own registration; global-role is Pro-only in v3 (roles are inert in OS), so it is intentionally not resolved here.It also fixes the same empty-selector symptom in the Test form lead, finding bulk-edit reviewer/assignee, and notification recipient resolution, which call the same functions.
Also in this PR —
get_authorized_users(same regression, sibling function)_get_authorized_usershad the identical v2→v3 regression: for any non-staff/non-superuser caller it returned only the caller themselves (pk=user.pk), whereas 2.58.4 returned the caller's collaborators — users sharing the caller's authorized products/types — plus global-role users and superusers. This collapsed several user dropdowns to self-only for scoped users:dojo/engagement/views.pyanddojo/test/views.py— the engagement/test "users" listsdojo/auditlog/filters.py— the audit-log actor / user filter dropdownsdojo/api_v2/serializers.py—get_authorized_users("edit", ...)Fix: resolve collaborators via the
authorized_usersM2M (users sharing the caller's authorized products / product types) plus superusers — the OS-applicable part of 2.58.4. Carrier roles (Product_Member,Global_Role, …) remain inert in OS; global-role resolution stays a Pro concern.Tests
unittests/test_user_queries.py:TestGetAuthorizedUsersViaAuthorizedUsers— a product-authorized user gets a non-empty list containing the product + product-type authorized users and superusers (and excludes unrelated users); product-type-authorized user resolutiontest_user_collaborators_via_authorized_users—get_authorized_usersreturns co-members of the caller's authorized product plus superusers🤖 Generated with Claude Code