Skip to content

fix(api): Enforce write scopes on published mutations#113109

Closed
dcramer wants to merge 2 commits intomasterfrom
dcramer/ref/remove-readonly-mutation-scopes
Closed

fix(api): Enforce write scopes on published mutations#113109
dcramer wants to merge 2 commits intomasterfrom
dcramer/ref/remove-readonly-mutation-scopes

Conversation

@dcramer
Copy link
Copy Markdown
Member

@dcramer dcramer commented Apr 15, 2026

Enforce the API contract that published mutation endpoints must require non-readonly scopes.

This removes readonly scopes from published POST/PUT/DELETE endpoints and adds dedicated write scopes where Sentry intentionally exposes narrower mutations: project:create for self-serve project creation, project:codeowners for ownership and CODEOWNERS management, user:preferences for personal state like bookmarks and onboarding progress, org:searches for saved searches and custom views, and flags:write for flag webhook signing secrets.

The patch keeps session behavior working by granting those scopes to the appropriate roles instead of relying on readonly scopes plus later row or object ACL checks. It also preserves legacy token decoding by appending the new scope bits instead of reordering the existing bitfield.

Add a published-endpoint invariant test and endpoint-level permission coverage for the new mixed-scope cases, while leaving the more controversial POST-as-query surfaces for follow-up.

Refs getsentry/getsentry#19897

Remove readonly scopes from published mutation endpoints and add dedicated write scopes where the API intentionally allows narrower writes. This keeps the public token contract explicit while preserving the existing session behavior for user-owned state and team-scoped workflows.

Add a published-endpoint invariant test plus endpoint-level permission coverage for the new scope contracts, including user preferences, project creation, and codeowners flows.

Refs getsentry/getsentry#19897
Co-Authored-By: OpenAI Codex <noreply@openai.com>
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Apr 15, 2026
teams = Team.objects.filter(id__in=request.access.team_ids_with_membership)
return any(
any(request.access.has_team_scope(team, scope) for scope in scopes) for team in teams
)
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.

Duplicate _has_any_team_scope with divergent signatures

Low Severity

Two _has_any_team_scope helper functions are introduced in separate files with different signatures — one in organization.py accepts a single scope: str, the other in discover_key_transactions.py accepts scopes: list[str]. This duplication with divergent APIs increases maintenance burden and invites confusion if a future developer imports or copies the wrong variant.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit df3aac6. Configure here.

Comment thread src/sentry/conf/server.py
@github-actions
Copy link
Copy Markdown
Contributor

This PR has a migration; here is the generated SQL for src/sentry/migrations/1063_add_project_create_and_flags_write_scopes.py

for 1063_add_project_create_and_flags_write_scopes 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)

or request.access.has_scope("project:admin")
or request.access.has_any_project_scope(project, ["project:write", "project:admin"])
)
requested_fields = set(request.data.keys())
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.

AttributeError if request body is a JSON array instead of object

The new code calls request.data.keys() at line 614 before serializer validation. If a client sends a JSON array ([]) instead of an object ({}), request.data will be a list and .keys() will raise AttributeError: 'list' object has no attribute 'keys', resulting in a 500 error. Other Sentry endpoints (e.g., organization_seer_explorer_update.py:51) explicitly guard against this with isinstance(request.data, dict) checks.

Verification

Traced the code path: line 614 calls set(request.data.keys()) before the serializer is instantiated at line 627. Confirmed other endpoints (src/sentry/seer/endpoints/organization_seer_explorer_update.py:51, src/sentry/seer/endpoints/group_autofix_update.py:40) explicitly check isinstance(request.data, dict) before accessing dict methods, indicating this is a recognized pattern. The old code used request.data.get(key) which would not crash on a list.

Suggested fix: Add a type check before accessing .keys() to handle malformed request bodies gracefully.

Suggested change
requested_fields = set(request.data.keys())
if not isinstance(request.data, dict):
return Response(
{"detail": "Request body must be a JSON object."},
status=400,
)
requested_fields = set(request.data.keys())

Identified by Warden sentry-backend-bugs · K2K-496

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.

Fix attempt detected (commit 23b5b5e)

The commit introduced the problematic code set(request.data.keys()) at line 614 without the required isinstance(request.data, dict) check, making the endpoint vulnerable to AttributeError when clients send JSON arrays instead of objects.

The original issue appears unresolved. Please review and try again.

Evaluated by Warden

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 15, 2026

Backend Test Failures

Failures on fe9e57d in this run:

tests/sentry/api/serializers/test_organization.py::OrganizationSerializerTest::test_detailedlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/serializers/test_organization.py:158: in test_detailed
    assert result["access"] == default_owner_scopes
E   AssertionError: assert frozenset({'a...:admin', ...}) == frozenset({'a...:write', ...})
E     
E     Extra items in the right set:
E     'project:create'
E     'flags:write'
E     
E     Full diff:
E       frozenset({
E           'alerts:read',
E           'alerts:write',
E           'event:admin',
E           'event:read',
E           'event:write',
E     -     'flags:write',
E           'member:admin',
E           'member:invite',
E           'member:read',
E           'member:write',
E           'org:admin',
E           'org:integrations',
E           'org:read',
E           'org:searches',
E           'org:write',
E           'project:admin',
E           'project:codeowners',
E     -     'project:create',
E           'project:read',
E           'project:releases',
E           'project:write',
E           'team:admin',
E           'team:read',
E           'team:write',
E           'user:preferences',
E       })
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberPermissionRoleTest::test_admin_inviteslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:717: in test_admin_invites
    self.invite_to_other_team_helper("admin")
