예제 #1
0
    def get_repository_choices(self, group, **kwargs):
        """
        Returns the default repository and a set/subset of repositories of associated with the installation
        """
        try:
            repos = self.get_repositories()
        except ApiError:
            raise IntegrationError(
                "Unable to retrieve repositories. Please try again later.")
        else:
            repo_choices = [(repo["identifier"], repo["name"])
                            for repo in repos]

        repo = kwargs.get("repo")
        if not repo:
            params = kwargs.get("params", {})
            defaults = self.get_project_defaults(group.project_id)
            repo = params.get("repo", defaults.get("repo"))

        try:
            default_repo = repo or repo_choices[0][0]
        except IndexError:
            return "", repo_choices

        # If a repo has been selected outside of the default list of
        # repos, stick it onto the front of the list so that it can be
        # selected.
        try:
            next(True for r in repo_choices if r[0] == default_repo)
        except StopIteration:
            repo_choices.insert(0,
                                self.create_default_repo_choice(default_repo))

        return default_repo, repo_choices
예제 #2
0
 def dispatch(self, request, pipeline):
     data = pipeline.fetch_state("msteams")
     # check the expiration time of the link
     if int(time.time()) > data["expiration_time"]:
         return pipeline.error(
             IntegrationError("Installation link expired"))
     return pipeline.next_step()
예제 #3
0
    def update_organization_config(self, data: MutableMapping[str,
                                                              Any]) -> None:
        if "sync_status_forward" in data:
            project_ids_and_statuses = data.pop("sync_status_forward")
            if any(not mapping["on_unresolve"] or not mapping["on_resolve"]
                   for mapping in project_ids_and_statuses.values()):
                raise IntegrationError(
                    "Resolve and unresolve status are required.")

            data["sync_status_forward"] = bool(project_ids_and_statuses)

            IntegrationExternalProject.objects.filter(
                organization_integration_id=self.org_integration.id).delete()

            for project_id, statuses in project_ids_and_statuses.items():
                IntegrationExternalProject.objects.create(
                    organization_integration_id=self.org_integration.id,
                    external_id=project_id,
                    resolved_status=statuses["on_resolve"],
                    unresolved_status=statuses["on_unresolve"],
                )

        config = self.org_integration.config
        config.update(data)
        self.org_integration.update(config=config)
예제 #4
0
def _get_channels_from_rules(pipeline):
    organization = pipeline.organization
    integration_id = pipeline.fetch_state("integration_id")

    try:
        integration = Integration.objects.get(
            id=integration_id,
            provider="slack",
        )
    except Integration.DoesNotExist:
        raise IntegrationError("Could not find Slack integration.")

    rules = Rule.objects.filter(
        project__in=organization.project_set.all(),
        status=RuleStatus.ACTIVE,
    )

    channels = set()
    for rule in rules:
        # try and see if its used for slack
        for rule_action in rule.data["actions"]:
            rule_integration_id = rule_action.get("workspace")
            if rule_integration_id and rule_integration_id == six.text_type(
                    integration.id):

                channel_id = rule_action["channel_id"]
                channel_name = rule_action["channel"]

                # don't care if its a user
                if channel_name[0] == "@":
                    continue

                channels.add(Channel(channel_name, channel_id))

    return channels
예제 #5
0
파일: utils.py 프로젝트: pasala91/test
def get_option_value(function, option):
    region = parse_arn(function["FunctionArn"])["region"]
    runtime = function["Runtime"]

    # currently only supporting node runtimes
    if runtime.startswith("nodejs"):
        prefix = "node"
    elif runtime.startswith("python"):
        prefix = "python"
    else:
        raise Exception("Unsupported runtime")

    # account number doesn't depend on the runtime prefix
    if option == OPTION_ACCOUNT_NUMBER:
        option_field = "aws-lambda.account-number"
    else:
        option_field = f"aws-lambda.{prefix}.{option}"

    # if we don't have the settings set, read from our options
    if not settings.SENTRY_RELEASE_REGISTRY_BASEURL:
        return options.get(option_field)

    # otherwise, read from the cache
    cache_options = cache.get(LAYER_INDEX_CACHE_KEY) or {}
    key = f"aws-layer:{prefix}"
    cache_value = cache_options.get(key)

    if cache_value is None:
        raise IntegrationError(f"Could not find cache value with key {key}")

    # special lookup for the version since it depends on the region
    if option == OPTION_VERSION:
        region_release_list = cache_value.get("regions", [])
        matched_regions = filter(lambda x: x["region"] == region,
                                 region_release_list)
        # see if there is the specific region in our list
        if matched_regions:
            version = matched_regions[0]["version"]
            return version
        else:
            raise IntegrationError(f"Unsupported region {region}")

    # we use - in options but _ in the registry
    registry_field = option.replace("-", "_")

    # return the value out of the cache
    return cache_value.get(registry_field)
