diff --git a/src/sentry/auth/access.py b/src/sentry/auth/access.py index d7b17713d34aa1..0bcc0c769c3d29 100644 --- a/src/sentry/auth/access.py +++ b/src/sentry/auth/access.py @@ -901,6 +901,10 @@ def from_request_org_and_scopes( rpc_user_org_context: RpcUserOrganizationContext | None = None, scopes: Iterable[str] | None = None, ) -> Access: + """ + Note that `scopes` is usually None because request.auth is not set at `get_authorization_header` + when the request is made from the frontend using cookies + """ is_superuser = is_active_superuser(request) is_staff = is_active_staff(request) @@ -929,6 +933,8 @@ def from_request_org_and_scopes( superuser_scopes = get_superuser_scopes(auth_state, request.user, rpc_user_org_context) if scopes: superuser_scopes = superuser_scopes.union(set(scopes)) + if member and member.scopes: + superuser_scopes = superuser_scopes.union(set(member.scopes)) return ApiBackedOrganizationGlobalAccess( rpc_user_organization_context=rpc_user_org_context, @@ -1033,6 +1039,8 @@ def from_request( superuser_scopes = get_superuser_scopes(auth_state, request.user, organization) if scopes: superuser_scopes = superuser_scopes.union(set(scopes)) + if member and (member_scopes := member.get_scopes()): + superuser_scopes = superuser_scopes.union(set(member_scopes)) return OrganizationGlobalAccess( organization=organization, diff --git a/tests/sentry/auth/test_access.py b/tests/sentry/auth/test_access.py index 65078da07faeec..277be5c8f6e2b6 100644 --- a/tests/sentry/auth/test_access.py +++ b/tests/sentry/auth/test_access.py @@ -587,15 +587,17 @@ def test_superuser_readonly_scopes(self): # superuser in organization member = self.create_member(user=self.superuser, organization=self.org, role="member") + # If superuser is a member of the organization, it should have both + # the member scopes and the superuser scopes result = self.from_request(request, self.org) - assert result.scopes == SUPERUSER_READONLY_SCOPES + assert result.scopes == set(member.get_scopes()).union(SUPERUSER_READONLY_SCOPES) # readonly scopes does not override owner scopes if passed in with assume_test_silo_mode(SiloMode.REGION): member.update(role="owner") result = self.from_request(request, self.org, scopes=member.get_scopes()) - assert result.scopes == set(member.get_scopes()).union({"org:superuser"}) + assert result.scopes == set(member.get_scopes()).union(SUPERUSER_READONLY_SCOPES) @override_options({"superuser.read-write.ga-rollout": True}) @override_settings(SENTRY_SELF_HOSTED=False)