Skip to content

Commit

Permalink
Revert "Revert slack org does not exist changes breaking escalate com…
Browse files Browse the repository at this point in the history
…mand (#2057)" (#2096)

# What this PR does

Closes grafana/oncall-private#1836

- Revert "Revert slack org does not exist changes breaking escalate
command (#2057)" + add some unit tests to ensure we don't break the
`/escalate` command in the future
- cleanup how we destructure the `payload` dict in the endpoint handler

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
  • Loading branch information
joeyorlando authored Jun 6, 2023
1 parent f1a8cd2 commit cf949ac
Show file tree
Hide file tree
Showing 3 changed files with 312 additions and 122 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Allow mobile app to consume "internal" schedules API endpoints by @joeyorlando ([#2109](https://github.com/grafana/oncall/pull/2109))

### Fixed

- Fix + revert [#2057](https://github.com/grafana/oncall/pull/2057) which reverted a change which properly handles
`Organization.DoesNotExist` exceptions for Slack events by @joeyorlando ([#TBD](https://github.com/grafana/oncall/pull/TBD))

## v1.2.39 (2023-06-06)

### Changed
Expand Down
134 changes: 134 additions & 0 deletions engine/apps/slack/tests/test_interactive_api_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import json
from unittest.mock import call, patch

import pytest
from django.conf import settings
from rest_framework import status
from rest_framework.test import APIClient

from apps.slack.scenarios.scenario_step import PAYLOAD_TYPE_BLOCK_ACTIONS

EVENT_TRIGGER_ID = "5333959822612.4122782784722.4734ff484b2ac4d36a185bb242ee9932"
WARNING_TEXT = (
"OnCall is not able to process this action because one of the following scenarios: \n"
"1. The Slack chatops integration was disconnected from the instance that the Alert Group belongs "
"to, BUT the Slack workspace is still connected to another instance as well. In this case, simply log "
"in to the OnCall web interface and re-install the Slack Integration with this workspace again.\n"
"2. (Less likely) The Grafana instance belonging to this Alert Group was deleted. In this case the Alert Group is orphaned and cannot be acted upon."
)

SLACK_TEAM_ID = "T043LP0P2M8"
SLACK_ACCESS_TOKEN = "asdfasdf"
SLACK_BOT_ACCESS_TOKEN = "cmncvmnvcnm"
SLACK_BOT_USER_ID = "mncvnmvcmnvcmncv,,cx,"

SLACK_USER_ID = "iurtiurituritu"


def _make_request(payload):
return APIClient().post(
"/slack/interactive_api_endpoint/",
format="json",
data=payload,
**{
"HTTP_X_SLACK_SIGNATURE": "asdfasdf",
"HTTP_X_SLACK_REQUEST_TIMESTAMP": "xxcxcvx",
},
)


@pytest.fixture
def slack_team_identity(make_slack_team_identity):
return make_slack_team_identity(
slack_id=SLACK_TEAM_ID,
detected_token_revoked=None,
access_token=SLACK_ACCESS_TOKEN,
bot_access_token=SLACK_BOT_ACCESS_TOKEN,
bot_user_id=SLACK_BOT_USER_ID,
)


@patch("apps.slack.views.SlackEventApiEndpointView.verify_signature", return_value=True)
@patch("apps.slack.views.SlackEventApiEndpointView._open_warning_window_if_needed")
@pytest.mark.django_db
def test_organization_not_found_scenario_properly_handled(
mock_open_warning_window_if_needed,
_mock_verify_signature,
make_organization,
make_slack_user_identity,
slack_team_identity,
):
# SCENARIO 1
# two orgs connected to same slack workspace, the one belonging to the alert group/slack message
# is no longer connected to the slack workspace, but another org still is
make_slack_user_identity(slack_team_identity=slack_team_identity, slack_id=SLACK_USER_ID)

make_organization(slack_team_identity=slack_team_identity)
org2 = make_organization()
event_payload_actions = [
{
"value": json.dumps({"organization_id": org2.id}),
}
]

event_payload = {
"type": PAYLOAD_TYPE_BLOCK_ACTIONS,
"trigger_id": EVENT_TRIGGER_ID,
"user": {
"id": SLACK_USER_ID,
},
"team": {
"id": SLACK_TEAM_ID,
},
"actions": event_payload_actions,
}

response = _make_request(event_payload)
assert response.status_code == status.HTTP_200_OK

# SCENARIO 2
# the org that was associated w/ the alert group, has since been deleted
# and the slack message is now orphaned
org2.hard_delete()

response = _make_request(event_payload)
assert response.status_code == status.HTTP_200_OK

mock_call = call(event_payload, slack_team_identity, WARNING_TEXT)
mock_open_warning_window_if_needed.assert_has_calls([mock_call, mock_call])


@patch("apps.slack.views.SlackEventApiEndpointView.verify_signature", return_value=True)
@patch("apps.slack.views.SlackEventApiEndpointView._open_warning_window_if_needed")
@pytest.mark.django_db
def test_organization_not_found_scenario_doesnt_break_slash_commands(
mock_open_warning_window_if_needed,
_mock_verify_signature,
make_organization,
make_slack_user_identity,
slack_team_identity,
):

make_organization(slack_team_identity=slack_team_identity)
make_slack_user_identity(slack_team_identity=slack_team_identity, slack_id=SLACK_USER_ID)

response = _make_request(
{
"token": "axvnc,mvc,mv,mcvmnxcmnxc",
"team_id": SLACK_TEAM_ID,
"team_domain": "testingtest-nim4013",
"channel_id": "C043HQ70QMB",
"channel_name": "testy-testing",
"user_id": "U043HQ3VABF",
"user_name": "bob.smith",
"command": settings.SLACK_DIRECT_PAGING_SLASH_COMMAND,
"text": "potato",
"api_app_id": "A0909234092340293402934234234234234234",
"is_enterprise_install": "false",
"response_url": "https://hooks.slack.com/commands/cvcv/cvcv/cvcv",
"trigger_id": "asdfasdf.4122782784722.cvcv",
}
)

assert response.status_code == status.HTTP_200_OK
mock_open_warning_window_if_needed.assert_not_called()
Loading

0 comments on commit cf949ac

Please sign in to comment.