Skip to content

Conversation

@runningcode
Copy link
Contributor

@runningcode runningcode commented Oct 23, 2025

Summary

Adds a new permission scope project:distribution for Sentry Build Distribution functionality. This scope allows checking for updates of a given mobile app distribution.

Changes

  • Added project:distribution to ApiScopes.project tuple in src/sentry/models/apiscopes.py
  • Added project:distribution to ScopesDict TypedDict
  • Added project:distribution to SENTRY_SCOPES in src/sentry/conf/server.py
  • Added project:distribution to SENTRY_SCOPE_HIERARCHY_MAPPING in src/sentry/conf/server.py
  • Generated database migrations to update BitField scopes for API token models

Scope Availability

Available for:

  • ApiToken
  • ApiKey
  • ApiAuthorization
  • SentryApp
  • OrgAuthToken

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Oct 23, 2025
@codecov
Copy link

codecov bot commented Oct 23, 2025

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
41363 2 41361 249
View the top 2 failed test(s) by shortest run time
tests.sentry.api.serializers.test_organization.DetailedOrganizationSerializerTest::test_detailed
Stack Traces | 1.41s run time
#x1B[1m#x1B[.../api/serializers/test_organization.py#x1B[0m:159: in test_detailed
    assert result["access"] == default_owner_scopes
#x1B[1m#x1B[31mE   AssertionError: assert frozenset({'a...:admin', ...}) == frozenset({'a...:admin', ...})#x1B[0m
#x1B[1m#x1B[31mE     #x1B[0m
#x1B[1m#x1B[31mE     Extra items in the right set:#x1B[0m
#x1B[1m#x1B[31mE     'project:distribution'#x1B[0m
#x1B[1m#x1B[31mE     #x1B[0m
#x1B[1m#x1B[31mE     Full diff:#x1B[0m
#x1B[1m#x1B[31mE       frozenset({#x1B[0m
#x1B[1m#x1B[31mE           'alerts:read',#x1B[0m
#x1B[1m#x1B[31mE           'alerts:write',#x1B[0m
#x1B[1m#x1B[31mE           'event:admin',#x1B[0m
#x1B[1m#x1B[31mE           'event:read',#x1B[0m
#x1B[1m#x1B[31mE           'event:write',#x1B[0m
#x1B[1m#x1B[31mE           'member:admin',#x1B[0m
#x1B[1m#x1B[31mE           'member:invite',#x1B[0m
#x1B[1m#x1B[31mE           'member:read',#x1B[0m
#x1B[1m#x1B[31mE           'member:write',#x1B[0m
#x1B[1m#x1B[31mE           'org:admin',#x1B[0m
#x1B[1m#x1B[31mE           'org:integrations',#x1B[0m
#x1B[1m#x1B[31mE           'org:read',#x1B[0m
#x1B[1m#x1B[31mE           'org:write',#x1B[0m
#x1B[1m#x1B[31mE           'project:admin',#x1B[0m
#x1B[1m#x1B[31mE     -     'project:distribution',#x1B[0m
#x1B[1m#x1B[31mE           'project:read',#x1B[0m
#x1B[1m#x1B[31mE           'project:releases',#x1B[0m
#x1B[1m#x1B[31mE           'project:write',#x1B[0m
#x1B[1m#x1B[31mE           'team:admin',#x1B[0m
#x1B[1m#x1B[31mE           'team:read',#x1B[0m
#x1B[1m#x1B[31mE           'team:write',#x1B[0m
#x1B[1m#x1B[31mE       })#x1B[0m
tests.sentry.api.serializers.test_organization.DetailedOrganizationSerializerWithProjectsAndTeamsTest::test_detailed_org_projs_teams
Stack Traces | 2.43s run time
#x1B[1m#x1B[.../api/serializers/test_organization.py#x1B[0m:177: in test_detailed_org_projs_teams
    assert result["access"] == default_owner_scopes
