Skip to content

feat(search): Add team: filter for issues by project ownership#1

Open
mishamo wants to merge 366 commits intomasterfrom
feat/team-issue-filter
Open

feat(search): Add team: filter for issues by project ownership#1
mishamo wants to merge 366 commits intomasterfrom
feat/team-issue-filter

Conversation

@mishamo
Copy link
Copy Markdown

@mishamo mishamo commented Jan 18, 2026

Summary

Adds a new team: search filter that allows filtering issues by the team that owns the project. This addresses getsentry#45367.

Usage:

  • team:data-engineering - Issues from projects owned by data-engineering
  • team:#data-engineering - Same (# prefix supported for consistency with other team references)
  • !team:data-engineering - Issues NOT from data-engineering's projects

Changes

  • src/sentry/issues/issue_search.py: Add team key mapping and convert_team_value() converter
  • src/sentry/search/snuba/backend.py: Add team_filter() function and condition
  • tests/snuba/search/test_backend.py: Add tests for team filter, negation, and invalid team handling

Test plan

  • test_team_filter - Verifies filtering by team slug with and without # prefix
  • test_team_filter_negation - Verifies !team: excludes issues from team's projects
  • test_team_filter_invalid_team - Verifies error handling for non-existent teams

🤖 Generated with Claude Code

@mishamo
Copy link
Copy Markdown
Author

mishamo commented Jan 18, 2026

Code Review

Issues Found

1. Potential IDOR Vulnerability (src/sentry/issues/issue_search.py:280-286)

The team lookup only filters by organization_id, but doesn't verify the requesting user has access to that team.

team = Team.objects.filter(
    slug__iexact=team_slug,
    organization_id=organization_id,
).first()

Per Sentry's security guidelines, you should verify the user has permission to reference this team. Consider checking team membership or visibility.

2. Empty projects list edge case (src/sentry/issues/issue_search.py:279)

organization_id = projects[0].organization_id

If projects is empty, this will raise an IndexError. Add a guard:

if not projects:
    return []
organization_id = projects[0].organization_id

3. Pre-existing bug in convert_query_values (src/sentry/issues/issue_search.py:457)

The function accesses projects[0] without checking if the list is empty:

organization = projects[0].organization

This would cause an IndexError for all search queries with an empty projects list, not just team filters. This is a pre-existing issue in the codebase (not introduced by this PR), but worth noting since the new convert_team_value function has the same pattern at line 280.

Recommendation: Either add a guard at the top of convert_query_values to handle empty projects, or ensure callers always pass a non-empty projects list (and document this requirement). This could be addressed in a follow-up PR if out of scope for this feature.


Suggestions

Additional test coverage to consider:

  • Test for multiple teams (team:[team1,team2])
  • Test for team with no projects assigned

Code Quality Assessment

Aspect Rating Notes
Correctness Good Logic is sound
Style Good Follows existing patterns
Testing Good Core cases covered
Security Needs Review Team access not verified
Performance Good Uses indexed queries

Verdict

The implementation is clean and follows existing patterns in the codebase. The main concerns are:

  1. Security: Verify user has access to the team being filtered on (IDOR concern)
  2. Edge case: Handle empty projects list

Once the security concern is addressed, this should be ready for merge.

