Files
2024-02-15 17:01:50 +00:00

433 lines
15 KiB
Python

import responses
from requests.exceptions import ReadTimeout
from sentry.integrations.jira_server import JiraServerIntegrationProvider
from sentry.models.identity import Identity, IdentityProvider
from sentry.models.integrations.integration import Integration
from sentry.models.integrations.organization_integration import OrganizationIntegration
from sentry.testutils.cases import IntegrationTestCase
from sentry.testutils.silo import control_silo_test
from sentry.utils import json, jwt
from . import EXAMPLE_PRIVATE_KEY
@control_silo_test
class JiraServerInstallationTest(IntegrationTestCase):
provider = JiraServerIntegrationProvider
def test_config_view(self):
resp = self.client.get(self.init_path)
assert resp.status_code == 200
resp = self.client.get(self.setup_path)
assert resp.status_code == 200
self.assertContains(resp, "Connect Sentry")
self.assertContains(resp, "Submit</button>")
@responses.activate
def test_validate_url(self):
# Start pipeline and go to setup page.
self.client.get(self.setup_path)
# Submit credentials
data = {
"url": "jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 200
self.assertContains(resp, "Enter a valid URL")
@responses.activate
def test_validate_private_key(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=503,
)
# Start pipeline and go to setup page.
self.client.get(self.setup_path)
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": "hot-garbage",
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 200
self.assertContains(
resp, "Private key must be a valid SSH private key encoded in a PEM format."
)
@responses.activate
def test_validate_consumer_key_length(self):
# Start pipeline and go to setup page.
self.client.get(self.setup_path)
# Submit credentials
data = {
"url": "jira.example.com/",
"verify_ssl": False,
"consumer_key": "x" * 201,
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 200
self.assertContains(resp, "Consumer key is limited to 200")
@responses.activate
def test_authentication_request_token_timeout(self):
timeout = ReadTimeout("Read timed out. (read timeout=30)")
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
body=timeout,
)
# Start pipeline and go to setup page.
self.client.get(self.setup_path)
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 200
self.assertContains(resp, "Setup Error")
self.assertContains(resp, "request token from Jira")
self.assertContains(resp, "Timed out")
@responses.activate
def test_authentication_request_token_fails(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=503,
)
# Start pipeline and go to setup page.
self.client.get(self.setup_path)
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 200
self.assertContains(resp, "Setup Error")
self.assertContains(resp, "request token from Jira")
@responses.activate
def test_authentication_request_token_redirect(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
# Start pipeline
self.client.get(self.init_path)
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 302
redirect = "https://jira.example.com/plugins/servlet/oauth/authorize?oauth_token=abc123"
assert redirect == resp["Location"]
@responses.activate
def test_authentication_access_token_failure(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=500,
content_type="text/plain",
body="<html>it broke</html>",
)
# Get config page
resp = self.client.get(self.init_path)
assert resp.status_code == 200
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 302
assert resp["Location"]
resp = self.client.get(self.setup_path + "?oauth_token=xyz789")
assert resp.status_code == 200
self.assertContains(resp, "Setup Error")
self.assertContains(resp, "access token from Jira")
def install_integration(self):
# Get config page
resp = self.client.get(self.setup_path)
assert resp.status_code == 200
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "sentry-bot",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 302
assert resp["Location"]
resp = self.client.get(self.setup_path + "?oauth_token=xyz789")
assert resp.status_code == 200
return resp
@responses.activate
def test_authentication_verifier_expired(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=404,
content_type="text/plain",
body="oauth_error=token+expired",
)
# Try getting the token but it has expired for some reason,
# perhaps a stale reload/history navigate.
resp = self.install_integration()
self.assertContains(resp, "Setup Error")
self.assertContains(resp, "access token from Jira")
@responses.activate
def test_authentication_success(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=200,
content_type="text/plain",
body="oauth_token=valid-token&oauth_token_secret=valid-secret",
)
responses.add(
responses.POST,
"https://jira.example.com/rest/webhooks/1.0/webhook",
status=204,
body="",
)
self.install_integration()
integration = Integration.objects.get()
assert integration.name == "sentry-bot"
assert integration.metadata["domain_name"] == "jira.example.com"
assert integration.metadata["base_url"] == "https://jira.example.com"
assert integration.metadata["verify_ssl"] is False
assert integration.metadata["webhook_secret"]
org_integration = OrganizationIntegration.objects.get(
integration=integration, organization_id=self.organization.id
)
assert org_integration.config == {}
idp = IdentityProvider.objects.get(type="jira_server")
identity = Identity.objects.get(
idp=idp, user=self.user, external_id="jira.example.com:sentry-bot"
)
assert identity.data["consumer_key"] == "sentry-bot"
assert identity.data["access_token"] == "valid-token"
assert identity.data["access_token_secret"] == "valid-secret"
assert identity.data["private_key"] == EXAMPLE_PRIVATE_KEY
@responses.activate
def test_setup_create_webhook(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=200,
content_type="text/plain",
body="oauth_token=valid-token&oauth_token_secret=valid-secret",
)
expected_id = "jira.example.com:sentry-bot"
def webhook_response(request):
# Ensure the webhook token contains our integration
# external id
data = json.loads(request.body)
url = data["url"]
token = url.split("/")[-2]
token_data = jwt.peek_claims(token)
assert "id" in token_data
assert token_data["id"] == expected_id
return (204, {}, "")
responses.add_callback(
responses.POST,
"https://jira.example.com/rest/webhooks/1.0/webhook",
callback=webhook_response,
)
self.install_integration()
integration = Integration.objects.get()
assert integration.external_id == expected_id
@responses.activate
def test_setup_external_id_length(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=200,
content_type="text/plain",
body="oauth_token=valid-token&oauth_token_secret=valid-secret",
)
responses.add(
responses.POST,
"https://jira.example.com/rest/webhooks/1.0/webhook",
status=204,
body="",
)
# Start pipeline and go to setup page.
self.client.get(self.setup_path)
# Submit credentials
data = {
"url": "https://jira.example.com/",
"verify_ssl": False,
"consumer_key": "a-very-long-consumer-key-that-when-combined-with-host-would-overflow",
"private_key": EXAMPLE_PRIVATE_KEY,
}
resp = self.client.post(self.setup_path, data=data)
assert resp.status_code == 302
redirect = "https://jira.example.com/plugins/servlet/oauth/authorize?oauth_token=abc123"
assert redirect == resp["Location"]
resp = self.client.get(self.setup_path + "?oauth_token=xyz789")
assert resp.status_code == 200
integration = Integration.objects.get(provider="jira_server")
assert (
integration.external_id
== "jira.example.com:a-very-long-consumer-key-that-when-combined-wit"
)
@responses.activate
def test_setup_create_webhook_failure(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=200,
content_type="text/plain",
body="oauth_token=valid-token&oauth_token_secret=valid-secret",
)
responses.add(
responses.POST,
"https://jira.example.com/rest/webhooks/1.0/webhook",
status=502,
body="Bad things",
)
resp = self.install_integration()
self.assertContains(resp, "webhook")
assert Integration.objects.count() == 0
@responses.activate
def test_setup_create_webhook_failure_forbidden(self):
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/request-token",
status=200,
content_type="text/plain",
body="oauth_token=abc123&oauth_token_secret=def456",
)
responses.add(
responses.POST,
"https://jira.example.com/plugins/servlet/oauth/access-token",
status=200,
content_type="text/plain",
body="oauth_token=valid-token&oauth_token_secret=valid-secret",
)
responses.add(
responses.POST,
"https://jira.example.com/rest/webhooks/1.0/webhook",
status=403,
json={
"messages": [
{"key": "You do not have permission to create WebHook 'Sentry Issue Sync'."}
]
},
)
resp = self.install_integration()
self.assertContains(resp, "You do not have permission to create")
self.assertContains(resp, "Could not create issue webhook")
assert Integration.objects.count() == 0