import json import demistomock as demisto import pytest from CommonServerPython import Common FILE_INDICATOR = { "CustomFields": { "cyrenfeedrelationships": [ { "indicatortype": "SHA-256", "timestamp": "2020-10-28T14:45:24.921Z", "entitycategory": "malware", "description": "downloaded from malware ip", "relationshiptype": "downloaded from", "value": "0f6dbfb291ba1b84601b0372f70db3430df636c631d074c1c2463f9e5a033f21", }, ] } } SEARCH_INDICATORS_RESPONSE = { "total": 1, "iocs": [ { "id": "4467", "version": 4, "modified": "2020-08-09T16:38:12.862662+03:00", "sortValues": [" \x01\x16\x14g#Wjx\x1d\x00", "4467"], "comments": [ { "id": "b96b5331-1afb-46ed-8de7-645d74243d83", "version": 0, "modified": "0001-01-01T00:00:00Z", "sortValues": None, "content": "Created", "user": "@DBot", "created": "2020-08-09T13:53:55.851918+03:00", "type": "IndicatorCommentTimeLine", "source": "2@11", "entryId": "2@11", "category": "Sighting", } ], "account": "", "timestamp": "2020-08-09T13:53:55.907799+03:00", "indicator_type": "MITRE ATT&CK", "value": "T1345", "source": "DBot", "sourceInstances": ["MITRE ATT&CK"], "sourceBrands": ["MITRE ATT&CK"], "investigationIDs": ["11", "a2fcc0c4-c7a9-4fdb-89d9-3613aec57280"], "relatedIncCount": 1, "lastSeen": "2020-08-09T16:38:12.86248+03:00", "firstSeen": "2020-08-09T13:53:55.907473+03:00", "lastSeenEntryID": "610@a2fcc0c4-c7a9-4fdb-89d9-3613aec57280", "firstSeenEntryID": "2@11", "score": 0, "manualScore": False, "manualSetTime": "0001-01-01T00:00:00Z", "insightCache": { "id": "t1345", "version": 1, "modified": "2020-08-09T16:33:44.495265+03:00", "sortValues": None, "scores": { "MITRE ATT&CK": { "score": 0, "content": '## ["T1345"](https://ABCDEFG:8443/#/indicator/4467):\n ', "contentFormat": "markdown", "timestamp": "2020-08-09T16:33:44.49526+03:00", "scoreChangeTimestamp": "2020-08-09T16:33:44.49526+03:00", "isTypedIndicator": False, "type": "MITRE ATT&CK", "context": { "DBotScore(val.Indicator && val.Indicator == obj.Indicator && val.Vendor && val.Vendor " "== obj.Vendor)": { "Indicator": "T1345", "Score": 0, "Type": "MITRE ATT&CK", "Vendor": "MITRE ATT&CK", }, "MITRE.ATT&CK(val.value && val.value = obj.value)": { "customFields": {}, "indicatorid": "4467", "value": "T1345", }, }, "reliability": "", } }, }, "moduleToFeedMap": { "MITRE ATT&CK": { "reliability": "A+ - 3rd party enrichment", "fetchTime": "2020-08-09T16:33:44.49526+03:00", "sourceBrand": "MITRE ATT&CK", "sourceInstance": "MITRE ATT&CK", "moduleId": "MITRE ATT&CK", "expirationPolicy": "indicatorType", "expirationInterval": 0, "bypassExclusionList": False, "score": 0, "classifierVersion": 0, "classifierId": "", "mapperVersion": 0, "mapperId": "", "type": "MITRE ATT&CK", "value": "T1345", "timestamp": "0001-01-01T00:00:00Z", "fields": None, "modifiedTime": "0001-01-01T00:00:00Z", "ExpirationSource": { "setTime": "2020-08-09T16:38:12.845863+03:00", "source": "indicatorType", "user": "", "brand": "MITRE ATT&CK", "instance": "MITRE ATT&CK", "moduleId": "MITRE ATT&CK", "expirationPolicy": "indicatorType", "expirationInterval": 20160, }, "rawJSON": None, "isEnrichment": True, } }, "isShared": False, "expiration": "2020-08-23T16:38:12.845863+03:00", "manualExpirationTime": "0001-01-01T00:00:00Z", "expirationStatus": "active", "expirationSource": { "setTime": "2020-08-09T16:38:12.845863+03:00", "source": "indicatorType", "user": "", "brand": "MITRE ATT&CK", "instance": "MITRE ATT&CK", "moduleId": "MITRE ATT&CK", "expirationPolicy": "indicatorType", "expirationInterval": 20160, }, "deletedFeedFetchTime": "0001-01-01T00:00:00Z", "calculatedTime": "2020-08-09T16:38:12.86248+03:00", "lastReputationRun": "2020-08-09T16:33:44.506101+03:00", "comment": "", "manuallyEditedFields": None, "modifiedTime": "2020-08-09T16:33:44.49526+03:00", "aggregatedReliability": "", } ], "searchAfter": [" \x01\x16\x14g#Wjx\x1d\x00", "4467"], } SEARCH_INDICATORS_EMPTY_RESPONSE = {"total": 0, "iocs": []} def test_cyren_feed_relationship_no_indicator(): """ Given: no indicator When: Running cyren_feed_relationship command. Then: ValueError is raised """ from CyrenThreatInDepthRenderRelated import cyren_feed_relationship with pytest.raises(ValueError): cyren_feed_relationship({}) @pytest.mark.parametrize( "indicator", [ FILE_INDICATOR, json.dumps(FILE_INDICATOR), ], ) @pytest.mark.parametrize( "columns", [ "", " ", " test ", "IndicatorType", "RepuTation,Indicator Type", "other,Indicator Type", "Indicator Type,other,Reputation", ], ) def test_cyren_feed_relationship_wrong_columns(indicator, columns): """ Given: an indicator but unsupported columns When: Running cyren_feed_relationship command. Then: ValueError is raised """ from CyrenThreatInDepthRenderRelated import cyren_feed_relationship args = {"indicator": indicator, "columns": columns} with pytest.raises(ValueError): cyren_feed_relationship(args) @pytest.mark.parametrize( "indicator", [ FILE_INDICATOR, json.dumps(FILE_INDICATOR), ], ) @pytest.mark.parametrize( "columns", [ "Indicator Type, Reputation , Value", " Indicator Type, Reputation , Value ", " Indicator Type, Reputation , Value ,Value", "Indicator Type", " Indicator Type ", ], ) def test_cyren_feed_relationship_allowed_columns(mocker, indicator, columns): """ Given: an indicator and supported columns When: Running cyren_feed_relationship command. Then: no ValueError is raised """ from CyrenThreatInDepthRenderRelated import cyren_feed_relationship mocker.patch.object(demisto, "searchIndicators", return_value={"total": 0}) args = {"indicator": indicator, "columns": columns} cyren_feed_relationship(args) @pytest.mark.parametrize( "indicator", [ FILE_INDICATOR, json.dumps(FILE_INDICATOR), ], ) def test_cyren_feed_relationship_with_search_response(mocker, indicator): """ Given: File hash indicator. When: Running cyren_feed_relationship command. Then: Verify expected results returns """ from CyrenThreatInDepthRenderRelated import cyren_feed_relationship args = {"indicator": indicator} mocker.patch.object(demisto, "searchIndicators", return_value=SEARCH_INDICATORS_RESPONSE) result = cyren_feed_relationship(args) assert result.readable_output == ( "|Indicator Type|Value|Reputation|Relationship Type|Entity Category|Timestamp UTC|\n" "|---|---|---|---|---|---|\n" "| SHA-256 " "| " "[0f6dbfb291ba1b84601b0372f70db3430df636c631d074c1c2463f9e5a033f21]" "(#/indicator/4467)
| " "None (0) | downloaded from | malware | 2020-10-28, 14:45:24 |\n" ) @pytest.mark.parametrize( "indicator", [ FILE_INDICATOR, json.dumps(FILE_INDICATOR), ], ) def test_cyren_feed_relationship_with_search_response_other_columns(mocker, indicator): """ Given: File hash indicator. When: Running cyren_feed_relationship command. Then: Verify expected results returns """ from CyrenThreatInDepthRenderRelated import cyren_feed_relationship args = {"indicator": indicator, "columns": "Relationship Type,Indicator Type"} mocker.patch.object(demisto, "searchIndicators", return_value=SEARCH_INDICATORS_RESPONSE) result = cyren_feed_relationship(args) assert result.readable_output == ("|Relationship Type|Indicator Type|\n|---|---|\n| downloaded from | SHA-256 |\n") @pytest.mark.parametrize( "indicator", [ FILE_INDICATOR, json.dumps(FILE_INDICATOR), ], ) def test_cyren_feed_relationship_without_search_response(mocker, indicator): """ Given: File hash indicator. When: Running cyren_feed_relationship command. Then: Verify expected results returns """ from CyrenThreatInDepthRenderRelated import cyren_feed_relationship args = {"indicator": indicator} mocker.patch.object(demisto, "searchIndicators", return_value=SEARCH_INDICATORS_EMPTY_RESPONSE) result = cyren_feed_relationship(args) assert result.readable_output == ( "|Indicator Type|Value|Reputation|Relationship Type|Entity Category|Timestamp UTC|\n" "|---|---|---|---|---|---|\n" "| SHA-256 | 0f6dbfb291ba1b84601b0372f70db3430df636c631d074c1c2463f9e5a033f21
| " "None (0) | downloaded from | malware | 2020-10-28, 14:45:24 |\n" ) RELATED_INDICATOR_OBJECTS_PACK = [ ( "value1", "relates to", "some-type", "2020-10-28T14:45:24.921Z", "phishing", Common.DBotScore.BAD, { "Value": "value1\n", "Reputation": "Bad (3)", "Entity Category": "phishing", "Relationship Type": "relates to", "Indicator Type": "some-type", "Timestamp UTC": "2020-10-28, 14:45:24", }, ), ( "value1", "relates to", "some-type", "2020-10-28T14:45:24.921Z", "phishing", Common.DBotScore.GOOD, { "Value": "value1\n", "Reputation": "Good (1)", "Entity Category": "phishing", "Relationship Type": "relates to", "Indicator Type": "some-type", "Timestamp UTC": "2020-10-28, 14:45:24", }, ), ( "value1", "relates to", "some-type", "2020-10-28T14:45:24.921Z", "phishing", Common.DBotScore.NONE, { "Value": "value1\n", "Reputation": "None (0)", "Entity Category": "phishing", "Relationship Type": "relates to", "Indicator Type": "some-type", "Timestamp UTC": "2020-10-28, 14:45:24", }, ), ( "value1", "relates to", "some-type", "2020-10-28T14:45:24.921Z", "phishing", Common.DBotScore.SUSPICIOUS, { "Value": "value1\n", "Reputation": "Suspicious (2)", "Entity Category": "phishing", "Relationship Type": "relates to", "Indicator Type": "some-type", "Timestamp UTC": "2020-10-28, 14:45:24", }, ), ( "value1", "relates to", "some-type", "20201028", "phishing", Common.DBotScore.SUSPICIOUS, { "Value": "value1\n", "Reputation": "Suspicious (2)", "Entity Category": "phishing", "Relationship Type": "relates to", "Indicator Type": "some-type", "Timestamp UTC": "2020-10-28, 00:00:00", }, ), ( "value1", "relates to", "some-type", "11", "phishing", Common.DBotScore.SUSPICIOUS, { "Value": "value1\n", "Reputation": "Suspicious (2)", "Entity Category": "phishing", "Relationship Type": "relates to", "Indicator Type": "some-type", "Timestamp UTC": "11", # Invalid timestamp }, ), ] @pytest.mark.parametrize( ("value, relationship_type, indicator_type, timestamp, entity_category, reputation, expected_output"), RELATED_INDICATOR_OBJECTS_PACK, ) def test_create_related_indicator_object( value, relationship_type, indicator_type, timestamp, entity_category, reputation, expected_output ): """ Given: - value (str): Value of feed related indicator. - relationship_type (str): indicator relationship type - indicator_type (str): indicator type - timestamp (str): indicator timestamp - entity_category (str): indicator entity category - reputation (int): indicator DBot score When: - Processing data to show in widget. Then: - Verify that description is being processed at it should. """ from CyrenThreatInDepthRenderRelated import create_relationship_object assert ( create_relationship_object(value, relationship_type, indicator_type, timestamp, entity_category, reputation) == expected_output )