diff --git a/Packs/CommonScripts/ReleaseNotes/1_11_97.md b/Packs/CommonScripts/ReleaseNotes/1_11_97.md new file mode 100644 index 000000000000..b80daa331727 --- /dev/null +++ b/Packs/CommonScripts/ReleaseNotes/1_11_97.md @@ -0,0 +1,9 @@ + +#### Scripts + +##### DBotAverageScore + +- Migrated the script from JavaScript to Python. +- Fixed an issue where if all scores of an indicator are '0', a null value would be returned. +- Updated the script to ignore '0' values (which indicate an 'unknown' value) from average calculations. +- Updated the Docker image to: *demisto/python3:3.10.12.63474*. diff --git a/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.js b/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.js deleted file mode 100644 index b1aff695fce9..000000000000 --- a/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.js +++ /dev/null @@ -1,16 +0,0 @@ -var scores = dq(invContext, 'DBotScore(val.Indicator && val.Score)'); if (!(Array.isArray(scores))) { - scores = [scores] -} -var s = {}; -for (i=0; i CommandResults: + """ + Calculates the average score for each indicator in the context, and returns the results. + + Args: + context_data (dict): 'DBotScore' context data, containing DBotScore entries to calculate the average for. + + Returns: + CommandResults: A CommandResults object containing command's outputs. + """ + scores = defaultdict(list) # Format is 'indicator: [collected scores]' + + for dbot_score_item in context_data: + indicator = dbot_score_item['Indicator'] + + scores[indicator].append(dbot_score_item['Score']) + + context_output = [] + + for indicator, scores_list in scores.items(): + context_output.append(calculate_average_score(indicator=indicator, scores_list=scores_list)) + + return CommandResults( + outputs_prefix='DBotAvgScore', + outputs_key_field='Indicator', + outputs=context_output, + readable_output=tableToMarkdown('DBot Average Scores', t=context_output), + ) + + +def calculate_average_score(indicator: str, scores_list: list[int]) -> dict: + """ + Calculates the average score of a list of scores, and return a context entry with the average. + '0' values are ignored (since they indicate "unknown" score). + If no scores are provided, the average is 0. + + Args: + indicator (str): The indicator for which the average is calculated. + scores_list (list[int]): A list of scores. + + Returns: + dict: A context entry for a single indicator, containing the average score. + """ + scores_list = [score for score in scores_list if score != 0] # Remove '0' values + + if not scores_list: # If all values were '0', we have an empty list + return {'Indicator': indicator, 'Score': 0} + + return {'Indicator': indicator, 'Score': sum(scores_list) / len(scores_list)} + + +def main(): # pragma: no cover + dbot_score_context_data: list | dict = demisto.context().get('DBotScore', []) + + # If there is only a single DBotScore entry, the server returns it as a single dict, and not inside a list. + if isinstance(dbot_score_context_data, dict): + dbot_score_context_data = [dbot_score_context_data] + + return_results(calculate_all_average_scores(dbot_score_context_data)) + + +if __name__ in ("__main__", "builtin", "builtins"): # pragma: no cover + main() diff --git a/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.yml b/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.yml index aefce253ac7b..47af9b25073c 100644 --- a/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.yml +++ b/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore.yml @@ -3,17 +3,20 @@ commonfields: version: -1 name: DBotAverageScore script: '' -type: javascript -comment: Calculates average score for each indicator from context +type: python +comment: The script calculates the average DBot score for each indicator in the context. tags: - Utility outputs: - contextPath: DBotAvgScore.Indicator - description: The indicator we calculate average score for + description: The indicator the average score is for. + type: string - contextPath: DBotAvgScore.Score - description: The average score per indicator + description: The average score for the indicator. + type: number enabled: true -scripttarget: 0 +subtype: python3 +dockerimage: demisto/python3:3.10.12.63474 fromversion: 5.0.0 tests: - DbotAverageScore-Test diff --git a/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore_test.py b/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore_test.py new file mode 100644 index 000000000000..e6cb5cde0e68 --- /dev/null +++ b/Packs/CommonScripts/Scripts/DBotAverageScore/DBotAverageScore_test.py @@ -0,0 +1,56 @@ +from CommonServerPython import * + +from pathlib import Path + +import pytest + +from DBotAverageScore import * + + +def load_test_data(json_file_name: str) -> list | dict: + """ + Loads test data from a JSON file. + """ + with open(Path('test_data', json_file_name)) as json_file: + return json.load(json_file) + + +SAMPLE_DATA = load_test_data('sample_data.json') + + +@pytest.mark.parametrize('indicator, scores_list, expected_average', [ + ('192.0.2.0', [1, 2, 3], 2), # General check + ('192.0.2.1', [0, 0, 0], 0), # Assure '0' is returned when all scores are '0' + ('192.0.2.2', [1, 1, 0, 0], 1), # Assure '0' values are ignored + ('192.0.2.3', [1, 2, 3, 4], 2.5), # Assure float value is returned +]) +def test_calculate_average_score(indicator: str, scores_list: list[int], expected_average: float): + """ + Given: + An indicator and a list of scores. + When: + Creating a context entry with the average score. + Then: + Ensure the average and context entry are valid and correct. + """ + assert calculate_average_score(indicator, scores_list) == {'Indicator': indicator, 'Score': expected_average} + + +@pytest.mark.parametrize('context_data, expected_context_output, expected_readable_output', [ + (SAMPLE_DATA['context_data'], SAMPLE_DATA['expected_context_output'], SAMPLE_DATA['expected_readable_output']), +]) +def test_calculate_all_average_scores(context_data: list[dict[str, Any]], + expected_context_output: dict, expected_readable_output: str): + """ + Given: + A list of DBotScore context entries. + When: + Calculating the average score for each indicator using 'calculate_all_average_scores' function. + Then: + Ensure the context and readable outputs are valid and correct. + """ + results = calculate_all_average_scores(context_data) + assert results.outputs_prefix == 'DBotAvgScore' + assert results.outputs_key_field == 'Indicator' + assert results.outputs == expected_context_output + assert results.readable_output == expected_readable_output diff --git a/Packs/CommonScripts/Scripts/DBotAverageScore/README.md b/Packs/CommonScripts/Scripts/DBotAverageScore/README.md index 7272eaca14b4..792beae05749 100644 --- a/Packs/CommonScripts/Scripts/DBotAverageScore/README.md +++ b/Packs/CommonScripts/Scripts/DBotAverageScore/README.md @@ -1,22 +1,29 @@ -Calculates the average score for each indicator from context. +The script calculates the average DBot score for each indicator in the context. +The script will ignore '0' scores (which are for an 'unknown' reputation). +If all scores for an indicator are '0', the indicator will receive a score of '0'. + +For more information regarding DBot Scores, refer to the official ["Reputation and DBot Score" documentation](https://xsoar.pan.dev/docs/integrations/dbot). ## Script Data + --- | **Name** | **Description** | | --- | --- | -| Script Type | javascript | +| Script Type | python3 | | Tags | Utility | - +| Cortex XSOAR Version | 5.0.0 | ## Inputs + --- There are no inputs for this script. ## Outputs + --- | **Path** | **Description** | **Type** | | --- | --- | --- | -| DBotAvgScore.Indicator | The indicator that the average score was calculated for. | Unknown | -| DBotAvgScore.Score | The average score per indicator. | Unknown | +| DBotAvgScore.Indicator | The indicator the average score is for. | string | +| DBotAvgScore.Score | The average score for the indicator. | number | diff --git a/Packs/CommonScripts/Scripts/DBotAverageScore/test_data/sample_data.json b/Packs/CommonScripts/Scripts/DBotAverageScore/test_data/sample_data.json new file mode 100644 index 000000000000..5dcead3e8b89 --- /dev/null +++ b/Packs/CommonScripts/Scripts/DBotAverageScore/test_data/sample_data.json @@ -0,0 +1,40 @@ +{ + "context_data": [ + {"Indicator": "192.0.2.0", "Reliability": "A - Completely reliable", "Score": 1, "Vendor": "Vendor1"}, + {"Indicator": "192.0.2.0", "Reliability": "B - Usually reliable", "Score": 2, "Vendor": "Vendor2"}, + {"Indicator": "192.0.2.0", "Reliability": "C - Fairly reliable", "Score": 3, "Vendor": "Vendor3"}, + + {"Indicator": "192.0.2.1", "Reliability": "A - Completely reliable", "Score": 0, "Vendor": "Vendor1"}, + {"Indicator": "192.0.2.1", "Reliability": "B - Usually reliable", "Score": 0, "Vendor": "Vendor2"}, + {"Indicator": "192.0.2.1", "Reliability": "C - Fairly reliable", "Score": 0, "Vendor": "Vendor3"}, + + {"Indicator": "192.0.2.2", "Reliability": "A - Completely reliable", "Score": 1, "Vendor": "Vendor1"}, + {"Indicator": "192.0.2.2", "Reliability": "B - Usually reliable", "Score": 1, "Vendor": "Vendor2"}, + {"Indicator": "192.0.2.2", "Reliability": "C - Fairly reliable", "Score": 0, "Vendor": "Vendor3"}, + {"Indicator": "192.0.2.2", "Reliability": "D - Not usually reliable", "Score": 0, "Vendor": "Vendor4"}, + + {"Indicator": "192.0.2.3", "Reliability": "A - Completely reliable", "Score": 1, "Vendor": "Vendor1"}, + {"Indicator": "192.0.2.3", "Reliability": "B - Usually reliable", "Score": 2, "Vendor": "Vendor2"}, + {"Indicator": "192.0.2.3", "Reliability": "C - Fairly reliable", "Score": 3, "Vendor": "Vendor3"}, + {"Indicator": "192.0.2.3", "Reliability": "D - Not usually reliable", "Score": 4, "Vendor": "Vendor4"} + ], + "expected_context_output": [ + { + "Indicator": "192.0.2.0", + "Score": 2.0 + }, + { + "Indicator": "192.0.2.1", + "Score": 0 + }, + { + "Indicator": "192.0.2.2", + "Score": 1.0 + }, + { + "Indicator": "192.0.2.3", + "Score": 2.5 + } + ], + "expected_readable_output": "### DBot Average Scores\n|Indicator|Score|\n|---|---|\n| 192.0.2.0 | 2.0 |\n| 192.0.2.1 | 0 |\n| 192.0.2.2 | 1.0 |\n| 192.0.2.3 | 2.5 |\n" +} \ No newline at end of file diff --git a/Packs/CommonScripts/pack_metadata.json b/Packs/CommonScripts/pack_metadata.json index 465854730bec..0d9d9c074ccc 100644 --- a/Packs/CommonScripts/pack_metadata.json +++ b/Packs/CommonScripts/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Common Scripts", "description": "Frequently used scripts pack.", "support": "xsoar", - "currentVersion": "1.11.96", + "currentVersion": "1.11.97", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Tests/known_words.txt b/Tests/known_words.txt index 9e9357ac5421..147ce0fe2990 100644 --- a/Tests/known_words.txt +++ b/Tests/known_words.txt @@ -239,4 +239,5 @@ GCP Qradar XSIAM fromversion -xpanse \ No newline at end of file +xpanse +JavaScript \ No newline at end of file