コード例 #1
0
    def setUp(self):
        super(OrganizationAlertRuleAvailableActionIndexEndpointTest,
              self).setUp()
        self.login_as(self.user)

        self.email = AlertRuleTriggerAction.get_registered_type(
            AlertRuleTriggerAction.Type.EMAIL)
        self.slack = AlertRuleTriggerAction.get_registered_type(
            AlertRuleTriggerAction.Type.SLACK)
コード例 #2
0
    def test_slack(self):
        self.run_fail_validation_test(
            {
                "type":
                AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type.SLACK).slug,
                "target_type":
                action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.USER],
                "target_identifier":
                "123",
            },
            {
                "targetType":
                ["Invalid target type for slack. Valid types are [specific]"]
            },
        )
        self.run_fail_validation_test(
            {
                "type":
                AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type.SLACK).slug,
                "targetType":
                action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.SPECIFIC],
                "targetIdentifier":
                "123",
            },
            {"integration": ["Integration must be provided for slack"]},
        )
        integration = Integration.objects.create(
            external_id="1",
            provider="slack",
            metadata={
                "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"
            },
        )
        integration.add_organization(self.organization, self.user)

        base_params = self.valid_params.copy()
        base_params.update({
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type.SLACK).slug,
            "targetType":
            action_target_type_to_string[
                AlertRuleTriggerAction.TargetType.SPECIFIC],
            "targetIdentifier":
            "123",
            "integration":
            six.text_type(integration.id),
        })
        serializer = AlertRuleTriggerActionSerializer(context=self.context,
                                                      data=base_params)
        assert serializer.is_valid()
        with self.assertRaises(serializers.ValidationError):
            serializer.save()
コード例 #3
0
ファイル: test_serializers.py プロジェクト: aaganja/sentry
    def test_remove_unchanged_fields(self):
        type = AlertRuleTriggerAction.Type.EMAIL
        target_type = AlertRuleTriggerAction.TargetType.USER
        identifier = six.text_type(self.user.id)
        action = create_alert_rule_trigger_action(self.trigger, type, target_type, identifier)

        self._run_changed_fields_test(
            action,
            {
                "type": AlertRuleTriggerAction.get_registered_type(type).slug,
                "target_type": action_target_type_to_string[target_type],
                "target_identifier": identifier,
            },
            {},
        )

        integration = Integration.objects.create(external_id="1", provider="slack", metadata={})

        self._run_changed_fields_test(
            action,
            {
                "type": AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type.SLACK
                ).slug,
                "targetIdentifier": identifier,
                "targetType": action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.SPECIFIC
                ],
                "integration": integration.id,
            },
            {
                "type": AlertRuleTriggerAction.Type.SLACK,
                "integration": integration,
                "target_identifier": identifier,
                "target_type": AlertRuleTriggerAction.TargetType.SPECIFIC,
            },
        )

        new_team = self.create_team(self.organization)
        self._run_changed_fields_test(
            action,
            {
                "type": AlertRuleTriggerAction.get_registered_type(type).slug,
                "target_type": action_target_type_to_string[AlertRuleTriggerAction.TargetType.TEAM],
                "target_identifier": six.text_type(new_team.id),
            },
            {
                "type": type,
                "target_type": AlertRuleTriggerAction.TargetType.TEAM,
                "target_identifier": six.text_type(new_team.id),
            },
        )
コード例 #4
0
    def serialize(self, obj, attrs, user):
        from sentry.incidents.endpoints.serializers import action_target_type_to_string

        return {
            "id":
            str(obj.id),
            "alertRuleTriggerId":
            str(obj.alert_rule_trigger_id),
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type(obj.type)).slug,
            "targetType":
            action_target_type_to_string[AlertRuleTriggerAction.TargetType(
                obj.target_type)],
            "targetIdentifier":
            self.get_identifier_from_action(obj),
            "integrationId":
            obj.integration_id,
            "sentryAppId":
            obj.sentry_app_id,
            "dateCreated":
            obj.date_added,
            "desc":
            self.human_desc(obj),
        }
