Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance ms teams functionalities part1 #37268

Merged
merged 50 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3d2fada
Added token_permissions_list command
ShacharKidor Nov 18, 2024
acac4f5
Added the token_permissions_list_command
ShacharKidor Nov 18, 2024
3b78114
Added support for getting auth code flow api permissions
ShacharKidor Nov 18, 2024
b76543e
Fixed Auth Type string
ShacharKidor Nov 19, 2024
021b818
Added the 'create_messaging_endpoint' command
ShacharKidor Nov 21, 2024
8fc6b62
Pre commit fixes
ShacharKidor Nov 21, 2024
7b9d91d
Added the RN file
ShacharKidor Nov 21, 2024
0adea01
pre-commit
ShacharKidor Nov 21, 2024
13a02ba
Merge branch 'master' into enhance_ms_teams_functionalities_part1
ShacharKidor Nov 21, 2024
f7d1223
Updated the docker image tag
ShacharKidor Nov 21, 2024
0b89f47
Added unit tests
ShacharKidor Nov 21, 2024
59dade0
Ignore secrets
ShacharKidor Nov 21, 2024
1469fff
Merge remote-tracking branch 'origin/master' into enhance_ms_teams_fu…
ShacharKidor Nov 21, 2024
4e66b40
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 24, 2024
834b467
Post CR fixes + Improved documentation
ShacharKidor Nov 24, 2024
7399d38
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 25, 2024
350ff00
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 25, 2024
97d87a7
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 25, 2024
1b181b0
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 25, 2024
bad9ffb
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
a851537
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
b3d4bf3
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
6de7cfd
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
9eb7d65
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
c6dc2ed
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
588031d
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
b6b4a3f
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
4f06237
Update Packs/MicrosoftTeams/ReleaseNotes/1_5_6.md
ShacharKidor Nov 25, 2024
35f653f
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
97f3149
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 25, 2024
fb7e904
fixed hr
ShacharKidor Nov 25, 2024
c2933a3
Handled the xsoar engine case
ShacharKidor Nov 25, 2024
84764ee
pre commit fixes
ShacharKidor Nov 25, 2024
d2df96c
Fixed err messages
ShacharKidor Nov 25, 2024
c40b91c
Improved tenant id err msg
ShacharKidor Nov 25, 2024
92895cd
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
a2f82a6
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
1c71631
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/README.md
ShacharKidor Nov 26, 2024
fb45feb
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
0831b7a
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
d76230f
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
9304b77
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
4de0dd4
Update Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeam…
ShacharKidor Nov 26, 2024
a657cdd
fixed inner numbering
ShacharKidor Nov 26, 2024
fd25fe5
removed space
ShacharKidor Nov 26, 2024
599459d
pre commit fixes
ShacharKidor Nov 26, 2024
62640fe
Merged master into current branch.
Nov 26, 2024
0fdbb0d
Bump pack from version MicrosoftTeams to 1.5.7.
Nov 26, 2024
36676b1
Post CR fixes
ShacharKidor Nov 28, 2024
c7bda40
Merge branch 'master' into enhance_ms_teams_functionalities_part1
ShacharKidor Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Packs/MicrosoftTeams/.secrets-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@ MmFiOWM3OTYtMjkwMi00NWY4LWI3MTItN2M1YTYzY2Y0MWM0IyNlZWY5Y2IzNi0wNmRlLTQ2OWItODdj
MmFiOWM3OTYtMjkwMi00NWY4LWI3MTItN2M1YTYzY2Y0MWM0IyNlZWY5Y2IzNi0wNmRlLTQ2OWItODdjZC03MGY0Y2JlMz6Jk45=
MmFiOWM3OTYtMjkwamii00NWY4LWI3MTItN2M1YTYzY2Y0MWM0IyNlZWY5Y2IzNi0wNmRlLTQ2OWItODdjZC03MGY0Y2JlMzJkM123=
MCMjMCMjZGNkMjE5ZGQtYmM2OC00YjliLWJmMGItNGEzM2E3OTZiZTM1IyMxOTowOWRkYzk5MC0zODIxLTRjZWItODAxOS0yNGQzOTk5OGY5M2VfNDhkMzE4ODctNWZhZC00ZDczLWE5ZjUtM2MzNTZlNjhhMDM4QHVucS5nYmwuc3BhY2VzIyM0OGQzMTg4Ny01ZmFkLTRkNzMtYTlmNS0zYzM1NmU2OGEwMzg=
https://make.powerautomate.com
https://make.powerautomate.com
https://ext-
http://ext-
http://IP
https://IP
https://my
https://dns-test.name
109 changes: 107 additions & 2 deletions Packs/MicrosoftTeams/Integrations/MicrosoftTeams/MicrosoftTeams.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class FormType(Enum): # Used for 'send-message', and by the MicrosoftTeamsAsk s