@mishamo mishamo force-pushed the feat/team-issue-filter branch from 5aba036 to 81d8ffc Compare January 18, 2026 17:27
GabeVillalobos and others added 28 commits January 20, 2026 15:43
…route (getsentry#106348)

## Summary

Removes `deprecatedRouteProps: true` from the `metricAlertRuleDetails`
route by refactoring the component to use React Router v6 hooks.

## Changes

- **Route file** (`static/app/router/routes.tsx`):  
  - Removed `deprecatedRouteProps: true` from line 1472

- **Component**
(`static/app/views/alerts/rules/metric/details/index.tsx`):
- Added functional wrapper `MetricAlertDetailsWrapper` that uses
`useLocation()`, `useOrganization()`, and `useParams()` hooks
  - Removed `RouteComponentProps` from Props interface
- Class component remains unchanged and receives props from the wrapper

- **Tests**
(`static/app/views/alerts/rules/metric/details/index.spec.tsx`):
- Updated all 7 tests to use `initialRouterConfig` with proper routing
setup
  - Removed manual prop passing in favor of context-based routing
  - All tests passing ✅

## Test Plan

- ✅ All existing tests pass
- ✅ Manual verification: navigated to alert rule details page
- ✅ Verified routing works correctly with params extraction

## Related Work

Part of the effort to remove all `deprecatedRouteProps` from the
codebase and migrate to React Router v6 patterns. This is route 1 of 11
leaf routes that need updating.
…ntry#106428)

MonitorEnvironmentSerializer relies on Monitor data, but fetching it via
implicit query results in lots of unnecessary queries.
We can avoid this by batch fetching when it isn't cached, and using the
cached value when available.
By ensuring the Monitor is cached in MonitorSerializer, where we already
have the Monitors, no queries are required.
…alsy if doesn't exist (getsentry#106639)

This PR aims to fix a minor inconsistency between the list view and the
detail view for the seer code review repository settings where the list
view was falling back to false if settings didn't exist, but the detail
view was falling back to the org defaults and then true in the event the
repository settings doesn't exist.

<!--

  Sentry employees and contractors can delete or ignore the following.

-->

### Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated
in the State of Delaware in 2015 as Functional Software, Inc. and is
gonna need some rights from me in order to utilize my contributions in
this here PR. So here's the deal: I retain all rights, title and
interest in and to my contributions, and by keeping this boilerplate
intact I confirm that Sentry can use, modify, copy, and redistribute my
contributions, under Sentry's choice of terms.
…etsentry#106638)

It looks like we have some extra status checks being called but hard to
definitively tell without extra logging.

---------

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
Add deprecation decorators to GroupActivitiesEndpoint and update tests
to use the org-scoped variant's URL pattern. Follow-up PR coming to
update frontend references.
…impler props (getsentry#106503)

This doesn't change how things look, but I was able to simplify some
props and consolidate some rendering which makes things easier to read a
bit.
…try#106642)

We need to add extra handling to show the correct UI for the case where
the builds succeeded but the status check should fail because of a rule
they set in the settings

Before:
<img width="878" height="336" alt="image"
src="https://github.com/user-attachments/assets/78cfb91b-f734-4b4d-88f0-ed58dfefc189"
/>

After:
<img width="1108" height="429" alt="image"
src="https://github.com/user-attachments/assets/4ecaab80-8107-46f6-bb6b-516340673032"
/>
…ry#106627)

This makes all pages use the same variable names, definitions, etc for
the same thing. Also disables the `background agent` toggle on the
Settings>Project>Seer list page in the same way as its disabled on the
project-details page.

Depends on getsentry#106615
Ensure docs URL is used correctly
Use exact integration names from docs table (e.g., zodErrorIntegration)
Clarify auto-enabled vs manual setup distinction

- part of [TET-1749: Improve missing integrations detector response
quality](https://linear.app/getsentry/issue/TET-1749/improve-missing-integrations-detector-response-quality)
…tsentry#106451)

## Summary

Implements OAuth 2.0 public client support for CLI authentication per
GitHub issue getsentry#99002. This enables CLIs and native apps to authenticate
securely without storing client secrets.

### Public Client Support (RFC 6749 §2.1)
- Public clients (CLIs, native apps, SPAs) cannot securely store secrets
- Created with `client_secret=None` (NULL in database)
- Authenticate with just `client_id` (no `client_secret` required)
- Supported grant types: `authorization_code`, `device_code`,
`refresh_token`

### Implementation

**ApiApplication model:**
- `client_secret` field now allows NULL (`null=True`) - cheap migration
- Added `is_public` property that returns `True` when `client_secret is
None`
- Public clients created via `ApiApplication.objects.create(...,
client_secret=None)`

**Token endpoint (`oauth_token.py`):**
- Unified client authentication handling for both public and
confidential clients
- Public clients provide only `client_id` to identify themselves
- Confidential clients provide `client_id` + `client_secret`
- Same error message for invalid client_id vs missing secret (prevents
oracle attacks)
- Both client types use the same `get_refresh_token()` /
`ApiToken.refresh()` for token rotation

### Security Considerations
- Public clients are restricted to specific grant types (no
`client_credentials`)
- Oracle attack prevention: same error returned for invalid `client_id`
and missing `client_secret`
- Token rotation already exists for all clients via `ApiToken.refresh()`

## Test Plan
- 73 tests pass in `tests/sentry/web/frontend/test_oauth_token.py`
- New tests for public client flows:
  - Authorization code with/without PKCE
  - Device code flow
  - Refresh token rotation
  - Confidential client refresh with wrong/empty secret fails
  - Confidential client refresh rotates tokens in-place

Closes getsentry#99002

---------

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
…trics (getsentry#106373)

- Use `SpanMRI.COUNT_PER_ROOT_PROJECT` tagged with `is_segment` instead
of `TransactionMRI.COUNT_PER_ROOT_PROJECT`

Closes TET-1316
<!-- Describe your PR here. -->

<!--

  Sentry employees and contractors can delete or ignore the following.

-->

### Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated
in the State of Delaware in 2015 as Functional Software, Inc. and is
gonna need some rights from me in order to utilize my contributions in
this here PR. So here's the deal: I retain all rights, title and
interest in and to my contributions, and by keeping this boilerplate
intact I confirm that Sentry can use, modify, copy, and redistribute my
contributions, under Sentry's choice of terms.

---------

Co-authored-by: Lukas Bloder <lukas.bloder@gmail.com>
Co-authored-by: Priscila Oliveira <priscila.oliveira@sentry.io>
…ashboards (getsentry#106570)" (getsentry#106603)

Unrevert getsentry#106570
This Pr was only reverted because another PR needed to be reverted. The
other PR could not be reverted without conflicts
…etsentry#106599)

if `is_starred_transaction` is a selected field in the table widget, we
should always sort by it in descending order, so a users starred ones
appear first.
…ry#106366)

## Summary

Part 2 of 3-part deployment to restructure preprod URLs. This PR updates
backend URL generation to use the new format.

**Deployment order:**
1. Frontend PR (getsentry#106354) - Already deployed ✅
2. **This PR** (Backend) - Deploy second
3. Frontend cleanup PR (remove old routes - tracked in EME-735) - Deploy
last

## Example URLs Generated

**Before:**
- `/organizations/sentry/preprod/my-project/artifact-123`
-
`/organizations/sentry/preprod/my-project/compare/artifact-123/artifact-456`

**After:**
- `/organizations/sentry/preprod/size/artifact-123?project=my-project`
-
`/organizations/sentry/preprod/size/compare/artifact-123/artifact-456?project=my-project`

## Why This Approach

Since frontend deployed first with redirects:
- Old URLs from emails/status checks already sent → Frontend redirects
them
- After this PR: New URLs generated → Frontend handles them directly 
- After cleanup PR: Remove redirects, only new format remains 

## Dependencies

- **Requires**: PR getsentry#106354 must be deployed first
- **Enables**: Frontend cleanup PR (EME-735) can deploy after this
…oint (getsentry#106658)

Improves performance of the existing endpoint and adds more telemetry to
get more insight into what's slow.
…on` in project settings (getsentry#106002)

Support configuring filters for `size` and `distribution` in project
settings.
These filters are synced to the backend where they can be used to decide
which builds get which analyses.
… span metrics (getsentry#106373)"

This reverts commit 15693e2.

Co-authored-by: shellmayr <6788060+shellmayr@users.noreply.github.com>
This PR adds a section in organization settings to manage GitHub invites
to our Console SDK repositories.

This organization option will only show up if an organization has one or
more console platforms enabled in the `_admin` portal.
…tsentry#106654)

## Summary

Adds frontend UI support for creating and viewing public OAuth clients,
building on the backend support added in getsentry#106451.

<img width="1216" height="698" alt="image"
src="https://github.com/user-attachments/assets/9477513f-1b1a-4d7c-9888-0efdb5b9260a"
/>


### Changes

**Backend (`api_applications.py`):**
- Accept `isPublic` parameter when creating new applications
- When `isPublic=True`, create application with `client_secret=None`

**Serializer:**
- Add `is_public` field to `ApiApplicationSerializer` output

**Frontend UI:**
- Add client type selection modal when creating new applications (Public
vs Confidential)
- Show "Public Client" or "Confidential Client" tag on application
details page
- Hide client secret section for public clients (they don't have one)
- Add info alert explaining public client behavior and security
considerations

### Screenshots

_Client type selection when creating new application_

_Public client details page showing no client secret_

## Test Plan

- Added frontend tests for new UI components
- Added backend tests for `isPublic` parameter handling
- Existing OAuth token tests cover the backend functionality

Depends on getsentry#106451 (merged)
Closes getsentry#99002

---------

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
aliu39 and others added 29 commits January 23, 2026 18:28
…int (getsentry#106828)

relates to [ISWF-402: Issue details: tags should respond to event
filters](https://linear.app/getsentry/issue/ISWF-402/issue-details-tags-should-respond-to-event-filters)
and [AIML-2248: update tag distribution and timeseries to respect time
range in
get_issue_details](https://linear.app/getsentry/issue/AIML-2248/update-tag-distribution-and-timeseries-to-respect-time-range-in-get).
This adds functionality that allows the tag summary UI to update with
event time filters, if issues team decides to do so. This also enables a
query we need for seer explorer, which I'll add in a followup
Previously it would crash on some number of hooks error when adding a
story
…etsentry#106884)

emails now check if you're a 24-hour time person and format accordingly.
issue alerts, digests, and feedback emails all got the change.

Fixes getsentry#106581

the html is kinda miserable to review but it works
<img width="586" height="113" alt="24tz"
src="https://github.com/user-attachments/assets/a5d44869-aabb-42c6-a13f-bf9639b38d9b"
/>

---------

Co-authored-by: Claude <noreply@anthropic.com>
…e" (getsentry#106674)

when using "resolve in next release" with multiple builds sharing the
same version number, sentry was incorrectly selecting archived builds
instead of the latest active one. this adds a filter for
`ReleaseStatus.OPEN` to both `most_recent_release()` and
`get_semver_releases()` to ensure only non-archived releases are
considered.

Fixes getsentry#103441

---------

Co-authored-by: Claude <noreply@anthropic.com>
The chart palette in dark mode incorrectly used `purple` instead of
`indigo`, making charts with less than 6 series difficult to
differentiate

**Before**
`#7B52FF`
`#613CB9`
Contrast of 1.57

**After**
`#7B52FF`
`#561EA2`
Contrast of 2.14
Not called in seer, deprecated in favor of execute_table_query
…#106908)

We previously showed an "Open in Discover" button when fullscreening a
dashboard widget that would lead to a broken page. We can investigate
getting our data in Discover/Explore at some later point.
)

Creates new snapshots DB models for upcoming Emerge snapshots
integration. Nested in a `/snapshots` folder to try to start organizing
by product surface.
…rectly detected it as being setup (getsentry#106910)

The messages that users see on other pages indicated that they need to
re-install the integration. lets check that when we find an integration
the status is ready before skipping steps.

On the Integration page we can see these errors:
<img width="1173" height="407" alt="SCR-20260123-liqr"
src="https://github.com/user-attachments/assets/e68421e4-64da-4bf1-b6aa-ce9f9f965462"
/>


And we can see from the integration itself that it's in a type of
disabled state: disabled by the system (not by the user)
<img width="712" height="266" alt="SCR-20260123-lhsx"
src="https://github.com/user-attachments/assets/bd85a619-76ff-4d3a-b1e7-77b22580d450"
/>

So we cannot rely on the presence of an integration to mean that things
are good. Instead we should check that the integration is good-to-go.

Fixes
https://linear.app/getsentry/issue/CW-676/user-feedback-cannot-connect-to-projects-or-organization
…t order (getsentry#106634)

We haven't always had correct relationships encoded for DataSource and
the tables it references, and we've oberserved cases in production where
relocated projects got partial data due to improper relative ordering of
QuerySubscription and DataSource.

By moving from trying to order import data properly rather than trusting
the ordering in the JSON, such cases should be recoverable.

If there are cases where old data is more correct about the order than
current code, it's unclear that they should successfully import, but
actual dependency changes are rare, so this is likely to mostly affect
DataSource and related tables.


Fixes ACI-519.
instead of branching to our own util to parse and validate `start` `end`
`statsPeriod`, lean on the existing sentry api validation and util.

Changes: 
- When invoking an endpoint, directly pass the params to it (already has
validation)
- When passing date params for other use, use
`get_date_range_from_params`
- Adds a `get_group_date_range` convenience util for getting a group's
first/last seen time range, clamped by retention.
- Updates the baselines rpc for suspect tags to default to the
first/last seen range instead of last 7d. This matches the behavior of
the issue tool when no date is specified

Note: I removed some default stats periods from explorer tools, as it
seems better to maintain and pass them from seer only. Right now Seer
mostly defaults to passing 7d, so the sentry-side defaults aren't used
…ver (getsentry#106850)

Fixes getsentry#101578

Hide 'View more events' button when discover isn't available, since
clicking it leads to an empty view anyways.
<img width="291" height="45" alt="Screenshot 2026-01-23 at 9 47 02 AM"
src="https://github.com/user-attachments/assets/245a269b-d5dc-4a30-a573-9838c8820b6c"
/>
…point (getsentry#106791)

Add deprecation decorator to DELETE method of
GroupExternalIssueDetailsEndpoint and update tests to use org-scoped URL
pattern.
getsentry#106793)

Update the deleteExternalIssue function and its callers to use the
org-scoped URL pattern
/organizations/{org}/issues/{id}/external-issues/{id}/ instead of the
deprecated /issues/{id}/external-issues/{id}/ pattern.
Deprecate GroupTagKeyValues endpoint and update tests to use correct
org-scoped URL.
)

Deprecate GroupTagKeyDetails endpoint and replace test URLs with
org-scoped variant.
Noisy diffs, but high-level summary is:
- Fixed: color conversion previously resulted in improperly clamped
values. HEX codes are now 1:1 with Figma.
- Renamed: `theme.shadow → theme.elevation` (dimension)
- Renamed: `theme.tokens.shadow.elevation* -> theme.tokens.elevation.*`
(color)
- Added: `theme.shadow` (box-shadow) with `low`, `medium`, `high`
- Modified: corrected inaccurate JSDoc comments
- Added: `Surface` component uses actual shadow tokens
Remove references to `seer-user-billing` feature. We're relying on
`seer-user-billing-launch` instead.

I'll follow up with getsentry/getsentry#19179 to
remove `seer-user-billing` entirely
…int URLs (getsentry#106928)

It seems we missed this file in our endpoint-specific PRs.
…entry#106115)"

This reverts commit afe0978.

Co-authored-by: cvxluo <27893746+cvxluo@users.noreply.github.com>
…)"

This reverts commit 6f29e42.

Co-authored-by: ryan953 <187460+ryan953@users.noreply.github.com>
Adds a new `team:` search filter that allows filtering issues by the team
that owns the project. This enables searching for issues like `team:platform`
to find all issues in projects owned by the platform team.

Implementation:
- Added `team` to `key_mappings` in issue search config
- Added `convert_team_value` to convert team slugs to Team objects
- Added `team_filter` QCallbackCondition in snuba backend
- Added `team` to NO_CONVERSION_FIELDS to skip Snuba conversion
- Uses case-insensitive slug matching consistent with existing patterns

Closes getsentry#45367

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@mishamo mishamo force-pushed the feat/team-issue-filter branch from 7d7accf to 6c9f1c4 Compare January 24, 2026 19:09
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.