示例#1
0
def get_event_command():
    # get event data from IronAPI
    event_id = demisto.getArg('event_id')
    results = IRON_DEFENSE.get_event(event_id)

    # Output the event data
    event = results.get('event')
    vue_markdown_link = IRON_DEFENSE.create_markdown_link("Open in IronVue", event.get("vue_url"))
    event_readable_output = tableToMarkdown(f'IronDefense Event: {event.get("category")} -'
                                            f' {event.get("sub_category")}\n'
                                            f'{vue_markdown_link}', event)

    return_outputs(readable_output=event_readable_output,
                   outputs={
                       'IronDefense.Event(val.id == obj.id)': event,
                   },
                   raw_response=event)

    # Output each context table
    context_tables = results.get('context')
    for table in context_tables:
        if IRON_DEFENSE.event_context_table_contains_multi_columns(table):
            output_table = IRON_DEFENSE.event_context_table_to_dict_list(table)
            headers = [*output_table[0]]
        else:
            output_table = IRON_DEFENSE.event_context_table_to_dict(table)
            headers = []

        return_outputs(readable_output=tableToMarkdown(f'Event Context: {table.get("name")}', output_table,
                                                       headers=headers),
                       outputs={
                       'IronDefense.Event.Context(val.name == obj.name)': table,
                       },
                       raw_response=table)
def test_tbl_to_md_empty_fields():
    # all fields are empty
    data = [{
        'a': None,
        'b': None,
        'c': None,
    } for _ in range(3)]
    table_all_none = tableToMarkdown(
        'tableToMarkdown test with all none fields', data)
    expected_table_all_none = '''### tableToMarkdown test with all none fields
|a|b|c|
|---|---|---|
||||
||||
||||
'''
    assert table_all_none == expected_table_all_none

    # all fields are empty - removed
    table_all_none2 = tableToMarkdown(
        'tableToMarkdown test with all none fields2', data, removeNull=True)
    expected_table_all_none2 = '''### tableToMarkdown test with all none fields2
**No entries.**
'''
    assert table_all_none2 == expected_table_all_none2
示例#3
0
def get_events_command():
    alert_id = demisto.getArg('alert_id')
    limit = demisto.getArg('limit')
    offset = demisto.getArg('offset')

    results = IRON_DEFENSE.get_events(alert_id=alert_id, limit=limit, offset=offset)
    events = results.get('events')
    total_count = results.get('constraint').get('total')
    offset = results.get('constraint').get('offset')
    for i, event in enumerate(events):
        vue_markdown_link = IRON_DEFENSE.create_markdown_link("Open in IronVue", event.get("vue_url"))
        event_readable_output = tableToMarkdown(f'IronDefense Event {i + offset + 1}/{total_count}\n'
                                                f'{vue_markdown_link}', event)
        # Send each event
        return_outputs(readable_output=event_readable_output,
                       outputs={
                           'IronDefense.Event(val.id == obj.id)': event,
                       },
                       raw_response=event)

    # Send constraints
    constraint = results.get('constraint')
    return_outputs(readable_output=tableToMarkdown('Query Constraints', constraint),
                   outputs={
                   'IronDefense.Query.GetEvents': constraint,
                   },
                   raw_response=constraint)
示例#4
0
def test_translate(requests_mock):
    """
    Given
            An API key, and text to translate
    When
            Calling translate
    Then
            Test the command result structure
    """
    from YodaSpeak import Client, translate_command
    client = Client(base_url=BASE_URL,
                    verify=False,
                    api_key='foo',
                    proxy=False)
    args = {'text': 'this is some sentence for translation'}

    raw_response = util_load_json('test_data/translate.json')
    requests_mock.post(ENDPOINT_URL, json=raw_response)
    command_result = translate_command(client, **args)

    output = {
        'Original': 'this is some sentence for translation',
        'Translation': 'Some sentence for translation, this is.'
    }

    expected_result = CommandResults(
        outputs_prefix='YodaSpeak',
        outputs_key_field=f'{TRANSLATE_OUTPUT_PREFIX}.Original',
        outputs={TRANSLATE_OUTPUT_PREFIX: output},
        raw_response=raw_response,
        readable_output=tableToMarkdown(name='Yoda Says...', t=output))

    assert command_result.to_context() == expected_result.to_context()