INCIDENT_TYPE: str = PARAMS.get('incidentType', '')
URL_REGEX = r'(?<!\]\()https?://[^\s]*'
XSOAR_ENGINE_URL_REGEX = r'\bhttps?://(?:\w+[\w.-]*\w+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):\d+(?:/(?:\w+/)*\w+)?'
ENTITLEMENT_REGEX: str = \
r'(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}'
MENTION_REGEX = r'^@([^@;]+);| @([^@;]+);'
Expand Down Expand Up @@ -2774,6 +2775,109 @@ def long_running_loop():
time.sleep(5)


def token_permissions_list_command():
"""
Gets the Graph access token stored in the integration context and displays the token's API permissions in the war room.

Use-case:
This command is ideal for users encountering insufficient permissions errors when attempting to
execute an integration command.
By utilizing this command, the user can identify the current permissions associated with their token (app), compare them to
the required permissions for executing the desired command (detailed in the integration's docs), and determine any additional
permissions needed to be added to their application.
"""
# Get the used token from the integration context:
access_token: str = get_graph_access_token()

# Decode the token and extract the roles:
if access_token:
decoded_token = jwt.decode(access_token, options={"verify_signature": False})

if AUTH_TYPE == CLIENT_CREDENTIALS_FLOW:
roles = decoded_token.get('roles', [])

else: # Authorization code flow
roles = decoded_token.get('scp', '')
roles = roles.split()

if roles:
roles = sorted(roles)
hr = tableToMarkdown(f'The API permissions obtained for the used graph access token are: ({len(roles)})',
roles, headers=['Permission'])
else:
hr = 'No permissions obtained for the used graph access token.'

else:
hr = 'Graph access token is not set.'

demisto.debug(f"'microsoft-teams-token-permissions-list' command result is: {hr}")

result = CommandResults(
readable_output=hr
)

return_results(result)


def create_messaging_endpoint_command():
"""
Generates the messaging endpoint, based on the server url, the server version and the instance configurations.

The messaging endpoint should be added to the Demisto bot configuration in Microsoft Teams as part of the Prerequisites of
the integration's set-up.
Link to documentation: https://xsoar.pan.dev/docs/reference/integrations/microsoft-teams#create-the-demisto-bot-in-microsoft-teams
"""
server_address = ''
messaging_endpoint = ''

# Get instance name and server url:
urls = demisto.demistoUrls()
instance_name = demisto.integrationInstance()
xsoar_url = urls.get('server', '')

# In case of an xsoar engine user - He must provide us with the engine address:
engine_url = demisto.args().get('engine_url', '')
if engine_url and not re.search(XSOAR_ENGINE_URL_REGEX, engine_url):
raise ValueError("Invalid engine URL - Please ensure that the engine_url includes the IP (or DNS name)"
" and the port in use, and that it is in the correct format: `https://IP:port` or `http://IP:port`.")

if is_xsoar_on_prem():
if engine_url: # user uses an engine
messaging_endpoint += urljoin(urljoin(engine_url, 'instance/execute'), instance_name)
else:
messaging_endpoint += urljoin(urljoin(xsoar_url, 'instance/execute'), instance_name)

else: # XSIAM or XSOAR SAAS
if engine_url: # user uses an engine
messaging_endpoint += urljoin(urljoin(engine_url, 'xsoar/instance/execute'), instance_name)
else:
# Add the 'ext-' prefix to the xsoar url
if xsoar_url.startswith('http://'):
server_address = xsoar_url.replace('http://', 'http://ext-', 1)
elif xsoar_url.startswith('https://'):
server_address = xsoar_url.replace('https://', 'https://ext-', 1)

messaging_endpoint += urljoin(urljoin(server_address, 'xsoar/instance/execute'), instance_name)

if is_xsiam():
# Replace the '.xdr-' with '.crtx-' for XSIAM tenants
messaging_endpoint = messaging_endpoint.replace('.xdr-', '.crtx-', 1)

hr = f"The messaging endpoint is: ```{messaging_endpoint}```\n\n The messaging endpoint should be added to the Demisto bot"\
f"configuration in Microsoft Teams as part of the Prerequisites of the integration's set-up.\n"\
f"For more information see: [Integration Documentation](https://xsoar.pan.dev/docs/reference/integrations/microsoft-teams#create-the-demisto-bot-in-microsoft-teams)."

demisto.debug(
f"The messaging endpoint that should be added to the Demisto bot configuration in Microsoft Teams is:"
f"{messaging_endpoint}")

result = CommandResults(
readable_output=hr
)

return_results(result)


def validate_auth_code_flow_params(command: str = ''):
"""
Validates that the necessary parameters for the Authorization Code flow have been received.
Expand Down Expand Up @@ -2870,8 +2974,9 @@ def main(): # pragma: no cover
'microsoft-teams-channel-user-list': channel_user_list_command,
'microsoft-teams-user-remove-from-channel': user_remove_from_channel_command,
'microsoft-teams-generate-login-url': generate_login_url_command,
'microsoft-teams-auth-reset': reset_graph_auth

'microsoft-teams-auth-reset': reset_graph_auth,
'microsoft-teams-token-permissions-list': token_permissions_list_command,
'microsoft-teams-create-messaging-endpoint': create_messaging_endpoint_command
}

commands_auth_code: dict = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,24 @@ script:
- description: Run this command if you need to rerun the authentication process.
name: microsoft-teams-auth-reset
arguments: []
dockerimage: demisto/teams:1.0.0.112095
- description: |-
Retrieves the API permissions associated with the used graph access token.

Note: Use this command if you encounter insufficient permissions error when attempting to execute an integration command.
Compare the permissions list obtained for the token with the permissions required for the desired command (can be found in the integration documentation), if there are missing API permissions, add them to your application.
name: microsoft-teams-token-permissions-list
arguments: []
- description: |-
Generates the messaging endpoint, based on the server url, the server version and the instance configurations.

Note: The messaging endpoint should be added to the Demisto bot configuration in Microsoft Teams as part of the Prerequisites of the integration's set-up. For more information see - https://xsoar.pan.dev/docs/reference/integrations/microsoft-teams#create-the-demisto-bot-in-microsoft-teams.
name: microsoft-teams-create-messaging-endpoint
arguments:
- description: |-
If your instance configuration involve an xsoar engine, provide the engine's IP (or DNS name) and the port in use in the following format - `https://IP:port` or `http://IP:port`.
For example - `https://my-engine.name:443`, `http://1.1.1.1:443`.
name: engine_url
dockerimage: demisto/teams:1.0.0.116912
longRunning: true
longRunningPort: true
script: ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2471,3 +2471,205 @@ def test_add_data_to_actions_non_dict_data():
data_value = "string_data"
add_data_to_actions(card_json, data_value)
assert card_json["data"] == data_value


@pytest.mark.parametrize('token, decoded_token, auth_type, expected_hr', [
('dummy_token',
{'aud': 'url', 'exp': '1111', 'roles': ['AppCatalog.Read.All', 'Group.ReadWrite.All', 'User.Read.All']},
'Client Credentials',
'The API permissions obtained for the used graph access token are'),
('dummy_token',
{'aud': 'url', 'exp': '1111', 'roles': []},
'Client Credentials',
'No permissions obtained for the used graph access token.'),
('dummy_token',
{'aud': 'url', 'exp': '1111', 'scp': 'AppCatalog.Read.All Group.ReadWrite.All User.Read.All'},
'Authorization Code',
'The API permissions obtained for the used graph access token are'),
('dummy_token',
{'aud': 'url', 'exp': '1111', 'scp': ''},
'Authorization Code',
'No permissions obtained for the used graph access token.'),
('',
{'roles': []},
'Client Credentials',
'Graph access token is not set.')
])
def test_token_permissions_list_command(mocker, token, decoded_token, auth_type, expected_hr):
"""
Tests the 'token_permissions_list_command' logic:
For client credentials auth flow, the api permissions are found under the 'roles' key in the decoded token data,
while for the auth code flow they are found under the 'scp' key.
This test checks that we extract the api permissions from the graph access token successfully for both auth types.

Given:
1. A dummy token, mocked response of the jet.decode func with API permissions roles under the 'roles' key -
(auth type is client credentials).
2. A dummy token, mocked response of the jet.decode func without API permissions roles under the 'roles' key -
(auth type is client credentials).
3. A dummy token, mocked response of the jet.decode func with API permissions roles under the 'scp' key -
(auth type is Authorization Code).
4. A dummy token, mocked response of the jet.decode func without API permissions roles under the 'scp' key -
(auth type is Authorization Code).
5. Missing token.
When:
- Running the token_permissions_list_command.
Then:
Verify that the human readable output is as expected:
1. API permissions list.
2. No permissions obtained for the used graph access token.
3. API permissions list.
4. No permissions obtained for the used graph access token.
5. Graph access token is not set.
"""
from MicrosoftTeams import token_permissions_list_command
import MicrosoftTeams
mocker.patch('MicrosoftTeams.get_graph_access_token', return_value=token)
mocker.patch('MicrosoftTeams.AUTH_TYPE', new=auth_type)
mocker.patch('jwt.decode', return_value=decoded_token)
results = mocker.patch.object(MicrosoftTeams, 'return_results')

token_permissions_list_command()

assert expected_hr in results.call_args[0][0].readable_output


@pytest.mark.parametrize('xsoar_server, is_xsoar_on_prem, is_xsiam, expected_hr', [
('https://dns-test.name:443', True, False, 'https://dns-test.name:443/instance/execute/teams'),
('https://viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com', False, False,
'https://ext-viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com/xsoar/instance/execute/teams'),
('http://viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com', False, False,
'http://ext-viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com/xsoar/instance/execute/teams'),
('https://viso-test-dummy.xdr-qa-ttt.ss.paloaltonetworks.com', False, True,
'https://ext-viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com/xsoar/instance/execute/teams'),
('http://viso-test-dummy.xdr-qa-ttt.ss.paloaltonetworks.com', False, True,
'http://ext-viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com/xsoar/instance/execute/teams'),
('http://viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com', False, True,
'http://ext-viso-test-dummy.crtx-qa-ttt.ss.paloaltonetworks.com/xsoar/instance/execute/teams'),
],
ids=["Test xsoar 6 server url",
"Test xsoar 8 server url (with https:// prefix)",
"Test xsoar 8 server url (with http:// prefix)",
"Test xsiam server url (with https:// prefix)",
"Test xsiam server url (with http:// prefix)",
"Test xsiam server url without the '.xdr-' string in the dns name"
])
def test_create_messaging_endpoint_command(mocker, xsoar_server, is_xsoar_on_prem, is_xsiam, expected_hr):
"""
Tests the 'create_messaging_endpoint_command' logic.

Given:
1. An xsoar 6 server url.
2. An xsoar 8 server url (with https:// prefix).
3. An xsoar 8 server url (with http:// prefix).
4. An xsiam server url (with https:// prefix).
5. An xsiam server url (with http:// prefix).
6. An xsiam server url without the '.xdr-' string in the dns name.

When:
- Running the create_messaging_endpoint_command.
Then:
Verify that the messaging endpoint was created as expected:
1. The 'instance/execute/teams' suffix was added.
2. The 'ext' prefix was added to the dns name, and the 'xsoar/instance/execute/teams' suffix was added.
3. The 'ext' prefix was added to the dns name, and the 'xsoar/instance/execute/teams' suffix was added.
4. The 'ext' prefix was added to the dns name, the 'xdr-' was replaced with 'crtx-' and the 'xsoar/instance/execute/teams'
suffix was added.
5. The 'ext' prefix was added to the dns name, the 'xdr-' was replaced with 'crtx-' and the 'xsoar/instance/execute/teams'
suffix was added.
6. The 'ext' prefix was added to the dns name, and the 'xsoar/instance/execute/teams' suffix was added.
"""
from MicrosoftTeams import create_messaging_endpoint_command
import MicrosoftTeams
mocker.patch.object(demisto, 'demistoUrls', return_value={'server': xsoar_server})
mocker.patch.object(demisto, 'integrationInstance', return_value="teams")
mocker.patch.object(demisto, 'args', return_value={'engine_url': ''})
mocker.patch('MicrosoftTeams.is_xsoar_on_prem', return_value=is_xsoar_on_prem)
mocker.patch('MicrosoftTeams.is_xsiam', return_value=is_xsiam)
results = mocker.patch.object(MicrosoftTeams, 'return_results')

create_messaging_endpoint_command()

assert expected_hr in results.call_args[0][0].readable_output


@pytest.mark.parametrize('engine_url, is_xsoar_on_prem, is_xsiam, expected_hr', [
('https://my-engine.com:333', True, False, 'https://my-engine.com:333/instance/execute/teams'),
('https://my-engine.com:333', False, False, 'https://my-engine.com:333/xsoar/instance/execute/teams'),
('https://my-engine.com:333', False, True, 'https://my-engine.com:333/xsoar/instance/execute/teams'),
('https://1.1.1.1:333', False, True, 'https://1.1.1.1:333/xsoar/instance/execute/teams')
],
ids=["Test xsoar 6 engine url",
"Test xsoar 8 engine url",
"Test xsiam engine url",
"Test xsoar engine url - with IP",
])
def test_create_messaging_endpoint_command_for_xsoar_engine(mocker, engine_url, is_xsoar_on_prem, is_xsiam, expected_hr):
"""
Tests the 'create_messaging_endpoint_command' logic when the user uses an xsoar engine.

Given:
- An xsoar engine url.

When:
- Running the create_messaging_endpoint_command on:
1. xsoar 6
2. xsoar 8
3. xsiam
4. The engine url include an IP and not a DNS name.
Then:
Verify that the messaging endpoint was created as expected:
1. The 'instance/execute/teams' suffix was added to the engine url.
2. The 'xsoar/instance/execute/teams' suffix was added to the engine url.
3. The 'xsoar/instance/execute/teams' suffix was added to the engine url.
4. The 'xsoar/instance/execute/teams' suffix was added to the engine url.
"""
from MicrosoftTeams import create_messaging_endpoint_command
import MicrosoftTeams
mocker.patch.object(demisto, 'demistoUrls', return_value={'server': 'https://test-server.com:443'})
mocker.patch.object(demisto, 'integrationInstance', return_value="teams")
mocker.patch.object(demisto, 'args', return_value={'engine_url': engine_url})
mocker.patch('MicrosoftTeams.is_xsoar_on_prem', return_value=is_xsoar_on_prem)
mocker.patch('MicrosoftTeams.is_xsiam', return_value=is_xsiam)
results = mocker.patch.object(MicrosoftTeams, 'return_results')

create_messaging_endpoint_command()

assert expected_hr in results.call_args[0][0].readable_output


@pytest.mark.parametrize('engine_url', [
('https://my-engine.com'),
('my-engine.com:333'),
('https://my engine.com:433'),
],
ids=["Test engine url without a port",
"Test engine url without an http or https prefix",
"Test engine url with spaces in the dns name",
])
def test_create_messaging_endpoint_command_invalid_xsoar_engine(mocker, engine_url):
"""
Tests the 'create_messaging_endpoint_command' logic when the user uses an xsoar engine, and provides an invalid engine url.

Given:
- An invalid engine url:
1. without a port.
2. without an http:// or https:// prefix
3. with a space in the dns name

When:
- Running the create_messaging_endpoint_command.

Then:
Verify that a valueError exception is raised with the error description.
"""
from MicrosoftTeams import create_messaging_endpoint_command
import MicrosoftTeams
mocker.patch.object(demisto, 'demistoUrls', return_value={'server': 'https://test-server.com:443'})
mocker.patch.object(demisto, 'integrationInstance', return_value="teams")
mocker.patch.object(demisto, 'args', return_value={'engine_url': engine_url})
mocker.patch.object(MicrosoftTeams, 'return_results')

with pytest.raises(ValueError) as e:
create_messaging_endpoint_command()
assert 'Invalid engine URL -' in str(e.value)
Loading
Loading