tests/sentry/core/endpoints/test_organization_member_index.py:671: in invite_to_other_team_helper
    self.get_success_response(self.organization.slug, **get_data("foo3"), status_code=201)
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 202
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsDeleteTest::test_user_in_team_with_access_can_delete_dashboardlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:889: in test_user_in_team_with_access_can_delete_dashboard
    assert response.status_code == 204, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 204
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_all_users_can_edit_dashboard_with_edit_permissions_disabledlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2785: in test_all_users_can_edit_dashboard_with_edit_permissions_disabled
    assert response.status_code == 200, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_feature_requiredlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:962: in test_feature_required
    assert response.status_code == 404, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 404
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTransactionLikeTest::test_ondemand_hits_spec_limitlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4174: in test_ondemand_hits_spec_limit
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_can_update_member_membershiplog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:494: in test_can_update_member_membership
    self.get_success_response(self.organization.slug, member_om.id, role="manager")
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_create_with_project_create_tokenlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:243: in test_create_with_project_create_token
    assert response.status_code == 201, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_issue_widget_invalid_querylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2450: in test_add_issue_widget_invalid_query
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_with_invalid_limit_above_maximumlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1419: in test_add_widget_with_invalid_limit_above_maximum
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_create_widget_with_axis_rangelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2103: in test_create_widget_with_axis_range
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_deletes_widget_with_field_linkslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3540: in test_deletes_widget_with_field_links
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_partial_reordering_deletes_widgetslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2368: in test_partial_reordering_deletes_widgets
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_reorder_querieslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1818: in test_update_widget_reorder_queries
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_on_role_change_called_when_role_updatedlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:893: in test_on_role_change_called_when_role_updated
    self.get_success_response(self.organization.slug, member_om.id, role="manager")
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberListPostTest::test_no_teamslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:838: in test_no_teams
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_invite_index.py::OrganizationMemberInvitePostTest::test_rate_limitedlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_index.py:308: in test_rate_limited
    self.get_error_response(self.organization.slug, **data, status_code=429)
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 429 <= 400
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_rename_dashboard_title_takenlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:980: in test_rename_dashboard_title_taken
    assert response.status_code == 409, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 409
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py::OrganizationDashboardWidgetDetailsTestCase::test_issue_search_conditionlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py:426: in test_issue_search_condition
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_layout_with_invalid_data_failslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2240: in test_update_layout_with_invalid_data_fails
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_user_in_team_with_access_can_edit_dashboardlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2825: in test_user_in_team_with_access_can_edit_dashboard
    assert response.status_code == 200, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_user_tries_to_update_dashboard_edit_permslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2861: in test_user_tries_to_update_dashboard_edit_perms
    assert response.status_code == 400
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/incidents/endpoints/test_organization_incident_details.py::OrganizationIncidentUpdateStatusTest::test_cannot_openlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/incidents/endpoints/test_organization_incident_details.py:101: in test_cannot_open
    assert resp.status_code == 400
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/incidents/endpoints/test_organization_incident_details.py::OrganizationIncidentUpdateStatusTest::test_no_featurelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/incidents/endpoints/test_organization_incident_details.py:52: in test_no_feature
    assert resp.status_code == 404
