Cyberint Premium Feed
Use the Check Point EM ThreatCloud Intelligence Feed integration to ingest high-fidelity IOC indicators from the Cyberint Infinity External Risk Management IOC APIs and to enrich a single indicator on demand.
Data Enrichment & Threat Intelligence · Cyberint · Feed
Details
| ID | Cyberint Premium Feed |
|---|---|
| Provider | Check Point Software Technologies |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.9.0 |
| Docker Image | demisto/fastapi:0.125.0.10158186 |
| Supported Modules | Agentix XSIAM |
README
Use the Check Point EM ThreatCloud Intelligence Feed integration to ingest high-fidelity Indicators-of-Compromise from the Cyberint Infinity External Risk Management IOC APIs into your Cortex Threat Intelligence Module (Cortex XSOAR or Cortex XSIAM), and to enrich a single IOC on demand from the war room or a playbook task.
Configure Check Point EM ThreatCloud Intelligence Feed in Cortex
| Parameter | Description | Required |
|---|---|---|
| Cyberint API URL | Cyberint API URL on which the services run (i.e https://your-company.cyberint.io) | True |
| Company Name | Company (client) name associated with Cyberint instance. | True |
| API access token | True | |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Fetch indicators | False | |
| Indicator Reputation | Indicators from this integration instance will be marked with this reputation | False |
| Source Reliability | Reliability of the source providing the intelligence data | True |
| Traffic Light Protocol Color | The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed | False |
| Indicator Type | Which indicator types to fetch | True |
| Activity | Filter by activity classification | False |
| Confidence Min | Minimum confidence score (0-100) to fetch indicators from. | False |
| Confidence Max | Maximum confidence score (0-100) to fetch indicators from. | False |
| Severity Min | Minimum severity level (1-5) to fetch indicators from. | False |
| Severity Max | Maximum severity level (1-5) to fetch indicators from. | False |
| Malicious | Filter by malicious classification. | False |
| First Fetch Time | How far back to fetch indicators on the first run. Subsequent runs fetch only new indicators since the last successful fetch. Supports relative expressions like “3 days”, “7 days”, “24 hours”. | False |
| False | ||
| False | ||
| Feed Fetch Interval | False | |
| Tags | Supports CSV values. | False |
| Bypass exclusion list | When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
cyberint-premium-get-indicators
Gets indicators from the Infinity External Risk Management feed.
Base Command
cyberint-premium-get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of results to return. The default value is 50. Default is 50. | Optional |
| offset | Specifies the starting position from which data retrieval should begin. Default is 0. | Optional |
| indicator_type | Filter by indicator type. Supports comma-separated values. Possible values are: ipv4, domain, url, sha256, sha1, md5. | Optional |
| activity | Filter by activity classification. Supports comma-separated values. | Optional |
| confidence_min | Minimum confidence score (0-100). | Optional |
| severity_min | Minimum severity level (1-5). | Optional |
| malicious | Filter by malicious classification. Possible values are: yes, no, inconclusive. | Optional |
| added_to_feed_after | Filter indicators added to the feed after this date-time (ISO 8601). | Optional |
| added_to_feed_before | Filter indicators added to the feed before this date-time (ISO 8601). | Optional |
| sort_field | Field to sort by. Possible values are: confidence, severity, first_seen, last_seen, added_to_feed. Default is last_seen. | Optional |
| sort_direction | Sort direction. Possible values are: asc, desc. Default is desc. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| CyberintPremium.Indicator.indicator_type | String | The indicator type. |
| CyberintPremium.Indicator.indicator_value | String | The indicator value. |
| CyberintPremium.Indicator.activity | String | Activity classification. |
| CyberintPremium.Indicator.confidence | Number | Confidence score (0-100). |
| CyberintPremium.Indicator.severity | Number | Severity level (1-5). |
| CyberintPremium.Indicator.malicious | String | Malicious classification (yes/no/inconclusive). |
| CyberintPremium.Indicator.kill_chain_stage | String | Kill chain stage. |
| CyberintPremium.Indicator.first_seen | Date | First seen date-time. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Indicator.last_seen | Date | Last seen date-time. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Indicator.added_to_feed | Date | Date-time when added to the feed. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Indicator.valid_until | Date | Valid until date-time. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Indicator.is_blocking | Boolean | Whether the indicator is blocking. |
| CyberintPremium.Indicator.is_unique | Boolean | Whether the indicator is unique. |
| CyberintPremium.Indicator.malware_types | Unknown | List of malware types. |
| CyberintPremium.Indicator.has_cve | Boolean | Whether the indicator has associated CVEs. |
| CyberintPremium.Indicator.has_campaign | Boolean | Whether the indicator has an associated campaign. |
cyberint-premium-enrich
Enriches a single IOC indicator with reputation, threat intelligence, and type-specific enrichment data.
Base Command
cyberint-premium-enrich
Input
| Argument Name | Description | Required |
|---|---|---|
| type | The IOC type. Possible values are: ipv4, domain, url, sha256, sha1, md5. | Required |
| value | The indicator value (e.g. IP address, domain name, URL, or file hash). | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| CyberintPremium.Enrichment.indicator_type | String | The indicator type. |
| CyberintPremium.Enrichment.indicator_value | String | The indicator value. |
| CyberintPremium.Enrichment.activity | String | Activity classification. |
| CyberintPremium.Enrichment.confidence | Number | Confidence score (0-100). |
| CyberintPremium.Enrichment.severity | Number | Severity level (0-5). |
| CyberintPremium.Enrichment.malicious | String | Malicious classification (yes/no/inconclusive). |
| CyberintPremium.Enrichment.kill_chain_stage | String | Kill chain stage. |
| CyberintPremium.Enrichment.first_seen | Date | First seen date-time. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Enrichment.last_seen | Date | Last seen date-time. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Enrichment.valid_until | Date | Valid until date-time. ISO8601 format: 2020-01-01T00:11:22Z. |
| CyberintPremium.Enrichment.malware_types | Unknown | List of malware types. |
| CyberintPremium.Enrichment.malware_family | String | Malware family name. |
| CyberintPremium.Enrichment.origin_countries | Unknown | Origin countries. |
| CyberintPremium.Enrichment.targeted_countries | Unknown | Targeted countries. |
| CyberintPremium.Enrichment.targeted_sectors | Unknown | Targeted sectors. |
| CyberintPremium.Enrichment.targeted_brands | Unknown | Targeted brands. |
| CyberintPremium.Enrichment.threat_actors | Unknown | Associated threat actors. |
| CyberintPremium.Enrichment.campaigns | Unknown | Associated campaigns. |
| CyberintPremium.Enrichment.cves | Unknown | Associated CVEs. |
| CyberintPremium.Enrichment.ttps | Unknown | Associated TTPs with MITRE IDs. |
| CyberintPremium.Enrichment.tags | Unknown | Tags. |
| CyberintPremium.Enrichment.enrichment | Unknown | Type-specific enrichment data (geo, whois, file info, etc.). |
Configuration parameters
url— Cyberint API URL (required)client_name— Company Name (required)access_token— API Key (Leave empty. Fill in the API Key in the password field.) (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsfeed— Fetch indicatorsfeedReputation— Indicator ReputationfeedReliability— Source Reliability (required)tlp_color— Traffic Light Protocol Colorindicator_type— Indicator Type (required)activity— Activityconfidence_min— Confidence Minconfidence_max— Confidence Maxseverity_min— Severity Minseverity_max— Severity Maxmalicious— Maliciousfirst_fetch— First Fetch TimefeedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch IntervalfeedTags— TagsfeedBypassExclusionList— Bypass exclusion list
Commands (2)
-
cyberint-premium-enrichEnriches a single IOC indicator with reputation, threat intelligence, and type-specific enrichment data.
-
cyberint-premium-get-indicatorsGets indicators from the Infinity External Risk Management feed.
import json from unittest import mock from unittest.mock import MagicMock, patch import pytest import FeedCyberintPremium BASE_URL = "https://feed-example.com" TOKEN = "example_token" FEED_PATH = "/ioc-intel/feed-api/v1/feed/jsonl" ENRICH_PATH = "/ioc-intel/enrichment-api/v1/enrichment" def load_mock_response() -> str: with open("test_data/premium_indicators.jsonl") as file: return file.read() def load_mock_empty_response() -> str: with open("test_data/empty.jsonl") as file: return file.read() @pytest.fixture() def mock_client(mocker) -> FeedCyberintPremium.Client: # ContentClient.__init__ touches the XSOAR runtime (support_multithreading), # which isn't available under demistomock — bypass it in tests. mocker.patch("FeedCyberintPremium.ContentClient.__init__", return_value=None) client = FeedCyberintPremium.Client( base_url=BASE_URL, access_token=TOKEN, verify=False, proxy=False, ) client._base_url = BASE_URL client._verify = False client._headers = {} client._ok_codes = () return client def _http_responder(feed_text: str | list[str] | None = None, enrich_json: dict | None = None): """Build a side_effect for Client._http_request that routes by url_suffix.""" feed_responses = feed_text if isinstance(feed_text, list) else ([feed_text] if feed_text is not None else []) feed_iter = iter(feed_responses) def side_effect(*args, **kwargs): url_suffix = kwargs.get("url_suffix", "") if url_suffix == FEED_PATH: return next(feed_iter) if url_suffix == ENRICH_PATH: return enrich_json raise AssertionError(f"Unexpected url_suffix: {url_suffix}") return side_effect def test_fetch_feed_page(mocker, mock_client: FeedCyberintPremium.Client): """ Scenario: Test fetching a single page of IOCs from the premium feed. Given: mock_client. When: Called fetch_feed_page. Then: Ensure that indicators are returned. """ mocker.patch.object(FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=load_mock_response())) with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" if "." in str(x) and len(str(x)) < 16 else "URL" indicators = mock_client.fetch_feed_page(filters={}, limit=10, offset=0) assert indicators is not None assert len(indicators) > 0 def test_get_indicators_command(mocker, mock_client): """ Scenario: Test retrieving indicators via get_indicators_command. Given: mock_client. When: Called the get_indicators_command. Then: Ensure that the result is returned. """ mocker.patch.object(FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=load_mock_response())) args = {"limit": 10, "offset": 0} with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" if x and "." in str(x) and len(str(x)) < 16 else "URL" result = FeedCyberintPremium.get_indicators_command(mock_client, args) assert result is not None assert result.outputs is not None assert len(result.outputs) > 0 def test_get_indicators_command_with_filters(mocker, mock_client): """ Scenario: Test retrieving indicators with filters. Given: mock_client with filters. When: Called the get_indicators_command with indicator_type and severity_min. Then: Ensure that the result is returned and filters were sent to the API. """ http_mock = mocker.patch.object( FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=load_mock_response()) ) args = { "limit": 10, "offset": 0, "indicator_type": "ipv4", "severity_min": "3", "malicious": "yes", } with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" if x and "." in str(x) and len(str(x)) < 16 else "URL" result = FeedCyberintPremium.get_indicators_command(mock_client, args) assert result is not None body = http_mock.call_args.kwargs["json_data"] assert body["filters"]["indicator_type"] == ["ipv4"] assert body["filters"]["severity_min"] == 3 assert body["filters"]["malicious"] == "yes" @mock.patch("FeedCyberintPremium.demisto") @mock.patch("FeedCyberintPremium.is_execution_time_exceeded") def test_fetch_indicators_with_publish( is_execution_time_exceeded_mock, mock_demisto, mocker, mock_client: FeedCyberintPremium.Client, ): """ Scenario: Test that fetch publishes indicators page-by-page. Given: mock_client with 2 pages (page 1 has data, page 2 is empty). When: Called fetch_indicators_with_publish. Then: - demisto.createIndicators is called once (for the one non-empty page). - The published indicators have the correct XSOAR format. """ is_execution_time_exceeded_mock.return_value = False mock_demisto.getIntegrationContext.return_value = {"offset": 0} mock_demisto.debug = MagicMock() mock_demisto.setIntegrationContext = MagicMock() mock_demisto.createIndicators = MagicMock() mocker.patch.object( FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=[load_mock_response(), load_mock_empty_response()]), ) with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" if x and "." in str(x) and len(str(x)) < 16 else "File" total = FeedCyberintPremium.fetch_indicators_with_publish( client=mock_client, tlp_color="GREEN", filters={}, feed_tags=["test"], ) assert total > 0 assert mock_demisto.createIndicators.call_count >= 1 first_call_args = mock_demisto.createIndicators.call_args_list[0][0][0] assert first_call_args[0]["service"] == "Cyberint Premium Feed" assert "rawJSON" in first_call_args[0] assert first_call_args[0]["fields"]["trafficlightprotocol"] == "GREEN" assert first_call_args[0]["fields"]["tags"] == ["test"] @mock.patch("FeedCyberintPremium.demisto") @mock.patch("FeedCyberintPremium.is_execution_time_exceeded") def test_fetch_saves_offset_on_timeout( is_execution_time_exceeded_mock, mock_demisto, mock_client: FeedCyberintPremium.Client, ): """ Scenario: When execution time is exceeded, offset is saved for next run. Given: is_execution_time_exceeded returns True immediately. When: Called fetch_indicators_with_publish. Then: offset is saved to integration context, no indicators published. """ is_execution_time_exceeded_mock.return_value = True mock_demisto.getIntegrationContext.return_value = {"offset": 40000, "last_fetch_time": "2025-01-01T00:00:00Z"} mock_demisto.debug = MagicMock() mock_demisto.setIntegrationContext = MagicMock() mock_demisto.createIndicators = MagicMock() total = FeedCyberintPremium.fetch_indicators_with_publish( client=mock_client, tlp_color="", filters={}, feed_tags=[], ) assert total == 0 call_args = mock_demisto.setIntegrationContext.call_args[0][0] assert call_args["offset"] == 40000 mock_demisto.createIndicators.assert_not_called() @mock.patch("FeedCyberintPremium.demisto") @mock.patch("FeedCyberintPremium.is_execution_time_exceeded") def test_fetch_indicators_command_incremental( is_execution_time_exceeded_mock, mock_demisto, mocker, mock_client: FeedCyberintPremium.Client, ): """ Scenario: On subsequent runs, fetch only new indicators since last run. Given: integration context has last_fetch_time set. When: Called fetch_indicators_command. Then: - The API request includes added_to_feed_after matching last_fetch_time. - last_fetch_time is updated after successful fetch. """ is_execution_time_exceeded_mock.return_value = False mock_demisto.getIntegrationContext.return_value = { "offset": 0, "last_fetch_time": "2025-01-05T00:00:00Z", } mock_demisto.debug = MagicMock() mock_demisto.setIntegrationContext = MagicMock() mock_demisto.createIndicators = MagicMock() http_mock = mocker.patch.object( FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=[load_mock_response(), load_mock_empty_response()]), ) params = { "feed": True, "indicator_type": "All", } with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" if x and "." in str(x) and len(str(x)) < 16 else "File" FeedCyberintPremium.fetch_indicators_command(mock_client, params) first_body = http_mock.call_args_list[0].kwargs["json_data"] assert first_body["filters"]["added_to_feed_after"] == "2025-01-05T00:00:00Z" final_ctx = mock_demisto.setIntegrationContext.call_args_list[-1][0][0] assert "last_fetch_time" in final_ctx assert final_ctx["offset"] == 0 @mock.patch("FeedCyberintPremium.demisto") @mock.patch("FeedCyberintPremium.is_execution_time_exceeded") def test_fetch_indicators_command_first_run( is_execution_time_exceeded_mock, mock_demisto, mocker, mock_client: FeedCyberintPremium.Client, ): """ Scenario: On first run (no last_fetch_time), uses first_fetch window. Given: integration context has no last_fetch_time. When: Called fetch_indicators_command with first_fetch="3 days". Then: The API request includes added_to_feed_after from ~3 days ago. """ is_execution_time_exceeded_mock.return_value = False mock_demisto.getIntegrationContext.return_value = {} mock_demisto.debug = MagicMock() mock_demisto.setIntegrationContext = MagicMock() mock_demisto.createIndicators = MagicMock() http_mock = mocker.patch.object( FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=[load_mock_response(), load_mock_empty_response()]), ) params = { "feed": True, "indicator_type": "All", "first_fetch": "3 days", } with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" if x and "." in str(x) and len(str(x)) < 16 else "File" FeedCyberintPremium.fetch_indicators_command(mock_client, params) first_body = http_mock.call_args_list[0].kwargs["json_data"] assert "added_to_feed_after" in first_body["filters"] def test_raw_to_indicator(): """Test raw_to_indicator conversion.""" item = { "indicator_type": "ipv4", "indicator_value": "1.1.1.1", "activity": "CnC Server", "confidence": 90, "severity": 4, "malicious": "yes", "kill_chain_stage": "command-and-control", "first_seen": "2025-01-01T12:00:00Z", "last_seen": "2025-01-06T12:49:40Z", "is_blocking": True, "is_unique": True, "malware_types": ["Trojan"], "has_cve": False, "has_campaign": True, "valid_until": "2025-07-06T13:00:00Z", } with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.return_value = "IP" result = FeedCyberintPremium.raw_to_indicator(item, tlp_color="AMBER", feed_tags=["tag1"]) assert result is not None assert result["type"] == "IP" assert result["value"] == "1.1.1.1" assert result["service"] == "Cyberint Premium Feed" assert result["fields"]["severity"] == "High" assert result["fields"]["trafficlightprotocol"] == "AMBER" assert result["fields"]["tags"] == ["tag1"] assert result["fields"]["hascampaign"] is True def test_raw_to_indicator_returns_none_for_invalid(): """Test that raw_to_indicator returns None for unrecognized values.""" with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.return_value = None result = FeedCyberintPremium.raw_to_indicator({"indicator_value": "not-valid"}, tlp_color="", feed_tags=[]) assert result is None result = FeedCyberintPremium.raw_to_indicator({}, tlp_color="", feed_tags=[]) assert result is None def test_build_filters(): """Test building filters from integration parameters.""" params = { "indicator_type": "IP,Domain", "activity": "CnC Server,Phishing", "confidence_min": "50", "severity_min": "3", "malicious": "yes", } filters = FeedCyberintPremium.build_filters(params) assert filters["indicator_type"] == ["ipv4", "domain"] assert filters["activity"] == ["CnC Server", "Phishing"] assert filters["confidence_min"] == 50 assert filters["severity_min"] == 3 assert filters["malicious"] == "yes" def test_build_filters_all_types(): """Test that 'All' indicator type results in no type filter.""" params = {"indicator_type": "All"} filters = FeedCyberintPremium.build_filters(params) assert "indicator_type" not in filters def test_build_filters_from_args(): """Test building filters from command arguments.""" args = { "indicator_type": "ipv4,domain", "severity_min": "3", "added_to_feed_after": "2025-01-01T00:00:00Z", } filters = FeedCyberintPremium.build_filters_from_args(args) assert filters["indicator_type"] == ["ipv4", "domain"] assert filters["severity_min"] == 3 assert filters["added_to_feed_after"] == "2025-01-01T00:00:00Z" def test_premium_header_transformer(): """Test the premium_header_transformer function.""" assert FeedCyberintPremium.premium_header_transformer("indicator_type") == "Indicator Type" assert FeedCyberintPremium.premium_header_transformer("indicator_value") == "Indicator Value" assert FeedCyberintPremium.premium_header_transformer("activity") == "Activity" assert FeedCyberintPremium.premium_header_transformer("confidence") == "Confidence" assert FeedCyberintPremium.premium_header_transformer("severity") == "Severity" assert FeedCyberintPremium.premium_header_transformer("malicious") == "Malicious" assert FeedCyberintPremium.premium_header_transformer("kill_chain_stage") == "Kill Chain Stage" assert FeedCyberintPremium.premium_header_transformer("first_seen") == "First Seen" assert FeedCyberintPremium.premium_header_transformer("last_seen") == "Last Seen" assert FeedCyberintPremium.premium_header_transformer("added_to_feed") == "Added to Feed" assert FeedCyberintPremium.premium_header_transformer("is_blocking") == "Is Blocking" assert FeedCyberintPremium.premium_header_transformer("has_cve") == "Has CVE" assert FeedCyberintPremium.premium_header_transformer("has_campaign") == "Has Campaign" def test_test_module(mocker, mock_client): """Test the test_module function.""" mocker.patch.object(FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(feed_text=load_mock_response())) with patch("FeedCyberintPremium.auto_detect_indicator_type") as mock_auto_detect: mock_auto_detect.side_effect = lambda x: "IP" result = FeedCyberintPremium.test_module(mock_client) assert result == "ok" def test_enrich_command_ipv4(mocker, mock_client): """Test enrichment of an IPv4 indicator.""" with open("test_data/enrichment_ipv4.json") as f: mock_response = json.load(f) mocker.patch.object(FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(enrich_json=mock_response)) args = {"type": "ipv4", "value": "192.0.2.1"} result = FeedCyberintPremium.enrich_command(mock_client, args) assert result is not None assert result.outputs["indicator_type"] == "ipv4" assert result.outputs["indicator_value"] == "1.1.1.1" assert result.outputs["activity"] == "CnC Server" assert result.outputs["confidence"] == 90 assert result.outputs["severity"] == 4 assert result.outputs["malicious"] == "yes" assert result.outputs["malware_family"] == "LockBit" assert "APT28" in result.outputs["threat_actors"] assert "CVE-2024-1234" in result.outputs["cves"] assert result.outputs["enrichment"]["geo"]["country"] == "Russia" assert result.outputs["enrichment"]["asn"]["number"] == 12345 assert "Indicator Details" in result.readable_output assert "Threat Intelligence" in result.readable_output assert "TTPs" in result.readable_output assert "IPv4 Enrichment" in result.readable_output def test_enrich_command_domain(mocker, mock_client): """Test enrichment of a domain indicator.""" with open("test_data/enrichment_domain.json") as f: mock_response = json.load(f) http_mock = mocker.patch.object( FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(enrich_json=mock_response) ) args = {"type": "domain", "value": "malicious-example.com"} result = FeedCyberintPremium.enrich_command(mock_client, args) assert result is not None assert result.outputs["indicator_type"] == "domain" assert result.outputs["indicator_value"] == "malicious-example.com" assert result.outputs["activity"] == "Phishing" assert result.outputs["enrichment"]["ips"] == ["2.2.2.2", "3.3.3.3"] assert result.outputs["enrichment"]["whois"]["registrant_name"] == "John Doe" assert "Indicator Details" in result.readable_output assert "Domain Enrichment" in result.readable_output body = http_mock.call_args.kwargs["json_data"] assert body["type"] == "domain" assert body["value"] == "malicious-example.com" def test_enrich_command_no_enrichment(mocker, mock_client): """Test enrichment when no type-specific enrichment data is returned.""" mock_response = { "indicator_type": "ipv4", "indicator_value": "9.9.9.9", "activity": "Unknown", "confidence": 10, "severity": 1, "malicious": "inconclusive", "first_seen": None, "last_seen": None, "valid_until": None, "kill_chain_stage": None, "malware_types": [], "malware_family": None, "origin_countries": [], "targeted_countries": [], "targeted_sectors": [], "targeted_brands": [], "threat_actors": [], "campaigns": [], "cves": [], "ttps": [], "tags": [], "enrichment": None, } mocker.patch.object(FeedCyberintPremium.Client, "_http_request", side_effect=_http_responder(enrich_json=mock_response)) args = {"type": "ipv4", "value": "9.9.9.9"} result = FeedCyberintPremium.enrich_command(mock_client, args) assert result is not None assert result.outputs["indicator_value"] == "9.9.9.9" assert "Indicator Details" in result.readable_output assert "IPv4 Enrichment" not in result.readable_output