コード例 #5
0
    def validate(self, attrs):
        if ("type" in attrs) != ("target_type" in attrs) != ("target_identifier" in attrs):
            raise serializers.ValidationError(
                "type, targetType and targetIdentifier must be passed together"
            )
        type = attrs.get("type")
        target_type = attrs.get("target_type")
        access = self.context["access"]
        identifier = attrs.get("target_identifier")

        if type is not None:
            type_info = AlertRuleTriggerAction.get_registered_type(type)
            if target_type not in type_info.supported_target_types:
                allowed_target_types = ",".join(
                    action_target_type_to_string[type_name]
                    for type_name in type_info.supported_target_types
                )
                raise serializers.ValidationError(
                    {
                        "target_type": "Invalid target type for %s. Valid types are [%s]"
                        % (type_info.slug, allowed_target_types)
                    }
                )

        if attrs.get("type") == AlertRuleTriggerAction.Type.EMAIL:
            if target_type == AlertRuleTriggerAction.TargetType.TEAM:
                try:
                    team = Team.objects.get(id=identifier)
                except Team.DoesNotExist:
                    raise serializers.ValidationError("Team does not exist")
                if not access.has_team(team):
                    raise serializers.ValidationError("Team does not exist")
            elif target_type == AlertRuleTriggerAction.TargetType.USER:
                try:
                    user = User.objects.get(id=identifier)
                except User.DoesNotExist:
                    raise serializers.ValidationError("User does not exist")

                if not OrganizationMember.objects.filter(
                    organization=self.context["organization"], user=user
                ).exists():
                    raise serializers.ValidationError("User does not belong to this organization")
        elif attrs.get("type") == AlertRuleTriggerAction.Type.SLACK:
            if not attrs.get("integration"):
                raise serializers.ValidationError(
                    {"integration": "Integration must be provided for slack"}
                )

        elif attrs.get("type") == AlertRuleTriggerAction.Type.SENTRY_APP:
            if not attrs.get("sentry_app"):
                raise serializers.ValidationError(
                    {"sentry_app": "SentryApp must be provided for sentry_app"}
                )
        attrs["use_async_lookup"] = self.context.get("use_async_lookup")
        attrs["input_channel_id"] = self.context.get("input_channel_id")
        should_validate_channel_id = self.context.get("validate_channel_id", True)
        # validate_channel_id is assumed to be true unless explicitly passed as false
        if attrs["input_channel_id"] and should_validate_channel_id:
            validate_channel_id(identifier, attrs["integration"].id, attrs["input_channel_id"])
        return attrs
コード例 #6
0
    def serialize(self, obj, attrs, user, **kwargs):
        from sentry.incidents.serializers import ACTION_TARGET_TYPE_TO_STRING

        result = {
            "id":
            str(obj.id),
            "alertRuleTriggerId":
            str(obj.alert_rule_trigger_id),
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type(obj.type)).slug,
            "targetType":
            ACTION_TARGET_TYPE_TO_STRING[AlertRuleTriggerAction.TargetType(
                obj.target_type)],
            "targetIdentifier":
            self.get_identifier_from_action(obj),
            "inputChannelId":
            self.get_input_channel_id(obj),
            "integrationId":
            obj.integration_id,
            "sentryAppId":
            obj.sentry_app_id,
            "dateCreated":
            obj.date_added,
            "desc":
            self.human_desc(obj),
        }

        # Check if action is a Sentry App that has Alert Rule UI Component settings
        if obj.sentry_app_id and obj.sentry_app_config:
            result["settings"] = obj.sentry_app_config

        return result