示例#5
0
def test_upload_valid_entry(mocker):
    """

    Given:
        - Valid entry id of a file, str
    When:
        - When the user uploads a file for later conversion via entry
    Then:
        - Returns the response data

    """

    client = create_client()
    mocker.patch.object(
        client,
        'upload_entry_id',
        return_value=util_load_json('./test_data/upload_entry_response.json'))
    results = upload_command(client, {'entry_id': MOCK_ENTRY_ID})
    raw_response = util_load_json('./test_data/upload_entry_response.json')
    raw_response['data']['operation'] = 'upload/entry'
    readable_output = tableToMarkdown(
        'Upload Results',
        remove_empty_elements(raw_response.get('data')),
        headers=('id', 'operation', 'created_at', 'status'),
        headerTransform=string_to_table_header,
    )

    assert results.outputs == remove_empty_elements(raw_response.get('data'))
    assert results.readable_output == readable_output
示例#6
0
def test_convert_valid_format_and_id(mocker):
    """

    Given:
        - Valid destination format for given file
    When:
        - When the user converts a file that was priorly uploaded
    Then:
        - Returns the response data

    """
    client = create_client()
    mocker.patch.object(
        client,
        'convert',
        return_value=util_load_json(
            'test_data/convert_valid_format_and_id_response.json'))
    results = convert_command(client, {
        'task_id': 'id',
        'output_format': 'pdf'
    })
    readable_output = tableToMarkdown(
        'Convert Results',
        remove_empty_elements(
            util_load_json('test_data/convert_val'
                           'id_format_and_id_response.'
                           'json').get('data')),
        headers=('id', 'operation', 'created_at', 'status',
                 'depends_on_task_ids'),
        headerTransform=string_to_table_header)
    assert results.outputs == remove_empty_elements(
        util_load_json(
            'test_data/convert_valid_format_and_id_response.json').get('data'))
    assert results.readable_output == readable_output
示例#7
0
def test_get_indicators_command(mocker):
    """

    Given:
        - Output of the feed API as list
    When:
        - Getting a limited number of indicators from the API
    Then:
        - Return results as war-room entry

    """
    client = Client(base_url=URL)
    indicators_list = util_load_json(
        './test_data/build_iterator_results.json')[:10]
    mocker.patch.object(Client, 'build_iterator', return_value=indicators_list)
    results = get_indicators_command(client,
                                     params={
                                         'tlp_color': 'RED',
                                         'create_relationships': 'false'
                                     },
                                     args={'limit': '10'})
    human_readable = tableToMarkdown('Indicators from HelloWorld Feed:',
                                     indicators_list,
                                     headers=['value', 'type'],
                                     headerTransform=string_to_table_header,
                                     removeNull=True)
    assert results.readable_output == human_readable
def test_tbl_to_md_no_header():
    # no header
    table_no_headers = tableToMarkdown('tableToMarkdown test with no headers', DATA,
                                       headers=['no', 'header', 'found'], removeNull=True)
    expected_table_no_headers = '''### tableToMarkdown test with no headers
**No entries.**
'''
    assert table_no_headers == expected_table_no_headers
示例#9
0
def test_tbl_to_md_dict_with_special_character():
    data = {'header_1': u'foo', 'header_2': [u'\xe2.rtf']}
    table_with_character = tableToMarkdown(
        'tableToMarkdown test with special character', data)
    expected_string_with_special_character = '''### tableToMarkdown test with special character
|header_1|header_2|
|---|---|
| foo | â.rtf |
'''
    assert table_with_character == expected_string_with_special_character