E   assert 403 == 404
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/models/test_organizationmember.py::OrganizationMemberTest::test_get_allowed_org_roles_to_invitelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/models/test_organizationmember.py:523: in test_get_allowed_org_roles_to_invite
    assert member.get_allowed_org_roles_to_invite() == [
E   assert [Organization..._global=True)] == [Organization..._global=True)]
E     
E     At index 0 diff: OrganizationRole(parent=<sentry.roles.manager.RoleManager object at 0x7fea36df9d30>, priority=1, id='admin', name='Admin', desc="Admin privileges on any teams of which they're a member. They can create new teams and projects, as well as remove teams and projects on which they already hold membership (or all teams, if open membership is enabled). Additionally, they can manage memberships of teams that they are members of. By default, they can invite members to the organization unless the organization has disabled this feature.", scopes=frozenset({'team:admin', 'project:admin', 'team:write', 'alerts:read', 'alerts:write', 'project:read', 'event:read', 'org:read', 'org:integrations', 'project:releases', 'team:read', 'org:searches', 'member:invite', 'member:read', 'project:codeowners', 'user:preferences', 'event:admin', 'event:write', 'project:write'}), is_retired=True, is_team_roles_allowed=True, is_global=False) != OrganizationRole(parent=<sentry.roles.manager.RoleManager object at 0x7fea36df9d30>, priority=0, id='member', name='Member', desc='Members can view and act on events, as well as view most other data within the organization. By default, they can invite members to the organization unless the organization has disabled this feature.', scopes=frozenset({'alerts:read', 'alerts:write', 'project:create', 'org:read', 'event:read', 'project:read', 'flags:write', 'project:releases', 'team:read', 'org:searches', 'member:invite', 'member:read', 'project:codeowners', 'user:preferences', 'event:admin', 'event:write'}), is_retired=False, is_team_roles_allowed=True, is_global=False)
E     Right contains one more item: OrganizationRole(parent=<sentry.roles.manager.RoleManager object at 0x7fea36df9d30>, priority=2, id='manager', name='M...admin', 'event:write', 'project:write', 'member:write'}), is_retired=False, is_team_roles_allowed=True, is_global=True)
E     
E     Full diff:
E       [
E     -     OrganizationRole(
E     -         parent=<sentry.roles.manager.RoleManager object at 0x7fea36df9d30>,
E     -         priority=0,
E     -         id='member',
E     -         name='Member',
E     -         desc='Members can view and act on events, as well as view most other '
E     -              'data within the organization. By default, they can invite '
E     -              'members to the organization unless the organization has disabled '
E     -              'this feature.',
E     -         scopes=frozenset({
E     -                    'alerts:read',
E     -                    'alerts:write',
E     -                    'event:admin',
E     -                    'event:read',
E     -                    'event:write',
E     -                    'flags:write',
E     -                    'member:invite',
E     -                    'member:read',
E     -                    'org:read',
E     -                    'org:searches',
E     -                    'project:codeowners',
E     -                    'project:create',
E     -                    'project:read',
E     -                    'project:releases',
E     -                    'team:read',
E     -                    'user:preferences',
E     -                }),
E     -         is_retired=False,
E     -         is_team_roles_allowed=True,
E     -         is_global=False,
E     -     ),
E           OrganizationRole(
E               parent=<sentry.roles.manager.RoleManager object at 0x7fea36df9d30>,
E               priority=1,
E               id='admin',
E               name='Admin',
E               desc="Admin privileges on any teams of which they're a member. They "
E                    'can create new teams and projects, as well as remove teams and '
E                    'projects on which they already hold membership (or all teams, if '
E                    'open membership is enabled). Additionally, they can manage '
... (64 more lines)
tests/sentry/api/endpoints/test_organization_api_key_details.py::OrganizationApiKeyDetailsPut::test_update_api_key_details_legacy_datalog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_organization_api_key_details.py:89: in test_update_api_key_details_legacy_data
    assert api_key.get_scopes() == ["org:read", "project:read", "project:write", "team:read"]
E   AssertionError: assert ['org:read', ..., 'team:read'] == ['org:read', ..., 'team:read']
E     
E     At index 1 diff: 'project:codeowners' != 'project:read'
E     Left contains 2 more items, first extra item: 'project:write'
E     
E     Full diff:
E       [
E           'org:read',
E     +     'project:codeowners',
E     +     'project:create',
E           'project:read',
E           'project:write',
E           'team:read',
E       ]
tests/sentry/api/endpoints/test_organization_auth_token_details.py::OrganizationAuthTokenDetailsPermissionTest::test_member_can_putlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_organization_auth_token_details.py:437: in test_member_can_put
    self.assert_member_can_access(
src/sentry/testutils/cases.py:881: in assert_member_can_access
    return self.assert_role_can_access(path, "member", **kwargs)
src/sentry/testutils/cases.py:905: in assert_role_can_access
    return self.assert_can_access(user, path, **kwargs)
src/sentry/testutils/cases.py:872: in assert_can_access
    assert resp.status_code >= 200 and resp.status_code < 300
E   assert (403 >= 200 and 403 < 300)
E    +  where 403 = <Response status_code=403, "application/json">.status_code
E    +  and   403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_dashboard_widget_missing_columns_can_successfully_savelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3260: in test_dashboard_widget_missing_columns_can_successfully_save
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_prebuilt_dashboard_with_transactions_deprecation_feature_flaglog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2349: in test_update_prebuilt_dashboard_with_transactions_deprecation_feature_flag
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_invalid_orderbylog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1869: in test_update_widget_invalid_orderby
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_hits_card_limitlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4220: in test_ondemand_hits_card_limit
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTransactionLikeTest::test_ondemand_without_flagslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4059: in test_ondemand_without_flags
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/api/endpoints/issues/test_organization_derive_code_mappings.py::OrganizationDeriveCodeMappingsTest::test_idor_project_from_different_orglog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/issues/test_organization_derive_code_mappings.py:267: in test_idor_project_from_different_org
    assert response.status_code == status.HTTP_404_NOT_FOUND
E   assert 403 == 404
E    +  where 403 = <Response status_code=403, "application/json">.status_code
E    +  and   404 = status.HTTP_404_NOT_FOUND
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_discover_widget_invalid_issue_querylog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2476: in test_add_discover_widget_invalid_issue_query
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_description_exceeds_max_lengthlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1310: in test_add_widget_description_exceeds_max_length
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_missing_titlelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1284: in test_add_widget_missing_title
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_does_not_update_if_linked_dashboard_does_not_appear_in_fieldslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3729: in test_does_not_update_if_linked_dashboard_does_not_appear_in_fields
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_invalid_aggregate_parameterlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1928: in test_update_widget_invalid_aggregate_parameter
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_invalid_fieldslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1952: in test_update_widget_invalid_fields
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTransactionLikeTest::test_add_widget_with_split_widget_type_writes_to_split_decisionlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4590: in test_add_widget_with_split_widget_type_writes_to_split_decision
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/api/endpoints/test_organization_invite_request_details.py::OrganizationInviteRequestApproveTest::test_can_approve_join_request_with_enabled_settinglog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_organization_invite_request_details.py:249: in test_can_approve_join_request_with_enabled_setting
    assert resp.status_code == 200
E   assert 400 == 200
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsDeleteTest::test_delete_permissionlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:707: in test_delete_permission
    self.test_delete()
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:695: in test_delete
    assert response.status_code == 204
E   assert 403 == 204
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py::OrganizationDashboardWidgetDetailsTestCase::test_valid_widget_permissionslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py:67: in test_valid_widget_permissions
    self.test_valid_widget()
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py:63: in test_valid_widget
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_can_edit_prebuilt_insights_dashboard_global_filterslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3906: in test_can_edit_prebuilt_insights_dashboard_global_filters
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_dashboard_exisiting_transaction_widget_deprecation_with_flaglog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3344: in test_dashboard_exisiting_transaction_widget_deprecation_with_flag
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_text_widget_errors_provided_querieslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4010: in test_text_widget_errors_provided_queries
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_with_axis_rangelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2050: in test_update_widget_with_axis_range
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_feature_check_takes_precedence_over_cardinalitylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4491: in test_feature_check_takes_precedence_over_cardinality
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_hits_spec_limitlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4174: in test_ondemand_hits_spec_limit
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_updates_new_widgetlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4355: in test_ondemand_updates_new_widget
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/integrations/api/endpoints/test_organization_repositories.py::OrganizationRepositoriesCreateTest::test_member_oklog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/integrations/api/endpoints/test_organization_repositories.py:371: in test_member_ok
    assert response.status_code == 201, (response.status_code, response.content)
E   AssertionError: (403, b'{"detail":"You do not have permission to perform this action."}')
E   assert 403 == 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_can_update_from_retired_role_without_flaglog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:665: in test_can_update_from_retired_role_without_flag
    self.get_success_response(self.organization.slug, member_om.id, role="member")
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 201
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_invite_index.py::OrganizationMemberInvitePostTest::test_simplelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_index.py:215: in test_simple
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_cannot_update_to_retired_role_with_flaglog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:712: in test_cannot_update_to_retired_role_with_flag
    self.get_error_response(self.organization.slug, member_om.id, role="admin", status_code=400)
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 401
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsDeleteTest::test_allow_delete_when_no_project_accesslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:725: in test_allow_delete_when_no_project_access
    assert response.status_code == 204
E   assert 403 == 204
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_text_widget_description_exceeds_max_lengthlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1331: in test_add_text_widget_description_exceeds_max_length
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_with_aggregates_and_columnslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1251: in test_add_widget_with_aggregates_and_columns
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_dashboard_permissions_with_none_does_not_create_permissions_objectlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3024: in test_update_dashboard_permissions_with_none_does_not_create_permissions_object
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_dashboard_with_widget_filter_requiring_environmentlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2683: in test_update_dashboard_with_widget_filter_requiring_environment
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_titlelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1718: in test_update_widget_title
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_without_specifying_layout_does_not_change_saved_layoutlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2259: in test_update_without_specifying_layout_does_not_change_saved_layout
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/api/endpoints/issues/test_organization_derive_code_mappings.py::OrganizationDeriveCodeMappingsTest::test_non_project_member_permissionslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/issues/test_organization_derive_code_mappings.py:288: in test_non_project_member_permissions
    assert response.status_code == status.HTTP_201_CREATED
E   assert 403 == 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
E    +  and   201 = status.HTTP_201_CREATED
tests/sentry/core/endpoints/test_organization_member_invite_details.py::UpdateOrganizationMemberInviteTest::test_can_update_from_retired_role_with_flaglog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_details.py:118: in test_can_update_from_retired_role_with_flag
    self.get_success_response(self.organization.slug, invite.id, orgRole="member")
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 201
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_dashboard_permissions_with_invalid_valuelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2752: in test_update_dashboard_permissions_with_invalid_value
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_add_querylog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1750: in test_update_widget_add_query
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberListPostTest::test_no_emaillog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:856: in test_no_email
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_cannot_demote_team_member_to_role_where_team_roles_disabledlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:829: in test_cannot_demote_team_member_to_role_where_team_roles_disabled
    assert (
E   KeyError: 'detail'
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_categorical_bar_widget_with_valid_limitlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1445: in test_add_categorical_bar_widget_with_valid_limit
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widgetlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1098: in test_add_widget
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_cannot_edit_prebuilt_insights_dashboard_titlelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3885: in test_cannot_edit_prebuilt_insights_dashboard_title
    assert response.status_code == 409
E   assert 403 == 409
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_dashboard_does_not_existlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:954: in test_dashboard_does_not_exist
    assert response.status_code == 404
E   assert 403 == 404
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_dashboard_with_filterslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2586: in test_update_dashboard_with_filters
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_unknown_prebuiltlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2357: in test_update_unknown_prebuilt
    assert response.status_code == 404
E   assert 403 == 404
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_updates_existing_widgetlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4265: in test_ondemand_updates_existing_widget
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTransactionLikeTest::test_cardinality_skips_non_discover_widget_typeslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4534: in test_cardinality_skips_non_discover_widget_types
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/sentry_apps/test_sentry_app_updater.py::TestUpdater::test_updates_unpublished_app_scopeslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests

... (truncated due to GitHub comment size limit)

Expand token scope hierarchies during permission evaluation so leaf scopes like org:searches, project:create, and project:codeowners do not need parent fallbacks in endpoint scope maps.

Move clearly user-owned search and starring endpoints onto user:preferences, keep org:searches for real saved-search and custom-view resources, and reject user:preferences and flags:write when third-party API apps request scopes.

This keeps personal state out of app-granted scopes while preserving the intended session and broad-token behavior for higher-level write scopes.

Refs getsentry/getsentry#19897
Co-Authored-By: OpenAI Codex <noreply@openai.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.

There are 2 total unresolved issues (including 1 from previous review).

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 23b5b5e. Configure here.

Comment thread src/sentry/conf/server.py
"project:read",
"project:write",
"project:admin",
"project:codeowners",
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.

Admin/manager/owner roles missing project:create scope breaks project creation

High Severity

The project:create scope is only added to the member role, but not to admin, manager, or owner roles. Since TeamProjectPermission and OrgProjectPermission scope_maps now exclusively require project:create for POST, and session-based auth uses raw role scopes without hierarchy expansion, admin/manager/owner users can no longer create projects through either endpoint. The project:writeproject:create hierarchy expansion only applies to token scopes_upper_bound via _wrap_scopes, not to session-based access.scopes.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 23b5b5e. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 15, 2026

Backend Test Failures

Failures on d29b98c in this run:

tests/sentry/auth/test_access.py::FromRequestTest__InControlMode::test_superuser_readonly_scopeslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/auth/test_access.py:601: in test_superuser_readonly_scopes
    assert result.scopes == set(member.get_scopes()).union(SUPERUSER_READONLY_SCOPES)
E   AssertionError: assert frozenset({'a...:write', ...}) == {'alerts:read...r:admin', ...}
E     
E     Extra items in the left set:
E     'project:create'
E     'flags:write'
E     
E     Full diff:
E     - {
E     + frozenset({
E           'alerts:read',
E           'alerts:write',
E           'event:admin',
E           'event:read',
E           'event:write',
E     +     'flags:write',
E           'member:admin',
E           'member:invite',
E           'member:read',
E           'member:write',
E           'org:admin',
E           'org:integrations',
E           'org:read',
E           'org:searches',
E           'org:superuser',
E           'org:write',
E           'project:admin',
E           'project:codeowners',
E     +     'project:create',
E           'project:read',
E           'project:releases',
E           'project:write',
E           'team:admin',
E           'team:read',
E           'team:write',
E           'user:preferences',
E     - }
E     + })
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_on_role_change_called_when_role_updatedlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:893: in test_on_role_change_called_when_role_updated
    self.get_success_response(self.organization.slug, member_om.id, role="manager")
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_invite_index.py::OrganizationMemberInvitePostTest::test_rate_limitedlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_index.py:308: in test_rate_limited
    self.get_error_response(self.organization.slug, **data, status_code=429)
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 429 <= 400
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberListPostTest::test_no_teamslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:838: in test_no_teams
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_projects_experiment.py::OrganizationProjectsExperimentCreateTest::test_create_project_with_originlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_projects_experiment.py:298: in test_create_project_with_origin
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_project_autofix_tuning_defaults_to_medium_with_seat_based_tierlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:560: in test_project_autofix_tuning_defaults_to_medium_with_seat_based_tier
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py::OrganizationDashboardWidgetDetailsTestCase::test_issue_search_conditionlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py:426: in test_issue_search_condition
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_rename_dashboard_title_takenlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:980: in test_rename_dashboard_title_taken
    assert response.status_code == 409, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 409
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_layout_with_invalid_data_failslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2240: in test_update_layout_with_invalid_data_fails
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_user_in_team_with_access_can_edit_dashboardlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2825: in test_user_in_team_with_access_can_edit_dashboard
    assert response.status_code == 200, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_user_tries_to_update_dashboard_edit_permslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2861: in test_user_tries_to_update_dashboard_edit_perms
    assert response.status_code == 400
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/incidents/endpoints/test_organization_incident_details.py::OrganizationIncidentUpdateStatusTest::test_cannot_openlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/incidents/endpoints/test_organization_incident_details.py:101: in test_cannot_open
    assert resp.status_code == 400
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/incidents/endpoints/test_organization_incident_details.py::OrganizationIncidentUpdateStatusTest::test_no_featurelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/incidents/endpoints/test_organization_incident_details.py:52: in test_no_feature
    assert resp.status_code == 404
E   assert 403 == 404
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/models/test_organizationmember.py::OrganizationMemberTest::test_get_allowed_org_roles_to_invitelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/models/test_organizationmember.py:523: in test_get_allowed_org_roles_to_invite
    assert member.get_allowed_org_roles_to_invite() == [
E   assert [Organization..._global=True)] == [Organization..._global=True)]
E     
E     At index 0 diff: OrganizationRole(parent=<sentry.roles.manager.RoleManager object at 0x7fb5613f1e80>, priority=1, id='admin', name='Admin', desc="Admin privileges on any teams of which they're a member. They can create new teams and projects, as well as remove teams and projects on which they already hold membership (or all teams, if open membership is enabled). Additionally, they can manage memberships of teams that they are members of. By default, they can invite members to the organization unless the organization has disabled this feature.", scopes=frozenset({'team:admin', 'project:admin', 'team:write', 'alerts:read', 'alerts:write', 'project:read', 'event:read', 'org:read', 'org:integrations', 'project:releases', 'team:read', 'org:searches', 'member:invite', 'member:read', 'project:codeowners', 'user:preferences', 'event:admin', 'event:write', 'project:write'}), is_retired=True, is_team_roles_allowed=True, is_global=False) != OrganizationRole(parent=<sentry.roles.manager.RoleManager object at 0x7fb5613f1e80>, priority=0, id='member', name='Member', desc='Members can view and act on events, as well as view most other data within the organization. By default, they can invite members to the organization unless the organization has disabled this feature.', scopes=frozenset({'alerts:read', 'alerts:write', 'project:create', 'org:read', 'event:read', 'project:read', 'flags:write', 'project:releases', 'team:read', 'org:searches', 'member:invite', 'member:read', 'project:codeowners', 'user:preferences', 'event:admin', 'event:write'}), is_retired=False, is_team_roles_allowed=True, is_global=False)
E     Right contains one more item: OrganizationRole(parent=<sentry.roles.manager.RoleManager object at 0x7fb5613f1e80>, priority=2, id='manager', name='M...admin', 'event:write', 'project:write', 'member:write'}), is_retired=False, is_team_roles_allowed=True, is_global=True)
E     
E     Full diff:
E       [
E     -     OrganizationRole(
E     -         parent=<sentry.roles.manager.RoleManager object at 0x7fb5613f1e80>,
E     -         priority=0,
E     -         id='member',
E     -         name='Member',
E     -         desc='Members can view and act on events, as well as view most other '
E     -              'data within the organization. By default, they can invite '
E     -              'members to the organization unless the organization has disabled '
E     -              'this feature.',
E     -         scopes=frozenset({
E     -                    'alerts:read',
E     -                    'alerts:write',
E     -                    'event:admin',
E     -                    'event:read',
E     -                    'event:write',
E     -                    'flags:write',
E     -                    'member:invite',
E     -                    'member:read',
E     -                    'org:read',
E     -                    'org:searches',
E     -                    'project:codeowners',
E     -                    'project:create',
E     -                    'project:read',
E     -                    'project:releases',
E     -                    'team:read',
E     -                    'user:preferences',
E     -                }),
E     -         is_retired=False,
E     -         is_team_roles_allowed=True,
E     -         is_global=False,
E     -     ),
E           OrganizationRole(
E               parent=<sentry.roles.manager.RoleManager object at 0x7fb5613f1e80>,
E               priority=1,
E               id='admin',
E               name='Admin',
E               desc="Admin privileges on any teams of which they're a member. They "
E                    'can create new teams and projects, as well as remove teams and '
E                    'projects on which they already hold membership (or all teams, if '
E                    'open membership is enabled). Additionally, they can manage '
... (64 more lines)
tests/sentry/api/endpoints/test_project_repo_path_parsing.py::ProjectStacktraceLinkGithubTest::test_member_can_accesslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_project_repo_path_parsing.py:308: in test_member_can_access
    assert resp.status_code == 200, resp.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/auth/test_access.py::FromRequestTest__InCellMode::test_superuser_readonly_scopeslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/auth/test_access.py:601: in test_superuser_readonly_scopes
    assert result.scopes == set(member.get_scopes()).union(SUPERUSER_READONLY_SCOPES)
E   AssertionError: assert frozenset({'a...:write', ...}) == {'alerts:read...r:admin', ...}
E     
E     Extra items in the left set:
E     'project:create'
E     'flags:write'
E     
E     Full diff:
E     - {
E     + frozenset({
E           'alerts:read',
E           'alerts:write',
E           'event:admin',
E           'event:read',
E           'event:write',
E     +     'flags:write',
E           'member:admin',
E           'member:invite',
E           'member:read',
E           'member:write',
E           'org:admin',
E           'org:integrations',
E           'org:read',
E           'org:searches',
E           'org:superuser',
E           'org:write',
E           'project:admin',
E           'project:codeowners',
E     +     'project:create',
E           'project:read',
E           'project:releases',
E           'project:write',
E           'team:admin',
E           'team:read',
E           'team:write',
E           'user:preferences',
E     - }
E     + })
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberListTest::test_valid_for_inviteslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:441: in test_valid_for_invites
    self.get_success_response(self.organization.slug, method="post", **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_invite_index.py::OrganizationMemberInvitePostTest::test_referrer_paramlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_index.py:240: in test_referrer_param
    response = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_builtin_symbol_sources_unreallog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:450: in test_builtin_symbol_sources_unreal
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_console_platform_not_enabledlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:615: in test_console_platform_not_enabled
    response = self.get_error_response(
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 401
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_big_number_widget_with_equationlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1199: in test_add_big_number_widget_with_equation
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_simplelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:65: in test_simple
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_invalid_intervallog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1631: in test_add_widget_invalid_interval
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_with_invalid_limit_below_minimumlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1508: in test_add_widget_with_invalid_limit_below_minimum
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_change_dashboard_titlelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:968: in test_change_dashboard_title
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_dashboard_with_all_projectslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2609: in test_update_dashboard_with_all_projects
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTransactionLikeTest::test_ondemand_with_flagslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4135: in test_ondemand_with_flags
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/flags/endpoints/test_secrets.py::OrganizationFlagsWebHookSigningSecretsEndpointTestCase::test_post_launchdarklylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/flags/endpoints/test_secrets.py:58: in test_post_launchdarkly
    assert response.status_code == 201, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/integrations/api/endpoints/test_organization_code_mapping_details.py::OrganizationCodeMappingDetailsTest::test_basic_edit_from_member_permissionslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/integrations/api/endpoints/test_organization_code_mapping_details.py:103: in test_basic_edit_from_member_permissions
    assert resp.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/snuba/api/endpoints/test_discover_key_transactions.py::TeamKeyTransactionTest::test_delete_key_transaction_no_access_teamlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/snuba/api/endpoints/test_discover_key_transactions.py:615: in test_delete_key_transaction_no_access_team
    assert response.status_code == 400, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_can_update_to_retired_role_without_flaglog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:697: in test_can_update_to_retired_role_without_flag
    self.get_success_response(self.organization.slug, member_om.id, role="admin")
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsDeleteTest::test_allow_delete_all_projects_dashboard_when_no_open_membershiplog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:747: in test_allow_delete_all_projects_dashboard_when_no_open_membership
    assert response.status_code == 204
E   assert 403 == 204
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_issue_widget_valid_querylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2425: in test_add_issue_widget_valid_query
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_text_widget_without_feature_flaglog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3948: in test_add_text_widget_without_feature_flag
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_e2e_test_with_translationlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1663: in test_add_widget_e2e_test_with_translation
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_with_field_aliaseslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1132: in test_add_widget_with_field_aliases
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_add_widget_with_selected_aggregatelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1166: in test_add_widget_with_selected_aggregate
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_save_widget_with_custom_measurement_in_equation_line_chartlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3170: in test_save_widget_with_custom_measurement_in_equation_line_chart
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_with_unapplicable_querylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4097: in test_ondemand_with_unapplicable_query
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_details.py::UpdateOrganizationMemberTest::test_cannot_lower_superior_rolelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_details.py:736: in test_cannot_lower_superior_role
    self.get_error_response(self.organization.slug, owner_om.id, role="member", status_code=403)
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 403 <= 400
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberListTest::test_invalid_user_for_direct_addlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:520: in test_invalid_user_for_direct_add
    self.get_success_response(self.organization.slug, method="post", **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_index.py::OrganizationMemberListTest::test_owner_inviteslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_index.py:435: in test_owner_invites
    response = self.get_success_response(self.organization.slug, method="post", **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_invite_details.py::UpdateOrganizationMemberInviteTest::test_approve_invitelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_details.py:210: in test_approve_invite
    self.get_success_response(self.organization.slug, self.invite_request.id, approve=True)
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 201
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_member_invite_index.py::OrganizationMemberInvitePostTest::test_no_teamslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_member_invite_index.py:229: in test_no_teams
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=400, "application/json">
E   assert 400 < 300
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_projects_experiment.py::OrganizationProjectsExperimentCreateTest::test_without_default_ruleslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_projects_experiment.py:165: in test_without_default_rules
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_cannot_edit_prebuilt_insights_dashboard_widgetslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3871: in test_cannot_edit_prebuilt_insights_dashboard_widgets
    assert response.status_code == 409
E   assert 403 == 409
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_migrated_spans_widget_reset_changed_reasonlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2157: in test_update_migrated_spans_widget_reset_changed_reason
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_prebuilt_dashboardlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2313: in test_update_prebuilt_dashboard
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_with_field_linkslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3462: in test_update_widget_with_field_links
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/flags/endpoints/test_secrets.py::OrganizationFlagsWebHookSigningSecretsEndpointTestCase::test_post_genericlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/flags/endpoints/test_secrets.py:70: in test_post_generic
    assert response.status_code == 201, response.content
E   AssertionError: b'{"detail":"You do not have permission to perform this action."}'
E   assert 403 == 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/api/endpoints/test_organization_api_key_details.py::OrganizationApiKeyDetailsPut::test_update_api_key_details_legacy_datalog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_organization_api_key_details.py:89: in test_update_api_key_details_legacy_data
    assert api_key.get_scopes() == ["org:read", "project:read", "project:write", "team:read"]
E   AssertionError: assert ['org:read', ..., 'team:read'] == ['org:read', ..., 'team:read']
E     
E     At index 1 diff: 'project:codeowners' != 'project:read'
E     Left contains 2 more items, first extra item: 'project:write'
E     
E     Full diff:
E       [
E           'org:read',
E     +     'project:codeowners',
E     +     'project:create',
E           'project:read',
E           'project:write',
E           'team:read',
E       ]
tests/sentry/api/endpoints/test_organization_auth_token_details.py::OrganizationAuthTokenDetailsPermissionTest::test_member_can_putlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_organization_auth_token_details.py:437: in test_member_can_put
    self.assert_member_can_access(
src/sentry/testutils/cases.py:881: in assert_member_can_access
    return self.assert_role_can_access(path, "member", **kwargs)
src/sentry/testutils/cases.py:905: in assert_role_can_access
    return self.assert_can_access(user, path, **kwargs)
src/sentry/testutils/cases.py:872: in assert_can_access
    assert resp.status_code >= 200 and resp.status_code < 300
E   assert (403 >= 200 and 403 < 300)
E    +  where 403 = <Response status_code=403, "application/json">.status_code
E    +  and   403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_projects_experiment.py::OrganizationProjectsExperimentCreateTest::test_consecutive_reqs_adds_team_suffixlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_organization_projects_experiment.py:177: in test_consecutive_reqs_adds_team_suffix
    resp1 = self.get_success_response(self.organization.slug, name=self.p1, status_code=201)
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_disable_member_project_creationlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:198: in test_disable_member_project_creation
    self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 202
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_dashboard_widget_missing_columns_can_successfully_savelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3260: in test_dashboard_widget_missing_columns_can_successfully_save
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_prebuilt_dashboard_with_transactions_deprecation_feature_flaglog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2349: in test_update_prebuilt_dashboard_with_transactions_deprecation_feature_flag
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_invalid_orderbylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:1869: in test_update_widget_invalid_orderby
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_hits_card_limitlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4220: in test_ondemand_hits_card_limit
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTransactionLikeTest::test_ondemand_without_flagslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4059: in test_ondemand_without_flags
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/api/endpoints/test_organization_invite_request_details.py::OrganizationInviteRequestApproveTest::test_can_approve_join_request_with_enabled_settinglog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/api/endpoints/test_organization_invite_request_details.py:249: in test_can_approve_join_request_with_enabled_setting
    assert resp.status_code == 200
E   assert 400 == 200
E    +  where 400 = <Response status_code=400, "application/json">.status_code
tests/sentry/core/endpoints/test_team_projects.py::TeamProjectsCreateTest::test_invalid_platformlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/core/endpoints/test_team_projects.py:104: in test_invalid_platform
    response = self.get_error_response(
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:46: in assert_status_code
    assert minimum <= response.status_code < maximum, response
E   AssertionError: <Response status_code=403, "application/json">
E   assert 403 < 401
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsDeleteTest::test_delete_permissionlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:707: in test_delete_permission
    self.test_delete()
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:695: in test_delete
    assert response.status_code == 204
E   assert 403 == 204
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_can_edit_prebuilt_insights_dashboard_global_filterslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3906: in test_can_edit_prebuilt_insights_dashboard_global_filters
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py::OrganizationDashboardWidgetDetailsTestCase::test_valid_widget_permissionslog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py:67: in test_valid_widget_permissions
    self.test_valid_widget()
tests/sentry/dashboards/endpoints/test_organization_dashboard_widget_details.py:63: in test_valid_widget
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_dashboard_exisiting_transaction_widget_deprecation_with_flaglog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:3344: in test_dashboard_exisiting_transaction_widget_deprecation_with_flag
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_text_widget_errors_provided_querieslog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4010: in test_text_widget_errors_provided_queries
    assert response.status_code == 400, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 400
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsPutTest::test_update_widget_with_axis_rangelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:2050: in test_update_widget_with_axis_range
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_feature_check_takes_precedence_over_cardinalitylog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4491: in test_feature_check_takes_precedence_over_cardinality
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_hits_spec_limitlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4174: in test_ondemand_hits_spec_limit
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py::OrganizationDashboardDetailsOnDemandTest::test_ondemand_updates_new_widgetlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py:4355: in test_ondemand_updates_new_widget
    assert response.status_code == 200, response.data
E   AssertionError: {'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
E   assert 403 == 200
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/integrations/api/endpoints/test_organization_repositories.py::OrganizationRepositoriesCreateTest::test_member_oklog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/integrations/api/endpoints/test_organization_repositories.py:371: in test_member_ok
    assert response.status_code == 201, (response.status_code, response.content)
E   AssertionError: (403, b'{"detail":"You do not have permission to perform this action."}')
E   assert 403 == 201
E    +  where 403 = <Response status_code=403, "application/json">.status_code
tests/sentry/auth/test_access.py::FromUserTest::test_enforce_upper_bound_scopelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/auth/test_access.py:497: in test_enforce_upper_bound_scope
    assert not result.has_team_scope(team, "team:write")
E   AssertionError: assert not True
E    +  where True = <bound method DbAccess.has_team_scope of OrganizationMemberAccess(sso_is_valid=True, requires_sso=False, has_open_memb...OrganizationMember at 0x7f7e4b6184b0: id=66, organization_id=4557974112108576, user_id=93, email=None, role='member'>)>(<Team at 0x7f7e4c050410: id=4557974112108576, name='Stirring Elephant', slug='stirring-elephant'>, 'team:write')
E    +    where <bound method DbAccess.has_team_scope of OrganizationMemberAccess(sso_is_valid=True, requires_sso=False, has_open_memb...OrganizationMember at 0x7f7e4b6184b0: id=66, organization_id=4557974112108576, user_id=93, email=None, role='member'>)> = OrganizationMemberAccess(sso_is_valid=True, requires_sso=False, has_open_membership=False, has_global_access=True, sco...<OrganizationMember at 0x7f7e4b6184b0: id=66, organization_id=4557974112108576, user_id=93, email=None, role='member'>).has_team_scope
tests/sentry/core/endpoints/test_organization_projects_experiment.py::OrganizationProjectsExperimentCreateTest::test_disable_member_project_creation

"GET": ["org:read", "org:write", "org:admin", "org:integrations", "org:ci"],
"POST": ["org:read", "org:write", "org:admin", "org:integrations"],
"PUT": ["org:read", "org:write", "org:admin", "org:integrations"],
"POST": ["org:write", "org:admin", "org:integrations"],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

unless I missed it, but this is going to restrict code mappings creation only to admins/owners. We might want to introduce a new scope org:codemappings or something like that

@dcramer
Copy link
Copy Markdown
Member Author

dcramer commented Apr 15, 2026

fyi i will dig through any feedback here but i broke this up into 4 somewhat-smaller changes (they're a little tightly coupled so its tough)

@dcramer dcramer closed this Apr 15, 2026
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