コード例 #7
0
    def test_build_action_response_pagerduty(self):
        service_name = SERVICES[0]["service_name"]
        integration = Integration.objects.create(
            provider="pagerduty",
            name="Example PagerDuty",
            external_id="example-pagerduty",
            metadata={"services": SERVICES},
        )
        integration.add_organization(self.organization, self.user)
        service = PagerDutyService.objects.create(
            service_name=service_name,
            integration_key=SERVICES[0]["integration_key"],
            organization_integration=integration.organizationintegration_set.
            first(),
        )

        pagerduty = AlertRuleTriggerAction.get_registered_type(
            AlertRuleTriggerAction.Type.PAGERDUTY)
        data = build_action_response(pagerduty,
                                     integration=integration,
                                     organization=self.organization)

        assert data["type"] == "pagerduty"
        assert data["allowedTargetTypes"] == ["specific"]
        assert data["options"] == [{
            "value": service.id,
            "label": service_name
        }]
コード例 #8
0
 def test_sentry_app_action_creator_fails(self):
     responses.add(
         method=responses.POST,
         url="https://example.com/sentry/alert-rule",
         status=400,
         body="Invalid channel.",
     )
     self.run_fail_validation_test(
         {
             "type":
             AlertRuleTriggerAction.get_registered_type(
                 AlertRuleTriggerAction.Type.SENTRY_APP).slug,
             "target_type":
             action_target_type_to_string[
                 AlertRuleTriggerAction.TargetType.SENTRY_APP],
             "target_identifier":
             "1",
             "sentry_app":
             self.sentry_app.id,
             "sentry_app_config": {
                 "channel": "#santry"
             },
             "sentry_app_installation_uuid":
             self.sentry_app_installation.uuid,
         },
         {"sentryApp": ["Super Awesome App: Invalid channel."]},
     )
コード例 #9
0
ファイル: test_serializers.py プロジェクト: aaganja/sentry
 def valid_params(self):
     return {
         "type": AlertRuleTriggerAction.get_registered_type(
             AlertRuleTriggerAction.Type.EMAIL
         ).slug,
         "target_type": action_target_type_to_string[AlertRuleTriggerAction.TargetType.SPECIFIC],
         "target_identifier": "*****@*****.**",
     }
コード例 #10
0
 def assert_action_serialized(self, action, result):
     assert result["id"] == six.text_type(action.id)
     assert result["alertRuleTriggerId"] == six.text_type(
         action.alert_rule_trigger_id)
     assert (result["type"] == AlertRuleTriggerAction.get_registered_type(
         AlertRuleTriggerAction.Type(action.type)).slug)
     assert (result["targetType"] == action_target_type_to_string[
         AlertRuleTriggerAction.TargetType(action.target_type)])
     assert result["targetIdentifier"] == action.target_identifier
     assert result["integrationId"] == action.integration_id
     assert result["dateCreated"] == action.date_added
コード例 #11
0
 def valid_params(self):
     return {
         "type":
         AlertRuleTriggerAction.get_registered_type(
             AlertRuleTriggerAction.Type.EMAIL).slug,
         "target_type":
         ACTION_TARGET_TYPE_TO_STRING[
             AlertRuleTriggerAction.TargetType.SPECIFIC],
         "target_identifier":
         "*****@*****.**",
     }
コード例 #12
0
    def validate(self, attrs):
        if ("type" in attrs) != ("target_type" in attrs) != ("target_identifier" in attrs):
            raise serializers.ValidationError(
                "type, targetType and targetIdentifier must be passed together"
            )
        type = attrs.get("type")
        target_type = attrs.get("target_type")
        access = self.context["access"]
        identifier = attrs.get("target_identifier")

        if type is not None:
            type_info = AlertRuleTriggerAction.get_registered_type(type)
            if target_type not in type_info.supported_target_types:
                allowed_target_types = ",".join(
                    [
                        action_target_type_to_string[type_name]
                        for type_name in type_info.supported_target_types
                    ]
                )
                raise serializers.ValidationError(
                    {
                        "target_type": "Invalid target type for %s. Valid types are [%s]"
                        % (type_info.slug, allowed_target_types)
                    }
                )

        if attrs.get("type") == AlertRuleTriggerAction.Type.EMAIL:
            if target_type == AlertRuleTriggerAction.TargetType.TEAM:
                try:
                    team = Team.objects.get(id=identifier)
                except Team.DoesNotExist:
                    raise serializers.ValidationError("Team does not exist")
                if not access.has_team(team):
                    raise serializers.ValidationError("Team does not exist")
            elif target_type == AlertRuleTriggerAction.TargetType.USER:
                try:
                    user = User.objects.get(id=identifier)
                except User.DoesNotExist:
                    raise serializers.ValidationError("User does not exist")

                if not OrganizationMember.objects.filter(
                    organization=self.context["organization"], user=user
                ).exists():
                    raise serializers.ValidationError("User does not belong to this organization")
        elif attrs.get("type") == AlertRuleTriggerAction.Type.SLACK:
            if not attrs.get("integration"):
                raise serializers.ValidationError(
                    {"integration": "Integration must be provided for slack"}
                )

        return attrs
