Skip to content

Commit 1d154a0

Browse files
authored
ref(prevent): Use prevent seer url (#101186)
- Also make seer requests with connection pool
1 parent dbc1615 commit 1d154a0

File tree

2 files changed

+81
-29
lines changed

2 files changed

+81
-29
lines changed

src/sentry/prevent/endpoints/organization_github_repos.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from collections import defaultdict
33

44
import orjson
5-
import requests
65
from django.conf import settings
76
from rest_framework.request import Request
87
from rest_framework.response import Response
@@ -16,10 +15,18 @@
1615
from sentry.integrations.types import IntegrationProviderSlug
1716
from sentry.models.organization import Organization
1817
from sentry.models.repository import Repository
19-
from sentry.seer.signed_seer_api import sign_with_seer_secret
18+
from sentry.net.http import connection_from_url
19+
from sentry.seer.signed_seer_api import make_signed_seer_api_request
2020

2121
logger = logging.getLogger(__name__)
2222

23+
PREVENT_AI_CONNECTION_POOL = connection_from_url(
24+
settings.SEER_PREVENT_AI_URL,
25+
maxsize=3,
26+
)
27+
28+
SEER_PREVENT_AI_TIMEOUT = 30
29+
2330

2431
@region_silo_endpoint
2532
class OrganizationPreventGitHubReposEndpoint(OrganizationEndpoint):
@@ -48,15 +55,19 @@ def _fetch_seer_integrated_repos(self, organization_names: list[str]) -> dict[st
4855
}
4956
)
5057