示例#10
0
def test_tbl_to_md_header_with_special_character():
    data = {'header_1': u'foo'}
    table_with_character = tableToMarkdown(
        'tableToMarkdown test with special character Ù', data)
    expected_string_with_special_character = '''### tableToMarkdown test with special character Ù
|header_1|
|---|
| foo |
'''
    assert table_with_character == expected_string_with_special_character
def test_tbl_to_md_only_data():
    # sanity
    table = tableToMarkdown('tableToMarkdown test', DATA)
    expected_table = '''### tableToMarkdown test
|header_1|header_2|header_3|
|---|---|---|
|a1|b1|c1|
|a2|b2|c2|
|a3|b3|c3|
'''
    assert table == expected_table
def test_tbl_to_md_list_of_strings_instead_of_dict():
    # list of string values instead of list of dict objects
    table_string_array = tableToMarkdown('tableToMarkdown test with string array', ['foo', 'bar', 'katz'], ['header_1'])
    expected_string_array_tbl = '''### tableToMarkdown test with string array
|header_1|
|---|
| foo |
| bar |
| katz |
'''
    assert table_string_array == expected_string_array_tbl
def test_tbl_to_md_single_column():
    # single column table
    table_single_column = tableToMarkdown('tableToMarkdown test with single column', DATA, ['header_1'])
    expected_table_single_column = '''### tableToMarkdown test with single column
|header_1|
|---|
| a1 |
| a2 |
| a3 |
'''
    assert table_single_column == expected_table_single_column
示例#14
0
def index_doc_infos(doc_infos: List[DocInfo], link_prefix: str):
    if not doc_infos:
        return ''
    table_items = []
    for d in doc_infos:
        table_items.append({
            'Name': f'[{d.name}]({link_prefix}/{d.id})',
            'Description': d.description
        })
    res = tableToMarkdown('', table_items, headers=['Name', 'Description'])
    return fix_mdx(res)
def test_tbl_to_md_string_header():
    # string header (instead of list)
    table_string_header = tableToMarkdown('tableToMarkdown string header', DATA, 'header_1')
    expected_string_header_tbl = '''### tableToMarkdown string header
|header_1|
|---|
| a1 |
| a2 |
| a3 |
'''
    assert table_string_header == expected_string_header_tbl
def test_tbl_to_md_list_of_strings_instead_of_dict_and_string_header():
    # combination: string header + string values list
    table_string_array_string_header = tableToMarkdown('tableToMarkdown test with string array and string header',
                                                       ['foo', 'bar', 'katz'], 'header_1')
    expected_string_array_string_header_tbl = '''### tableToMarkdown test with string array and string header
|header_1|
|---|
| foo |
| bar |
| katz |
'''
    assert table_string_array_string_header == expected_string_array_string_header_tbl
def test_tbl_to_md_header_transform_underscoreToCamelCase():
    # header transform
    table = tableToMarkdown('tableToMarkdown test with headerTransform', DATA,
                            headerTransform=underscoreToCamelCase)
    expected_table = '''### tableToMarkdown test with headerTransform
|Header1|Header2|Header3|
|---|---|---|
| a1 | b1 | c1 |
| a2 | b2 | c2 |
| a3 | b3 | c3 |
'''
    assert table == expected_table
def test_tbl_to_md_header_not_on_first_object():
    # header not on first object
    data = copy.deepcopy(DATA)
    data[1]['extra_header'] = 'sample'
    table_extra_header = tableToMarkdown('tableToMarkdown test with extra header', data,
                                         headers=['header_1', 'header_2', 'extra_header'])
    expected_table_extra_header = '''### tableToMarkdown test with extra header
|header_1|header_2|extra_header|
|---|---|---|
| a1 | b1 |  |
| a2 | b2 | sample |
| a3 | b3 |  |
'''
    assert table_extra_header == expected_table_extra_header