コード例 #13
0
ファイル: test_serializers.py プロジェクト: stephen2m/sentry
    def test_valid_slack_channel_id(self):
        """
        Test that when a valid Slack channel ID is provided, we look up the channel name and validate it against the targetIdentifier.
        """
        integration = Integration.objects.create(
            external_id="1",
            provider="slack",
            metadata={
                "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"
            },
        )
        integration.add_organization(self.organization, self.user)

        base_params = self.valid_params.copy()
        base_params.update({
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type.SLACK).slug,
            "targetType":
            action_target_type_to_string[
                AlertRuleTriggerAction.TargetType.SPECIFIC],
            "targetIdentifier":
            "merp",
            "integration":
            str(integration.id),
        })
        context = self.context.copy()
        context.update({"input_channel_id": "CSVK0921"})
        responses.add(
            method=responses.GET,
            url="https://slack.com/api/conversations.info",
            status=200,
            content_type="application/json",
            body=json.dumps({
                "ok": "true",
                "channel": {
                    "name": "merp",
                    "id": "CSVK0921"
                }
            }),
        )
        serializer = AlertRuleTriggerActionSerializer(context=context,
                                                      data=base_params)
        assert serializer.is_valid()

        serializer.save()

        # # Make sure the action was created.
        alert_rule_trigger_actions = list(
            AlertRuleTriggerAction.objects.filter(integration=integration))
        assert len(alert_rule_trigger_actions) == 1
コード例 #14
0
    def test_invalid_slack_channel_name(self):
        """
        Test that an invalid Slack channel name is detected and blocks the action from being saved.
        """
        integration = Integration.objects.create(
            external_id="1",
            provider="slack",
            metadata={
                "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"
            },
        )
        integration.add_organization(self.organization, self.user)

        base_params = self.valid_params.copy()
        base_params.update({
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type.SLACK).slug,
            "targetType":
            ACTION_TARGET_TYPE_TO_STRING[
                AlertRuleTriggerAction.TargetType.SPECIFIC],
            "targetIdentifier":
            "123",
            "integration":
            str(integration.id),
        })
        context = self.context.copy()
        context.update({"input_channel_id": "CSVK0921"})
        responses.add(
            method=responses.GET,
            url="https://slack.com/api/conversations.info",
            status=200,
            content_type="application/json",
            body=json.dumps({
                "ok": "true",
                "channel": {
                    "name": "merp",
                    "id": "CSVK0921"
                }
            }),
        )
        serializer = AlertRuleTriggerActionSerializer(context=context,
                                                      data=base_params)
        assert not serializer.is_valid()

        # # Make sure the action was not created.
        alert_rule_trigger_actions = list(
            AlertRuleTriggerAction.objects.filter(integration=integration))
        assert len(alert_rule_trigger_actions) == 0
    def test_sentry_apps(self):
        sentry_app = self.install_new_sentry_app("foo")

        with self.feature(
            ["organizations:incidents", "organizations:integrations-sentry-app-metric-alerts"]
        ):
            resp = self.get_valid_response(self.organization.slug)

        assert resp.data == [
            build_action_response(
                AlertRuleTriggerAction.get_registered_type(AlertRuleTriggerAction.Type.SENTRY_APP),
                sentry_app=sentry_app,
            ),
            build_action_response(self.email),
        ]
    def test_blocked_sentry_apps(self):
        internal_sentry_app = self.install_new_sentry_app("internal")
        # Should not show up in available actions.
        self.install_new_sentry_app("published", published=True)

        with self.feature(
            ["organizations:incidents", "organizations:integrations-sentry-app-metric-alerts"]
        ):
            resp = self.get_valid_response(self.organization.slug)

        assert resp.data == [
            build_action_response(
                AlertRuleTriggerAction.get_registered_type(AlertRuleTriggerAction.Type.SENTRY_APP),
                sentry_app=internal_sentry_app,
            ),
            build_action_response(self.email),
        ]
コード例 #17
0
    def serialize(self, obj, attrs, user):
        from sentry.incidents.endpoints.serializers import action_target_type_to_string

        return {
            "id": six.text_type(obj.id),
            "alertRuleTriggerId": six.text_type(obj.alert_rule_trigger_id),
            "type": AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type(obj.type)
            ).slug,
            "targetType": action_target_type_to_string[
                AlertRuleTriggerAction.TargetType(obj.target_type)
            ],
            "targetIdentifier": obj.target_display
            if obj.target_display is not None
            else obj.target_identifier,
            "integrationId": obj.integration_id,
            "dateCreated": obj.date_added,
        }
コード例 #18
0
    def test_sentry_app_action_missing_params(self):

        self.run_fail_validation_test(
            {
                "type":
                AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type.SENTRY_APP).slug,
                "target_type":
                action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.SENTRY_APP],
                "target_identifier":
                "123",
                "sentry_app":
                self.sentry_app.id,
                "sentry_app_config": {
                    "tag": "asdfasdfads"
                },
            },
            {"sentryApp": ["Missing paramater: sentry_app_installation_uuid"]},
        )
コード例 #19
0
    def test_invalid_slack_channel(self):
        # We had an error where an invalid slack channel was spitting out unclear
        # error for the user, and CREATING THE RULE. So the next save (after fixing slack action)
        # says "Name already in use". This test makes sure that is not happening anymore.
        # We save a rule with an invalid slack, make sure we get back a useful error
        # and that the rule is not created.
        base_params = self.valid_params.copy()
        base_params["name"] = "Aun1qu3n4m3"
        integration = Integration.objects.create(
            external_id="1",
            provider="slack",
            metadata={
                "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"
            },
        )
        integration.add_organization(self.organization, self.user)
        base_params["triggers"][0]["actions"].append({
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type.SLACK).slug,
            "targetType":
            action_target_type_to_string[
                AlertRuleTriggerAction.TargetType.SPECIFIC],
            "targetIdentifier":
            "123",
            "integration":
            six.text_type(integration.id),
        })
        serializer = AlertRuleSerializer(context=self.context,
                                         data=base_params)
        assert serializer.is_valid()
        with self.assertRaises(serializers.ValidationError):
            serializer.save()

        # Make sure the rule was not created.
        assert len(list(AlertRule.objects.filter(name="Aun1qu3n4m3"))) == 0

        # Make sure the action was not created.
        alert_rule_trigger_actions = list(
            AlertRuleTriggerAction.objects.filter(integration=integration))
        assert len(alert_rule_trigger_actions) == 0
 def test_simple(self):
     self.create_member(user=self.user,
                        organization=self.organization,
                        role="owner",
                        teams=[self.team])
     self.login_as(self.user)
     with self.feature("organizations:incidents"):
         resp = self.get_valid_response(
             self.organization.slug,
             self.alert_rule.id,
             self.trigger.id,
             type=AlertRuleTriggerAction.get_registered_type(
                 AlertRuleTriggerAction.Type.EMAIL).slug,
             target_type=action_target_type_to_string[
                 AlertRuleTriggerAction.TargetType.USER],
             target_identifier=six.text_type(self.user.id),
             status_code=201,
         )
     assert "id" in resp.data
     action = AlertRuleTriggerAction.objects.get(id=resp.data["id"])
     assert resp.data == serialize(action, self.user)
    def test_not_updated_fields(self):
        self.create_member(user=self.user,
                           organization=self.organization,
                           role="owner",
                           teams=[self.team])
        self.login_as(self.user)
        with self.feature("organizations:incidents"):
            resp = self.get_valid_response(
                self.organization.slug,
                self.alert_rule.id,
                self.trigger.id,
                self.action.id,
                type=AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type(self.action.type)).slug,
                targetType=action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType(
                        self.action.target_type)],
                targetIdentifier=self.action.target_identifier,
            )

        # Alert rule should be exactly the same
        assert resp.data == serialize(self.action)
    def test_simple(self):
        self.create_member(user=self.user,
                           organization=self.organization,
                           role="owner",
                           teams=[self.team])

        self.login_as(self.user)
        with self.feature("organizations:incidents"):
            resp = self.get_response(
                self.organization.slug,
                self.alert_rule.id,
                self.trigger.id,
                self.action.id,
                type=AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type(self.action.type)).slug,
                target_type=action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.TEAM],
                target_identifier=six.text_type(self.team.id),
            )

        self.action.target_type = AlertRuleTriggerAction.TargetType.TEAM.value
        self.action.target_identifier = six.text_type(self.team.id)
        assert resp.data == serialize(self.action)
        assert resp.data["targetIdentifier"] == six.text_type(self.team.id)
class OrganizationAlertRuleAvailableActionIndexEndpointTest(APITestCase):
    endpoint = "sentry-api-0-organization-alert-rule-available-actions"
    email = AlertRuleTriggerAction.get_registered_type(
        AlertRuleTriggerAction.Type.EMAIL)
    slack = AlertRuleTriggerAction.get_registered_type(
        AlertRuleTriggerAction.Type.SLACK)
    sentry_app = AlertRuleTriggerAction.get_registered_type(
        AlertRuleTriggerAction.Type.SENTRY_APP)
    pagerduty = AlertRuleTriggerAction.get_registered_type(
        AlertRuleTriggerAction.Type.PAGERDUTY)

    def setUp(self):
        super().setUp()
        self.login_as(self.user)

    def install_new_sentry_app(self, name, **kwargs):
        kwargs.update(name=name,
                      organization=self.organization,
                      is_alertable=True,
                      verify_install=False)
        sentry_app = self.create_sentry_app(**kwargs)
        installation = self.create_sentry_app_installation(
            slug=sentry_app.slug,
            organization=self.organization,
            user=self.user)
        return installation

    def test_build_action_response_email(self):
        data = build_action_response(self.email)

        assert data["type"] == "email"
        assert sorted(data["allowedTargetTypes"]) == ["team", "user"]

    def test_build_action_response_slack(self):
        data = build_action_response(self.slack)

        assert data["type"] == "slack"
        assert data["allowedTargetTypes"] == ["specific"]

    def test_build_action_response_pagerduty(self):
        service_name = SERVICES[0]["service_name"]
        integration = Integration.objects.create(
            provider="pagerduty",
            name="Example PagerDuty",
            external_id="example-pagerduty",
            metadata={"services": SERVICES},
        )
        integration.add_organization(self.organization, self.user)
        service = PagerDutyService.objects.create(
            service_name=service_name,
            integration_key=SERVICES[0]["integration_key"],
            organization_integration=integration.organizationintegration_set.
            first(),
        )

        data = build_action_response(self.pagerduty,
                                     integration=integration,
                                     organization=self.organization)

        assert data["type"] == "pagerduty"
        assert data["allowedTargetTypes"] == ["specific"]
        assert data["options"] == [{
            "value": service.id,
            "label": service_name
        }]

    def test_build_action_response_sentry_app(self):
        installation = self.install_new_sentry_app("foo")

        data = build_action_response(self.sentry_app,
                                     sentry_app_installation=installation)

        assert data["type"] == "sentry_app"
        assert data["allowedTargetTypes"] == ["sentry_app"]
        assert data["status"] == SentryAppStatus.UNPUBLISHED_STR

    def test_no_integrations(self):
        with self.feature("organizations:incidents"):
            response = self.get_success_response(self.organization.slug)

        assert response.data == [build_action_response(self.email)]

    def test_simple(self):
        integration = Integration.objects.create(external_id="1",
                                                 provider="slack")
        integration.add_organization(self.organization)

        with self.feature("organizations:incidents"):
            response = self.get_success_response(self.organization.slug)

        assert len(response.data) == 2
        assert build_action_response(self.email) in response.data
        assert (build_action_response(self.slack,
                                      integration=integration,
                                      organization=self.organization)
                in response.data)

    def test_duplicate_integrations(self):
        integration = Integration.objects.create(external_id="1",
                                                 provider="slack",
                                                 name="slack 1")
        integration.add_organization(self.organization)
        other_integration = Integration.objects.create(external_id="2",
                                                       provider="slack",
                                                       name="slack 2")
        other_integration.add_organization(self.organization)

        with self.feature("organizations:incidents"):
            response = self.get_success_response(self.organization.slug)

        assert len(response.data) == 3
        assert build_action_response(self.email) in response.data
        assert (build_action_response(self.slack,
                                      integration=integration,
                                      organization=self.organization)
                in response.data)
        assert (build_action_response(self.slack,
                                      integration=other_integration,
                                      organization=self.organization)
                in response.data)

    def test_no_feature(self):
        self.create_team(organization=self.organization, members=[self.user])
        self.get_error_response(self.organization.slug, status_code=404)

    def test_sentry_apps(self):
        installation = self.install_new_sentry_app("foo")

        with self.feature("organizations:incidents"):
            response = self.get_success_response(self.organization.slug)

        assert len(response.data) == 2
        assert build_action_response(self.email) in response.data
        assert (build_action_response(self.sentry_app,
                                      sentry_app_installation=installation)
                in response.data)

    def test_published_sentry_apps(self):
        # Should show up in available actions.
        installation = self.install_new_sentry_app("published", published=True)

        with self.feature("organizations:incidents"):
            response = self.get_success_response(self.organization.slug)

        assert len(response.data) == 2
        assert (build_action_response(self.sentry_app,
                                      sentry_app_installation=installation)
                in response.data)

    def test_no_ticket_actions(self):
        integration = Integration.objects.create(external_id="1",
                                                 provider="jira")
        integration.add_organization(self.organization)

        with self.feature([
                "organizations:incidents",
                "organizations:integrations-ticket-rules"
        ]):
            response = self.get_success_response(self.organization.slug)

        # There should be no ticket actions for Metric Alerts.
        assert len(response.data) == 1
        assert build_action_response(self.email) in response.data
コード例 #24
0
    def validate(self, attrs):
        if ("type" in attrs) != ("target_type"
                                 in attrs) != ("target_identifier" in attrs):
            raise serializers.ValidationError(
                "type, targetType and targetIdentifier must be passed together"
            )
        type = attrs.get("type")
        target_type = attrs.get("target_type")
        access = self.context["access"]
        identifier = attrs.get("target_identifier")

        if type is not None:
            type_info = AlertRuleTriggerAction.get_registered_type(type)
            if target_type not in type_info.supported_target_types:
                allowed_target_types = ",".join(
                    ACTION_TARGET_TYPE_TO_STRING[type_name]
                    for type_name in type_info.supported_target_types)
                raise serializers.ValidationError({
                    "target_type":
                    "Invalid target type for %s. Valid types are [%s]" %
                    (type_info.slug, allowed_target_types)
                })

        if attrs.get("type") == AlertRuleTriggerAction.Type.EMAIL:
            if target_type == AlertRuleTriggerAction.TargetType.TEAM:
                try:
                    team = Team.objects.get(id=identifier)
                except Team.DoesNotExist:
                    raise serializers.ValidationError("Team does not exist")
                if not access.has_team(team):
                    raise serializers.ValidationError("Team does not exist")
            elif target_type == AlertRuleTriggerAction.TargetType.USER:
                try:
                    user = User.objects.get(id=identifier)
                except User.DoesNotExist:
                    raise serializers.ValidationError("User does not exist")

                if not OrganizationMember.objects.filter(
                        organization=self.context["organization"],
                        user=user).exists():
                    raise serializers.ValidationError(
                        "User does not belong to this organization")
        elif attrs.get("type") == AlertRuleTriggerAction.Type.SLACK:
            if not attrs.get("integration"):
                raise serializers.ValidationError(
                    {"integration": "Integration must be provided for slack"})

        elif attrs.get("type") == AlertRuleTriggerAction.Type.SENTRY_APP:
            if not attrs.get("sentry_app"):
                raise serializers.ValidationError({
                    "sentry_app":
                    "SentryApp must be provided for sentry_app"
                })
            if attrs.get("sentry_app_config"):
                if attrs.get("sentry_app_installation_uuid") is None:
                    raise serializers.ValidationError({
                        "sentry_app":
                        "Missing parameter: sentry_app_installation_uuid"
                    })

                try:
                    install = SentryAppInstallation.objects.get(
                        uuid=attrs.get("sentry_app_installation_uuid"))
                except SentryAppInstallation.DoesNotExist:
                    raise serializers.ValidationError(
                        {"sentry_app": "The installation does not exist."})
                # Check response from creator and bubble up errors from providers as a ValidationError
                result = alert_rule_actions.AlertRuleActionCreator.run(
                    install=install,
                    fields=attrs.get("sentry_app_config"),
                )

                if not result["success"]:
                    raise serializers.ValidationError(
                        {"sentry_app": result["message"]})

                del attrs["sentry_app_installation_uuid"]

        attrs["use_async_lookup"] = self.context.get("use_async_lookup")
        attrs["input_channel_id"] = self.context.get("input_channel_id")
        should_validate_channel_id = self.context.get("validate_channel_id",
                                                      True)
        # validate_channel_id is assumed to be true unless explicitly passed as false
        if attrs["input_channel_id"] and should_validate_channel_id:
            validate_channel_id(identifier, attrs["integration"].id,
                                attrs["input_channel_id"])
        return attrs