51-
response = requests.post(
52-
f"{settings.SEER_AUTOFIX_URL}{path}",
53-
data=body,
54-
headers={
55-
"content-type": "application/json;charset=utf-8",
56-
**sign_with_seer_secret(body),
57-
},
58+
response = make_signed_seer_api_request(
59+
connection_pool=PREVENT_AI_CONNECTION_POOL,
60+
path=path,
61+
body=body,
62+
timeout=SEER_PREVENT_AI_TIMEOUT,
5863
)
59-
response.raise_for_status()
64+
65+
if response.status >= 400:
66+
logger.warning(
67+
"Failed to fetch integrated repos from Seer",
68+
extra={"status": response.status, "organization_names": organization_names},
69+
)
70+
return {}
6071

6172
return response.json().get("integrated_repos", {})
6273

tests/sentry/prevent/endpoints/test_organization_github_repos.py

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ def test_get_prevent_github_repos_empty(self):
2222

2323
assert response.data == {"orgRepos": []}
2424

25-
@patch("sentry.prevent.endpoints.organization_github_repos.requests.post")
26-
def test_get_prevent_github_repos_with_integration(self, mock_requests_post):
25+
@patch("sentry.prevent.endpoints.organization_github_repos.make_signed_seer_api_request")
26+
def test_get_prevent_github_repos_with_integration(self, mock_make_seer_request):
2727
"""Test that the endpoint returns GitHub org data when integrations exist"""
2828
self.login_as(user=self.user)
2929

3030
# Mock the Seer API response (empty response since we're just testing Sentry integration)
3131
mock_response = Mock()
32-
mock_response.raise_for_status.return_value = None
32+
mock_response.status = 200
3333
mock_response.json.return_value = {"integrated_repos": {}}
34-
mock_requests_post.return_value = mock_response
34+
mock_make_seer_request.return_value = mock_response
3535

3636
# Create a GitHub integration
3737
integration = self.create_integration(
@@ -74,8 +74,8 @@ def test_get_prevent_github_repos_with_integration(self, mock_requests_post):
7474
assert repo_data["hasGhAppSeerBySentry"] is False
7575
assert "id" not in repo_data # Verify id is not in response
7676

77-
@patch("sentry.prevent.endpoints.organization_github_repos.requests.post")
78-
def test_get_prevent_github_repos_with_seer_integration(self, mock_requests_post):
77+
@patch("sentry.prevent.endpoints.organization_github_repos.make_signed_seer_api_request")
78+
def test_get_prevent_github_repos_with_seer_integration(self, mock_make_seer_request):
7979
"""Test that repos from both Sentry and Seer are merged correctly"""
8080
self.login_as(user=self.user)
8181

@@ -104,7 +104,7 @@ def test_get_prevent_github_repos_with_seer_integration(self, mock_requests_post
104104

105105
# Mock the Seer API response
106106
mock_response = Mock()
107-
mock_response.raise_for_status.return_value = None
107+
mock_response.status = 200
108108
mock_response.json.return_value = {
109109
"integrated_repos": {
110110
"test-org": [
@@ -113,7 +113,7 @@ def test_get_prevent_github_repos_with_seer_integration(self, mock_requests_post
113113
]
114114
}
115115
}
116-
mock_requests_post.return_value = mock_response
116+
mock_make_seer_request.return_value = mock_response
117117

118118
response = self.get_success_response(self.organization.slug)
119119

@@ -139,23 +139,23 @@ def test_get_prevent_github_repos_with_seer_integration(self, mock_requests_post
139139
assert seer_only_repo_data["hasGhAppSeerBySentry"] is True
140140

141141
# Verify the Seer API was called correctly
142-
mock_requests_post.assert_called_once()
143-
call_args = mock_requests_post.call_args
142+
mock_make_seer_request.assert_called_once()
143+
call_args = mock_make_seer_request.call_args
144144

145-
request_body = orjson.loads(call_args[1]["data"])
145+
request_body = orjson.loads(call_args[1]["body"])
146146
assert request_body["organization_names"] == ["test-org"]
147147
assert request_body["provider"] == "github"
148148

149-
@patch("sentry.prevent.endpoints.organization_github_repos.requests.post")
150-
def test_get_prevent_github_repos_multiple_orgs(self, mock_requests_post):
149+
@patch("sentry.prevent.endpoints.organization_github_repos.make_signed_seer_api_request")
150+
def test_get_prevent_github_repos_multiple_orgs(self, mock_make_seer_request):
151151
"""Test that multiple GitHub orgs are handled"""
152152
self.login_as(user=self.user)
153153

154154
# Mock empty Seer response
155155
mock_response = Mock()
156-
mock_response.raise_for_status.return_value = None
156+
mock_response.status = 200
157157
mock_response.json.return_value = {"integrated_repos": {}}
158-
mock_requests_post.return_value = mock_response
158+
mock_make_seer_request.return_value = mock_response
159159

160160
# Create two GitHub integrations
161161
integration1 = self.create_integration(
@@ -209,16 +209,16 @@ def test_get_prevent_github_repos_multiple_orgs(self, mock_requests_post):
209209
assert len(orgs_by_name["github-org-2"]["repos"]) == 1
210210
assert orgs_by_name["github-org-2"]["repos"][0]["name"] == "repo2"
211211

212-
@patch("sentry.prevent.endpoints.organization_github_repos.requests.post")
213-
def test_get_prevent_github_repos_multiple_repos_same_org(self, mock_requests_post):
212+
@patch("sentry.prevent.endpoints.organization_github_repos.make_signed_seer_api_request")
213+
def test_get_prevent_github_repos_multiple_repos_same_org(self, mock_make_seer_request):
214214
"""Test that multiple repositories for the same GitHub organization are all returned"""
215215
self.login_as(user=self.user)
216216

217217
# Mock empty Seer response
218218
mock_response = Mock()
219-
mock_response.raise_for_status.return_value = None
219+
mock_response.status = 200
220220
mock_response.json.return_value = {"integrated_repos": {}}
221-
mock_requests_post.return_value = mock_response
221+
mock_make_seer_request.return_value = mock_response
222222

223223
# Create one GitHub integration
224224
integration = self.create_integration(
@@ -268,3 +268,44 @@ def test_get_prevent_github_repos_multiple_repos_same_org(self, mock_requests_po
268268
# Verify all three repos are present
269269
repo_names = {repo["name"] for repo in github_org["repos"]}
270270
assert repo_names == {"repo1", "repo2", "repo3"}
271+
272+
@patch("sentry.prevent.endpoints.organization_github_repos.make_signed_seer_api_request")
273+
def test_get_prevent_github_repos_seer_error(self, mock_make_seer_request):
274+
"""Test that the endpoint gracefully handles Seer API errors"""
275+
self.login_as(user=self.user)
276+
277+
# Mock Seer API returning an error
278+
mock_response = Mock()
279+
mock_response.status = 500
280+
mock_make_seer_request.return_value = mock_response
281+
282+
# Create a GitHub integration and repo
283+
integration = self.create_integration(
284+
organization=self.organization,
285+
provider="github",
286+
name="test-github-org",
287+
external_id="123456",
288+
metadata={"account_id": "987654"},
289+
)
290+
291+
project = self.create_project(organization=self.organization)
292+
self.create_repo(
293+
project=project,
294+
name="test-github-org/test-repo",
295+
provider="integrations:github",
296+
integration_id=integration.id,
297+
external_id="111222",
298+
)
299+
300+
# Should still return Sentry repos even if Seer fails
301+
response = self.get_success_response(self.organization.slug)
302+
303+
assert len(response.data["orgRepos"]) == 1
304+
github_org = response.data["orgRepos"][0]
305+
assert github_org["name"] == "test-github-org"
306+
assert len(github_org["repos"]) == 1
307+
308+
repo_data = github_org["repos"][0]
309+
assert repo_data["name"] == "test-repo"
310+
assert repo_data["hasGhAppSentryIo"] is True
311+
assert repo_data["hasGhAppSeerBySentry"] is False

0 commit comments

Comments
 (0)