import json from unittest.mock import patch import pytest from django.urls import reverse from rest_framework import status from rest_framework.response import Response from rest_framework.test import APIClient from apps.api.permissions import LegacyAccessControlRole from apps.api.views.webhooks import RECENT_RESPONSE_LIMIT, WEBHOOK_URL from apps.webhooks.models import Webhook from apps.webhooks.models.webhook import WEBHOOK_FIELD_PLACEHOLDER TEST_URL = "https://some-url" @pytest.fixture() def webhook_internal_api_setup(make_organization_and_user_with_plugin_token, make_custom_webhook): organization, user, token = make_organization_and_user_with_plugin_token() webhook = make_custom_webhook( name="some_webhook", url="https://github.com/", username="Chris Vanstras", password="qwerty", data='{"name": "{{ alert_payload }}"}', authorization_header="auth_token", organization=organization, forward_all=False, ) return user, token, webhook @pytest.mark.django_db def test_get_list_webhooks(webhook_internal_api_setup, make_custom_webhook, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup # connected integration webhooks are not included make_custom_webhook(organization=user.organization, is_from_connected_integration=True) client = APIClient() url = reverse("api-internal:webhooks-list") expected_payload = [ { "id": webhook.public_primary_key, "name": "some_webhook", "team": None, "url": "https://github.com/", "data": '{"name": "{{ alert_payload }}"}', "username": "Chris Vanstras", "password": WEBHOOK_FIELD_PLACEHOLDER, "authorization_header": WEBHOOK_FIELD_PLACEHOLDER, "forward_all": False, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": "0", "trigger_type_name": "Escalation step", "preset": None, } ] response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK assert response.json() == expected_payload @pytest.mark.django_db def test_get_detail_webhook(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) expected_payload = { "id": webhook.public_primary_key, "name": "some_webhook", "team": None, "url": "https://github.com/", "data": '{"name": "{{ alert_payload }}"}', "username": "Chris Vanstras", "password": WEBHOOK_FIELD_PLACEHOLDER, "authorization_header": WEBHOOK_FIELD_PLACEHOLDER, "forward_all": False, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": "0", "trigger_type_name": "Escalation step", "preset": None, } response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK assert response.json() == expected_payload @pytest.mark.django_db def test_get_detail_connected_integration_webhook( webhook_internal_api_setup, make_custom_webhook, make_user_auth_headers ): user, token, _ = webhook_internal_api_setup # it is possible to get details for a connected integration webhook webhook = make_custom_webhook(organization=user.organization, is_from_connected_integration=True) client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) expected_payload = { "id": webhook.public_primary_key, "name": webhook.name, "team": None, "url": webhook.url, "data": webhook.data, "username": None, "password": None, "authorization_header": None, "forward_all": True, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": "0", "trigger_type_name": "Escalation step", "preset": None, } response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK assert response.json() == expected_payload @pytest.mark.django_db def test_create_webhook(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-list") data = { "name": "the_webhook", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) webhook = Webhook.objects.get(public_primary_key=response.json()["id"]) expected_response = data | { "id": webhook.public_primary_key, "data": None, "username": None, "password": None, "authorization_header": None, "forward_all": True, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": str(data["trigger_type"]), "trigger_type_name": "Alert Group Created", "preset": None, } assert response.status_code == status.HTTP_201_CREATED assert response.json() == expected_response # user creating the webhook is set assert webhook.user == user @pytest.mark.django_db @pytest.mark.parametrize( "field_name,value", [ ("data", '{"name": "{{ alert_payload }}"}'), ("headers", '"request-id": "{{ alert_payload.id }}"'), ("trigger_template", "integration_id == {{ some_var_value }}"), ("url", "https://myserver/{{ alert_payload.id }}/triggered"), ], ) def test_create_valid_templated_field(webhook_internal_api_setup, make_user_auth_headers, field_name, value): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-list") data = { "name": "webhook_with_valid_data", "url": TEST_URL, field_name: value, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) # modify initial data by adding id and None for optional fields webhook = Webhook.objects.get(public_primary_key=response.data["id"]) expected_response = data | { "id": webhook.public_primary_key, "username": None, "password": None, "authorization_header": None, "forward_all": True, "headers": None, "data": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": str(data["trigger_type"]), "trigger_type_name": "Alert Group Created", "preset": None, } # update expected value for changed field expected_response[field_name] = value assert response.status_code == status.HTTP_201_CREATED assert response.json() == expected_response @pytest.mark.django_db @pytest.mark.parametrize( "field_name,value", [ ("data", "{{%"), ("headers", '"request-id": "{{}}"'), ("trigger_template", "integration_id == {{}}"), ("url", "invalid-url/{{}}/triggered"), ], ) def test_create_invalid_templated_field(webhook_internal_api_setup, make_user_auth_headers, field_name, value): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-list") data = { "name": "webhook_with_valid_data", "url": TEST_URL, field_name: value, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST @pytest.mark.django_db def test_update_webhook(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) data = { "name": "github_button_updated", "url": "https://github.com/", "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, } response = client.put( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token) ) updated_instance = Webhook.objects.get(public_primary_key=webhook.public_primary_key) assert response.status_code == status.HTTP_200_OK assert updated_instance.name == "github_button_updated" @pytest.mark.django_db def test_delete_webhook(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) response = client.delete(url, **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_204_NO_CONTENT @pytest.mark.django_db def test_webhook_integration_filter(webhook_internal_api_setup, make_alert_receive_channel, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup alert_receive_channel_1 = make_alert_receive_channel(user.organization) alert_receive_channel_2 = make_alert_receive_channel(user.organization) client = APIClient() # create webhook setting integrations filter url = reverse("api-internal:webhooks-list") data = { "name": "the_webhook", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, "integration_filter": [alert_receive_channel_1.public_primary_key], } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_201_CREATED webhook = Webhook.objects.get(public_primary_key=response.json()["id"]) assert list(webhook.filtered_integrations.all()) == [alert_receive_channel_1] assert response.json()["integration_filter"] == [alert_receive_channel_1.public_primary_key] # update filter url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) data = { "name": "github_button_updated", "url": "https://github.com/", "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, "integration_filter": [alert_receive_channel_1.public_primary_key, alert_receive_channel_2.public_primary_key], } response = client.put( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token) ) webhook.refresh_from_db() assert response.status_code == status.HTTP_200_OK assert list(webhook.filtered_integrations.all()) == [alert_receive_channel_1, alert_receive_channel_2] assert response.json()["integration_filter"] == [ alert_receive_channel_1.public_primary_key, alert_receive_channel_2.public_primary_key, ] # clear filter url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) data = { "name": "github_button_updated", "url": "https://github.com/", "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, "integration_filter": [], } response = client.put( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token) ) webhook.refresh_from_db() assert response.status_code == status.HTTP_200_OK assert list(webhook.filtered_integrations.all()) == [] assert response.json()["integration_filter"] == [] # clear filter also works if set to None url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) data = { "name": "github_button_updated", "url": "https://github.com/", "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, "integration_filter": None, } response = client.put( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token) ) webhook.refresh_from_db() assert response.status_code == status.HTTP_200_OK assert list(webhook.filtered_integrations.all()) == [] assert response.json()["integration_filter"] == [] @pytest.mark.django_db @pytest.mark.parametrize( "role,expected_status", [ (LegacyAccessControlRole.ADMIN, status.HTTP_200_OK), (LegacyAccessControlRole.EDITOR, status.HTTP_403_FORBIDDEN), (LegacyAccessControlRole.VIEWER, status.HTTP_403_FORBIDDEN), (LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN), ], ) def test_webhook_create_permissions( make_organization_and_user_with_plugin_token, make_user_auth_headers, role, expected_status, ): _, user, token = make_organization_and_user_with_plugin_token(role) client = APIClient() url = reverse("api-internal:webhooks-list") with patch( "apps.api.views.webhooks.WebhooksView.create", return_value=Response( status=status.HTTP_200_OK, ), ): response = client.post(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == expected_status @pytest.mark.django_db @pytest.mark.parametrize( "role,expected_status", [ (LegacyAccessControlRole.ADMIN, status.HTTP_200_OK), (LegacyAccessControlRole.EDITOR, status.HTTP_403_FORBIDDEN), (LegacyAccessControlRole.VIEWER, status.HTTP_403_FORBIDDEN), (LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN), ], ) def test_webhook_update_permissions( make_organization_and_user_with_plugin_token, make_custom_webhook, make_user_auth_headers, role, expected_status, ): organization, user, token = make_organization_and_user_with_plugin_token(role) webhook = make_custom_webhook(organization=organization) client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) with patch( "apps.api.views.webhooks.WebhooksView.update", return_value=Response( status=status.HTTP_200_OK, ), ): response = client.put(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == expected_status response = client.patch(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == expected_status @pytest.mark.django_db @pytest.mark.parametrize( "role,expected_status", [ (LegacyAccessControlRole.ADMIN, status.HTTP_200_OK), (LegacyAccessControlRole.EDITOR, status.HTTP_200_OK), (LegacyAccessControlRole.VIEWER, status.HTTP_200_OK), (LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN), ], ) def test_webhook_list_permissions( make_organization_and_user_with_plugin_token, make_custom_webhook, make_user_auth_headers, role, expected_status, ): organization, user, token = make_organization_and_user_with_plugin_token(role) make_custom_webhook(organization=organization) client = APIClient() url = reverse("api-internal:webhooks-list") with patch( "apps.api.views.webhooks.WebhooksView.list", return_value=Response( status=status.HTTP_200_OK, ), ): response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == expected_status @pytest.mark.django_db @pytest.mark.parametrize( "role,expected_status", [ (LegacyAccessControlRole.ADMIN, status.HTTP_200_OK), (LegacyAccessControlRole.EDITOR, status.HTTP_200_OK), (LegacyAccessControlRole.VIEWER, status.HTTP_200_OK), (LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN), ], ) def test_webhook_retrieve_permissions( make_organization_and_user_with_plugin_token, make_custom_webhook, make_user_auth_headers, role, expected_status, ): organization, user, token = make_organization_and_user_with_plugin_token(role) webhook = make_custom_webhook(organization=organization) client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) with patch( "apps.api.views.webhooks.WebhooksView.retrieve", return_value=Response( status=status.HTTP_200_OK, ), ): response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == expected_status @pytest.mark.django_db @pytest.mark.parametrize( "role,expected_status", [ (LegacyAccessControlRole.ADMIN, status.HTTP_204_NO_CONTENT), (LegacyAccessControlRole.EDITOR, status.HTTP_403_FORBIDDEN), (LegacyAccessControlRole.VIEWER, status.HTTP_403_FORBIDDEN), (LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN), ], ) def test_webhook_delete_permissions( make_organization_and_user_with_plugin_token, make_custom_webhook, make_user_auth_headers, role, expected_status, ): organization, user, token = make_organization_and_user_with_plugin_token(role) webhook = make_custom_webhook(organization=organization) client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) with patch( "apps.api.views.webhooks.WebhooksView.destroy", return_value=Response( status=status.HTTP_204_NO_CONTENT, ), ): response = client.delete(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == expected_status @pytest.mark.django_db def test_get_webhook_from_other_team_with_flag( make_organization_and_user_with_plugin_token, make_team, make_user_auth_headers, make_custom_webhook, ): organization, user, token = make_organization_and_user_with_plugin_token() team = make_team(organization) webhook = make_custom_webhook(organization=organization, team=team) client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) url = f"{url}?from_organization=true" response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK @pytest.mark.django_db def test_webhook_from_other_team_without_flag( make_organization_and_user_with_plugin_token, make_team, make_user_auth_headers, make_custom_webhook, ): organization, user, token = make_organization_and_user_with_plugin_token() team = make_team(organization) webhook = make_custom_webhook(organization=organization, team=team) client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK @pytest.mark.django_db def test_get_webhook_responses( make_organization_and_user_with_plugin_token, make_team, make_user_auth_headers, make_custom_webhook, make_webhook_response, ): organization, user, token = make_organization_and_user_with_plugin_token() team = make_team(organization) webhook = make_custom_webhook( organization=organization, team=team, trigger_type=Webhook.TRIGGER_ALERT_GROUP_CREATED ) for i in range(0, RECENT_RESPONSE_LIMIT + 1): make_webhook_response( webhook=webhook, trigger_type=webhook.trigger_type, status_code=200, content=json.dumps({"id": "third-party-id"}), event_data=json.dumps({"test": f"{i}"}), ) client = APIClient() url = reverse("api-internal:webhooks-responses", kwargs={"pk": webhook.public_primary_key}) response = client.get(url, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK assert len(response.data) == RECENT_RESPONSE_LIMIT @pytest.mark.django_db @pytest.mark.parametrize( "test_template, test_payload, expected_result", [ ("https://test.com", None, "https://test.com"), ("https://test.com", "", "https://test.com"), ("{{ name }}", {"name": "test_1"}, "test_1"), ("{{ name }}", '{"name": "test_1"}', "test_1"), ], ) def test_webhook_preview_template( webhook_internal_api_setup, make_user_auth_headers, test_template, test_payload, expected_result ): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-preview-template", kwargs={"pk": webhook.public_primary_key}) data = { "template_name": WEBHOOK_URL, "template_body": test_template, "payload": test_payload, } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK assert response.data["preview"] == expected_result @pytest.mark.django_db def test_webhook_field_masking(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-list") data = { "name": "the_webhook", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, "password": "secret_password", "authorization_header": "auth 1234", } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) webhook = Webhook.objects.get(public_primary_key=response.data["id"]) expected_response = data | { "id": webhook.public_primary_key, "data": None, "username": None, "password": WEBHOOK_FIELD_PLACEHOLDER, "authorization_header": WEBHOOK_FIELD_PLACEHOLDER, "forward_all": True, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": str(data["trigger_type"]), "trigger_type_name": "Alert Group Created", "preset": None, } assert response.status_code == status.HTTP_201_CREATED assert response.json() == expected_response assert webhook.password == data["password"] assert webhook.authorization_header == data["authorization_header"] assert webhook.user == user @pytest.mark.django_db def test_webhook_copy(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-list") data = { "name": "the_webhook", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "team": None, "password": "secret_password", "authorization_header": "auth 1234", } response1 = client.post(url, data, format="json", **make_user_auth_headers(user, token)) get_url = reverse("api-internal:webhooks-detail", kwargs={"pk": response1.data["id"]}) response2 = client.get(get_url, format="json", **make_user_auth_headers(user, token)) to_copy = response2.json() to_copy["name"] = "copied_webhook" response3 = client.post(url, to_copy, format="json", **make_user_auth_headers(user, token)) webhook = Webhook.objects.get(public_primary_key=response3.data["id"]) expected_response = data | { "id": webhook.public_primary_key, "name": to_copy["name"], "data": None, "username": None, "password": WEBHOOK_FIELD_PLACEHOLDER, "authorization_header": WEBHOOK_FIELD_PLACEHOLDER, "forward_all": True, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "labels": [], "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": str(data["trigger_type"]), "trigger_type_name": "Alert Group Created", "preset": None, } assert response3.status_code == status.HTTP_201_CREATED assert response3.json() == expected_response assert webhook.password == data["password"] assert webhook.authorization_header == data["authorization_header"] assert webhook.id != to_copy["id"] assert webhook.user == user @pytest.mark.django_db def test_create_invalid_missing_fields(webhook_internal_api_setup, make_user_auth_headers): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-list") data = {"url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST"} response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json()["name"][0] == "This field is required." data = {"name": "test webhook 1", "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST"} response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json()["url"][0] == "This field is required." data = {"name": "test webhook 2", "url": TEST_URL, "http_method": "POST"} response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json()["trigger_type"][0] == "This field is required." data = { "name": "test webhook 3", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST assert ( response.json()["http_method"][0] == "This field must be one of ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH']." ) data = { "name": "test webhook 3", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "TOAST", } response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST assert ( response.json()["http_method"][0] == "This field must be one of ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH']." ) data = {"name": "test webhook 3", "url": TEST_URL, "trigger_type": 2000000, "http_method": "POST"} response = client.post(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json()["trigger_type"][0] == "This field is required." @pytest.mark.django_db def test_webhook_filter_by_labels( make_organization_and_user_with_plugin_token, make_custom_webhook, make_webhook_label_association, make_label_key_and_value, make_user_auth_headers, ): organization, user, token = make_organization_and_user_with_plugin_token() webhook_with_label = make_custom_webhook(organization) label = make_webhook_label_association(organization, webhook_with_label) webhook_with_another_label = make_custom_webhook(organization) another_label = make_webhook_label_association(organization, webhook_with_another_label) not_attached_key, not_attached_value = make_label_key_and_value(organization) client = APIClient() # test filter by label, which is attached to only one webhook url = reverse("api-internal:webhooks-list") response = client.get( f"{url}?label={label.key_id}:{label.value_id}", content_type="application/json", **make_user_auth_headers(user, token), ) assert response.status_code == status.HTTP_200_OK assert len(response.json()) == 1 assert response.json()[0]["id"] == webhook_with_label.public_primary_key url = reverse("api-internal:webhooks-list") response = client.get( f"{url}?label={another_label.key_id}:{another_label.value_id}", content_type="application/json", **make_user_auth_headers(user, token), ) assert response.status_code == status.HTTP_200_OK assert len(response.json()) == 1 assert response.json()[0]["id"] == webhook_with_another_label.public_primary_key # test filter by label which is not attached to any webhooks response = client.get( f"{url}?label={not_attached_key.id}:{not_attached_value.id}", content_type="application/json", **make_user_auth_headers(user, token), ) assert len(response.json()) == 0 @pytest.mark.django_db def test_update_webhook_labels( webhook_internal_api_setup, make_user_auth_headers, ): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) key_id = "testkey" value_id = "testvalue" data = { "labels": [ { "key": {"id": key_id, "name": "test", "prescribed": False}, "value": {"id": value_id, "name": "testv", "prescribed": False}, } ] } response = client.patch( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token), ) webhook.refresh_from_db() assert response.status_code == status.HTTP_200_OK assert webhook.labels.count() == 1 label = webhook.labels.first() assert label.key_id == key_id assert label.value_id == value_id response = client.patch( url, data=json.dumps({"labels": []}), content_type="application/json", **make_user_auth_headers(user, token), ) webhook.refresh_from_db() assert response.status_code == status.HTTP_200_OK assert webhook.labels.count() == 0 @pytest.mark.django_db def test_create_webhook_with_labels( make_organization_and_user_with_plugin_token, make_user_auth_headers, ): organization, user, token = make_organization_and_user_with_plugin_token() client = APIClient() url = reverse("api-internal:webhooks-list") key_id = "testkey" value_id = "testvalue" data = { "name": "the_webhook", "url": TEST_URL, "trigger_type": Webhook.TRIGGER_ALERT_GROUP_CREATED, "http_method": "POST", "labels": [ { "key": {"id": key_id, "name": "test", "prescribed": False}, "value": {"id": value_id, "name": "testv", "prescribed": False}, } ], "team": None, } response = client.post( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token), ) assert response.status_code == 201 webhook = Webhook.objects.get(public_primary_key=response.json()["id"]) expected_response = data | { "id": webhook.public_primary_key, "data": None, "username": None, "password": None, "authorization_header": None, "forward_all": True, "headers": None, "http_method": "POST", "integration_filter": [], "is_webhook_enabled": True, "is_legacy": False, "last_response_log": { "request_data": "", "request_headers": "", "timestamp": None, "content": "", "status_code": None, "request_trigger": "", "url": "", "event_data": "", }, "trigger_template": None, "trigger_type": str(data["trigger_type"]), "trigger_type_name": "Alert Group Created", "preset": None, } assert response.status_code == status.HTTP_201_CREATED assert response.json() == expected_response @pytest.mark.django_db def test_update_webhook_labels_duplicate_key( webhook_internal_api_setup, make_user_auth_headers, ): user, token, webhook = webhook_internal_api_setup client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) key_id = "testkey" data = { "labels": [ {"key": {"id": key_id, "name": "test"}, "value": {"id": "testvalue1", "name": "testv1"}}, {"key": {"id": key_id, "name": "test"}, "value": {"id": "testvalue2", "name": "testv2"}}, ] } response = client.patch( url, data=json.dumps(data), content_type="application/json", **make_user_auth_headers(user, token), ) webhook.refresh_from_db() assert response.status_code == status.HTTP_400_BAD_REQUEST assert webhook.labels.count() == 0 @pytest.mark.django_db def test_team_not_updated_if_not_in_data( make_organization_and_user_with_plugin_token, make_team, make_custom_webhook, make_user_auth_headers, ): organization, user, token = make_organization_and_user_with_plugin_token() team = make_team(organization) webhook = make_custom_webhook( name="some_webhook", url="https://github.com/", organization=organization, forward_all=False, team=team, ) assert webhook.team == team client = APIClient() url = reverse("api-internal:webhooks-detail", kwargs={"pk": webhook.public_primary_key}) data = {"name": "renamed"} response = client.put(url, data=data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK assert response.json()["team"] == webhook.team.public_primary_key webhook.refresh_from_db() assert webhook.team == team