Browse Source

feat(secrecy): enable data secrecy for organizations (#53322)

Cathy Teng 1 year ago
parent
commit
8891bb5ba1

+ 2 - 0
.github/CODEOWNERS

@@ -347,6 +347,8 @@ yarn.lock                                                @getsentry/owners-js-de
 /static/app/views/settings/organizationAuth/          @getsentry/enterprise
 /tests/sentry/api/endpoints/test_auth*.py             @getsentry/enterprise
 
+/tests/sentry/api/test_data_secrecy.py                @getsentry/enterprise
+
 /src/sentry/scim/                                     @getsentry/enterprise
 /tests/sentry/api/test_scim*.py                       @getsentry/enterprise
 /src/sentry/tasks/integrations/github/pr_comment.py   @getsentry/enterprise @AniketDas-Tekky

+ 5 - 0
src/sentry/api/exceptions.py

@@ -85,6 +85,11 @@ class SuperuserRequired(SentryAPIException):
     message = "You need to re-authenticate for superuser."
 
 
+class DataSecrecyError(SentryAPIException):
+    status_code = status.HTTP_401_UNAUTHORIZED
+    code = "data-secrecy"
+
+
 class SudoRequired(SentryAPIException):
     status_code = status.HTTP_401_UNAUTHORIZED
     code = "sudo-required"

+ 9 - 0
src/sentry/api/permissions.py

@@ -5,7 +5,9 @@ from typing import TYPE_CHECKING, Any, Sequence
 from rest_framework import permissions
 from rest_framework.request import Request
 
+from sentry import features
 from sentry.api.exceptions import (
+    DataSecrecyError,
     MemberDisabledOverLimit,
     SsoRequired,
     SuperuserRequired,
@@ -122,6 +124,13 @@ class SentryPermission(ScopedPermission):
         if org_context is None:
             assert False, "Failed to fetch organization in determine_access"
 
+        if (
+            request.user
+            and request.user.is_superuser
+            and features.has("organizations:enterprise-data-secrecy", org_context.organization)
+        ):
+            raise DataSecrecyError()
+
         if request.auth and request.user and request.user.is_authenticated:
             request.access = access.from_request_org_and_scopes(
                 request=request,

+ 2 - 0
src/sentry/conf/server.py

@@ -1364,6 +1364,8 @@ SENTRY_FEATURES = {
     "organizations:discover-basic": True,
     # Enable discover 2 custom queries and saved queries
     "organizations:discover-query": True,
+    # Enables data secrecy mode
+    "organizations:enterprise-data-secrecy": False,
     # Enable archive/escalating issue workflow
     "organizations:escalating-issues": False,
     # Enable archive/escalating issue workflow in MS Teams

+ 1 - 0
src/sentry/features/__init__.py

@@ -77,6 +77,7 @@ default_manager.add("organizations:dashboards-rh-widget", OrganizationFeature, F
 default_manager.add("organizations:dashboards-import", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
 default_manager.add("organizations:discover", OrganizationFeature, FeatureHandlerStrategy.INTERNAL)
 default_manager.add("organizations:discover-events-rate-limit", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
+default_manager.add("organizations:enterprise-data-secrecy", OrganizationFeature, FeatureHandlerStrategy.INTERNAL)
 default_manager.add("organizations:grouping-stacktrace-ui", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
 default_manager.add("organizations:grouping-title-ui", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
 default_manager.add("organizations:grouping-tree-ui", OrganizationFeature, FeatureHandlerStrategy.REMOTE)

+ 36 - 0
tests/sentry/api/test_data_secrecy.py

@@ -0,0 +1,36 @@
+from sentry.testutils import APITestCase
+from sentry.testutils.helpers.features import with_feature
+
+
+class SuperuserDataSecrecyTestCase(APITestCase):
+    endpoint = "sentry-api-0-organization-details"
+    method = "get"
+
+    def setUp(self):
+        super().setUp()
+        self.login_as(self.user)
+
+    @with_feature("organizations:enterprise-data-secrecy")
+    def test_superuser_no_access(self):
+        """
+        Please contact the Enterprise team if your code change causes this test to fail
+        """
+        superuser = self.create_user(is_superuser=True)
+        self.login_as(superuser, superuser=True)
+
+        # superuser cannot access orgs with data secrecy
+        self.get_error_response(self.organization.slug, status_code=401)
+
+    def test_superuser_has_access(self):
+        superuser = self.create_user(is_superuser=True)
+        self.login_as(superuser, superuser=True)
+
+        # superuser can access orgs without data secrecy
+        self.get_success_response(self.organization.slug)
+
+    def test_non_member_no_access(self):
+        self.login_as(self.create_user())
+        self.get_error_response(self.organization.slug, status_code=403)
+
+    def test_member_has_access(self):
+        self.get_success_response(self.organization.slug)