#x1B[1m#x1B[31mE   AssertionError: assert frozenset({'a...:admin', ...}) == frozenset({'a...:admin', ...})#x1B[0m
#x1B[1m#x1B[31mE     #x1B[0m
#x1B[1m#x1B[31mE     Extra items in the right set:#x1B[0m
#x1B[1m#x1B[31mE     'project:distribution'#x1B[0m
#x1B[1m#x1B[31mE     #x1B[0m
#x1B[1m#x1B[31mE     Full diff:#x1B[0m
#x1B[1m#x1B[31mE       frozenset({#x1B[0m
#x1B[1m#x1B[31mE           'alerts:read',#x1B[0m
#x1B[1m#x1B[31mE           'alerts:write',#x1B[0m
#x1B[1m#x1B[31mE           'event:admin',#x1B[0m
#x1B[1m#x1B[31mE           'event:read',#x1B[0m
#x1B[1m#x1B[31mE           'event:write',#x1B[0m
#x1B[1m#x1B[31mE           'member:admin',#x1B[0m
#x1B[1m#x1B[31mE           'member:invite',#x1B[0m
#x1B[1m#x1B[31mE           'member:read',#x1B[0m
#x1B[1m#x1B[31mE           'member:write',#x1B[0m
#x1B[1m#x1B[31mE           'org:admin',#x1B[0m
#x1B[1m#x1B[31mE           'org:integrations',#x1B[0m
#x1B[1m#x1B[31mE           'org:read',#x1B[0m
#x1B[1m#x1B[31mE           'org:write',#x1B[0m
#x1B[1m#x1B[31mE           'project:admin',#x1B[0m
#x1B[1m#x1B[31mE     -     'project:distribution',#x1B[0m
#x1B[1m#x1B[31mE           'project:read',#x1B[0m
#x1B[1m#x1B[31mE           'project:releases',#x1B[0m
#x1B[1m#x1B[31mE           'project:write',#x1B[0m
#x1B[1m#x1B[31mE           'team:admin',#x1B[0m
#x1B[1m#x1B[31mE           'team:read',#x1B[0m
#x1B[1m#x1B[31mE           'team:write',#x1B[0m
#x1B[1m#x1B[31mE       })#x1B[0m

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@github-actions
Copy link
Contributor

This PR has a migration; here is the generated SQL for src/sentry/hybridcloud/migrations/0024_add_distribution_scope.py src/sentry/migrations/0998_add_distribution_scope.py

for 0024_add_distribution_scope in hybridcloud

--
-- Alter field scopes on apikeyreplica
--
-- (no-op)
--
-- Alter field scopes on apitokenreplica
--
-- (no-op)

for 0998_add_distribution_scope in sentry

--
-- Alter field scopes on apiauthorization
--
-- (no-op)
--
-- Alter field scopes on apikey
--
-- (no-op)
--
-- Alter field scopes on apitoken
--
-- (no-op)
--
-- Alter field scopes on sentryapp
--
-- (no-op)

Adds a new permission scope for Sentry Distribution functionality.

Changes:
- Added project:distribution to ApiScopes.project tuple
- Added project:distribution to ScopesDict TypedDict
- Added project:distribution to SENTRY_SCOPES
- Added project:distribution to SENTRY_SCOPE_HIERARCHY_MAPPING
- Added project:distribution to SENTRY_SCOPE_SETS with description
- Updated tests to verify the new scope works correctly
@github-actions
Copy link
Contributor

This PR has a migration; here is the generated SQL for src/sentry/hybridcloud/migrations/0024_add_distribution_token.py src/sentry/migrations/0999_add_distribution_token.py

for 0024_add_distribution_token in hybridcloud

--
-- Alter field scopes on apikeyreplica
--
-- (no-op)
--
-- Alter field scopes on apitokenreplica
--
-- (no-op)

for 0999_add_distribution_token in sentry

--
-- Alter field scopes on apiauthorization
--
-- (no-op)
--
-- Alter field scopes on apikey
--
-- (no-op)
--
-- Alter field scopes on apitoken
--
-- (no-op)
--
-- Alter field scopes on sentryapp
--
-- (no-op)

@runningcode runningcode marked this pull request as ready for review October 23, 2025 17:41
@runningcode runningcode requested a review from a team as a code owner October 23, 2025 17:41
cursor[bot]

This comment was marked as outdated.

… mapping

Registers the project:distribution scope in SENTRY_SCOPES and
SENTRY_SCOPE_HIERARCHY_MAPPING to make it available for permission
checks throughout the system.
"project:write": {"project:read", "project:write"},
"project:admin": {"project:read", "project:write", "project:admin"},
"project:releases": {"project:releases"},
"project:distribution": {"project:distribution"},
Copy link
Contributor

Choose a reason for hiding this comment

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

Bug: Scope Misalignment in Token Validation

The project:distribution scope was added to SENTRY_SCOPES and SENTRY_SCOPE_HIERARCHY_MAPPING. This goes against the design intent to restrict this scope to API tokens only, making it incorrectly available for OrgAuthToken validation.

Fix in Cursor Fix in Web

"alerts:read": bool,
"alerts:write": bool,
"member:invite": bool,
"project:distribution": bool,
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this scope will not be used with OAuth, I don't think it needs to be added here.

),
migrations.AlterField(
model_name="apitoken",
name="scopes",
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this field still being used? The last time this value was not 0 was in 2017... 🤔

operations = [
migrations.AlterField(
model_name="apiauthorization",
name="scopes",
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks unused, as the value is always 0.

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