diff --git a/.github/workflows/expensive-e2e-tests.yml b/.github/workflows/expensive-e2e-tests.yml deleted file mode 100644 index 8ea7a1c05..000000000 --- a/.github/workflows/expensive-e2e-tests.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Expensive e2e tests -on: - push: - branches: - - main - # allows manual run on github actions - workflow_dispatch: - schedule: - - cron: "0 6 * * 1-5" - -jobs: - end-to-end-tests: - name: Expensive e2e tests - strategy: - matrix: - grafana_version: - - 10.3.0 - - 11.2.0 - - latest - fail-fast: false - # Run one version at a time to avoid the issue when SMS notification are bundled together for multiple versions - # running at the same time (the affected test is in grafana-plugin/e2e-tests/alerts/sms.test.ts) - max-parallel: 1 - uses: ./.github/workflows/e2e-tests.yml - with: - grafana_version: ${{ matrix.grafana_version }} - run-expensive-tests: true - browsers: "chromium" - secrets: inherit - - post-status-to-slack: - runs-on: ubuntu-latest - needs: end-to-end-tests - if: failure() - steps: - # Useful references - # https://stackoverflow.com/questions/59073850/github-actions-get-url-of-test-build - # https://github.com/orgs/community/discussions/26822#discussioncomment-3305794 - # - - uses: slackapi/slack-github-action@v1.24.0 - with: - channel-id: gops-irm-dev - # yamllint disable rule:line-length - payload: | - { - "blocks": [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "Daily e2e tests build result: ${{ needs.end-to-end-tests.result == 'success' && ':check:' || ':alert:' }}\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - } - } - ] - } - # yamllint enable rule:line-length - env: - SLACK_BOT_TOKEN: ${{ secrets.SLACK_DAILY_E2E_TESTS_BOT_TOKEN }} diff --git a/engine/apps/api/tests/test_alert_receive_channel.py b/engine/apps/api/tests/test_alert_receive_channel.py index 6378de0c4..460c335e2 100644 --- a/engine/apps/api/tests/test_alert_receive_channel.py +++ b/engine/apps/api/tests/test_alert_receive_channel.py @@ -2066,6 +2066,12 @@ def test_alert_receive_channel_test_connection( data = { "integration": integration_config.slug, "team": None, + "create_default_webhooks": True, + "alert_group_labels": { + "inheritable": {}, + "custom": [], + "template": None, + }, } # no test connection setup diff --git a/engine/apps/api/views/alert_receive_channel.py b/engine/apps/api/views/alert_receive_channel.py index e70be1429..19c40a579 100644 --- a/engine/apps/api/views/alert_receive_channel.py +++ b/engine/apps/api/views/alert_receive_channel.py @@ -24,6 +24,7 @@ AlertReceiveChannelSerializer, AlertReceiveChannelUpdateSerializer, FilterAlertReceiveChannelSerializer, + IntegrationAlertGroupLabelsSerializer, ) from apps.api.serializers.alert_receive_channel_connection import ( AlertReceiveChannelConnectedChannelSerializer, @@ -309,7 +310,10 @@ def _test_connection(self, request, pk=None): # check we have all the required information serializer.is_valid(raise_exception=True) if instance is None: + # pop extra fields so they are not passed to AlertReceiveChannel(**serializer.validated_data) serializer.validated_data.pop("create_default_webhooks", None) + IntegrationAlertGroupLabelsSerializer.pop_alert_group_labels(serializer.validated_data) + # create in-memory instance to test with the (possible) unsaved data instance = AlertReceiveChannel(**serializer.validated_data) else: diff --git a/engine/apps/email/inbound.py b/engine/apps/email/inbound.py index 950728f22..6456d9fb2 100644 --- a/engine/apps/email/inbound.py +++ b/engine/apps/email/inbound.py @@ -144,8 +144,9 @@ def message(self) -> AnymailInboundMessage | None: messages = [event.message for event in events if isinstance(event, AnymailInboundEvent)] if messages: - logger.info(f"Received inbound email message from ESP: {esp}") - return messages[0] + message: AnymailInboundMessage = messages[0] + logger.info(f"Received inbound email message from ESP: {esp}, is HTML: {message.html is not None}") + return message logger.error("Failed to parse inbound email message") return None diff --git a/engine/apps/public_api/tests/test_escalation_chain.py b/engine/apps/public_api/tests/test_escalation_chain.py index f8bab811b..b27740b31 100644 --- a/engine/apps/public_api/tests/test_escalation_chain.py +++ b/engine/apps/public_api/tests/test_escalation_chain.py @@ -1,8 +1,12 @@ +import httpretty import pytest from django.urls import reverse from rest_framework import status from rest_framework.test import APIClient +from apps.api import permissions +from apps.auth_token.tests.helpers import setup_service_account_api_mocks + @pytest.mark.django_db def test_get_escalation_chains(make_organization_and_user_with_token): @@ -54,6 +58,43 @@ def test_create_escalation_chain(make_organization_and_user_with_token): assert response.data == expected_data +@pytest.mark.django_db +@httpretty.activate(verbose=True, allow_net_connect=False) +def test_create_escalation_chain_via_service_account( + make_organization, + make_service_account_for_organization, + make_token_for_service_account, + make_team, +): + organization = make_organization(grafana_url="http://grafana.test") + team = make_team(organization=organization) + service_account = make_service_account_for_organization(organization) + token_string = "glsa_token" + make_token_for_service_account(service_account, token_string) + + perms = { + permissions.RBACPermission.Permissions.ESCALATION_CHAINS_WRITE.value: ["*"], + } + setup_service_account_api_mocks(organization.grafana_url, perms) + + client = APIClient() + url = reverse("api-public:escalation_chains-list") + data = {"name": "test", "team_id": team.public_primary_key} + response = client.post( + url, + data=data, + format="json", + HTTP_AUTHORIZATION=f"{token_string}", + HTTP_X_GRAFANA_URL=organization.grafana_url, + ) + if not organization.is_rbac_permissions_enabled: + assert response.status_code == status.HTTP_403_FORBIDDEN + else: + assert response.status_code == status.HTTP_201_CREATED + escalation_chain = organization.escalation_chains.get(name="test") + assert escalation_chain.team == team + + @pytest.mark.django_db def test_change_name(make_organization_and_user_with_token): organization, user, token = make_organization_and_user_with_token() diff --git a/engine/apps/user_management/models/service_account.py b/engine/apps/user_management/models/service_account.py index 50e4e578a..bb9d82711 100644 --- a/engine/apps/user_management/models/service_account.py +++ b/engine/apps/user_management/models/service_account.py @@ -29,6 +29,10 @@ def pk(self): def current_team(self): return None + @property + def available_teams(self): + return self.organization.teams + @property def organization_id(self): return self.organization.id diff --git a/engine/requirements-dev.txt b/engine/requirements-dev.txt index 03cf4606a..cfb600e9e 100644 --- a/engine/requirements-dev.txt +++ b/engine/requirements-dev.txt @@ -18,7 +18,7 @@ charset-normalizer==3.3.2 # requests distlib==0.3.8 # via virtualenv -django==4.2.16 +django==4.2.17 # via # -c requirements.txt # django-stubs diff --git a/engine/requirements.in b/engine/requirements.in index 1ecf5d519..e8fa1d3e5 100644 --- a/engine/requirements.in +++ b/engine/requirements.in @@ -2,7 +2,7 @@ babel==2.12.1 beautifulsoup4==4.12.2 celery[redis]==5.3.1 cryptography==43.0.1 -django==4.2.16 +django==4.2.17 django-add-default-value==0.10.0 django-anymail[amazon-ses]==12.0 django-cors-headers==3.7.0 diff --git a/engine/requirements.txt b/engine/requirements.txt index 7ac3a6ea2..a85334b20 100644 --- a/engine/requirements.txt +++ b/engine/requirements.txt @@ -75,7 +75,7 @@ deprecated==1.2.14 # opentelemetry-api # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-semantic-conventions -django==4.2.16 +django==4.2.17 # via # -r requirements.in # django-add-default-value diff --git a/engine/tox.ini b/engine/tox.ini index be2959bbe..0f57f7ffa 100644 --- a/engine/tox.ini +++ b/engine/tox.ini @@ -21,7 +21,8 @@ banned-modules = # --allow-hosts = allow connections to the given hostnames/IPs. # - localhost = our tests on CI use localhost as the host to connect to databases running locally in docker container # - oncall-dev-mariadb = if you're running things locally, with a MariaDB instance running, there's a good chance the hostname will be this -addopts = --dist no --no-migrations --color=yes --showlocals --disable-socket --allow-hosts=localhost,oncall-dev-mariadb +# pytest-socket is disabled for now as it's making tests hang on CI +addopts = --dist no --no-migrations --color=yes --showlocals # https://pytest-django.readthedocs.io/en/latest/faq.html#my-tests-are-not-being-found-why python_files = tests.py test_*.py *_tests.py