Skip to content

ref(search): Resolve issue: short ids org-wide with explicit project_ids=None#117398

Merged
oioki merged 4 commits into
masterfrom
oioki/feat/short-id-scoping-search
Jun 11, 2026
Merged

ref(search): Resolve issue: short ids org-wide with explicit project_ids=None#117398
oioki merged 4 commits into
masterfrom
oioki/feat/short-id-scoping-search

Conversation

@oioki

@oioki oioki commented Jun 11, 2026

Copy link
Copy Markdown
Member

Migrates the three issue:PROJECT-123 short-id resolution sites (filter.py, datasets/discover.py, eap/resolver.py) to pass an explicit project_ids=None into by_qualified_short_id_bulk, preparing for the upcoming change that makes project_ids a required argument.

Why None (org-wide), not the query's projects? Project-level enforcement is unnecessary at this resolution step:

  • The resolved group id is only ever applied inside a Snuba query already scoped to the requested projects (RequestMeta.project_ids in the EAP resolver; a project_id condition in discover/filter). A short id for a project outside the query simply matches zero rows.
  • The access boundary is enforced upstream, where the endpoint builds SnubaParams via get_projects() (which runs has_project_access). And by_qualified_short_id is itself org-scoped, so cross-org never resolves.
  • SnubaParams.project_ids is the query's project scope, not the caller's access set (internal callers can construct arbitrary project_ids), so scoping resolution to it would be both unnecessary and semantically misleading.

So these sites resolve org-wide and document that intent with project_ids=None. No behavior change from master — it just makes the org-wide choice explicit and forward-compatible with the required-project_ids hardening. (Earlier revisions scoped to params.project_ids; superseded per review — the genuinely protective scoping lives in the issue mutation path, not search.)

When an issue:PROJECT-123 filter is resolved to a group id, pass the query's project scope into by_qualified_short_id_bulk so a short id for a project outside the search scope does not resolve. filter.py passes params['project_id'] (None when absent -> org-wide query); discover.py and eap/resolver.py pass SnubaParams.project_ids. The resolved ids already feed a Snuba query scoped to those projects, so this is defense-in-depth that fails closed at resolution time.

Co-Authored-By: Claude <noreply@anthropic.com>
@oioki oioki requested a review from a team as a code owner June 11, 2026 09:24
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Jun 11, 2026
Comment thread src/sentry/search/events/datasets/discover.py
@oioki oioki requested a review from cvxluo June 11, 2026 15:32
Comment thread src/sentry/search/eap/resolver.py Outdated
Comment on lines +259 to +260
# Scope to the projects the query is restricted to so a short id for a
# project outside the search scope does not resolve.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Scope to the projects the query is restricted to so a short id for a
# project outside the search scope does not resolve.

Comment thread src/sentry/search/eap/resolver.py Outdated
short_ids_raw=list(collected),
# Scope to the projects the query is restricted to so a short id for a
# project outside the search scope does not resolve.
project_ids=self.params.project_ids,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i don't think the params are same as projects that the caller has access to here. e.g. you can write a search query for project_ids 1, 2, 3, even if you don't have access to project id 1.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i think you're right, will ruminate a bit with the agent here

oioki and others added 3 commits June 11, 2026 18:43
… lookup

SnubaParams.project_ids returns [] when a query has no projects. Passing [] to
by_qualified_short_id_bulk filters to zero projects, so the short id never resolves and
the bulk lookup raises Group.DoesNotExist -> InvalidIssueSearchQuery, erroring a query
that previously returned empty results. Fall back to None (no pre-filter) for an empty
scope, which is safe because the downstream Snuba query still enforces the project
filter. Non-empty scopes are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
…ids=None

Supersedes scoping issue: short id resolution to the query's project_ids. SnubaParams.project_ids is the query's project scope, not the caller's access set, and project enforcement is unnecessary here: the resolved group id is only applied inside a Snuba query already scoped to the requested projects (RequestMeta.project_ids), with access enforced upstream by get_projects(). So the search sites resolve org-wide and pass project_ids=None explicitly -- no behavior change from master, but the org-wide intent is explicit and forward-compatible with making project_ids required.

Co-Authored-By: Claude <noreply@anthropic.com>
@oioki oioki changed the title ref(search): Scope issue: short id resolution to the query's projects ref(search): Resolve issue: short ids org-wide with explicit project_ids=None Jun 11, 2026
@oioki oioki requested a review from cvxluo June 11, 2026 17:26
organization_id=self.params.organization_id, short_ids_raw=list(collected)
organization_id=self.params.organization_id,
short_ids_raw=list(collected),
# org-wide: the Snuba query is already scoped to the requested projects.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

hm ok. it seems like we should just have a by_qualified_short_id_bulk_unscoped sort of function instead, so you have one function that does validation and one that explicitly doesn't

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i'm afraid people might misuse by_qualified_short_id_bulk_unscoped and an IDOR slips through. having a single method where a developer has to set project_ids explicitly is more secure imo

@oioki oioki merged commit d294505 into master Jun 11, 2026
86 checks passed
@oioki oioki deleted the oioki/feat/short-id-scoping-search branch June 11, 2026 21:56
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