def test_tbl_to_md_dict_value():
    # dict value
    data = copy.deepcopy(DATA)
    data[1]['extra_header'] = {'sample': 'qwerty', 'sample2': 'asdf'}
    table_dict_record = tableToMarkdown('tableToMarkdown test with dict record', data,
                                        headers=['header_1', 'header_2', 'extra_header'])
    expected_dict_record = '''### tableToMarkdown test with dict record
|header_1|header_2|extra_header|
|---|---|---|
| a1 | b1 |  |
| a2 | b2 | sample: qwerty<br>sample2: asdf |
| a3 | b3 |  |
'''
    assert table_dict_record == expected_dict_record
def test_tbl_to_md_url():
    # url + empty data
    data = copy.deepcopy(DATA)
    for i, d in enumerate(data):
        d['header_3'] = '[url](https:\\demisto.com)'
        d['header_2'] = None
    table_url_missing_info = tableToMarkdown('tableToMarkdown test with url and missing info', data)
    expected_table_url_missing_info = '''### tableToMarkdown test with url and missing info
|header_1|header_2|header_3|
|---|---|---|
| a1 |  | [url](https:\\demisto.com) |
| a2 |  | [url](https:\\demisto.com) |
| a3 |  | [url](https:\\demisto.com) |
'''
    assert table_url_missing_info == expected_table_url_missing_info
def test_tbl_to_md_multiline():
    # escaping characters: multiline + md-chars
    data = copy.deepcopy(DATA)
    for i, d in enumerate(data):
        d['header_2'] = 'b%d.1\nb%d.2' % (i + 1, i + 1,)
        d['header_3'] = 'c%d|1' % (i + 1,)

    table = tableToMarkdown('tableToMarkdown test with multiline', data)
    expected_table = '''### tableToMarkdown test with multiline
|header_1|header_2|header_3|
|---|---|---|
| a1 | b1.1<br>b1.2 | c1\|1 |
| a2 | b2.1<br>b2.2 | c2\|1 |
| a3 | b3.1<br>b3.2 | c3\|1 |
'''
    assert table == expected_table
def test_tbl_to_md_list_values():
    # list values
    data = copy.deepcopy(DATA)
    for i, d in enumerate(data):
        d['header_3'] = [i + 1, 'second item']
        d['header_2'] = 'hi'

    table_list_field = tableToMarkdown('tableToMarkdown test with list field', data)
    expected_table_list_field = '''### tableToMarkdown test with list field
|header_1|header_2|header_3|
|---|---|---|
| a1 | hi | 1,<br>second item |
| a2 | hi | 2,<br>second item |
| a3 | hi | 3,<br>second item |
'''
    assert table_list_field == expected_table_list_field
示例#23
0
def test_check_status_valid_id_download(mocker, create_war_room_entry):
    """

    Given:
        - A valid task id, of an download operation
    When:
        - When the user checks the status of a task that was priorly done, and it is an download operation.

    Then:
        - When checking on a download operation and the argument 'create_war_room_entry' is set to True, the output is a
        warroom entry. if set to False, then a regular response is retrieved.

    """
    import CloudConvert
    client = create_client()
    mocker.patch.object(client,
                        'check_status',
                        return_value=util_load_json(
                            'test_data/check_status_download_response.json'))
    mocker.patch.object(client, 'get_file_from_url', return_value='')
    file_name = util_load_json('test_data/check_status_download_response.json').get('data'). \
        get('result').get('files')[0].get('filename')
    mocker.patch.object(CloudConvert,
                        'fileResult',
                        return_value={'File': file_name})
    results = check_status_command(
        client, {
            'task_id': 'id',
            'create_war_room_entry': create_war_room_entry
        })
    raw_response_data = util_load_json(
        'test_data/check_status_download_response.json').get('data')
    modify_results_dict(raw_response_data)
    if create_war_room_entry:
        raw_response_data['operation'] = 'download/entry'
        assert results.get('File') == file_name

    else:
        raw_response_data['operation'] = 'download/url'
        assert results.outputs == remove_empty_elements(raw_response_data)
        readable_output = tableToMarkdown(
            'Check Status Results',
            remove_empty_elements(raw_response_data),
            headers=('id', 'operation', 'created_at', 'status',
                     'depends_on_task_ids', 'file_name', 'url'),
            headerTransform=string_to_table_header)
        assert results.readable_output == readable_output
示例#24
0
def index_doc_infos(doc_infos: List[DocInfo],
                    link_prefix: str,
                    headers: Optional[Tuple[str, str]] = None):
    if not headers:
        headers = ('Name', 'Description')
    if not doc_infos:
        return ''
    table_items = []
    for d in doc_infos:
        name = html.escape(d.name)
        link_name = f'[{name}]({link_prefix}/{d.id})'
        for word in re.split(r'\s|-', name):
            if len(word
                   ) > 25:  # we have a long word tell browser ok to break it
                link_name = '<span style={{wordBreak: "break-word"}}>' + link_name + '</span>'
                break
        table_items.append({headers[0]: link_name, headers[1]: d.description})
    res = tableToMarkdown('', table_items, headers=headers)
    return fix_mdx(res)
示例#25
0
def test_download_valid_id(mocker, download_as):
    """

    Given:
        - Valid task id for given file
    When:
        - When the user wants to download a file that was priorly uploaded
    Then:
        - Returns the response message of invalid input

    """
    client = create_client()
    mocker.patch.object(client,
                        'download_url',
                        return_value=util_load_json(
                            'test_data/download_valid_id_response.json'))

    results = download_command(client, {
        'task_id': 'id',
        'download_as': download_as
    })
    raw_response = util_load_json('test_data/download_valid_id_response.json')
    if download_as == 'url':
        raw_response['data']['operation'] = 'download/url'
        readable_output = tableToMarkdown(
            'Download Results',
            remove_empty_elements(raw_response.get('data')),
            headers=('id', 'operation', 'created_at', 'status',
                     'depends_on_task_ids'),
            headerTransform=string_to_table_header,
        )
        assert results.outputs == remove_empty_elements(
            raw_response.get('data'))
        assert results.readable_output == readable_output

    else:
        raw_response['data']['operation'] = 'download/entry'
        assert results.outputs == remove_empty_elements(
            raw_response.get('data'))
示例#26
0
def test_check_status_valid_id_non_download(mocker, create_war_room_entry):
    """

    Given:
        - A valid task id, of a non-download operation
    When:
        - When the user checks the status of a task that was priorly done, and it is not download.
        the purpose here is to make sure that the extra argument, 'create_war_room_entry', only makes a difference
         when the id is of an actual download operation.
    Then:
        - Returns the response

    """
    client = create_client()
    mocker.patch.object(
        client,
        'check_status',
        return_value=util_load_json(
            'test_data/check_status_non_download_response.json'))
    results = check_status_command(
        client, {
            'task_id': 'id',
            'create_war_room_entry': create_war_room_entry
        })
    raw_response_data = util_load_json(
        'test_data/check_status_non_download_response.json').get('data')
    modify_results_dict(raw_response_data)
    readable_output = tableToMarkdown('Check Status Results',
                                      remove_empty_elements(raw_response_data),
                                      headers=('id', 'operation', 'created_at',
                                               'status', 'depends_on_task_ids',
                                               'file_name', 'url'),
                                      headerTransform=string_to_table_header)
    modify_results_dict(raw_response_data)
    assert results.outputs == remove_empty_elements(raw_response_data)
    assert results.readable_output == readable_output
示例#27
0
def get_alerts_command():
    alert_id = demisto.getArg('alert_id')
    category = demisto.getArg('category')
    sub_category = demisto.getArg('sub_category')
    status = demisto.getArg('status')
    analyst_severity = demisto.getArg('analyst_severity')
    analyst_expectation = demisto.getArg('analyst_expectation')
    min_severity = demisto.getArg('min_severity')
    max_severity = demisto.getArg('max_severity')
    min_created = demisto.getArg('min_created')
    max_created = demisto.getArg('max_created')
    min_updated = demisto.getArg('min_updated')
    max_updated = demisto.getArg('max_updated')
    min_first_event_created = demisto.getArg('min_first_event_created')
    max_first_event_created = demisto.getArg('max_first_event_created')
    min_last_event_created = demisto.getArg('min_last_event_created')
    max_last_event_created = demisto.getArg('max_last_event_created')
    min_first_event_start_time = demisto.getArg('min_first_event_start_time')
    max_first_event_start_time = demisto.getArg('max_first_event_start_time')
    min_last_event_end_time = demisto.getArg('min_last_event_end_time')
    max_last_event_end_time = demisto.getArg('max_last_event_end_time')
    analytic_version = demisto.getArg('analytic_version')
    limit = demisto.getArg('limit')
    offset = demisto.getArg('offset')
    sort = demisto.getArg('sort')
    results = IRON_DEFENSE.get_alerts(alert_id=alert_id, category=category, sub_category=sub_category, status=status,
                                      analyst_severity=analyst_severity,
                                      analyst_expectation=analyst_expectation, min_severity=min_severity,
                                      max_severity=max_severity, min_created=min_created, max_created=max_created,
                                      min_updated=min_updated, max_updated=max_updated,
                                      min_first_event_created=min_first_event_created,
                                      max_first_event_created=max_first_event_created,
                                      min_last_event_created=min_last_event_created,
                                      max_last_event_created=max_last_event_created,
                                      min_first_event_start_time=min_first_event_start_time,
                                      max_first_event_start_time=max_first_event_start_time,
                                      min_last_event_end_time=min_last_event_end_time,
                                      max_last_event_end_time=max_last_event_end_time,
                                      analytic_version=analytic_version,
                                      limit=limit, offset=offset, sort=sort)
    alerts = results.get('alerts')
    total_count = results.get('constraint').get('total')
    offset = results.get('constraint').get('offset')
    for i, alert in enumerate(alerts):
        # Send each alert
        vue_markdown_link = IRON_DEFENSE.create_markdown_link("Open in IronVue", alert.get("vue_url"))
        alert_readable_output = tableToMarkdown(f'IronDefense Alert {i + offset + 1}/{total_count}: {alert.get("category")} -'
                                                f' {alert.get("sub_category")}\n'
                                                f'{vue_markdown_link}', alert)
        return_outputs(readable_output=alert_readable_output,
                       outputs={
                           'IronDefense.Alert(val.id == obj.id)': alert,
                       },
                       raw_response=alert)

    # Send constraints
    constraint = results.get('constraint')
    return_outputs(readable_output=tableToMarkdown('Query Constraints', constraint),
                   outputs={
                   'IronDefense.Query.GetAlerts': constraint,
                   },
                   raw_response=constraint)
示例#28
0
def get_alert_irondome_information_command():
    alert_id = demisto.getArg('alert_id')
    results = IRON_DEFENSE.get_alert_irondome_information(alert_id)

    if len(results.get('correlations')) == 0 and \
            len(results.get('correlation_participation')) == 0 and \
            len(results.get('community_comments')) == 0 and \
            len(results.get('dome_notifications')) == 0:
        demisto.results(f'No correlations found for alert ID: {alert_id}')
        return

    # Output correlations
    correlations = results.get('correlations')
    for correlation in correlations:
        dome_tag = correlation.get('dome_tag')
        correlation_data = correlation.get('correlations')
        output = {
            'alert_id': alert_id,
            'correlation': correlation
        }
        ip_correlations = list(filter(lambda corr: corr.get('ip') is not None, correlation_data))
        domain_correlations = list(filter(lambda corr: corr.get('domain') is not None, correlation_data))
        behavior_correlations = list(filter(lambda corr: corr.get('behavior') is not None, correlation_data))

        if len(ip_correlations) != 0:
            return_outputs(readable_output=tableToMarkdown(f'IronDome IP Correlations in "{dome_tag}"', ip_correlations,
                                                           headers=[*ip_correlations[0]]),
                           outputs={
                           'IronDome.Correlations(val.alert_id = obj.alert.id)': output
                           },
                           raw_response=correlation)

        if len(domain_correlations) != 0:
            return_outputs(readable_output=tableToMarkdown(f'IronDome Domain Correlations in "{dome_tag}"',
                                                           domain_correlations,
                                                           headers=[*domain_correlations[0]]),
                           outputs={
                           'IronDome.Correlations(val.alert_id = obj.alert.id)': output
                           },
                           raw_response=correlation)

        if len(behavior_correlations) != 0:
            return_outputs(readable_output=tableToMarkdown(f'IronDome Behavior Correlations in "{dome_tag}"',
                                                           behavior_correlations,
                                                           headers=[*behavior_correlations[0]]),
                           outputs={
                           'IronDome.Correlations(val.alert_id = obj.alert.id)': output
                           },
                           raw_response=correlation)

    # Output correlation participation
    correlation_participation = results.get('correlation_participation')
    for participant in correlation_participation:
        dome_tag = participant.get('dome_tag')
        output = {
            'alert_id': alert_id,
            'correlation_participation': participant
        }

        table_data = []

        # append each correlation context to display in the table, if it exists
        behavior = participant.get('behavior')
        if behavior is not None:
            table_data.append(behavior)
        domain = participant.get('behavior')
        if domain is not None:
            table_data.append(domain)
        ip = participant.get('ip')
        if ip is not None:
            table_data.append(ip)

        # Send the participant info
        return_outputs(readable_output=tableToMarkdown(f'IronDome Correlation Participation in "{dome_tag}"',
                                                       table_data,
                                                       headers=[*table_data[0]]),
                       outputs={
                       'IronDome.CorrelationParticipation(val.alert_id = obj.alert.id)': output
                       },
                       raw_response=participant)

    # Output comments
    community_comments = results.get('community_comments')
    community_comments_output = {
        'alert_id': alert_id,
        'community_comments': community_comments,
    }
    if len(community_comments) > 0:
        return_outputs(readable_output=tableToMarkdown('IronDome Community Comments', community_comments,
                                                       headers=[*community_comments[0]]),
                       outputs={
                       'IronDome.CommunityComments(val.alert_id = obj.alert.id)': community_comments_output
                       },
                       raw_response=community_comments)

    # Output cognitive system score
    cognitive_system_score = results.get('cognitive_system_score')
    cognitive_system_score_output = {
        'alert_id': alert_id,
        'cognitive_system_score': cognitive_system_score,
    }
    return_outputs(readable_output=f'### Cognitive System Score: {cognitive_system_score}',
                   outputs={
                       'IronDome.CognitiveSystemScore(val.alert_id = obj.alert.id)': cognitive_system_score_output
                   },
                   raw_response=cognitive_system_score)

    # Output dome notifications
    dome_notifications = results.get('dome_notifications')
    for notification in dome_notifications:
        category = notification.get('category')
        output = {
            'alert_id': alert_id,
            'dome_notification': notification
        }
        return_outputs(readable_output=tableToMarkdown(f'IronDome Notification: {category}', notification),
                       outputs={
                       'IronDome.Notification(val.alert_id = obj.alert.id)': output
                       },
                       raw_response=notification)

    return_outputs(readable_output=IRON_DEFENSE.create_dome_markdown_link('Open IronDome information in IronVue',
                                                                          alert_id),
                   outputs={})