From 4bcfcbb1253066351d954f6d36c645151c693973 Mon Sep 17 00:00:00 2001 From: Rohan Agarwal Date: Wed, 8 Oct 2025 11:01:44 -0700 Subject: [PATCH] Restrict explorer to orgs with open membership --- .../organization_seer_explorer_chat.py | 14 ++++++++ .../test_organization_seer_explorer_chat.py | 33 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/sentry/seer/endpoints/organization_seer_explorer_chat.py b/src/sentry/seer/endpoints/organization_seer_explorer_chat.py index ad232fcff63b0b..4d218264d8dd10 100644 --- a/src/sentry/seer/endpoints/organization_seer_explorer_chat.py +++ b/src/sentry/seer/endpoints/organization_seer_explorer_chat.py @@ -152,6 +152,13 @@ def get( return Response( {"detail": "Seer has not been acknowledged by the organization."}, status=403 ) + if not organization.flags.allow_joinleave: + return Response( + { + "detail": "Organization does not have open team membership enabled. Seer requires this to aggregate context across all projects and allow members to ask questions freely." + }, + status=403, + ) if not run_id: return Response({"session": None}, status=404) @@ -186,6 +193,13 @@ def post( return Response( {"detail": "Seer has not been acknowledged by the organization."}, status=403 ) + if not organization.flags.allow_joinleave: + return Response( + { + "detail": "Organization does not have open team membership enabled. Seer requires this to aggregate context across all projects and allow members to ask questions freely." + }, + status=403, + ) serializer = SeerExplorerChatSerializer(data=request.data) if not serializer.is_valid(): diff --git a/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py b/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py index ab21aa88a59041..f2ee2f3d90d056 100644 --- a/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py +++ b/tests/sentry/seer/endpoints/test_organization_seer_explorer_chat.py @@ -167,6 +167,39 @@ def test_post_without_acknowledgement_returns_403( assert response.data == {"detail": "Seer has not been acknowledged by the organization."} mock_get_seer_org_acknowledgement.assert_called_once_with(self.organization.id) + def test_post_without_open_team_membership_returns_403(self) -> None: + self.organization.flags.allow_joinleave = False + self.organization.save() + + with patch( + "sentry.seer.endpoints.organization_seer_explorer_chat.get_seer_org_acknowledgement", + return_value=True, + ): + data = {"query": "Test query"} + response = self.client.post(self.url, data, format="json") + + assert response.status_code == 403 + assert ( + response.data["detail"] + == "Organization does not have open team membership enabled. Seer requires this to aggregate context across all projects and allow members to ask questions freely." + ) + + def test_get_without_open_team_membership_returns_403(self) -> None: + self.organization.flags.allow_joinleave = False + self.organization.save() + + with patch( + "sentry.seer.endpoints.organization_seer_explorer_chat.get_seer_org_acknowledgement", + return_value=True, + ): + response = self.client.get(f"{self.url}123/") + + assert response.status_code == 403 + assert ( + response.data["detail"] + == "Organization does not have open team membership enabled. Seer requires this to aggregate context across all projects and allow members to ask questions freely." + ) + class OrganizationSeerExplorerChatEndpointFeatureFlagTest(APITestCase): """Test feature flag requirements separately without the decorator"""