예제 #6
0
 def create_issue(self, data, **kwargs):
     if "assignee" not in data:
         raise IntegrationError("Assignee is required")
     return {
         "key": "APP-123",
         "title": "This is a test external issue title",
         "description": "This is a test external issue description",
     }
예제 #7
0
    def after_link_issue(self, external_issue: ExternalIssue, **kwargs: Any) -> None:
        data = kwargs["data"]
        client = self.get_client()

        repo, issue_num = external_issue.key.split("#")
        if not repo:
            raise IntegrationError("repo must be provided")

        if not issue_num:
            raise IntegrationError("issue number must be provided")

        comment = data.get("comment")
        if comment:
            try:
                client.create_comment(repo=repo, issue_id=issue_num, data={"body": comment})
            except ApiError as e:
                raise IntegrationError(self.message_from_error(e))
예제 #8
0
파일: base.py 프로젝트: waterdrops/sentry
    def raise_error(self, exc: ApiError, identity: Optional[Identity] = None) -> None:
        if isinstance(exc, ApiUnauthorized):
            raise InvalidIdentity(self.message_from_error(exc), identity=identity).with_traceback(
                sys.exc_info()[2]
            )
        elif isinstance(exc, ApiError):
            if exc.json:
                error_fields = self.error_fields_from_json(exc.json)
                if error_fields is not None:
                    raise IntegrationFormError(error_fields).with_traceback(sys.exc_info()[2])

            raise IntegrationError(self.message_from_error(exc)).with_traceback(sys.exc_info()[2])
        elif isinstance(exc, IntegrationError):
            raise
        else:
            self.logger.exception(str(exc))
            raise IntegrationError(self.message_from_error(exc)).with_traceback(sys.exc_info()[2])
예제 #9
0
    def after_link_issue(self, external_issue, **kwargs):
        data = kwargs["data"]
        project_id, issue_id = data.get("externalIssue", "").split("#")
        if not (project_id and issue_id):
            raise IntegrationError("Project and Issue id must be provided")

        client = self.get_client()
        comment = data.get("comment")
        if not comment:
            return

        try:
            client.create_issue_comment(
                project_id=project_id, issue_id=issue_id, data={"body": comment}
            )
        except ApiError as e:
            raise IntegrationError(self.message_from_error(e))
예제 #10
0
    def get_installation(self, integration_id, organization_id):
        if integration_id is None:
            raise IntegrationError("Bitbucket Server requires an integration id.")
        integration_model = Integration.objects.get(
            id=integration_id, organizations=organization_id, provider="bitbucket_server"
        )

        return integration_model.get_installation(organization_id)
예제 #11
0
    def compare_commits(self, repo, start_sha, end_sha):
        installation = Integration.objects.get(
            id=repo.integration_id).get_installation(repo.organization_id)

        try:
            raise IntegrationError("{'error': 'Repository not found'}")
        except Exception as e:
            installation.raise_error(e)
예제 #12
0
    def get_installation(self, integration_id, organization_id):
        if integration_id is None:
            raise IntegrationError("%s requires an integration id." %
                                   self.name)

        integration_model = Integration.objects.get(
            id=integration_id, organizations=organization_id, provider="vsts")

        return integration_model.get_installation(organization_id)
