Skip to content

Scope endpoint deletion to the caller's authorized products - #15742

Open
svader0 wants to merge 1 commit into
DefectDojo:bugfixfrom
svader0:hardening/location-delete-scoping
Open

Scope endpoint deletion to the caller's authorized products#15742
svader0 wants to merge 1 commit into
DefectDojo:bugfixfrom
svader0:hardening/location-delete-scoping

Conversation

@svader0

@svader0 svader0 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Hardening / consistency improvement to endpoint (Location) delete handling.

A Location row is shared by every product that records the same value. Both delete paths now
route through one shared helper. The helper removes only the references the caller's products
own, and it deletes the row itself once nothing points at it any more.

Adds regression tests. No functional change for correctly-permissioned users.

Hardening to the endpoint (Location) delete paths. A Location row is shared by
every product that records the same value, so both delete paths now route
through one helper that removes only the references the caller's products own.
Adds regression tests. No functional change for correctly-permissioned users.
@Maffooch Maffooch added this to the 3.2.300 milestone Aug 20, 2026
@Maffooch

Copy link
Copy Markdown
Contributor

Thanks for this. I looked into the failing test-rest-framework (v3 on) leg. It reproduces (not a flake), so flagging what I found before it can go green. Two separate issues:

1. finding_b fixture has no reporter (the 4 errors)

SharedLocationDeleteScopingTest.setUpTestData builds finding_b without a reporter. Finding.reporter (dojo/finding/models.py:299) is not nullable and defaults to 1, and there's no Dojo_User with pk=1 in the test DB, so the insert trips dojo_finding_reporter_id_..._fk_auth_user_id. Passing reporter=<a user you create> clears this one.

2. The delete tests can't pass under the OS authorization model (the 2 failures, and the real blocker)

With V3_FEATURE_LOCATIONS on, delete_endpoint maps to ("object", Location, "delete", "location_id") (dojo/authorization/url_permissions.py:315), so the middleware calls user_has_permission(user, location, "delete"). In the OS implementation, dojo/authorization/authorization.py:111-112 short-circuits Action.Delete to return bool(user.is_staff) for every object, before the Location product-membership branch at authorization.py:158. So a non-staff Writer like alice is denied delete on any Location and gets a 400 (custom_unauthorized_view). That's why test_delete_endpoint_cross_product_is_denied_and_persists passes (it happens to expect 400) while the legitimate single-delete tests fail with 400 not in (200, 302).

Making alice staff doesn't fix it either: for a staff user get_authorized_products returns all products (_is_unrestricted), so delete_locations_for_products would also drop Product B's references and break the "keeps the other product's shared row" assertion.

So exercising "delete scoped to the caller's authorized products" needs a non-staff user who can delete AND is limited to some products, which only holds under the Pro/RBAC auth filter, not the OS model this suite runs under. Since the PR doesn't change authorization.py, the paths forward are roughly:

  • gate these delete-scoping tests to the Pro model (skip under OS), or
  • intentionally make OS Location delete product-membership-based instead of staff-only (a core-authz change that deserves its own review).

Happy to help with whichever direction you pick. Leaving the PR to you rather than pushing a change to your branch, since this is a design call.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants