コード例 #1
0
    def test_no_actor(self):
        result = AppPlatformEvent(
            resource='event_alert',
            action='triggered',
            install=self.install,
            data={},
        )

        assert result.body == json.dumps({
            'action': 'triggered',
            'installation': {
                'uuid': self.install.uuid,
            },
            'data': {},
            'actor': {
                'type': 'application',
                'id': 'sentry',
                'name': 'Sentry',
            }
        })

        signature = self.sentry_app.build_signature(result.body)

        assert result.headers['Content-Type'] == 'application/json'
        assert result.headers['Sentry-Hook-Resource'] == 'event_alert'
        assert result.headers['Sentry-Hook-Signature'] == signature
コード例 #2
0
def send_alert_event(event, rule, sentry_app_id):
    group = event.group
    project = Project.objects.get_from_cache(id=group.project_id)
    organization = Organization.objects.get_from_cache(id=project.organization_id)

    extra = {
        "sentry_app_id": sentry_app_id,
        "project": project.slug,
        "organization": organization.slug,
        "rule": rule,
    }

    try:
        sentry_app = SentryApp.objects.get(id=sentry_app_id)
    except SentryApp.DoesNotExist:
        logger.info("event_alert_webhook.missing_sentry_app", extra=extra)
        return

    try:
        install = SentryAppInstallation.objects.get(
            organization=organization.id, sentry_app=sentry_app
        )
    except SentryAppInstallation.DoesNotExist:
        logger.info("event_alert_webhook.missing_installation", extra=extra)
        return

    event_context = _webhook_event_data(event, group.id, project.id)

    data = {"event": event_context, "triggered_rule": rule}

    request_data = AppPlatformEvent(
        resource="event_alert", action="triggered", install=install, data=data
    )

    send_and_save_webhook_request(sentry_app.webhook_url, sentry_app, request_data)
コード例 #3
0
def send_webhooks(installation, event, **kwargs):
    try:
        servicehook = ServiceHook.objects.get(
            organization_id=installation.organization_id,
            actor_id=installation.id)
    except ServiceHook.DoesNotExist:
        return

    if event not in servicehook.events:
        return

    # The service hook applies to all projects if there are no
    # ServiceHookProject records. Otherwise we want check if
    # the event is within the allowed projects.
    project_limited = ServiceHookProject.objects.filter(
        service_hook_id=servicehook.id).exists()

    if not project_limited:
        resource, action = event.split(".")

        kwargs["resource"] = resource
        kwargs["action"] = action
        kwargs["install"] = installation

        request_data = AppPlatformEvent(**kwargs)

        safe_urlopen(
            url=servicehook.sentry_app.webhook_url,
            data=request_data.body,
            headers=request_data.headers,
            timeout=5,
        )
コード例 #4
0
def send_webhooks(installation, event, **kwargs):
    project_ids = Project.objects.filter(
        organization_id=installation.organization_id, ).values_list('id',
                                                                    flat=True)

    servicehooks = ServiceHook.objects.filter(project_id__in=project_ids, )

    for servicehook in filter(lambda s: event in s.events, servicehooks):
        if not servicehook.created_by_sentry_app:
            continue

        if servicehook.sentry_app != installation.sentry_app:
            continue

        resource, action = event.split('.')

        kwargs['resource'] = resource
        kwargs['action'] = action
        kwargs['install'] = installation

        request_data = AppPlatformEvent(**kwargs)

        safe_urlopen(
            url=servicehook.sentry_app.webhook_url,
            data=request_data.body,
            headers=request_data.headers,
            timeout=5,
        )
コード例 #5
0
def send_alert_event(event,
                     rule,
                     sentry_app_id,
                     additional_payload_key=None,
                     additional_payload=None):
    """
    When an incident alert is triggered, send incident data to the SentryApp's webhook.
    :param event: The `Event` for which to build a payload.
    :param rule: The AlertRule that was triggered.
    :param sentry_app_id: The SentryApp to notify.
    :param additional_payload_key: The key used to attach additional data to the webhook payload
    :param additional_payload: The extra data attached to the payload body at the key specified by `additional_payload_key`.
    :return:
    """
    group = event.group
    project = Project.objects.get_from_cache(id=group.project_id)
    organization = Organization.objects.get_from_cache(
        id=project.organization_id)

    extra = {
        "sentry_app_id": sentry_app_id,
        "project_slug": project.slug,
        "organization_slug": organization.slug,
        "rule": rule,
    }

    try:
        sentry_app = SentryApp.objects.get(id=sentry_app_id)
    except SentryApp.DoesNotExist:
        logger.info("event_alert_webhook.missing_sentry_app", extra=extra)
        return

    try:
        install = SentryAppInstallation.objects.get(
            organization=organization.id,
            sentry_app=sentry_app,
            status=SentryAppInstallationStatus.INSTALLED,
        )
    except SentryAppInstallation.DoesNotExist:
        logger.info("event_alert_webhook.missing_installation", extra=extra)
        return

    event_context = _webhook_event_data(event, group.id, project.id)

    data = {"event": event_context, "triggered_rule": rule}

    # Attach extra payload to the webhook
    if additional_payload_key and additional_payload:
        data[additional_payload_key] = additional_payload

    request_data = AppPlatformEvent(resource="event_alert",
                                    action="triggered",
                                    install=install,
                                    data=data)

    send_and_save_webhook_request(sentry_app, request_data)
コード例 #6
0
def process_resource_change(action, sender, instance_id, *args, **kwargs):
    model = None
    name = None

    # Previous method signature.
    if inspect.isclass(sender):
        model = sender
    else:
        model = TYPES[sender]

    name = RESOURCE_RENAMES.get(model.__name__, model.__name__.lower())

    # We may run into a race condition where this task executes before the
    # transaction that creates the Group has committed.
    try:
        instance = model.objects.get(id=instance_id)
    except model.DoesNotExist as e:
        # Explicitly requeue the task, so we don't report this to Sentry until
        # we hit the max number of retries.
        return current.retry(exc=e)

    event = '{}.{}'.format(name, action)

    if event not in ALLOWED_EVENTS:
        return

    project = None

    if isinstance(instance, Group):
        project = instance.project

    if not project:
        return

    servicehooks = ServiceHook.objects.filter(project_id=project.id, )

    for servicehook in filter(lambda s: event in s.events, servicehooks):
        # For now, these ``post_save`` callbacks are only valid for service
        # hooks created by a Sentry App.
        if not servicehook.created_by_sentry_app:
            continue

        request_data = AppPlatformEvent(
            resource=name,
            action=action,
            install=SentryAppInstallation.objects.get(id=servicehook.actor_id),
            data=serialize(instance),
        )

        safe_urlopen(
            url=servicehook.url,
            data=request_data.body,
            headers=request_data.headers,
            timeout=5,
        )
コード例 #7
0
ファイル: sentry_apps.py プロジェクト: yangnaihua/sentry
def send_webhooks(installation, event, **kwargs):
    try:
        servicehook = ServiceHook.objects.get(
            organization_id=installation.organization_id, actor_id=installation.id
        )
    except ServiceHook.DoesNotExist:
        return

    if event not in servicehook.events:
        return

    # The service hook applies to all projects if there are no
    # ServiceHookProject records. Otherwise we want check if
    # the event is within the allowed projects.
    project_limited = ServiceHookProject.objects.filter(service_hook_id=servicehook.id).exists()

    if not project_limited:
        resource, action = event.split(".")

        kwargs["resource"] = resource
        kwargs["action"] = action
        kwargs["install"] = installation

        request_data = AppPlatformEvent(**kwargs)

        potential_error_kwargs = {
            "sentry_app_id": installation.sentry_app_id,
            "organization_id": installation.organization_id,
            "request_body": request_data.body,
            "request_headers": request_data.headers,
            "event_type": event,
            "webhook_url": servicehook.sentry_app.webhook_url,
        }

        try:
            resp = safe_urlopen(
                url=servicehook.sentry_app.webhook_url,
                data=request_data.body,
                headers=request_data.headers,
                timeout=5,
            )
        except RequestException as exc:
            potential_error_kwargs["response_body"] = repr(exc)
            _save_webhook_error(**potential_error_kwargs)
            # Re-raise the exception because some of these tasks might retry on the exception
            raise

        if not resp.ok:
            body = safe_urlread(resp)
            potential_error_kwargs["response_body"] = body
            potential_error_kwargs["response_code"] = resp.status_code
            _save_webhook_error(**potential_error_kwargs)
コード例 #8
0
def send_webhooks(installation, event, **kwargs):
    try:
        servicehook = ServiceHook.objects.get(
            organization_id=installation.organization_id,
            actor_id=installation.id)
    except ServiceHook.DoesNotExist:
        logger.info(
            "send_webhooks.missing_servicehook",
            extra={
                "installation_id": installation.id,
                "event": event
            },
        )
        return

    if event not in servicehook.events:
        return

    # The service hook applies to all projects if there are no
    # ServiceHookProject records. Otherwise we want check if
    # the event is within the allowed projects.
    project_limited = ServiceHookProject.objects.filter(
        service_hook_id=servicehook.id).exists()

    # TODO(nola): This is disabled for now, because it could potentially affect internal integrations w/ error.created
    # # If the event is error.created & the request is going out to the Org that owns the Sentry App,
    # # Make sure we don't send the request, to prevent potential infinite loops
    # if (
    #     event == "error.created"
    #     and installation.organization_id == installation.sentry_app.owner_id
    # ):
    #     # We just want to exclude error.created from the project that the integration lives in
    #     # Need to first implement project mapping for integration partners
    #     metrics.incr(
    #         "webhook_request.dropped",
    #         tags={"sentry_app": installation.sentry_app.id, "event": event},
    #     )
    #     return

    if not project_limited:
        resource, action = event.split(".")

        kwargs["resource"] = resource
        kwargs["action"] = action
        kwargs["install"] = installation

        request_data = AppPlatformEvent(**kwargs)
        send_and_save_webhook_request(
            installation.sentry_app,
            request_data,
            servicehook.sentry_app.webhook_url,
        )
コード例 #9
0
ファイル: sentry_apps.py プロジェクト: vetriselvan1187/sentry
def send_webhooks(installation, event, **kwargs):
    try:
        servicehook = ServiceHook.objects.get(
            organization_id=installation.organization_id, actor_id=installation.id
        )
    except ServiceHook.DoesNotExist:
        return

    if event not in servicehook.events:
        return

    # The service hook applies to all projects if there are no
    # ServiceHookProject records. Otherwise we want check if
    # the event is within the allowed projects.
    project_limited = ServiceHookProject.objects.filter(service_hook_id=servicehook.id).exists()

    if not project_limited:
        resource, action = event.split(".")

        kwargs["resource"] = resource
        kwargs["action"] = action
        kwargs["install"] = installation

        request_data = AppPlatformEvent(**kwargs)

        buffer = SentryAppWebhookRequestsBuffer(installation.sentry_app)

        try:
            resp = safe_urlopen(
                url=servicehook.sentry_app.webhook_url,
                data=request_data.body,
                headers=request_data.headers,
                timeout=5,
            )
        except RequestException:
            # Response code of 0 represents timeout
            buffer.add_request(
                response_code=0,
                org_id=installation.organization_id,
                event=event,
                url=servicehook.sentry_app.webhook_url,
            )
            # Re-raise the exception because some of these tasks might retry on the exception
            raise

        buffer.add_request(
            response_code=resp.status_code,
            org_id=installation.organization_id,
            event=event,
            url=servicehook.sentry_app.webhook_url,
        )
コード例 #10
0
    def request(self):
        data = SentryAppInstallationSerializer().serialize(
            self.install,
            attrs={'code': self.api_grant.code},
            user=self.user,
        )

        return AppPlatformEvent(
            resource='installation',
            action='created',
            install=self.install,
            data=data,
            actor=self.user,
        )
コード例 #11
0
ファイル: sentry_apps.py プロジェクト: wangzhichuang/sentry
def send_alert_event(event, rule, sentry_app_id):
    group = event.group
    project = Project.objects.get_from_cache(id=group.project_id)
    organization = Organization.objects.get_from_cache(
        id=project.organization_id)

    extra = {
        'sentry_app_id': sentry_app_id,
        'project': project.slug,
        'organization': organization.slug,
        'rule': rule,
    }

    try:
        sentry_app = SentryApp.objects.get(id=sentry_app_id)
    except SentryApp.DoesNotExist:
        logger.info('event_alert_webhook.missing_sentry_app', extra=extra)
        return

    try:
        install = SentryAppInstallation.objects.get(
            organization=organization.id,
            sentry_app=sentry_app,
        )
    except SentryAppInstallation.DoesNotExist:
        logger.info('event_alert_webhook.missing_installation', extra=extra)
        return

    event_context = _webhook_event_data(event, group.id, project.id)

    data = {
        'event': event_context,
        'triggered_rule': rule,
    }

    request_data = AppPlatformEvent(
        resource='event_alert',
        action='triggered',
        install=install,
        data=data,
    )

    safe_urlopen(
        url=sentry_app.webhook_url,
        data=request_data.body,
        headers=request_data.headers,
        timeout=5,
    )
コード例 #12
0
def send_webhooks(installation, event, **kwargs):
    try:
        servicehook = ServiceHook.objects.get(
            organization_id=installation.organization_id,
            actor_id=installation.id)
    except ServiceHook.DoesNotExist:
        return

    if event not in servicehook.events:
        return

    # The service hook applies to all projects if there are no
    # ServiceHookProject records. Otherwise we want check if
    # the event is within the allowed projects.
    project_limited = ServiceHookProject.objects.filter(
        service_hook_id=servicehook.id).exists()

    if not project_limited:
        resource, action = event.split(".")

        kwargs["resource"] = resource
        kwargs["action"] = action
        kwargs["install"] = installation

        request_data = AppPlatformEvent(**kwargs)

        resp = safe_urlopen(
            url=servicehook.sentry_app.webhook_url,
            data=request_data.body,
            headers=request_data.headers,
            timeout=5,
        )

        # Track any webhook errors for these event types
        if not resp.ok and event in [
                "issue.assigned", "issue.ignored", "issue.resolved"
        ]:
            body = safe_urlread(resp)
            SentryAppWebhookError.objects.create(
                sentry_app_id=installation.sentry_app_id,
                organization_id=installation.organization_id,
                request_body=request_data.body,
                request_headers=request_data.headers,
                event_type=event,
                webhook_url=servicehook.sentry_app.webhook_url,
                response_body=body,
                response_code=resp.status_code,
            )
コード例 #13
0
    def request(self):
        attrs = {}

        if self.action == "created" and self.api_grant:
            attrs["code"] = self.api_grant.code

        data = SentryAppInstallationSerializer().serialize(self.install,
                                                           attrs=attrs,
                                                           user=self.user)

        return AppPlatformEvent(
            resource="installation",
            action=self.action,
            install=self.install,
            data={"installation": data},
            actor=self.user,
        )
コード例 #14
0
    def test_user_actor(self):
        result = AppPlatformEvent(
            resource='installation',
            action='created',
            install=self.install,
            data={},
            actor=self.user,
        )
        assert result.body['actor'] == {
            'type': 'user',
            'id': self.user.id,
            'name': self.user.name,
        }
        body = json.dumps(result.body)
        signature = self.sentry_app.build_signature(body)

        assert result.headers['Content-Type'] == 'application/json'
        assert result.headers['Sentry-Hook-Resource'] == 'installation'
        assert result.headers['Sentry-Hook-Signature'] == signature
コード例 #15
0
    def test_no_actor(self):
        result = AppPlatformEvent(
            resource="event_alert", action="triggered", install=self.install, data={}
        )

        assert result.body == json.dumps(
            {
                "action": "triggered",
                "installation": {"uuid": self.install.uuid},
                "data": {},
                "actor": {"type": "application", "id": "sentry", "name": "Sentry"},
            }
        )

        signature = self.sentry_app.build_signature(result.body)

        assert result.headers["Content-Type"] == "application/json"
        assert result.headers["Sentry-Hook-Resource"] == "event_alert"
        assert result.headers["Sentry-Hook-Signature"] == signature
コード例 #16
0
    def request(self):
        attrs = {}

        if self.install.is_new and self.api_grant:
            attrs['code'] = self.api_grant.code

        data = SentryAppInstallationSerializer().serialize(
            self.install,
            attrs=attrs,
            user=self.user,
        )

        return AppPlatformEvent(
            resource='installation',
            action=self.action,
            install=self.install,
            data={'installation': data},
            actor=self.user,
        )
コード例 #17
0
    def test_user_actor(self):
        result = AppPlatformEvent(
            resource="installation",
            action="created",
            install=self.install,
            data={},
            actor=self.user,
        )

        assert json.loads(result.body)["actor"] == {
            "type": "user",
            "id": self.user.id,
            "name": self.user.name,
        }

        signature = self.sentry_app.build_signature(result.body)

        assert result.headers["Content-Type"] == "application/json"
        assert result.headers["Sentry-Hook-Resource"] == "installation"
        assert result.headers["Sentry-Hook-Signature"] == signature
