Skip to content

ref(saved-queries): align list endpoint access checks with detail#115379

Merged
oioki merged 4 commits into
masterfrom
ref/saved-query-list-access-consistency
May 19, 2026
Merged

ref(saved-queries): align list endpoint access checks with detail#115379
oioki merged 4 commits into
masterfrom
ref/saved-query-list-access-consistency

Conversation

@oioki
Copy link
Copy Markdown
Member

@oioki oioki commented May 12, 2026

Apply the same project-access logic the Discover and Explore detail saved-query endpoints already enforce to their corresponding list endpoints, so both report the same view of the org for any given actor.

The detail endpoints have been calling check_object_permissions since #72159 / #78830 — the list handlers were not updated alongside, and when the Explore endpoints landed (#86578, #86888) they inherited the same shape. This PR closes the gap on both Discover and Explore in one place.

Implementation: a small filter_to_accessible_*_queries(request, queryset) helper in each app's endpoints/bases.py that mirrors the existing has_object_permission logic at the queryset level (short-circuits for Open Membership / org:write, then Exists() subqueries on the through-tables for the project-scoped and unprojected cases). The list endpoints call it once after building the base queryset; the all=1 branch on Discover is covered by the same filter.

Behaviour is unchanged for any actor who could already see every saved query in the org.

Fixes EXP-942

The Discover and Explore saved-query list endpoints filtered results
only by organization, while their corresponding detail endpoints already
ran an object-level project-access check via `check_object_permissions`.
Apply the same project-access logic at the queryset level in the list
handlers so the two endpoints stay consistent. Behaviour is unchanged
for actors that can already see every query in the org (Open Membership,
Managers/Owners) and for the creator of an unprojected query.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label May 12, 2026
@oioki oioki marked this pull request as ready for review May 13, 2026 17:12
@oioki oioki requested review from a team as code owners May 13, 2026 17:12
Comment thread src/sentry/explore/endpoints/bases.py Outdated
…of project access

Prebuilt Explore saved queries are product-level content (no user data,
no project scope), but the existing access logic — both `has_object_permission`
on the detail endpoint and the new list-level filter — treated them as
"no-projects" queries authored by no one, which dropped them for any
member in a closed-membership org who is not a Manager/Owner.

Allow rows with `prebuilt_id IS NOT NULL` through both checks so prebuilts
behave the same for every org member.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8b7151d. Configure here.

Comment thread src/sentry/explore/endpoints/bases.py Outdated
oioki and others added 2 commits May 14, 2026 01:09
… exclude too

`has_object_permission` short-circuits prebuilt explore queries before any
project check, but the list filter's "exclude queries with an inaccessible
project" step still applied to them — so a prebuilt with a project the actor
couldn't access would 200 on detail and disappear from the list, breaking
the mirroring contract between the two checks.

Centralise the prebuilt exemption in a single `is_prebuilt` predicate and
apply it to both the exclude and the include step. Add a regression test
that pins this contract end-to-end.

Co-Authored-By: Claude <noreply@anthropic.com>
`PREBUILT_SAVED_QUERIES[0]["prebuilt_id"]` is typed `object`, which mypy
rejected when passed to `ExploreSavedQuery.objects.create(prebuilt_id=..., prebuilt_version=...)`.
Switch to literals (1, 1) with a comment explaining the coupling to the
canonical prebuilt list. If anyone bumps the canonical version of the
first entry, the test fails on the name assertion and the literal can be
bumped alongside.

Co-Authored-By: Claude <noreply@anthropic.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 19, 2026

EXP-942

@oioki oioki merged commit 17af391 into master May 19, 2026
64 checks passed
@oioki oioki deleted the ref/saved-query-list-access-consistency branch May 19, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants