33from typing import Any
44from unittest import mock
55
6- import jwt as pyjwt
76import responses
87
98from sentry .integrations .bitbucket .installed import BitbucketInstalledEndpoint
109from sentry .integrations .bitbucket .integration import BitbucketIntegrationProvider , scopes
1110from sentry .integrations .models .integration import Integration
12- from sentry .integrations .utils .atlassian_connect import get_query_hash
1311from sentry .models .project import Project
1412from sentry .models .repository import Repository
1513from sentry .organizations .services .organization .serial import serialize_rpc_organization
1816from sentry .silo .base import SiloMode
1917from sentry .testutils .cases import APITestCase
2018from sentry .testutils .silo import assume_test_silo_mode , control_silo_test
21- from sentry .utils .http import absolute_uri
22- from tests .sentry .utils .test_jwt import RS256_KEY , RS256_PUB_KEY
2319
2420
2521class BitbucketPlugin (IssueTrackingPlugin2 ):
@@ -33,7 +29,6 @@ class BitbucketInstalledEndpointTest(APITestCase):
3329 def setUp (self ) -> None :
3430 self .provider = "bitbucket"
3531 self .path = "/extensions/bitbucket/installed/"
36- self .kid = "bitbucket-kid"
3732 self .username = "sentryuser"
3833 self .client_key = "connection:123"
3934 self .public_key = "123abcDEFg"
@@ -103,118 +98,27 @@ def tearDown(self) -> None:
10398 plugins .unregister (BitbucketPlugin )
10499 super ().tearDown ()
105100
106- def jwt_token_cdn (self ) -> str :
107- return pyjwt .encode (
108- {
109- "iss" : self .client_key ,
110- "aud" : absolute_uri (),
111- "qsh" : get_query_hash (self .path , method = "POST" , query_params = {}),
112- },
113- RS256_KEY ,
114- algorithm = "RS256" ,
115- headers = {"kid" : self .kid , "alg" : "RS256" },
116- )
117-
118- def add_cdn_response (self ) -> None :
119- responses .add (
120- responses .GET ,
121- f"https://connect-install-keys.atlassian.com/{ self .kid } " ,
122- body = RS256_PUB_KEY ,
123- )
124-
125101 def test_default_permissions (self ) -> None :
126102 # Permissions must be empty so that it will be accessible to bitbucket.
127103 assert BitbucketInstalledEndpoint .authentication_classes == ()
128104 assert BitbucketInstalledEndpoint .permission_classes == ()
129105
130- def test_missing_token (self ) -> None :
131- response = self .client .post (self .path , data = self .team_data_from_bitbucket )
132- assert response .status_code == 400
133-
134- def test_invalid_token (self ) -> None :
135- response = self .client .post (
136- self .path ,
137- data = self .team_data_from_bitbucket ,
138- HTTP_AUTHORIZATION = "invalid" ,
139- )
140- assert response .status_code == 400
141-
142- @responses .activate
143- def test_missing_key_id (self ) -> None :
144- token = pyjwt .encode (
145- {
146- "iss" : self .client_key ,
147- "aud" : absolute_uri (),
148- "qsh" : get_query_hash (self .path , method = "POST" , query_params = {}),
149- },
150- RS256_KEY ,
151- algorithm = "RS256" ,
152- headers = {"alg" : "RS256" },
153- )
154- response = self .client .post (
155- self .path ,
156- data = self .team_data_from_bitbucket ,
157- HTTP_AUTHORIZATION = f"JWT { token } " ,
158- )
159- assert response .status_code == 400
160-
161- @responses .activate
162- def test_invalid_key_id (self ) -> None :
163- token = pyjwt .encode (
164- {
165- "iss" : self .client_key ,
166- "aud" : absolute_uri (),
167- "qsh" : get_query_hash (self .path , method = "POST" , query_params = {}),
168- },
169- RS256_KEY ,
170- algorithm = "RS256" ,
171- headers = {"kid" : "fake-kid" , "alg" : "RS256" },
172- )
173- response = self .client .post (
174- self .path ,
175- data = self .team_data_from_bitbucket ,
176- HTTP_AUTHORIZATION = f"JWT { token } " ,
177- )
178- assert response .status_code == 400
179-
180- @responses .activate
181- def test_jwt_issuer_mismatch (self ) -> None :
182- self .add_cdn_response ()
183- response = self .client .post (
184- self .path ,
185- data = {** self .team_data_from_bitbucket , "clientKey" : "different-client-key" },
186- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
187- )
188- assert response .status_code == 400
189-
190- @responses .activate
191106 def test_installed_with_public_key (self ) -> None :
192- self .add_cdn_response ()
193- response = self .client .post (
194- self .path ,
195- data = self .team_data_from_bitbucket ,
196- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
197- )
107+ response = self .client .post (self .path , data = self .team_data_from_bitbucket )
198108 assert response .status_code == 200
199109 integration = Integration .objects .get (provider = self .provider , external_id = self .client_key )
200110 assert integration .name == self .username
201111 del integration .metadata ["webhook_secret" ]
202112 assert integration .metadata == self .metadata
203113
204- @responses .activate
205114 def test_installed_without_public_key (self ) -> None :
206115 integration , created = Integration .objects .get_or_create (
207116 provider = self .provider ,
208117 external_id = self .client_key ,
209118 defaults = {"name" : self .user_display_name , "metadata" : self .user_metadata },
210119 )
211120 del self .user_data_from_bitbucket ["principal" ]["username" ]
212- self .add_cdn_response ()
213- response = self .client .post (
214- self .path ,
215- data = self .user_data_from_bitbucket ,
216- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
217- )
121+ response = self .client .post (self .path , data = self .user_data_from_bitbucket )
218122 assert response .status_code == 200
219123
220124 # assert no changes have been made to the integration
@@ -225,34 +129,22 @@ def test_installed_without_public_key(self) -> None:
225129 del integration_after .metadata ["webhook_secret" ]
226130 assert integration .metadata == integration_after .metadata
227131
228- @responses .activate
229132 def test_installed_without_username (self ) -> None :
230133 """Test a user (not team) installation where the user has hidden their username from public view"""
231134
232135 # Remove username to simulate privacy mode
233136 del self .user_data_from_bitbucket ["principal" ]["username" ]
234137
235- self .add_cdn_response ()
236- response = self .client .post (
237- self .path ,
238- data = self .user_data_from_bitbucket ,
239- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
240- )
138+ response = self .client .post (self .path , data = self .user_data_from_bitbucket )
241139 assert response .status_code == 200
242140 integration = Integration .objects .get (provider = self .provider , external_id = self .client_key )
243141 assert integration .name == self .user_display_name
244142 del integration .metadata ["webhook_secret" ]
245143 assert integration .metadata == self .user_metadata
246144
247- @responses .activate
248145 @mock .patch ("sentry.integrations.bitbucket.integration.generate_token" , return_value = "0" * 64 )
249146 def test_installed_with_secret (self , mock_generate_token : mock .MagicMock ) -> None :
250- self .add_cdn_response ()
251- response = self .client .post (
252- self .path ,
253- data = self .team_data_from_bitbucket ,
254- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
255- )
147+ response = self .client .post (self .path , data = self .team_data_from_bitbucket )
256148 assert mock_generate_token .called
257149 assert response .status_code == 200
258150 integration = Integration .objects .get (provider = self .provider , external_id = self .client_key )
@@ -280,12 +172,7 @@ def test_plugin_migration(self) -> None:
280172 config = {"name" : "otheruser/otherrepo" },
281173 )
282174
283- self .add_cdn_response ()
284- self .client .post (
285- self .path ,
286- data = self .team_data_from_bitbucket ,
287- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
288- )
175+ self .client .post (self .path , data = self .team_data_from_bitbucket )
289176
290177 integration = Integration .objects .get (provider = self .provider , external_id = self .client_key )
291178
@@ -332,12 +219,7 @@ def test_disable_plugin_when_fully_migrated(self) -> None:
332219 config = {"name" : "sentryuser/repo" },
333220 )
334221
335- self .add_cdn_response ()
336- self .client .post (
337- self .path ,
338- data = self .team_data_from_bitbucket ,
339- HTTP_AUTHORIZATION = f"JWT { self .jwt_token_cdn ()} " ,
340- )
222+ self .client .post (self .path , data = self .team_data_from_bitbucket )
341223
342224 integration = Integration .objects .get (provider = self .provider , external_id = self .client_key )
343225
0 commit comments