Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/sentry/conf/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -994,17 +994,12 @@ def create_partitioned_queues(name):
"organizations:integrations-incident-management": True,
# Allow orgs to automatically create Tickets in Issue Alerts
"organizations:integrations-ticket-rules": True,
# Allow orgs to install AzureDevops with limited scopes
"organizations:integrations-vsts-limited-scopes": False,
# Allow orgs to use the stacktrace linking feature
"organizations:integrations-stacktrace-link": False,
# Allow orgs to install a custom source code management integration
"organizations:integrations-custom-scm": False,
# Allow orgs to debug internal/unpublished sentry apps with logging
"organizations:sentry-app-debugging": False,
# Temporary safety measure, turned on for specific orgs only if
# absolutely necessary, to be removed shortly
"organizations:slack-allow-workspace": False,
# Enable data forwarding functionality for organizations.
"organizations:data-forwarding": True,
# Enable readonly dashboards
Expand Down
1 change: 0 additions & 1 deletion src/sentry/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@
default_manager.add("organizations:integrations-issue-sync", OrganizationFeature)
default_manager.add("organizations:integrations-stacktrace-link", OrganizationFeature)
default_manager.add("organizations:integrations-ticket-rules", OrganizationFeature, True)
default_manager.add("organizations:integrations-vsts-limited-scopes", OrganizationFeature)
default_manager.add("organizations:invite-members", OrganizationFeature)
default_manager.add("organizations:invite-members-rate-limits", OrganizationFeature)
default_manager.add("organizations:issue-list-trend-sort", OrganizationFeature, True)
Expand Down
18 changes: 1 addition & 17 deletions src/sentry/identity/vsts/provider.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sentry import features, http, options
from sentry import http, options
from sentry.identity.oauth2 import OAuth2CallbackView, OAuth2LoginView, OAuth2Provider
from sentry.utils.http import absolute_uri

Expand Down Expand Up @@ -40,18 +40,10 @@ class VSTSIdentityProvider(OAuth2Provider):
oauth_access_token_url = "https://app.vssps.visualstudio.com/oauth2/token"
oauth_authorize_url = "https://app.vssps.visualstudio.com/oauth2/authorize"

@property
def use_limited_scopes(self):
return use_limited_scopes(self.pipeline)

def get_oauth_client_id(self):
if self.use_limited_scopes:
return options.get("vsts-limited.client-id")
return options.get("vsts.client-id")

def get_oauth_client_secret(self):
if self.use_limited_scopes:
return options.get("vsts-limited.client-secret")
return options.get("vsts.client-secret")

def get_refresh_token_url(self):
Expand Down Expand Up @@ -137,11 +129,3 @@ def exchange_token(self, request, pipeline, code):
if req.headers["Content-Type"].startswith("application/x-www-form-urlencoded"):
return dict(parse_qsl(body))
return json.loads(body)


def use_limited_scopes(pipeline):
return features.has(
"organizations:integrations-vsts-limited-scopes",
pipeline.organization,
actor=pipeline.request.user,
)
5 changes: 1 addition & 4 deletions src/sentry/integrations/vsts/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from sentry.auth.exceptions import IdentityNotValid
from sentry.constants import ObjectStatus
from sentry.identity.pipeline import IdentityProviderPipeline
from sentry.identity.vsts import get_user_info, use_limited_scopes
from sentry.identity.vsts import get_user_info
from sentry.integrations import (
FeatureDescription,
IntegrationFeatures,
Expand Down Expand Up @@ -364,9 +364,6 @@ def post_install(
)

def get_scopes(self) -> Sequence[str]:
if use_limited_scopes(self.pipeline):
return ("vso.graph", "vso.serviceendpoint_manage", "vso.work_write")

return ("vso.code", "vso.graph", "vso.serviceendpoint_manage", "vso.work_write")

def get_pipeline_views(self) -> Sequence[PipelineView]:
Expand Down
37 changes: 0 additions & 37 deletions tests/sentry/integrations/vsts/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import responses

from sentry.models import Identity, IdentityProvider, Integration
from sentry.testutils.helpers import with_feature
from sentry.utils import json

from .testutils import VstsIntegrationTestCase
Expand Down Expand Up @@ -51,42 +50,6 @@ def test_refreshes_expired_token(self):
assert identity.data["access_token"] == "new-access-token"
assert identity.data["refresh_token"] == "new-refresh-token"

@with_feature("organizations:integrations-vsts-limited-scopes")
def test_refreshes_expired_token_limited_scopes(self):
self.assert_installation()
integration = Integration.objects.get(provider="vsts")

# Make the Identity have an expired token
idp = IdentityProvider.objects.get(external_id=self.vsts_account_id)
identity = Identity.objects.get(idp_id=idp.id)
identity.data["expires"] = int(time()) - int(123456789)
identity.save()

# New values VSTS will return on refresh
self.access_token = "new-access-token"
self.refresh_token = "new-refresh-token"
self._stub_vsts()

# Make a request with expired token
integration.get_installation(
integration.organizations.first().id
).get_client().get_projects(self.vsts_base_url)

# Second to last request, before the Projects request, was to refresh
# the Access Token.
assert responses.calls[-2].request.url == "https://app.vssps.visualstudio.com/oauth2/token"

# Then we request the Projects with the new token
assert (
responses.calls[-1].request.url.split("?")[0]
== f"{self.vsts_base_url.lower()}_apis/projects"
)

identity = Identity.objects.get(id=identity.id)
assert identity.scopes == ["vso.graph", "vso.serviceendpoint_manage", "vso.work_write"]
assert identity.data["access_token"] == "new-access-token"
assert identity.data["refresh_token"] == "new-refresh-token"

def test_project_pagination(self):
def request_callback(request):
query = parse_qs(request.url.split("?")[1])
Expand Down
15 changes: 0 additions & 15 deletions tests/sentry/integrations/vsts/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
Repository,
)
from sentry.shared_integrations.exceptions import IntegrationError, IntegrationProviderError
from sentry.testutils.helpers import with_feature

from .testutils import CREATE_SUBSCRIPTION, VstsIntegrationTestCase

Expand Down Expand Up @@ -48,20 +47,6 @@ def test_basic_flow(self):
assert metadata["subscription"]["id"] == CREATE_SUBSCRIPTION["id"]
assert metadata["domain_name"] == self.vsts_base_url

@with_feature("organizations:integrations-vsts-limited-scopes")
def test_limited_scopes_flow(self):
self.assert_installation()

integration = Integration.objects.get(provider="vsts")

assert integration.external_id == self.vsts_account_id
assert integration.name == self.vsts_account_name

metadata = integration.metadata
assert metadata["scopes"] == LIMITED_SCOPES
assert metadata["subscription"]["id"] == CREATE_SUBSCRIPTION["id"]
assert metadata["domain_name"] == self.vsts_base_url

def test_migrate_repositories(self):
accessible_repo = Repository.objects.create(
organization_id=self.organization.id,
Expand Down