コード例 #25
0
    def test_create_and_update_sentry_app_action_success(self):
        responses.add(
            method=responses.POST,
            url="https://example.com/sentry/alert-rule",
            status=200,
            json={},
        )

        serializer = AlertRuleTriggerActionSerializer(
            context=self.context,
            data={
                "type":
                AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type.SENTRY_APP).slug,
                "target_type":
                action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.SENTRY_APP],
                "target_identifier":
                "1",
                "sentry_app":
                self.sentry_app.id,
                "sentry_app_config": {
                    "channel": "#general"
                },
                "sentry_app_installation_uuid":
                self.sentry_app_installation.uuid,
            },
        )
        assert serializer.is_valid()

        # Create action
        serializer.save()

        # # Make sure the action was created.
        alert_rule_trigger_actions = list(
            AlertRuleTriggerAction.objects.filter(sentry_app=self.sentry_app))
        assert len(alert_rule_trigger_actions) == 1

        # Update action
        serializer = AlertRuleTriggerActionSerializer(
            context=self.context,
            data={
                "type":
                AlertRuleTriggerAction.get_registered_type(
                    AlertRuleTriggerAction.Type.SENTRY_APP).slug,
                "target_type":
                action_target_type_to_string[
                    AlertRuleTriggerAction.TargetType.SENTRY_APP],
                "target_identifier":
                "1",
                "sentry_app":
                self.sentry_app.id,
                "sentry_app_config": {
                    "channel": "#announcements"
                },
                "sentry_app_installation_uuid":
                self.sentry_app_installation.uuid,
            },
            instance=alert_rule_trigger_actions[0],
        )

        assert serializer.is_valid()

        # Update action
        serializer.save()

        alert_rule_trigger_action = AlertRuleTriggerAction.objects.get(
            sentry_app=self.sentry_app)

        # Make sure the changes got applied
        assert alert_rule_trigger_action.sentry_app_config == {
            "channel": "#announcements"
        }