コード例 #18
0
    def test_sentry_app_actor(self):
        result = AppPlatformEvent(
            resource='issue',
            action='assigned',
            install=self.install,
            data={},
            actor=self.sentry_app.proxy_user,
        )

        assert json.loads(result.body)['actor'] == {
            'type': 'application',
            'id': self.sentry_app.uuid,
            'name': self.sentry_app.name,
        }

        signature = self.sentry_app.build_signature(result.body)

        assert result.headers['Content-Type'] == 'application/json'
        assert result.headers['Sentry-Hook-Resource'] == 'issue'
        assert result.headers['Sentry-Hook-Signature'] == signature
コード例 #19
0
def send_alert_event(event, rule, sentry_app_id):

    group = event.group
    project = group.project

    try:
        sentry_app = SentryApp.objects.get(id=sentry_app_id)
    except SentryApp.DoesNotExist:
        logger.info(
            'event_alert_webhook.missing_sentry_app',
            extra={
                'sentry_app_id': sentry_app_id,
                'project': project.slug,
                'organization': project.organization.slug,
                'rule': rule,
            },
        )
        return

    try:
        install = SentryAppInstallation.objects.get(
            organization=event.project.organization_id,
            sentry_app=sentry_app,
        )
    except SentryAppInstallation.DoesNotExist:
        logger.info(
            'event_alert_webhook.missing_installation',
            extra={
                'sentry_app': sentry_app.slug,
                'project': project.slug,
                'organization': project.organization.slug,
                'rule': rule,
            },
        )
        return

    event_context = event.as_dict()
    event_context['url'] = absolute_uri(
        reverse('sentry-api-0-project-event-details',
                args=[
                    project.organization.slug,
                    project.slug,
                    event.id,
                ]))
    event_context['web_url'] = absolute_uri(
        reverse('sentry-group-event',
                args=[
                    project.organization.slug,
                    project.slug,
                    group.id,
                    event.id,
                ]))
    event_context['issue_url'] = absolute_uri(
        '/api/0/issues/{}/'.format(group.id), )

    data = {
        'event': event_context,
    }

    data['triggered_rule'] = rule

    request_data = AppPlatformEvent(
        resource='event_alert',
        action='triggered',
        install=install,
        data=data,
    )

    safe_urlopen(
        url=sentry_app.webhook_url,
        data=request_data.body,
        headers=request_data.headers,
        timeout=5,
    )
コード例 #20
0
def send_alert_event(event, rule, sentry_app_id):
    group = event.group
    project = group.project

    extra = {
        'sentry_app_id': sentry_app_id,
        'project': project.slug,
        'organization': project.organization.slug,
        'rule': rule,
    }

    try:
        sentry_app = SentryApp.objects.get(id=sentry_app_id)
    except SentryApp.DoesNotExist:
        logger.info('event_alert_webhook.missing_sentry_app', extra=extra)
        return

    try:
        install = SentryAppInstallation.objects.get(
            organization=event.project.organization_id,
            sentry_app=sentry_app,
        )
    except SentryAppInstallation.DoesNotExist:
        logger.info('event_alert_webhook.missing_installation', extra=extra)
        return

    event_context = event.as_dict()
    event_context['url'] = absolute_uri(
        reverse('sentry-api-0-project-event-details',
                args=[
                    project.organization.slug,
                    project.slug,
                    event.id,
                ]))
    event_context['web_url'] = absolute_uri(
        reverse('sentry-group-event',
                args=[
                    project.organization.slug,
                    project.slug,
                    group.id,
                    event.id,
                ]))

    # The URL has a regex OR in it ("|") which means `reverse` cannot generate
    # a valid URL (it can't know which option to pick). We have to manually
    # create this URL for, that reason.
    event_context['issue_url'] = absolute_uri(
        '/api/0/issues/{}/'.format(group.id), )

    data = {
        'event': event_context,
        'triggered_rule': rule,
    }

    request_data = AppPlatformEvent(
        resource='event_alert',
        action='triggered',
        install=install,
        data=data,
    )

    safe_urlopen(
        url=sentry_app.webhook_url,
        data=request_data.body,
        headers=request_data.headers,
        timeout=5,
    )