예제 #13
0
파일: utils.py 프로젝트: waterdrops/sentry
 def wrapped(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except Exception as e:
         err_message = str(e)
         is_custom_err, err_message = get_sentry_err_message(err_message)
         if is_custom_err:
             raise IntegrationError(_(err_message))
         # otherwise, re-raise the original error
         raise
예제 #14
0
    def dispatch(self, request, pipeline):
        integration_id = request.GET.get("integration_id")

        if integration_id:
            pipeline.bind_state("integration_id", integration_id)
            pipeline.bind_state("user_id", request.user.id)

            try:
                integration = Integration.objects.get(
                    id=integration_id,
                    provider="slack",
                )
            except Integration.DoesNotExist:
                return pipeline.error(
                    IntegrationError("Could not find Slack integration."))

            # We check if there are any other orgs tied to the integration to let the
            # user know those organizations will be affected by the migration
            extra_orgs = map(
                lambda x: x.slug,
                integration.organizations.filter(~Q(
                    id=pipeline.organization.id)))

            pipeline.bind_state("extra_orgs", extra_orgs)

            try:
                all_channels = _get_channels_from_rules(
                    pipeline.organization, integration)
            except IntegrationError as error:
                return pipeline.error(error)

            pipeline.bind_state("all_channels", all_channels)

            next_param = "?show_verification_results"

            return render_to_response(
                template="sentry/integrations/slack-reauth-introduction.html",
                context={
                    "next_url":
                    "%s%s" %
                    (absolute_uri("/extensions/slack/setup/"), next_param),
                    "workspace":
                    integration.name,
                    "extra_orgs":
                    extra_orgs,
                },
                request=request,
            )

        if "show_verification_results" in request.GET:
            return pipeline.next_step()

        # if we dont have the integration_id we dont care about the
        # migration path, skip straight to install
        return pipeline.next_step(step_size=2)
예제 #15
0
파일: utils.py 프로젝트: srknzl/sentry
 def wrapped(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except Exception as e:
         err_message = six.text_type(e)
         invalid_layer = get_invalid_layer_name(err_message)
         # only have one specific error to catch
         if invalid_layer:
             raise IntegrationError(_(INVALID_LAYER_TEXT) % invalid_layer)
         # otherwise, re-raise the original error
         raise
예제 #16
0
    def get_team_info(self, access_token):
        payload = {"token": access_token}

        client = SlackClient()
        try:
            resp = client.get("/team.info", params=payload)
        except ApiError as e:
            logger.error("slack.team-info.response-error", extra={"error": six.text_type(e)})
            raise IntegrationError("Could not retrieve Slack team information.")

        return resp["team"]
예제 #17
0
    def update_env_variable(self, client, vercel_project_id, data):
        envs = client.get_env_vars(vercel_project_id)["envs"]

        env_var_ids = [env_var["id"] for env_var in envs if env_var["key"] == data["key"]]
        if env_var_ids:
            return client.update_env_variable(vercel_project_id, env_var_ids[0], data)

        key = data["key"]
        raise IntegrationError(
            f"Could not update environment variable {key} in Vercel project {vercel_project_id}."
        )
예제 #18
0
    def get_client(self):
        if self.default_identity is None:
            try:
                self.default_identity = self.get_default_identity()
            except Identity.DoesNotExist:
                raise IntegrationError("Identity not found.")

        return JiraServerClient(
            self.model.metadata["base_url"],
            JiraServer(self.default_identity.data),
            self.model.metadata["verify_ssl"],
        )
예제 #19
0
    def build_integration(self, state):
        data = state["identity"]["data"]
        access_token = data["access_token"]
        team_id = data.get("team_id")
        client = VercelClient(access_token, team_id)

        if team_id:
            external_id = team_id
            installation_type = "team"
            team = client.get_team()
            name = team["name"]
        else:
            external_id = data["user_id"]
            installation_type = "user"
            user = client.get_user()
            name = user["name"]

        try:
            webhook = client.create_deploy_webhook()
        except ApiError as err:
            logger.info(
                "vercel.create_webhook.failed",
                extra={
                    "error": six.text_type(err),
                    "external_id": external_id
                },
            )
            try:
                details = err.json["messages"][0].values().pop()
            except Exception:
                details = "Unknown Error"
            message = u"Could not create deployment webhook in Vercel: {}".format(
                details)
            raise IntegrationError(message)

        configurations = self.get_configuration_metadata(external_id)

        integration = {
            "name": name,
            "external_id": external_id,
            "metadata": {
                "access_token": access_token,
                "installation_id": data["installation_id"],
                "installation_type": installation_type,
                "webhook_id": webhook["id"],
                "configurations": configurations,
            },
            "post_install_data": {
                "user_id": state["user_id"]
            },
        }

        return integration
예제 #20
0
    def get_payload_and_token(self, payload, organization_id,
                              sentry_project_id):
        meta = payload["deployment"]["meta"]

        # look up the project so we can get the slug
        project = Project.objects.get(id=sentry_project_id)

        # find the connected sentry app installation
        installation_for_provider = SentryAppInstallationForProvider.objects.select_related(
            "sentry_app_installation").get(organization_id=organization_id,
                                           provider=self.provider)
        sentry_app_installation = installation_for_provider.sentry_app_installation

        # find a token associated with the installation so we can use it for authentication
        sentry_app_installation_token = (
            SentryAppInstallationToken.objects.select_related("api_token").
            filter(sentry_app_installation=sentry_app_installation).first())
        if not sentry_app_installation_token:
            raise SentryAppInstallationToken.DoesNotExist()

        # find the commmit sha so we can  use it as as the release
        commit_sha = (meta.get("githubCommitSha")
                      or meta.get("gitlabCommitSha")
                      or meta.get("bitbucketCommitSha"))

        # contruct the repo depeding what provider we use
        if meta.get("githubCommitSha"):
            # we use these instead of githubOrg and githubRepo since it's the repo the user has access to
            repository = u"%s/%s" % (meta["githubCommitOrg"],
                                     meta["githubCommitRepo"])
        elif meta.get("gitlabCommitSha"):
            # gitlab repos are formatted with a space for some reason
            repository = u"%s / %s" % (
                meta["gitlabProjectNamespace"],
                meta["gitlabProjectName"],
            )
        elif meta.get("bitbucketCommitSha"):
            repository = u"%s/%s" % (meta["bitbucketRepoOwner"],
                                     meta["bitbucketRepoName"])
        else:
            # this should really never happen
            raise IntegrationError("No commit found")

        release_payload = {
            "version": commit_sha,
            "projects": [project.slug],
            "refs": [{
                "repository": repository,
                "commit": commit_sha
            }],
        }
        return [release_payload, sentry_app_installation_token.api_token.token]
예제 #21
0
    def get_team_info(self, access_token: str) -> JSONData:
        headers = {"Authorization": f"Bearer {access_token}"}

        client = SlackClient()
        try:
            resp = client.get("/team.info", headers=headers)
        except ApiError as e:
            logger.error("slack.team-info.response-error",
                         extra={"error": str(e)})
            raise IntegrationError(
                "Could not retrieve Slack team information.")

        return resp["team"]
예제 #22
0
    def get_installation(
        self, integration_id: Optional[int], organization_id: int
    ) -> IntegrationInstallation:
        if integration_id is None:
            raise IntegrationError(f"{self.name} requires an integration id.")

        integration_model = Integration.objects.get(
            id=integration_id, organizations=organization_id, provider="vsts"
        )

        # Explicitly typing to satisfy mypy.
        installation: IntegrationInstallation = integration_model.get_installation(organization_id)
        return installation
예제 #23
0
    def _validate_repo(self, client, installation, repo):
        try:
            repo_data = client.get_repo(repo)
        except Exception as e:
            installation.raise_error(e)

        try:
            # make sure installation has access to this specific repo
            client.get_commits(repo)
        except ApiError:
            raise IntegrationError(f"You must grant Sentry access to {repo}")

        return repo_data
예제 #24
0
 def get_repositories(self, query=None):
     try:
         repos = self.get_client().get_repos(self.instance)
     except (ApiError, IdentityNotValid) as e:
         raise IntegrationError(self.message_from_error(e))
     data = []
     for repo in repos["value"]:
         data.append(
             {
                 "name": "%s/%s" % (repo["project"]["name"], repo["name"]),
                 "identifier": repo["id"],
             }
         )
     return data
예제 #25
0
    def sync_status_outbound(self, external_issue, is_resolved, project_id,
                             **kwargs):
        """
        Propagate a sentry issue's status to a linked issue's status.
        """
        client = self.get_client()
        jira_issue = client.get_issue(external_issue.key)
        jira_project = jira_issue["fields"]["project"]

        try:
            external_project = IntegrationExternalProject.objects.get(
                external_id=jira_project["id"],
                organization_integration_id__in=OrganizationIntegration.
                objects.filter(
                    organization_id=external_issue.organization_id,
                    integration_id=external_issue.integration_id,
                ),
            )
        except IntegrationExternalProject.DoesNotExist:
            return

        jira_status = (external_project.resolved_status
                       if is_resolved else external_project.unresolved_status)

        # don't bother updating if it's already the status we'd change it to
        if jira_issue["fields"]["status"]["id"] == jira_status:
            return
        try:
            transitions = client.get_transitions(external_issue.key)
        except ApiHostError:
            raise IntegrationError("Could not reach host to get transitions.")

        try:
            transition = [
                t for t in transitions
                if t.get("to", {}).get("id") == jira_status
            ][0]
        except IndexError:
            # TODO(jess): Email for failure
            logger.warning(
                "jira.status-sync-fail",
                extra={
                    "organization_id": external_issue.organization_id,
                    "integration_id": external_issue.integration_id,
                    "issue_key": external_issue.key,
                },
            )
            return

        client.transition_issue(external_issue.key, transition["id"])
예제 #26
0
def validate_channel_id(name: str, integration_id: int,
                        input_channel_id: str) -> None:
    """
    In the case that the user is creating an alert via the API and providing the channel ID and name
    themselves, we want to make sure both values are correct.
    """
    try:
        integration = Integration.objects.get(id=integration_id)
    except Integration.DoesNotExist:
        raise Http404

    token = integration.metadata["access_token"]
    headers = {"Authorization": f"Bearer {token}"}
    payload = {"channel": input_channel_id}
    client = SlackClient()

    try:
        results = client.get("/conversations.info",
                             headers=headers,
                             params=payload)
    except ApiError as e:
        if e.text == "channel_not_found":
            raise ValidationError("Channel not found. Invalid ID provided.")
        logger.info("rule.slack.conversation_info_failed",
                    extra={"error": str(e)})
        raise IntegrationError("Could not retrieve Slack channel information.")

    if not isinstance(results, dict):
        raise IntegrationError("Bad slack channel list response.")

    stripped_channel_name = strip_channel_name(name)
    if not stripped_channel_name == results["channel"]["name"]:
        channel_name = results["channel"]["name"]
        raise ValidationError(
            f"Received channel name {channel_name} does not match inputted channel name {stripped_channel_name}."
        )
예제 #27
0
파일: issues.py 프로젝트: liang0/sentry-1
    def get_issue(self, issue_id, **kwargs):
        data = kwargs["data"]
        repo = data.get("repo")
        issue_num = data.get("externalIssue")
        client = self.get_client()

        if not repo:
            raise IntegrationError("repo must be provided")

        if not issue_num:
            raise IntegrationError("issue must be provided")

        try:
            issue = client.get_issue(repo, issue_num)
        except ApiError as e:
            raise IntegrationError(self.message_from_error(e))

        return {
            "key": issue["number"],
            "title": issue["title"],
            "description": issue["body"],
            "url": issue["html_url"],
            "repo": repo,
        }
예제 #28
0
    def _validate_repo(self, client, installation, repo):
        try:
            repo_data = client.get_repo(repo)
        except Exception as e:
            installation.raise_error(e)

        try:
            # make sure installation has access to this specific repo
            # use hooks endpoint since we explicitly ask for those permissions
            # when installing the app (commits can be accessed for public repos)
            # https://developer.github.com/v3/repos/hooks/#list-hooks
            client.repo_hooks(repo)
        except ApiError:
            raise IntegrationError("You must grant Sentry access to {}".format(repo))

        return repo_data
예제 #29
0
    def test_get_create_with_error(self):
        self.login_as(user=self.user)
        org = self.organization
        integration = Integration.objects.create(provider="example", name="Example")
        integration.add_organization(org, self.user)

        path = f"/api/0/issues/{self.group.id}/integrations/{integration.id}/?action=create"

        with self.feature("organizations:integrations-issue-basic"):
            with mock.patch.object(
                ExampleIntegration, "get_create_issue_config", side_effect=IntegrationError("oops")
            ):
                response = self.client.get(path)

                assert response.status_code == 400
                assert response.data == {"detail": "oops"}
예제 #30
0
 def get_repositories(self,
                      query: Optional[str] = None
                      ) -> Sequence[Mapping[str, str]]:
     try:
         repos = self.get_client().get_repos(self.instance)
     except (ApiError, IdentityNotValid) as e:
         raise IntegrationError(self.message_from_error(e))
     data = []
     for repo in repos["value"]:
         data.append({
             "name":
             "{}/{}".format(repo["project"]["name"], repo["name"]),
             "identifier":
             repo["id"],
         })
     return data