InfobloxBloxOneThreatDefense

Infoblox Threat Defense with DDI integration leverages DNS as the first line of defense to detect and block cyber threats, while also using threat intelligence to manage SOC Insight incident response and enrich indicators.

Data Enrichment & Threat Intelligence · Infoblox Threat Defense with DDI

Details

IDInfobloxBloxOneThreatDefense
ProviderInfoblox
CategoryData Enrichment & Threat Intelligence
From Version6.5.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Infoblox Threat Defense with DDI integration leverages DNS as the first line of defense to detect and block cyber threats, while also using threat intelligence to manage insight incident response and enrich indicators.
This integration was integrated and tested with version 1.0.0 of Infoblox Threat Defense with DDI.

Configure Infoblox Threat Defense with DDI in Cortex

Parameter Description Required
Service API Key   True
Source Reliability Reliability of the source providing the intelligence data. False
Create relationships Create relationships between indicators as part of Enrichment. False
Fetch incidents   False
Incident type   False
Ingestion Type Select the ingestion type to fetch as XSOAR incident. Default is SOC Insight. False
SOC Insight Status Retrieve the SOC Insights as specified status. False
SOC Insight Threat Type Retrieve the SOC Insights as specified threat type. False
SOC Insight Priority Level Retrieve the SOC Insights as specified priority level. False
DNS Security Event Feed Name Retrieve the DNS Security Events as specified feed name or custom list name. False
DNS Security Event Network Retrieve the DNS Security Events as specified network name. False
DNS Security Event Policy Action Retrieve the DNS Security Events as specified policy action. False
DNS Security Event Policy Name Retrieve the DNS Security Events as specified policy name. False
DNS Security Event Queried Name Retrieve the DNS Security Events as specified queried name. False
DNS Security Event Threat Class Retrieve the DNS Security Events as specified threat class. False
DNS Security Event Threat Family Retrieve the DNS Security Events as specified threat family. False
DNS Security Event Threat Indicator Retrieve the DNS Security Events as specified threat indicator. False
DNS Security Event Threat Level Retrieve the DNS Security Events as specified threat level. False
Max Fetch The maximum number of SOC Insights or DNS Security Events to fetch each time. If the value is greater than 200, it will be considered as 200. The maximum is 200. False
First fetch timestamp The date or relative timestamp from which to begin fetching incidents. Note: This parameter is only applicable for DNS Security Events.

Supported formats: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ.

For example: 01 May 2025, 01 May 2025 04:45:33, 2025-05-17T14:05:44Z.
False
Incidents Fetch Interval   False
Trust any certificate (not secure)   False
Use system proxy settings   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.

bloxone-td-dossier-lookup-get


The Dossier Lookup API returns detailed information on the specified indicator from the requested sources.

Base Command

bloxone-td-dossier-lookup-get

Input

Argument Name Description Required
indicator_type The type of indcator to search by. Possible values are: host, ip, url, hash, email. Required
value The indicator to search on. Required
sources The sources to query. Multiple sources can be specified. If no source is specified, the call will search on all available sources. (You can see the list of the available sources by running bloxone-td-dossier-source-list). Optional
interval_in_seconds The interval in seconds between each poll. Default is 10. Optional
timeout The timeout in seconds until polling ends. Default is 600. Optional
job_id used for polling. Optional

Context Output

Path Type Description
BloxOneTD.DossierLookup.source String The Dossier source.
BloxOneTD.DossierLookup.target String The targeted indicator.
BloxOneTD.DossierLookup.task_id String The Dossier task ID.
BloxOneTD.DossierLookup.type String The indicator type.

Command example

!bloxone-td-dossier-lookup-get indicator_type="ip" value="11.22.33.44" sources="activity,threatfox,ccb"

Context Example

{
    "BloxOneTD": {
        "DossierLookup": [
            {
                "params": {
                    "source": "ccb",
                    "target": "11.22.33.44",
                    "type": "ip"
                },
                "status": "success",
                "task_id": "97bdeca2-b66d-47b1-b1ef-9e4833654df2",
                "time": 6401,
                "v": "3.0.0"
            },
            {
                "data": {
                    "impacted_devices": [],
                    "requests_by_day": []
                },
                "params": {
                    "source": "activity",
                    "target": "11.22.33.44",
                    "type": "ip"
                },
                "status": "success",
                "task_id": "4074cb34-2bec-485d-8d6d-9e9cc88d5229",
                "time": 1708,
                "v": "3.0.0"
            },
            {
                "data": {
                    "matches": []
                },
                "params": {
                    "source": "threatfox",
                    "target": "11.22.33.44",
                    "type": "ip"
                },
                "status": "success",
                "task_id": "73892ea3-1e22-433f-bc74-f59133b914d0",
                "time": 8,
                "v": "3.0.0"
            }
        ]
    }
}

Human Readable Output

Lookalike Domain List

Task Id Type Target Source
d418b8d6-831c-4f6f-a31a-6d48995d2267 ip 11.22.33.44 threatfox
91945be3-0cef-4d03-afd7-e4f25864553d ip 11.22.33.44 ccb
7145a1ca-40a9-43df-b0a3-c4281e5abd7e ip 11.22.33.44 activity

bloxone-td-dossier-source-list


Get available Dossier sources.

Base Command

bloxone-td-dossier-source-list

Input

There are no input arguments for this command.

Context Output

Path Type Description
BloxOneTD.DossierSource String Available Dossier sources.

Command example


#### Context Example

```json
{
    "BloxOneTD": {
        "DossierSource": [
            "ccb",
            "activity",
            "geo",
            "threatfox"
        ]
    }
}

Human Readable Output

Results

DossierSource
activity
ccb
geo
threatfox

bloxone-td-lookalike-domain-list


Get lookalike domain lists.

Notice: Submitting indicators using this command might make the indicator data publicly available. See the vendor’s documentation for more details.

Base Command

bloxone-td-lookalike-domain-list

Input

Argument Name Description Required
filter The free query filter argument. Optional
target_domain Filter by target domain. Optional
detected_at Filter by values that are greater than or equal to the given value. You can use ISO format (e.g. ‘2023-02-14T00:11:22Z’) or use a relative time (e.g. “3 days”). Optional
limit Maximum number of results to return from the query. Default is 50. Optional
offset Return results starting at this offset. Should be an integer. Default is 0. Optional

Context Output

Path Type Description
BloxOneTD.LookalikeDomain.detected_at Date The date of the lookalike detection.
BloxOneTD.LookalikeDomain.lookalike_domain String The lookalike domain.
BloxOneTD.LookalikeDomain.lookalike_host String The lookalike host.
BloxOneTD.LookalikeDomain.reason String The reason for the detection.
BloxOneTD.LookalikeDomain.target_domain String The domain that was targeted by the lookalike domain.

Command example

!bloxone-td-lookalike-domain-list detected_at="1y"

Context Example

{
    "BloxOneTD": {
        "LookalikeDomain": [
            {
                "detected_at": "2023-01-27T18:43:01Z",
                "lookalike_domain": "test.a.com",
                "lookalike_host": "test.a.com",
                "reason": "Domain is a lookalike to test.com. The creation date is 2023-01-22.",
                "target_domain": "test.com"
            },
            {
                "detected_at": "2023-01-28T18:36:27Z",
                "lookalike_domain": "test.b.com",
                "lookalike_host": "test.b.com",
                "reason": "Domain is a lookalike to test.com and has suspicious registration, behavior, or associations with known threats. The creation date is 2022-11-30.",
                "suspicious": true,
                "target_domain": "test.com"
            },
            {
                "detected_at": "2023-01-28T18:37:03Z",
                "lookalike_domain": "test.c.com",
                "lookalike_host": "test.c.com",
                "reason": "Domain is a lookalike to test.com. The creation date is 2022-09-18.",
                "target_domain": "test.com"
            }
        ]
    }
}

Human Readable Output

Results

Detected At Lookalike Domain Lookalike Host Reason Target Domain
2023-01-27T18:43:01Z test.a.com test.a.com Domain is a lookalike to test.com. The creation date is 2023-01-22. test.com
2023-01-28T18:36:27Z test.b.com test.b.com Domain is a lookalike to test.com and has suspicious registration, behavior, or associations with known threats. The creation date is 2022-11-30. test.com
2023-01-28T18:37:03Z test.c.com test.c.com Domain is a lookalike to test.com. The creation date is 2022-09-18. test.com

infobloxcloud-block-ip


The given IP addresses will be added to the provided block list.

Base Command

infobloxcloud-block-ip

Input

Argument Name Description Required
ip Specify the IP addresses to block. Supports comma-separated values. Required
custom_list_name Specify the name of the custom list to add the given IP addresses to. Default is Default Block. Optional
custom_list_type Specify the type of the custom list to add the given IP addresses to. Possible values are: default_block, custom_list, threat_insight, dga, dnsm, zero_day_dns, threat_insight_nde. Default is default_block. Optional

Context Output

Path Type Description
InfobloxCloud.CustomList.id String The ID of the custom list.
InfobloxCloud.CustomList.name String The name of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.items String The items in the custom list.
InfobloxCloud.CustomList.items_described Array The items described in the custom list.
InfobloxCloud.CustomList.item_count Number The number of items in the custom list.
InfobloxCloud.CustomList.confidence_level String The confidence level of the custom list.
InfobloxCloud.CustomList.created_time String The time the custom list was created.
InfobloxCloud.CustomList.last_updated_time String The time the custom list was last updated.
InfobloxCloud.CustomList.description String The description of the custom list.
InfobloxCloud.CustomList.policies String The policies of the custom list.
InfobloxCloud.CustomList.tags String The tags of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.threat_level String The threat level of the custom list.

Command example

!infobloxcloud-block-ip ip=0.0.0.0

Context Example

{
    "InfobloxCloud": {
        "CustomList": {
            "confidence_level": "HIGH",
            "created_time": "2024-04-01T18:24:37Z",
            "description": "Auto-generated",
            "id": 456789,
            "item_count": 2,
            "items": [
                "0.0.0.0/32",
                "0.0.0.1/32"
            ],
            "items_described": [
                {
                    "description": "",
                    "item": "0.0.0.0/32",
                    "status": "ACTIVE",
                    "status_details": ""
                },
                {
                    "description": "",
                    "item": "0.0.0.1/32",
                    "status": "ACTIVE",
                    "status_details": ""
                }
            ],
            "name": "Test Block",
            "policies": [
                "Test Policy"
            ],
            "tags": {
                "test_key": "test_value"
            },
            "threat_level": "MEDIUM",
            "type": "test_block",
            "updated_time": "2025-07-29T08:47:54Z"
        }
    }
}

Human Readable Output

‘0.0.0.0’ indicators added to the ‘Test Block’ list

ID Name Type Description Items Confidence Level Threat Level Tags Created Time Updated Time
792594 Test Block test_block Auto-generated 0.0.0.0/32,
0.0.0.1/32
HIGH MEDIUM test_key: test_value 2024-04-01T18:24:37Z 2025-07-29T08:47:54Z

infobloxcloud-unblock-ip


The given IP addresses will be added to the provided allow list.

Base Command

infobloxcloud-unblock-ip

Input

Argument Name Description Required
ip Specify the IP addresses to unblock. Supports comma-separated values. Required
custom_list_name Specify the name of the custom list to add the given IP addresses to. Default is Default Allow. Optional
custom_list_type Specify the type of the custom list to add the given IP addresses to. Possible values are: default_allow, custom_list, threat_insight, threat_insight_nde. Default is default_allow. Optional

Context Output

Path Type Description
InfobloxCloud.CustomList.id String The ID of the custom list.
InfobloxCloud.CustomList.name String The name of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.items String The items in the custom list.
InfobloxCloud.CustomList.items_described Array The items described in the custom list.
InfobloxCloud.CustomList.item_count Number The number of items in the custom list.
InfobloxCloud.CustomList.confidence_level String The confidence level of the custom list.
InfobloxCloud.CustomList.created_time String The time the custom list was created.
InfobloxCloud.CustomList.last_updated_time String The time the custom list was last updated.
InfobloxCloud.CustomList.description String The description of the custom list.
InfobloxCloud.CustomList.policies String The policies of the custom list.
InfobloxCloud.CustomList.tags String The tags of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.threat_level String The threat level of the custom list.

Command example

!infobloxcloud-unblock-ip ip=0.0.0.0

Context Example

{
    "InfobloxCloud": {
        "CustomList": {
            "confidence_level": "HIGH",
            "created_time": "2024-04-01T18:24:37Z",
            "description": "Auto-generated",
            "id": 123456,
            "item_count": 2,
            "items": [
                "0.0.0.0/32",
                "0.0.0.1/32"
            ],
            "items_described": [
                {
                    "description": "",
                    "item": "0.0.0.0/32",
                    "status": "ACTIVE",
                    "status_details": ""
                },
                {
                    "description": "",
                    "item": "0.0.0.1/32",
                    "status": "ACTIVE",
                    "status_details": ""
                }
            ],
            "name": "Test Allow",
            "policies": [
                "Test Policy"
            ],
            "tags": {
                "test_key": "test_value"
            },
            "threat_level": "MEDIUM",
            "type": "test_allow",
            "updated_time": "2025-07-29T08:48:02Z"
        }
    }
}

Human Readable Output

‘0.0.0.0’ indicators added to the ‘Test Allow’ list

ID Name Type Description Items Confidence Level Threat Level Tags Created Time Updated Time
123456 Test Allow test_allow Auto-generated 0.0.0.0/32,
0.0.0.1/32
HIGH MEDIUM test_key: test_value 2024-04-01T18:24:37Z 2025-07-29T08:48:02Z

infobloxcloud-block-domain


The given domains will be added to the provided block list.

Base Command

infobloxcloud-block-domain

Input

Argument Name Description Required
domain Specify the Domains to block. Supports comma-separated values. Required
custom_list_name Specify the name of the custom list to add the given domains to. Default is Default Block. Optional
custom_list_type Specify the type of the custom list to add the given domains to. Possible values are: default_block, custom_list, threat_insight, dga, dnsm, zero_day_dns, threat_insight_nde. Default is default_block. Optional

Context Output

Path Type Description
InfobloxCloud.CustomList.id String The ID of the custom list.
InfobloxCloud.CustomList.name String The name of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.items String The items in the custom list.
InfobloxCloud.CustomList.items_described Array The items described in the custom list.
InfobloxCloud.CustomList.item_count Number The number of items in the custom list.
InfobloxCloud.CustomList.confidence_level String The confidence level of the custom list.
InfobloxCloud.CustomList.created_time String The time the custom list was created.
InfobloxCloud.CustomList.last_updated_time String The time the custom list was last updated.
InfobloxCloud.CustomList.description String The description of the custom list.
InfobloxCloud.CustomList.policies String The policies of the custom list.
InfobloxCloud.CustomList.tags String The tags of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.threat_level String The threat level of the custom list.

Command example

!infobloxcloud-block-domain domain="test.com"

Context Example

{
    "InfobloxCloud": {
        "CustomList": {
            "confidence_level": "HIGH",
            "created_time": "2024-04-01T18:24:37Z",
            "description": "Auto-generated",
            "id": 456789,
            "item_count": 2,
            "items": [
                "test.com",
                "test.org"
            ],
            "items_described": [
                {
                    "description": "",
                    "item": "test.com",
                    "status": "ACTIVE",
                    "status_details": ""
                },
                {
                    "description": "",
                    "item": "test.org",
                    "status": "ACTIVE",
                    "status_details": ""
                }
            ],
            "name": "Test Block",
            "policies": [
                "Test Policy"
            ],
            "tags": null,
            "threat_level": "MEDIUM",
            "type": "test_block",
            "updated_time": "2025-07-29T10:27:49Z"
        }
    }
}

Human Readable Output

‘test.com’ indicator added to the ‘Test Block’ list

ID Name Type Description Items Confidence Level Threat Level Created Time Updated Time
456789 Test Block test_block Auto-generated test.com,
test.org
HIGH MEDIUM 2024-04-01T18:24:37Z 2025-07-29T10:27:49Z

infobloxcloud-unblock-domain


The given domains will be added to the provided allow list.

Base Command

infobloxcloud-unblock-domain

Input

Argument Name Description Required
domain Specify the Domains to unblock. Supports comma-separated values. Required
custom_list_name Specify the name of the custom list to add the given domains to. Default is Default Allow. Optional
custom_list_type Specify the type of the custom list to add the given domains to. Possible values are: default_allow, custom_list, threat_insight, threat_insight_nde. Default is default_allow. Optional

Context Output

Path Type Description
InfobloxCloud.CustomList.id String The ID of the custom list.
InfobloxCloud.CustomList.name String The name of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.items String The items in the custom list.
InfobloxCloud.CustomList.items_described Array The items described in the custom list.
InfobloxCloud.CustomList.item_count Number The number of items in the custom list.
InfobloxCloud.CustomList.confidence_level String The confidence level of the custom list.
InfobloxCloud.CustomList.created_time String The time the custom list was created.
InfobloxCloud.CustomList.last_updated_time String The time the custom list was last updated.
InfobloxCloud.CustomList.description String The description of the custom list.
InfobloxCloud.CustomList.policies String The policies of the custom list.
InfobloxCloud.CustomList.tags String The tags of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.threat_level String The threat level of the custom list.

Command example

!infobloxcloud-unblock-domain domain="test.com"

Context Example

{
    "InfobloxCloud": {
        "CustomList": {
            "confidence_level": "HIGH",
            "created_time": "2024-04-01T18:24:37Z",
            "description": "Auto-generated",
            "id": 123456,
            "item_count": 2,
            "items": [
                "test.com",
                "test.org"
            ],
            "items_described": [
                {
                    "description": "",
                    "item": "test.com",
                    "status": "ACTIVE",
                    "status_details": ""
                },
                {
                    "description": "",
                    "item": "test.org",
                    "status": "ACTIVE",
                    "status_details": ""
                }
            ],
            "name": "Test Allow",
            "policies": [
                "Test Policy"
            ],
            "tags": {
                "test_key": "test_value"
            },
            "threat_level": "MEDIUM",
            "type": "test_allow",
            "updated_time": "2025-07-29T10:27:56Z"
        }
    }
}

Human Readable Output

‘test.com’ indicator added to the ‘Test Allow’ list

ID Name Type Description Items Confidence Level Threat Level Tags Created Time Updated Time
123456 Test Allow test_allow Auto-generated test.com,
test.org
HIGH MEDIUM test_key: test_value 2024-04-01T18:24:37Z 2025-07-29T10:27:56Z

infobloxcloud-customlist-indicator-remove


The given indicators will be removed from the provided custom list.

Base Command

infobloxcloud-customlist-indicator-remove

Input

Argument Name Description Required
indicators Specify the indicators to remove from the custom list. Format accepted is: “0.0.0.0, example.com”. Required
custom_list_name Specify the name of the custom list to remove the given indicators from. Required
custom_list_type Specify the type of the custom list to remove the given indicators from. Possible values are: default_allow, default_block, custom_list, threat_insight, dga, dnsm, zero_day_dns, threat_insight_nde. Required

Context Output

Path Type Description
InfobloxCloud.CustomList.id String The ID of the custom list.
InfobloxCloud.CustomList.name String The name of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.items String The items in the custom list.
InfobloxCloud.CustomList.items_described Array The items described in the custom list.
InfobloxCloud.CustomList.item_count Number The number of items in the custom list.
InfobloxCloud.CustomList.confidence_level String The confidence level of the custom list.
InfobloxCloud.CustomList.created_time String The time the custom list was created.
InfobloxCloud.CustomList.last_updated_time String The time the custom list was last updated.
InfobloxCloud.CustomList.description String The description of the custom list.
InfobloxCloud.CustomList.policies String The policies of the custom list.
InfobloxCloud.CustomList.tags String The tags of the custom list.
InfobloxCloud.CustomList.type String The type of the custom list.
InfobloxCloud.CustomList.threat_level String The threat level of the custom list.

Command example

!infobloxcloud-customlist-indicator-remove indicators="0.0.0.0" custom_list_name="Test Allow" custom_list_type="test_allow"

Context Example

{
    "InfobloxCloud": {
        "CustomList": {
            "confidence_level": "HIGH",
            "created_time": "2024-04-01T18:24:37Z",
            "description": "Auto-generated",
            "id": 123456,
            "item_count": 1,
            "items": [
                "example.com"
            ],
            "items_described": [
                {
                    "description": "",
                    "item": "example.com",
                    "status": "ACTIVE",
                    "status_details": ""
                }
            ],
            "name": "Test Allow",
            "policies": [
                "Test Policy",
            ],
            "tags": {
                "test_key": "test_value"
            },
            "threat_level": "MEDIUM",
            "type": "test_allow",
            "updated_time": "2025-07-31T11:07:41Z"
        }
    }
}

Human Readable Output

‘0.0.0.0’ indicators removed from the ‘Test Allow’ list

ID Name Type Description Items Confidence Level Threat Level Tags Created Time Updated Time
123456 Test Allow test_allow Auto-generated example.com HIGH MEDIUM test_key: test_value 2024-04-01T18:24:37Z 2025-07-31T11:07:41Z

ip


Gets the comprehensive IP reputation and threat intelligence from Infoblox Threat Defense, including threat indicators, IPAM address information, and standard IP reputation data.

Base Command

ip

Input

Argument Name Description Required
ip IP(s) for which to retrieve reputation and threat intelligence. Supports comma-separated values. Required

Context Output

Path Type Description
InfobloxCloud.IP.ip String The requested IP address.
IP.Address String IP address.
IP.Relationships.EntityA String The source of the relationship.
IP.Relationships.EntityB String The destination of the relationship.
IP.Relationships.Relationship String The name of the relationship.
IP.Relationships.EntityAType String The type of the source of the relationship.
IP.Relationships.EntityBType String The type of the destination of the relationship.
IP.ASN String The autonomous system name for the IP address, for example: “AS8948”.
IP.Hostname String The hostname that is mapped to this IP address.
IP.Geo.Location String The geolocation where the IP address is located, in the format: latitude:longitude.
IP.Geo.Country String The country in which the IP address is located.
IP.Geo.Description String Additional information about the location.
IP.DetectionEngines Number The total number of engines that checked the indicator.
IP.PositiveDetections Number The number of engines that positively detected the indicator as malicious.
IP.Malicious.Vendor String The vendor reporting the IP address as malicious.
IP.Malicious.Description String A description explaining why the IP address was reported as malicious.
IP.Tags Unknown (List) Tags of the IP address.
IP.FeedRelatedIndicators.value String Indicators that are associated with the IP address.
IP.FeedRelatedIndicators.type String The type of the indicators that are associated with the IP address.
IP.FeedRelatedIndicators.description String The description of the indicators that are associated with the IP address.
IP.MalwareFamily String The malware family associated with the IP address.
IP.Organization.Name String The organization of the IP address.
IP.Organization.Type String The organization type of the IP address.
IP.ASOwner String The autonomous system owner of the IP address.
IP.Region String The region in which the IP address is located.
IP.Port String Ports that are associated with the IP address.
IP.Internal Boolean Whether the IP address is internal or external.
IP.UpdatedDate Date The date that the IP address was last updated.
IP.Registrar.Abuse.Name String The name of the contact for reporting abuse.
IP.Registrar.Abuse.Address String The address of the contact for reporting abuse.
IP.Registrar.Abuse.Country String The country of the contact for reporting abuse.
IP.Registrar.Abuse.Network String The network of the contact for reporting abuse.
IP.Registrar.Abuse.Phone String The phone number of the contact for reporting abuse.
IP.Registrar.Abuse.Email String The email address of the contact for reporting abuse.
IP.Campaign String The campaign associated with the IP address.
IP.TrafficLightProtocol String The Traffic Light Protocol (TLP) color that is suitable for the IP address.
IP.CommunityNotes.note String Notes on the IP address that were given by the community.
IP.CommunityNotes.timestamp Date The time in which the note was published.
IP.Publications.source String The source in which the article was published.
IP.Publications.title String The name of the article.
IP.Publications.link String A link to the original article.
IP.Publications.timestamp Date The time in which the article was published.
IP.ThreatTypes.threatcategory String The threat category associated to this indicator by the source vendor. For example, Phishing, Control, TOR, etc.
IP.ThreatTypes.threatcategoryconfidence String The confidence level provided by the vendor for the threat type category For example, a confidence of 90 for the threat type category ‘malware’ means that the vendor rates that this is 90% confidence of being a malware.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
InfobloxCloud.IP.Threat.id String The unique identifier for the threat indicator.
InfobloxCloud.IP.Threat.type String The type of threat indicator.
InfobloxCloud.IP.Threat.ip String The IP address identified as a threat indicator.
InfobloxCloud.IP.Threat.profile String The threat profile or classification source.
InfobloxCloud.IP.Threat.property String The specific property or category of the threat.
InfobloxCloud.IP.Threat.class String The classification of the threat.
InfobloxCloud.IP.Threat.threat_level Number The numeric threat level score.
InfobloxCloud.IP.Threat.threat_label String The textual threat level label.
InfobloxCloud.IP.Threat.expiration Date The timestamp when the threat indicator will expire.
InfobloxCloud.IP.Threat.detected Date The timestamp when the threat activity was first detected.
InfobloxCloud.IP.Threat.received Date The timestamp when the threat indicator was received by the system.
InfobloxCloud.IP.Threat.imported Date The timestamp when the threat indicator was imported into the system.
InfobloxCloud.IP.Threat.up String The boolean status flag indicating whether the threat indicator is currently active.
InfobloxCloud.IP.Threat.batch_id String The batch ID of the threat indicator.
InfobloxCloud.IP.Threat.confidence Number The numeric confidence score representing the reliability of the threat indicator.
InfobloxCloud.IP.Threat.extended.notes String The additional notes or information about the threat indicator.
InfobloxCloud.IP.Threat.threat_score Number The numeric score representing the calculated threat severity.
InfobloxCloud.IP.Threat.threat_score_rating String The textual rating of the threat score.
InfobloxCloud.IP.Threat.threat_score_vector String The vector string representing threat scoring details.
InfobloxCloud.IP.Threat.risk_score Number The numeric risk score assigned to the threat indicator.
InfobloxCloud.IP.Threat.risk_score_rating String The textual rating of the risk score.
InfobloxCloud.IP.Threat.risk_score_vector String The vector string representing risk scoring details.
InfobloxCloud.IP.Threat.confidence_score Number The numeric confidence score for the threat assessment.
InfobloxCloud.IP.Threat.confidence_score_rating String The textual rating of the confidence score.
InfobloxCloud.IP.Threat.confidence_score_vector String The vector string representing confidence scoring details.
InfobloxCloud.IP.Threat.extended.cyberint_guid String The unique identifier for the threat indicator.
InfobloxCloud.IP.Threat.extended.attack_chain String The attack chain associated with the threat indicator.
InfobloxCloud.IP.Threat.extended.extended String The additional information or metadata associated with the threat indicator.
InfobloxCloud.IP.Threat.extended.protocol String The protocol associated with the threat indicator.
InfobloxCloud.IP.Threat.extended.references String The references associated with the threat indicator.
InfobloxCloud.IP.Threat.extended.threat_actor String The threat actor associated with the threat indicator.
InfobloxCloud.IP.Threat.extended.threat_actor_vector String The vector string representing threat actor details.
InfobloxCloud.IP.Threat.extended.risk_score String The numeric risk score assigned to the threat indicator.
InfobloxCloud.IP.Threat.extended.threat_score String The numeric threat score assigned to the threat indicator.
InfobloxCloud.IP.Threat.extended.sample_sha256 String The SHA-256 hash of the sample associated with the threat.
InfobloxCloud.IP.Threat.extended.original_profile String The original profile or classification source of the threat.
InfobloxCloud.IP.Address.address String The IP address assigned to the resource.
InfobloxCloud.IP.Address.comment String A user-provided comment or annotation for the address record.
InfobloxCloud.IP.Address.compartment_id String The compartment ID of the IP address.
InfobloxCloud.IP.Address.created_at Date The timestamp when the IP address was created.
InfobloxCloud.IP.Address.dhcp_info Unknown The DHCP information associated with the IP address.
InfobloxCloud.IP.Address.disable_dhcp Boolean A boolean flag indicating whether DHCP is disabled for the IP address.
InfobloxCloud.IP.Address.discovery_attrs Unknown The discovery attributes associated with the IP address.
InfobloxCloud.IP.Address.discovery_metadata Unknown The discovery metadata associated with the IP address.
InfobloxCloud.IP.Address.external_keys Unknown External keys associated with the IP address.
InfobloxCloud.IP.Address.host Unknown The host name of the IP address.
InfobloxCloud.IP.Address.hwaddr String The hardware address of the IP address.
InfobloxCloud.IP.Address.id String The unique identifier of the IP address.
InfobloxCloud.IP.Address.interface String The interface of the IP address.
InfobloxCloud.IP.Address.names Unknown The names associated with the IP address.
InfobloxCloud.IP.Address.parent String The parent of the IP address.
InfobloxCloud.IP.Address.protocol String The protocol of the IP address.
InfobloxCloud.IP.Address.range String The range of the IP address.
InfobloxCloud.IP.Address.space String The space of the IP address.
InfobloxCloud.IP.Address.state String The state of the IP address.
InfobloxCloud.IP.Address.tags Unknown The tags associated with the IP address.
InfobloxCloud.IP.Address.updated_at Date The timestamp when the IP address was last updated.
InfobloxCloud.IP.Address.usage String The usage of the IP address.
InfobloxCloud.IP.Address.names.name String The name of the IP address.
InfobloxCloud.IP.Address.names.type Unknown The type of the IP address.

Command example

!ip ip="0.0.0.1"

Context Example

{
    "DBotScore": {
        "Indicator": "0.0.0.1",
        "Reliability": "A - Completely reliable",
        "Score": 3,
        "Type": "ip",
        "Vendor": "InfobloxThreatDefensewithDDI"
    },
    "IP": {
        "Address": "0.0.0.1",
        "Description": "Malware Download associated with the APT group",
        "ThreatTypes": [
            {
                "threatcategory": "IP",
                "threatcategoryconfidence": "100"
            }
        ],
        "Hostname": "name",
        "DetectionEngines": 1,
        "Tags": [
            "cyberint_guid: simple_cyberint_guid",
            "notes: Malware Download associated with the APT group",
            "Protocol: ip4",
            "State: used",
            "temp: true"
        ],
        "MalwareFamily": "APT",
        "Malicious": {
            "Vendor": "InfobloxThreatDefensewithDDI",
            "Description": "Malware Download associated with the APT group"
        }
    },
    "InfobloxCloud": {
        "IP": {
            "ip": "0.0.0.1",
            "Threat": {
                "id": "00000000-0000-0000-0000-000000000000",
                "type": "IP",
                "ip": "0.0.0.1",
                "profile": "IID",
                "property": "APT_Malware",
                "class": "APT",
                "threat_level": 100,
                "expiration": "2042-11-01T09:29:18.721Z",
                "detected": "2025-07-29T09:29:18.721Z",
                "received": "2025-07-29T09:31:39.329Z",
                "imported": "2025-07-29T09:31:39.329Z",
                "up": "true",
                "confidence": 100,
                "batch_id": "00000000-0000-0000-0000-000000000000",
                "threat_score": 10,
                "threat_score_rating": "Critical",
                "threat_score_vector": "simple_threat_vector",
                "risk_score": 9.9,
                "risk_score_rating": "Critical",
                "risk_score_vector": "simple_risk_vector",
                "confidence_score": 0.1,
                "confidence_score_rating": "Unconfirmed",
                "confidence_score_vector": "simple_confidence_vector",
                "extended": {
                    "cyberint_guid": "simple_cyberint_guid",
                    "notes": "Malware Download associated with the APT group"
                }
            },
            "Address": {
                "address": "0.0.0.1",
                "comment": "comment",
                "compartment_id": "00000000-0000-0000-0000-000000000000",
                "created_at": "2025-06-27T13:07:21.476126Z",
                "disable_dhcp": false,
                "external_keys": {
                    "e3": "3e3"
                },
                "host": "ipam/host/00000000-0000-0000-0000-000000000000",
                "hwaddr": "00:00:00:00:00:00",
                "id": "ipam/address/00000000-0000-0000-0000-000000000000",
                "interface": "interface",
                "names": [
                    {
                        "name": "name",
                        "type": "user"
                    }
                ],
                "parent": "ipam/subnet/00000000-0000-0000-0000-000000000000",
                "protocol": "ip4",
                "range": "ipam/range/00000000-0000-0000-0000-000000000000",
                "space": "ipam/ip_space/00000000-0000-0000-0000-000000000000",
                "state": "used",
                "tags": {
                    "temp": "true"
                },
                "updated_at": "2025-06-27T13:07:21.429056Z",
                "usage": [
                    "IPAM RESERVED"
                ]
            }
        }
    }
}

Human Readable Output

Information for the given Bad IP: 0.0.0.1

Threat Intelligence Summary

Batch Id Class Confidence Confidence Score Confidence Score Rating Confidence Score Vector Detected Expiration Extended Id Imported IP Profile Property Received Risk Score Risk Score Rating Risk Score Vector Threat Level Threat Score Threat Score Rating Threat Score Vector Type Up
00000000-0000-0000-0000-000000000000 APT 100 0.1 Unconfirmed simple_confidence_vector 2025-07-29T09:29:18.721Z 2042-11-01T09:29:18.721Z cyberint_guid: simple_cyberint_guid
notes: Malware Download associated with the APT group
00000000-0000-0000-0000-000000000000 2025-07-29T09:31:39.329Z 0.0.0.1 IID APT_Malware 2025-07-29T09:31:39.329Z 9.9 Critical simple_risk_vector 100 10 Critical simple_threat_vector IP true

Address Information

Address Comment Compartment Id Created At Disable Dhcp External Keys Host Hwaddr Id Interface Names Parent Protocol Range Space State Tags Updated At Usage
0.0.0.1 comment 00000000-0000-0000-0000-000000000000 2025-06-27T13:07:21.476126Z False e3: 3e3 ipam/host/00000000-0000-0000-0000-000000000000 00:00:00:00:00:00 ipam/address/00000000-0000-0000-0000-000000000000 interface - name: name
type: user
ipam/subnet/00000000-0000-0000-0000-000000000000 ip4 ipam/range/00000000-0000-0000-0000-000000000000 ipam/ip_space/00000000-0000-0000-0000-000000000000 used temp: true 2025-06-27T13:07:21.429056Z values: IPAM RESERVED

domain


Gets the comprehensive domain/host reputation and threat intelligence from Infoblox Threat Defense, including threat indicators, IPAM address information and standard domain reputation data.

Base Command

domain

Input

Argument Name Description Required
domain Domain(s) or Hosts(s) for which to retrieve reputation and threat intelligence. Supports comma-separated values. Required

Context Output

Path Type Description
InfobloxCloud.Domain.domain String The requested domain.
Domain.Name String The domain name, for example: “google.com”.
Domain.Relationships.EntityA string The source of the relationship.
Domain.Relationships.EntityB string The destination of the relationship.
Domain.Relationships.Relationship string The name of the relationship.
Domain.Relationships.EntityAType string The type of the source of the relationship.
Domain.Relationships.EntityBType string The type of the destination of the relationship.
Domain.DNS String A list of IP objects resolved by DNS.
Domain.DetectionEngines Number The total number of engines that checked the indicator.
Domain.PositiveDetections Number The number of engines that positively detected the indicator as malicious.
Domain.CreationDate Date The date that the domain was created.
Domain.UpdatedDate String The date that the domain was last updated.
Domain.ExpirationDate Date The expiration date of the domain.
Domain.DomainStatus Datte The status of the domain.
Domain.NameServers Unknown (List<String>) Name servers of the domain.
Domain.Organization String The organization of the domain.
Domain.Subdomains Unknown (List<String>) Subdomains of the domain.
Domain.Admin.Country String The country of the domain administrator.
Domain.Admin.Email String The email address of the domain administrator.
Domain.Admin.Name String The name of the domain administrator.
Domain.Admin.Phone String The phone number of the domain administrator.
Domain.Registrant.Country String The country of the registrant.
Domain.Registrant.Email String The email address of the registrant.
Domain.Registrant.Name String The name of the registrant.
Domain.Registrant.Phone String The phone number for receiving abuse reports.
Domain.Tags Unknown (List) Tags of the domain.
Domain.FeedRelatedIndicators.value String Indicators that are associated with the domain.
Domain.FeedRelatedIndicators.type String The type of the indicators that are associated with the domain.
Domain.FeedRelatedIndicators.description String The description of the indicators that are associated with the domain.
Domain.MalwareFamily String The malware family associated with the domain.
Domain.WHOIS.DomainStatus String The status of the domain.
Domain.WHOIS.NameServers String (List<String>) Name servers of the domain.
Domain.WHOIS.CreationDate Date The date that the domain was created.
Domain.WHOIS.UpdatedDate Date The date that the domain was last updated.
Domain.WHOIS.ExpirationDate Date The expiration date of the domain.
Domain.WHOIS.Registrant.Name String The name of the registrant.
Domain.WHOIS.Registrant.Email String The email address of the registrant.
Domain.WHOIS.Registrant.Phone String The phone number of the registrant.
Domain.WHOIS.Registrar.Name String The name of the registrar.
Domain.WHOIS.Registrar.AbuseEmail String The email address of the contact for reporting abuse.
Domain.WHOIS.Registrar.AbusePhone String The phone number of contact for reporting abuse.
Domain.WHOIS.Admin.Name String The name of the domain administrator.
Domain.WHOIS.Admin.Email String The email address of the domain administrator.
Domain.WHOIS.Admin.Phone String The phone number of the domain administrator.
Domain.WHOIS/History String List of Whois objects.
Domain.Malicious.Vendor String The vendor reporting the domain as malicious.
Domain.Malicious.Description String A description explaining why the domain was reported as malicious.
Domain.DomainIDNName String The internationalized domain name (IDN) of the domain.
Domain.Port String Ports that are associated with the domain.
Domain.Internal Bool Whether or not the domain is internal or external.
Domain.Category String The category associated with the indicator.
Domain.Campaign String The campaign associated with the domain.
Domain.TrafficLightProtocol String The Traffic Light Protocol (TLP) color that is suitable for the domain.
Domain.ThreatTypes.threatcategory String The threat category associated to this indicator by the source vendor. For example, Phishing, Control, TOR, etc.
Domain.ThreatTypes.threatcategoryconfidence String Threat Category Confidence is the confidence level provided by the vendor for the threat type category For example a confidence of 90 for threat type category ‘malware’ means that the vendor rates that this is 90% confidence of being a malware.
Domain.Geo.Location String The geolocation where the domain address is located, in the format: latitude:longitude.
Domain.Geo.Country String The country in which the domain address is located.
Domain.Geo.Description String Additional information about the location.
Domain.Tech.Country String The country of the domain technical contact.
Domain.Tech.Name String The name of the domain technical contact.
Domain.Tech.Organization String The organization of the domain technical contact.
Domain.Tech.Email String The email address of the domain technical contact.
Domain.CommunityNotes.note String Notes on the domain that were given by the community.
Domain.CommunityNotes.timestamp Date The time in which the note was published.
Domain.Publications.source String The source in which the article was published.
Domain.Publications.title String The name of the article.
Domain.Publications.link String A link to the original article.
Domain.Publications.timestamp Date The time in which the article was published.
Domain.Billing String The billing address of the domain.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
InfobloxCloud.Domain.Threat.id String The unique identifier for the threat indicator.
InfobloxCloud.Domain.Threat.type String The type of threat indicator.
InfobloxCloud.Domain.Threat.domain String The domain identified as a threat indicator.
InfobloxCloud.Domain.Threat.profile String The threat profile or classification source.
InfobloxCloud.Domain.Threat.property String The specific property or category of the threat.
InfobloxCloud.Domain.Threat.class String The classification of the threat.
InfobloxCloud.Domain.Threat.threat_level Number The numeric threat level score.
InfobloxCloud.Domain.Threat.threat_label String The textual threat level label.
InfobloxCloud.Domain.Threat.expiration Date The timestamp when the threat indicator will expire.
InfobloxCloud.Domain.Threat.detected Date The timestamp when the threat activity was first detected.
InfobloxCloud.Domain.Threat.received Date The timestamp when the threat indicator was received by the system.
InfobloxCloud.Domain.Threat.imported Date The timestamp when the threat indicator was imported into the system.
InfobloxCloud.Domain.Threat.up String The boolean status flag indicating whether the threat indicator is currently active.
InfobloxCloud.Domain.Threat.batch_id String The batch ID of the threat indicator.
InfobloxCloud.Domain.Threat.confidence Number The numeric confidence score representing the reliability of the threat indicator.
InfobloxCloud.Domain.Threat.extended.notes String The additional notes or information about the threat indicator.
InfobloxCloud.Domain.Threat.threat_score Number The numeric score representing the calculated threat severity.
InfobloxCloud.Domain.Threat.threat_score_rating String The textual rating of the threat score.
InfobloxCloud.Domain.Threat.threat_score_vector String The vector string representing threat scoring details.
InfobloxCloud.Domain.Threat.risk_score Number The numeric risk score assigned to the threat indicator.
InfobloxCloud.Domain.Threat.risk_score_rating String The textual rating of the risk score.
InfobloxCloud.Domain.Threat.risk_score_vector String The vector string representing risk scoring details.
InfobloxCloud.Domain.Threat.confidence_score Number The numeric confidence score for the threat assessment.
InfobloxCloud.Domain.Threat.confidence_score_rating String The textual rating of the confidence score.
InfobloxCloud.Domain.Threat.confidence_score_vector String The vector string representing confidence scoring details.
InfobloxCloud.Domain.Threat.extended.cyberint_guid String The unique identifier for the threat indicator.
InfobloxCloud.Domain.Threat.extended.attack_chain String The attack chain associated with the threat indicator.
InfobloxCloud.Domain.Threat.extended.extended String The additional information or metadata associated with the threat indicator.
InfobloxCloud.Domain.Threat.extended.protocol String The protocol associated with the threat indicator.
InfobloxCloud.Domain.Threat.extended.references String The references associated with the threat indicator.
InfobloxCloud.Domain.Threat.extended.threat_actor String The threat actor associated with the threat indicator.
InfobloxCloud.Domain.Threat.extended.threat_actor_vector String The vector string representing threat actor details.
InfobloxCloud.Domain.Threat.extended.risk_score String The numeric risk score assigned to the threat indicator.
InfobloxCloud.Domain.Threat.extended.threat_score String The numeric threat score assigned to the threat indicator.
InfobloxCloud.Domain.Threat.extended.sample_sha256 String The SHA-256 hash of the sample associated with the threat.
InfobloxCloud.Domain.Threat.extended.original_profile String The original profile or classification source of the threat.
InfobloxCloud.Domain.Threat.dga String The domain name generated by a DGA (Domain Generation Algorithm).
InfobloxCloud.Domain.Threat.host String The host name of the domain.
InfobloxCloud.Domain.Threat.tld String The top-level domain (TLD) of the threat.
InfobloxCloud.Domain.Address.addresses.address String The address of the IP address.
InfobloxCloud.Domain.Address.addresses.ref String The reference of the IP address.
InfobloxCloud.Domain.Address.addresses.space String The space of the IP address.
InfobloxCloud.Domain.Address.auto_generate_records Boolean A boolean flag indicating whether auto generate records is enabled for the IP address.
InfobloxCloud.Domain.Address.comment String The description for the IPAM host.
InfobloxCloud.Domain.Address.created_at Date Time when the object has been created.
InfobloxCloud.Domain.Address.host_names Unknown The name records to be generated for the host.
InfobloxCloud.Domain.Address.id String The resource identifier.
InfobloxCloud.Domain.Address.name String The name of the IPAM host.
InfobloxCloud.Domain.Address.host_names.alias Boolean A boolean flag indicating whether the name record is an alias.
InfobloxCloud.Domain.Address.host_names.name String The name of the host.
InfobloxCloud.Domain.Address.host_names.primary_name Boolean A boolean flag indicating whether the name record is the primary name.
InfobloxCloud.Domain.Address.host_names.zone String The zone of the host.
InfobloxCloud.Domain.Address.tags Unknown The tags associated with the IP address.
InfobloxCloud.Domain.Address.addresses Unknown The IP address assigned to the resource.

Command example

!domain domain=test.com

Context Example

{
    "DBotScore": {
        "Indicator": "test.com",
        "Reliability": "A - Completely reliable",
        "Score": 3,
        "Type": "domain",
        "Vendor": "InfobloxBloxOneThreatDefense"
    },
    "Domain": {
        "Description": "cyber actors, possibly associated with the APT group Agent Serpens, created a fake website mimicking a modeling agency to collect detailed visitor.",
        "DetectionEngines": 1,
        "Malicious": {
            "Description": "cyber actors, possibly associated with the APT group Agent Serpens, created a fake website mimicking a modeling agency to collect detailed visitor.",
            "Vendor": "InfobloxThreatDefensewithDDI"
        },
        "MalwareFamily": "Phishing",
        "Name": "test.com",
        "Relationships": [
            {
                "EntityA": "test.com",
                "EntityAType": "Domain",
                "EntityB": "0.0.0.1",
                "EntityBType": "IP",
                "Relationship": "resolves-to"
            }
        ],
        "Tags": [
            "cyberint_guid: simple_cyberint_guid",
            "notes: cyber actors, possibly associated with the APT group Agent Serpens, created a fake website mimicking a modeling agency to collect detailed visitor."
        ],
        "ThreatTypes": [
            {
                "threatcategory": "HOST",
                "threatcategoryconfidence": "100"
            }
        ]
    },
    "InfobloxCloud": {
        "Domain": {
            "Address": {
                "addresses": [
                    {
                        "address": "0.0.0.1",
                        "ref": "ipam/address/00000000-0000-0000-0000-000000000000",
                        "space": "ipam/ip_space/00000000-0000-0000-0000-000000000000"
                    }
                ],
                "auto_generate_records": true,
                "comment": "comment",
                "created_at": "2025-07-22T05:26:46.834693Z",
                "host_names": [
                    {
                        "alias": false,
                        "name": "test.com",
                        "primary_name": true,
                        "zone": "dns/auth_zone/8ce66502-8d4b-439e-8690-0c59d3122b9f"
                    }
                ],
                "id": "ipam/host/00000000-0000-0000-0000-000000000000",
                "name": "test.com",
                "updated_at": "2025-07-22T05:26:57.219235Z"
            },
            "domain": "test.com",
            "Threat": {
                "batch_id": "00000000-0000-0000-0000-000000000001",
                "class": "Phishing",
                "confidence": 100,
                "detected": "2025-05-08T16:39:38.959Z",
                "dga": "false",
                "domain": "test.com",
                "expiration": "2025-09-05T16:39:38.959Z",
                "extended": {
                    "cyberint_guid": "simple_cyberint_guid",
                    "notes": "cyber actors, possibly associated with the APT group Agent Serpens, created a fake website mimicking a modeling agency to collect detailed visitor."
                },
                "host": "test.com",
                "id": "00000000-0000-0000-0000-000000000001",
                "imported": "2025-05-08T16:41:37.894Z",
                "profile": "IID",
                "property": "Phishing_Lookalike",
                "received": "2025-05-08T16:41:37.894Z",
                "threat_level": 100,
                "tld": "com",
                "type": "HOST",
                "up": "true"
            }
        }
    }
}

Human Readable Output

Information for the given Bad Domain: test.com

Threat Intelligence Summary

Batch Id Class Confidence Detected Dga Domain Expiration Extended Host Id Imported Profile Property Received Threat Level Tld Type Up
00000000-0000-0000-0000-000000000001 Phishing 100 2025-05-08T16:39:38.959Z false test.com 2025-09-05T16:39:38.959Z cyberint_guid: simple_cyberint_guid
notes: cyber actors, possibly associated with the APT group Agent Serpens, created a fake website mimicking a modeling agency to collect detailed visitor.
test.com 00000000-0000-0000-0000-000000000001 2025-05-08T16:41:37.894Z IID Phishing_Lookalike 2025-05-08T16:41:37.894Z 100 com HOST true

Address Information

Addresses Auto Generate Records Comment Created At Host Names Id Name Updated At
- address: 0.0.0.1
ref: ipam/address/00000000-0000-0000-0000-000000000000
space: ipam/ip_space/00000000-0000-0000-0000-000000000000
True comment 2025-07-22T05:26:46.834693Z - alias: False
name: test.com
primary_name: True
zone: dns/auth_zone/8ce66502-8d4b-439e-8690-0c59d3122b9f
ipam/host/00000000-0000-0000-0000-000000000000 test.com 2025-07-22T05:26:57.219235Z

url


Gets the comprehensive URL reputation and threat intelligence from Infoblox Threat Defense, including threat indicators, and standard URL reputation data.

Base Command

url

Input

Argument Name Description Required
url URL(s) for which to retrieve reputation and threat intelligence. Supports comma-separated values. Required

Context Output

Path Type Description
InfobloxCloud.URL.url String The requested URL.
URL.Data String The URL.
URL.Relationships.EntityA string The source of the relationship.
URL.Relationships.EntityB string The destination of the relationship.
URL.Relationships.Relationship string The name of the relationship.
URL.Relationships.EntityAType string The type of the source of the relationship.
URL.Relationships.EntityBType string The type of the destination of the relationship.
URL.DetectionEngines String The total number of engines that checked the indicator.
URL.PositiveDetections String The number of engines that positively detected the indicator as malicious.
URL.Category String The category associated with the indicator.
URL.Malicious.Vendor String The vendor reporting the URL as malicious.
URL.Malicious.Description String A description of the malicious URL.
URL.Tags Unknown (List) Tags of the URL.
URL.FeedRelatedIndicators.value String Indicators that are associated with the URL.
URL.FeedRelatedIndicators.type String The type of the indicators that are associated with the URL.
URL.FeedRelatedIndicators.description String The description of the indicators that are associated with the URL.
URL.MalwareFamily String The malware family associated with the URL.
URL.Port String Ports that are associated with the URL.
URL.Internal Bool Whether or not the URL is internal or external.
URL.Campaign String The campaign associated with the URL.
URL.TrafficLightProtocol String The Traffic Light Protocol (TLP) color that is suitable for the URL.
URL.ThreatTypes.threatcategory String The threat category associated to this indicator by the source vendor. For example, Phishing, Control, TOR, etc.
URL.ThreatTypes.threatcategoryconfidence String Threat Category Confidence is the confidence level provided by the vendor for the threat type category For example a confidence of 90 for threat type category ‘malware’ means that the vendor rates that this is 90% confidence of being a malware.
URL.ASN String The autonomous system name for the URL, for example: ‘AS8948’.
URL.ASOwner String The autonomous system owner of the URL.
URL.GeoCountry String The country in which the URL is located.
URL.Organization String The organization of the URL.
URL.CommunityNotes.note String Notes on the URL that were given by the community.
URL.CommunityNotes.timestamp Date The time in which the note was published.
URL.Publications.source String The source in which the article was published.
URL.Publications.title String The name of the article.
URL.Publications.link String A link to the original article.
URL.Publications.timestamp Date The time in which the article was published.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
InfobloxCloud.URL.Threat.id String The unique identifier for the threat indicator.
InfobloxCloud.URL.Threat.type String The type of threat indicator.
InfobloxCloud.URL.Threat.url String The URL identified as a threat indicator.
InfobloxCloud.URL.Threat.profile String The threat profile or classification source.
InfobloxCloud.URL.Threat.property String The specific property or category of the threat.
InfobloxCloud.URL.Threat.class String The classification of the threat.
InfobloxCloud.URL.Threat.threat_level Number The numeric threat level score.
InfobloxCloud.URL.Threat.threat_label String The textual threat level label.
InfobloxCloud.URL.Threat.expiration Date The timestamp when the threat indicator will expire.
InfobloxCloud.URL.Threat.detected Date The timestamp when the threat activity was first detected.
InfobloxCloud.URL.Threat.received Date The timestamp when the threat indicator was received by the system.
InfobloxCloud.URL.Threat.imported Date The timestamp when the threat indicator was imported into the system.
InfobloxCloud.URL.Threat.up String The boolean status flag indicating whether the threat indicator is currently active.
InfobloxCloud.URL.Threat.batch_id String The batch ID of the threat indicator.
InfobloxCloud.URL.Threat.confidence Number The numeric confidence score representing the reliability of the threat indicator.
InfobloxCloud.URL.Threat.extended.notes String The additional notes or information about the threat indicator.
InfobloxCloud.URL.Threat.threat_score Number The numeric score representing the calculated threat severity.
InfobloxCloud.URL.Threat.threat_score_rating String The textual rating of the threat score.
InfobloxCloud.URL.Threat.threat_score_vector String The vector string representing threat scoring details.
InfobloxCloud.URL.Threat.risk_score Number The numeric risk score assigned to the threat indicator.
InfobloxCloud.URL.Threat.risk_score_rating String The textual rating of the risk score.
InfobloxCloud.URL.Threat.risk_score_vector String The vector string representing risk scoring details.
InfobloxCloud.URL.Threat.confidence_score Number The numeric confidence score for the threat assessment.
InfobloxCloud.URL.Threat.confidence_score_rating String The textual rating of the confidence score.
InfobloxCloud.URL.Threat.confidence_score_vector String The vector string representing confidence scoring details.
InfobloxCloud.URL.Threat.extended.cyberint_guid String The unique identifier for the threat indicator.
InfobloxCloud.URL.Threat.extended.attack_chain String The attack chain associated with the threat indicator.
InfobloxCloud.URL.Threat.extended.extended String The additional information or metadata associated with the threat indicator.
InfobloxCloud.URL.Threat.extended.protocol String The protocol associated with the threat indicator.
InfobloxCloud.URL.Threat.extended.references String The references associated with the threat indicator.
InfobloxCloud.URL.Threat.extended.threat_actor String The threat actor associated with the threat indicator.
InfobloxCloud.URL.Threat.extended.threat_actor_vector String The vector string representing threat actor details.
InfobloxCloud.URL.Threat.extended.risk_score String The numeric risk score assigned to the threat indicator.
InfobloxCloud.URL.Threat.extended.threat_score String The numeric threat score assigned to the threat indicator.
InfobloxCloud.URL.Threat.extended.sample_sha256 String The SHA-256 hash of the sample associated with the threat.
InfobloxCloud.URL.Threat.extended.original_profile String The original profile or classification source of the threat.

Command example

!url url=https://test.com

Context Example

{
    "DBotScore": {
        "Indicator": "https://test.com",
        "Reliability": "A - Completely reliable",
        "Score": 3,
        "Type": "url",
        "Vendor": "InfobloxBloxOneThreatDefense"
    },
    "InfobloxCloud": {
        "URL": {
            "Threat": {
                "id": "00000000-0000-0000-0000-000000000001",
                "type": "URL",
                "host": "test.com",
                "url": "https://test.com",
                "domain": "test.com",
                "tld": "com",
                "profile": "IID",
                "property": "Scam_Generic",
                "class": "Scam",
                "threat_level": 100,
                "expiration": "2025-10-05T12:12:00.22Z",
                "detected": "2025-06-07T12:12:00.22Z",
                "received": "2025-06-07T12:16:32.337Z",
                "imported": "2025-06-07T12:16:32.337Z",
                "up": "true",
                "confidence": 100,
                "batch_id": "00000000-0000-0000-0000-000000000000",
                "extended": {
                    "cyberint_guid": "simple_cyberint_guid",
                    "notes": "Scam advertised. Lures victims to put their money into fake investments.",
                    "protocol": "https",
                    "references": "https://test.com"
                }
            },
            "url": "https://test.com"
        }
    },
    "URL": {
        "Data": "https://test.com",
        "Description": "Scam advertised. Lures victims to put their money into fake investments.",
        "DetectionEngines": 1,
        "Malicious": {
            "Description": "Scam advertised. Lures victims to put their money into fake investments.",
            "Vendor": "InfobloxThreatDefensewithDDI"
        },
        "MalwareFamily": "Scam",
        "Tags": [
            "cyberint_guid: simple_cyberint_guid",
            "notes: Scam advertised. Lures victims to put their money into fake investments.",
            "protocol: https",
            "references: https://test.com"
        ],
        "ThreatTypes": [
            {
                "threatcategory": "URL",
                "threatcategoryconfidence": "100"
            }
        ]
    }
}

Human Readable Output

Information for the given Bad URL: https://test.com

Threat Intelligence Summary

Batch Id Class Confidence Detected Domain Expiration Extended Host Id Imported Profile Property Received Threat Level Tld Type Up URL
00000000-0000-0000-0000-000000000000 Scam 100 2025-06-07T12:12:00.22Z test.com 2025-10-05T12:12:00.22Z cyberint_guid: simple_cyberint_guid
notes: Scam advertised. Lures victims to put their money into fake investments.
protocol: https
references: https://test.com
test.com 00000000-0000-0000-0000-000000000001 2025-06-07T12:16:32.337Z IID Scam_Generic 2025-06-07T12:16:32.337Z 100 com URL true https://test.com

infobloxcloud-mac-enrich


Enrich a MAC address with DHCP lease information.

Base Command

infobloxcloud-mac-enrich

Input

Argument Name Description Required
mac Specify the MAC Address to enrich. Required

Context Output

Path Type Description
InfobloxCloud.DHCPLease.address String The IP address assigned in the DHCP lease.
InfobloxCloud.DHCPLease.client_id String The identifier of the DHCP client.
InfobloxCloud.DHCPLease.ends String The timestamp indicating when the DHCP lease ends.
InfobloxCloud.DHCPLease.fingerprint String The DHCP client fingerprint, indicating device type or OS.
InfobloxCloud.DHCPLease.fingerprint_processed String The processed fingerprint result, if available.
InfobloxCloud.DHCPLease.ha_group Unknown The high-availability group associated with the lease, if any.
InfobloxCloud.DHCPLease.hardware String The hardware (MAC) address of the DHCP client.
InfobloxCloud.DHCPLease.host String The reference or identifier for the host associated with this lease.
InfobloxCloud.DHCPLease.hostname String The hostname provided by the DHCP client.
InfobloxCloud.DHCPLease.iaid Number The Identity Association Identifier (IAID) for the DHCP lease.
InfobloxCloud.DHCPLease.last_updated String The timestamp when the lease was last updated.
InfobloxCloud.DHCPLease.options String The encoded DHCP options provided with the lease.
InfobloxCloud.DHCPLease.preferred_lifetime String The preferred lifetime of the lease.
InfobloxCloud.DHCPLease.protocol String The protocol used for the lease.
InfobloxCloud.DHCPLease.space String The identifier for the IP space to which this lease belongs.
InfobloxCloud.DHCPLease.starts String The timestamp indicating when the DHCP lease started.
InfobloxCloud.DHCPLease.state String The current state of the lease.
InfobloxCloud.DHCPLease.type String The type of DHCP lease.

Command example

!infobloxcloud-mac-enrich mac="00:00:00:00:00:01"

Context Example

{
    "InfobloxCloud": {
        "DHCPLease": {
            "address": "0.0.0.1",
            "client_id": "01:00:00:00:00:00:01",
            "ends": "2025-07-01T19:25:24Z",
            "fingerprint": "VMware:Virtual Machine:Windows:",
            "fingerprint_processed": "processed",
            "hardware": "00:00:00:00:00:01",
            "host": "dhcp/host/123456",
            "hostname": "test-host01",
            "iaid": 0,
            "last_updated": "2025-07-01T18:25:24.792Z",
            "options": "{\"Options\":[{\"Code\":\"57\",\"Value\":\"test\"},{\"Code\":\"61\",\"Value\":\"sample\"},{\"Code\":\"53\",\"Value\":\"world\"},{\"Code\":\"55\",\"Value\":\"bar\"}]}",
            "preferred_lifetime": "2025-07-01T18:25:24Z",
            "protocol": "",
            "space": "ipam/ip_space/12345678-1234-1234-1234-123456789012",
            "starts": "2025-07-01T18:25:24Z",
            "state": "used",
            "type": "DHCPv4"
        }
    }
}

Human Readable Output

DHCP Lease Information for MAC: 00:00:00:00:00:01

Address Client Id Ends Fingerprint Fingerprint Processed Hardware Host Hostname Iaid Last Updated Options Preferred Lifetime Space Starts State Type
0.0.0.1 01:00:00:00:00:00:01 2025-07-01T19:25:24Z VMware:Virtual Machine:Windows: processed 00:00:00:00:00:01 dhcp/host/123456 test-host01 0 2025-07-01T18:25:24.792Z - Code: 57
Value: test
- Code: 61
Value: sample
- Code: 53
Value: world
- Code: 55
Value: bar
2025-07-01T18:25:24Z ipam/ip_space/12345678-1234-1234-1234-123456789012 2025-07-01T18:25:24Z used DHCPv4

infobloxcloud-soc-insight-list


List SOC Insights from Infoblox Cloud.

Base Command

infobloxcloud-soc-insight-list

Input

Argument Name Description Required
status Specify the status of SOC Insights to fetch. Possible values are: Active, Closed. Optional
threat_type Specify the threat type of SOC Insights to fetch. Possible values are: DGA, Undefined, Malicious, Open Resolver, Phishing, DNS Tunneling, MalwareDownload, Sinkhole, Zero Day DNS, Notional Data Exfiltration, MalwareC2DGA, MalwareC2, Restricted Country Communications, Suspicious, CompromisedHost, CompromisedDomain, Lookalike Threat, Sanctioned Feed Disabled, DNSTunnel. Optional
priority Specify the priority level of SOC Insights to fetch. Possible values are: INFO, MEDIUM, HIGH, CRITICAL. Optional

Context Output

Path Type Description
InfobloxCloud.SOCInsight.insightId String The ID of the SOC Insight.
InfobloxCloud.SOCInsight.priorityText String The priority level of the SOC Insight.
InfobloxCloud.SOCInsight.tClass String The threat class of the SOC Insight.
InfobloxCloud.SOCInsight.tFamily String The threat family of the SOC Insight.
InfobloxCloud.SOCInsight.startedAt String The start time of the SOC Insight.
InfobloxCloud.SOCInsight.status String The status of the SOC Insight.
InfobloxCloud.SOCInsight.persistentDate String Timestamp when the threat was first observed as persistent.
InfobloxCloud.SOCInsight.spreadingDate String Timestamp when the threat was first observed as spreading.
InfobloxCloud.SOCInsight.dateChanged String Timestamp when the SOC Insight was last updated.
InfobloxCloud.SOCInsight.changer String The user or process that last changed the SOC Insight status or data.
InfobloxCloud.SOCInsight.feedSource String The source feed or provider of the SOC Insight.
InfobloxCloud.SOCInsight.threatType String The threat type of the SOC Insight.
InfobloxCloud.SOCInsight.numEvents String The number of events associated with the SOC Insight.
InfobloxCloud.SOCInsight.eventsNotBlockedCount String The number of events not blocked by the SOC Insight.
InfobloxCloud.SOCInsight.mostRecentAt String The most recent time the SOC Insight was updated.

Command example


#### Context Example

```json
{
    "InfobloxCloud": {
        "SOCInsight": [
            {
                "changer": "abc@xyz.com",
                "dateChanged": "2025-05-21T00:54:49.407214Z",
                "eventsBlockedCount": "3",
                "feedSource": "Insight Detection Framework",
                "insightId": "00000000-0000-0000-0000-000000000000",
                "mostRecentAt": "2025-07-19T19:25:11.723397Z",
                "numEvents": "3",
                "persistentDate": "2025-04-14T07:00:00Z",
                "priorityText": "HIGH",
                "spreadingDate": "2025-05-10T19:00:00Z",
                "startedAt": "2025-04-14T07:00:00Z",
                "status": "Active",
                "tClass": "Suspicious",
                "tFamily": "EmergentDomain",
                "threatType": "Suspicious"
            },
            {
                "tClass": "TI-RESTRICTED",
                "tFamily": "OFAC",
                "insightId": "00000000-0000-0000-0000-000000000001",
                "feedSource": "Insight Detection Framework",
                "startedAt": "2025-04-12T18:00:00Z",
                "threatType": "Sanctioned Feed Disabled",
                "status": "Active",
                "persistentDate": "2025-04-12T15:00:00Z",
                "numEvents": "246",
                "mostRecentAt": "2025-08-07T23:59:19Z",
                "eventsNotBlockedCount": "246",
                "changer": "abc@xyz.com",
                "dateChanged": "2025-08-06T13:58:01.050800Z",
                "priorityText": "INFO"
            }
        ]
    }
}

Human Readable Output

SOC Insights

ID Priority Class Threat Type Status Threat Family Feed Source Most Recent At
00000000-0000-0000-0000-000000000000 HIGH Suspicious Suspicious Active EmergentDomain Insight Detection Framework 2025-07-19T19:25:11.723397Z
00000000-0000-0000-0000-000000000001 INFO TI-RESTRICTED Sanctioned Feed Disabled Active OFAC Insight Detection Framework 2025-08-07T23:59:19Z

infobloxcloud-soc-insight-event-list


List events for a specific SOC Insight.

Base Command

infobloxcloud-soc-insight-event-list

Input

Argument Name Description Required
soc_insight_id Specify the SOC Insight ID to fetch events for. Required
limit Specify the maximum number of events to fetch. Default is 50. Optional
start_time Specify the start time for the events.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
end_time Specify the end time for the events.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
threat_level Specify the threat level of the events. Possible values are: High, Medium, Low, Info. Optional
confidence_level Specify the confidence level of the events. Possible values are: High, Medium, Low, Info. Optional
query Specify the query to search for events. Optional
query_type Specify the query type to search for events. Possible values are: A, AAAA, ANY, TXT, RRSIG, CNAME, MX, NS, PTR, SOA, SRV. Optional
source Specify the source of the events. Optional
device_ip Specify the device IP of the events. Optional
indicator Specify the indicator of the events. Optional

Context Output

Path Type Description
InfobloxCloud.Event.confidenceLevel String The confidence level of the threat detection.
InfobloxCloud.Event.deviceCountry String The country where the device is located.
InfobloxCloud.Event.deviceName String The name or identifier of the device.
InfobloxCloud.Event.deviceRegion String The region where the device is located.
InfobloxCloud.Event.dnsView String The DNS view used for the query.
InfobloxCloud.Event.feed String The feed that identified the threat.
InfobloxCloud.Event.source String The source of the threat detection.
InfobloxCloud.Event.action String The action taken on the detected threat.
InfobloxCloud.Event.policy String The policy applied to the detection.
InfobloxCloud.Event.deviceIp String The IP address of the device.
InfobloxCloud.Event.query String The DNS query that triggered the detection.
InfobloxCloud.Event.queryType String The type of DNS query.
InfobloxCloud.Event.response String The DNS response for the query.
InfobloxCloud.Event.class String The classification of the threat.
InfobloxCloud.Event.threatFamily String The family of the threat.
InfobloxCloud.Event.threatIndicator String The indicator of the threat.
InfobloxCloud.Event.detected String The timestamp when the event was detected.
InfobloxCloud.Event.property String The property of the event.
InfobloxCloud.Event.user String The user associated with the detection.
InfobloxCloud.Event.threatLevel String The severity level of the event.

Command example

!infobloxcloud-soc-insight-event-list soc_insight_id="00000000-0000-0000-0000-000000000000"

Context Example

{
    "InfobloxCloud": {
        "Event": [
            {
                "action": "Allow - No Log",
                "class": "TI-CONFIGURATIONISSUE",
                "confidenceLevel": "High",
                "detected": "2025-08-11 23:42:04 +0000 UTC",
                "deviceIp": "0.0.0.0",
                "deviceName": "0.0.0.0",
                "policy": "DoH",
                "property": "example.com",
                "query": "example.com",
                "queryType": "A",
                "source": "unknown",
                "threatFamily": "OPENRESOLVER",
                "threatLevel": "Low",
                "user": "unknown"
            },
            {
                "action": "Block",
                "class": "Suspicious",
                "confidenceLevel": "High",
                "detected": "2025-07-16 07:37:29 +0000 UTC",
                "deviceIp": "0.0.0.1",
                "deviceName": "0.0.0.1",
                "policy": "Default Policy",
                "property": "EmergentDomain",
                "query": "example.org",
                "queryType": "RRSIG",
                "source": "Endpoint",
                "threatFamily": "EmergentDomain",
                "threatLevel": "High",
                "user": "unknown"
            }
        ]
    }
}

Human Readable Output

Events for the given SOC Insight: 00000000-0000-0000-0000-000000000000

Confidence Level Threat Level Threat Family Action Class Detected
High Low OPENRESOLVER Allow - No Log TI-CONFIGURATIONISSUE 2025-08-11 23:42:04 +0000 UTC
High High EmergentDomain Block Suspicious 2025-07-16 07:37:29 +0000 UTC

infobloxcloud-soc-insight-indicator-list


List indicators for a specific SOC Insight.

Base Command

infobloxcloud-soc-insight-indicator-list

Input

Argument Name Description Required
soc_insight_id Specify the SOC Insight ID to fetch indicators for. Required
limit Specify the maximum number of indicators to fetch. Default is 50. Optional
start_time Specify the start time for the indicators.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
end_time Specify the end time for the indicators.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
confidence Specify the confidence of the indicators. Possible values are: 1, 2, 3. Optional
indicator Specify the indicator of the indicators. Optional
action Specify the action of the indicators. Possible values are: Blocked, Not Blocked. Optional
actor Specify the actor of the indicators. Optional

Context Output

Path Type Description
InfobloxCloud.Indicator.action String The action taken for the indicator.
InfobloxCloud.Indicator.confidence String The confidence level of the indicator.
InfobloxCloud.Indicator.count Number The number of occurrences of the indicator.
InfobloxCloud.Indicator.feedName String The feed name that identified the indicator.
InfobloxCloud.Indicator.threatLevelMax String The maximum threat level associated with the indicator.
InfobloxCloud.Indicator.indicator String The value of the indicator.
InfobloxCloud.Indicator.timeMax Date The latest time the indicator was observed.
InfobloxCloud.Indicator.timeMin Date The earliest time the indicator was observed.

Command example

!infobloxcloud-soc-insight-indicator-list soc_insight_id="00000000-0000-0000-0000-000000000000"

Context Example

{
    "InfobloxCloud": {
        "Indicator": [
            {
                "action": "Not Blocked",
                "confidence": "3",
                "count": 189,
                "indicator": "example.org",
                "threatLevelMax": "1",
                "timeMax": "2025-08-11T23:00:00.000",
                "timeMin": "2025-07-13T15:00:00.000"
            },
            {
                "action": "Blocked",
                "confidence": "1",
                "count": 5,
                "indicator": "example.com",
                "threatLevelMax": "3",
                "timeMax": "2025-08-11T12:00:00.000",
                "timeMin": "2025-07-14T10:00:00.000"
            }
        ]
    }
}

Human Readable Output

Indicators for the given SOC Insight: 00000000-0000-0000-0000-000000000000

Action Confidence Max Threat Level Indicator Count Max Time Min Time
Not Blocked 3 1 example.org 189 2025-08-11T23:00:00.000 2025-07-13T15:00:00.000
Blocked 1 3 example.com 5 2025-08-11T12:00:00.000 2025-07-14T10:00:00.000

infobloxcloud-soc-insight-asset-list


List assets for a specific SOC Insight.

Base Command

infobloxcloud-soc-insight-asset-list

Input

Argument Name Description Required
soc_insight_id Specify the SOC Insight ID to fetch assets for. Required
limit Specify the maximum number of assets to fetch. Default is 50. Optional
start_time Specify the start time for the assets.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
end_time Specify the end time for the assets.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
qip Specify the IP address of the assets. Optional
cmac Specify the MAC address of the assets. Optional
os_version Specify the OS version of the assets. Optional
user Specify the user of the assets. Optional

Context Output

Path Type Description
InfobloxCloud.Asset.count Number The number of occurrences associated with the asset.
InfobloxCloud.Asset.qip String The IP address of the asset.
InfobloxCloud.Asset.location String The geographical location of the asset.
InfobloxCloud.Asset.threatLevelMax String The maximum threat level associated with the asset.
InfobloxCloud.Asset.threatIndicatorDistinctCount String The number of distinct threat indicators associated with the asset.
InfobloxCloud.Asset.timeMax Date The latest time the asset was observed.
InfobloxCloud.Asset.timeMin Date The earliest time the asset was observed.
InfobloxCloud.Asset.mostRecentAction String The most recent action taken for the asset.

Command example

!infobloxcloud-soc-insight-asset-list soc_insight_id="00000000-0000-0000-0000-000000000000"

Context Example

{
    "InfobloxCloud": {
        "Asset": [
            {
                "count": 5,
                "location": "Leidschendam,Netherlands",
                "mostRecentAction": "Not Blocked",
                "qip": "0.0.0.0",
                "threatIndicatorDistinctCount": "1",
                "threatLevelMax": "1",
                "timeMax": "2025-08-11T12:00:00.000",
                "timeMin": "2025-07-14T10:00:00.000"
            },
            {
                "count": 1,
                "location": "Minneapolis,United States",
                "mostRecentAction": "Not Blocked",
                "qip": "0.0.0.1",
                "threatIndicatorDistinctCount": "1",
                "threatLevelMax": "1",
                "timeMax": "2025-08-07T12:00:00.000",
                "timeMin": "2025-08-07T12:00:00.000"
            }
        ]
    }
}

Human Readable Output

Assets for the given SOC Insight: 00000000-0000-0000-0000-000000000000

Count QIP Max Threat Level Location Threat Indicator Distinct Count Time Max Time Min Most Recent Action
5 0.0.0.0 1 Leidschendam,Netherlands 1 2025-08-11T12:00:00.000 2025-07-14T10:00:00.000 Not Blocked
1 0.0.0.1 1 Minneapolis,United States 1 2025-08-07T12:00:00.000 2025-08-07T12:00:00.000 Not Blocked

infobloxcloud-soc-insight-comment-list


List comments for a specific SOC Insight.

Base Command

infobloxcloud-soc-insight-comment-list

Input

Argument Name Description Required
soc_insight_id Specify the SOC Insight ID to fetch comments for. Required
start_time Specify the start time for the comments.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
end_time Specify the end time for the comments.

Format: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DD, N days, N hours.

Example: 2025-04-25T00:00:00Z, 2025-04-25, 2 days, 5 hours, 01 Mar 2025, 01 Feb 2025 04:45:33, 15 Jun.
Optional
limit Specify the maximum number of comments to fetch. Default is 50. Optional

Context Output

Path Type Description
InfobloxCloud.Comment.commentsChanger String The user who created or changed the comment.
InfobloxCloud.Comment.dateChanged Date The timestamp when the comment was created or modified.
InfobloxCloud.Comment.status String The status associated with the comment.
InfobloxCloud.Comment.newComment String The comment text.

Command example

!infobloxcloud-soc-insight-comment-list soc_insight_id="00000000-0000-0000-0000-000000000000"

Context Example

{
    "InfobloxCloud": {
        "Comment": [
            {
                "commentsChanger": "abc.zyx.com",
                "dateChanged": "2025-08-02T08:39:43.675",
                "newComment": "\nAsset IP: 0.0.0.0\nScan ID: None\nReference ID: None\nQualys Scan Report URL: https://example.com/fo/report/report_view.php?&id=None\n",
                "status": "Active"
            },
            {
                "commentsChanger": "abc.zyx.com",
                "dateChanged": "2025-07-15T05:24:29.803",
                "newComment": "\nAsset IP: 0.0.0.0\nScan ID: None\nReference ID: None\nQualys Scan Report URL: https://example.com/fo/report/report_view.php?&id=None\n",
                "status": "Active"
            }
        ]
    }
}

Human Readable Output

Comments for the given SOC Insight: 00000000-0000-0000-0000-000000000000

Comment Changer Date Changed Status Comment
abc.zyx.com 2025-08-02T08:39:43.675 Active
Asset IP: 0.0.0.0
Scan ID: None
Reference ID: None
Qualys Scan Report URL: https://example.com/fo/report/report_view.php?&id=None
abc.zyx.com 2025-07-15T05:24:29.803 Active
Asset IP: 0.0.0.0
Scan ID: None
Reference ID: None
Qualys Scan Report URL: https://example.com/fo/report/report_view.php?&id=None

Configuration parameters

  • credentials — (required)
  • integrationReliability — Source Reliability
  • create_relationships — Create relationships
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • ingestion_type — Ingestion Type
  • soc_insight_status — SOC Insight Status
  • soc_insight_threat_type — SOC Insight Threat Type
  • soc_insight_priority_level — SOC Insight Priority Level
  • dns_events_feed_name — DNS Security Event Feed Name
  • dns_events_network — DNS Security Event Network
  • dns_events_policy_action — DNS Security Event Policy Action
  • dns_events_policy_name — DNS Security Event Policy Name
  • dns_events_queried_name — DNS Security Event Queried Name
  • dns_events_threat_class — DNS Security Event Threat Class
  • dns_events_threat_family — DNS Security Event Threat Family
  • dns_events_threat_indicator — DNS Security Event Threat Indicator
  • dns_events_threat_level — DNS Security Event Threat Level
  • max_fetch — Max Fetch
  • first_fetch — First fetch timestamp
  • incidentFetchInterval — Incidents Fetch Interval
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (17)

  • bloxone-td-dossier-lookup-get

    The Dossier Lookup API returns detailed information on the specified indicator from the requested sources.

  • bloxone-td-dossier-source-list

    Get available Dossier sources.

  • bloxone-td-lookalike-domain-list

    Get lookalike domain lists.

  • domain

    Gets the comprehensive domain/host reputation and threat intelligence from Infoblox Threat Defense, including threat indicators, IPAM address information and standard domain reputation data.

  • infobloxcloud-block-domain

    The given domains will be added to the provided block list.

  • infobloxcloud-block-ip

    The given IP addresses will be added to the provided block list.

  • infobloxcloud-customlist-indicator-remove

    The given indicators will be removed from the provided custom list.

  • infobloxcloud-mac-enrich

    Enrich a MAC address with DHCP lease information.

  • infobloxcloud-soc-insight-asset-list

    List assets for a specific SOC Insight.

  • infobloxcloud-soc-insight-comment-list

    List comments for a specific SOC Insight.

  • infobloxcloud-soc-insight-event-list

    List events for a specific SOC Insight.

  • infobloxcloud-soc-insight-indicator-list

    List indicators for a specific SOC Insight.

  • infobloxcloud-soc-insight-list

    List SOC Insights from Infoblox Cloud.

  • infobloxcloud-unblock-domain

    The given domains will be added to the provided allow list.

  • infobloxcloud-unblock-ip

    The given IP addresses will be added to the provided allow list.

  • ip

    Gets the comprehensive IP reputation and threat intelligence from Infoblox Threat Defense, including threat indicators, IPAM address information, and standard IP reputation data.

  • url

    Gets the comprehensive URL reputation and threat intelligence from Infoblox Threat Defense, including threat indicators, and standard URL reputation data.

import json
from pathlib import Path

import pytest
from copy import deepcopy
from freezegun import freeze_time
from unittest.mock import patch, call
from InfobloxBloxOneThreatDefense import *

TEST_PATH = Path(__file__).parent / "test_data"


def load_json_file(file_description):
    file_path = TEST_PATH / f"{file_description}.json"
    with open(file_path) as f:
        return f.read()


def util_load_json(file_name: str):
    """Load file in JSON format."""
    file_path = TEST_PATH / file_name
    with open(file_path, encoding="utf-8") as f:
        return json.loads(f.read())


def util_load_text_data(file_name: str) -> str:
    """Load a text file."""
    file_path = TEST_PATH / file_name
    with open(file_path, encoding="utf-8") as f:
        return f.read()


@pytest.fixture
def blox_client() -> BloxOneTDClient:
    return BloxOneTDClient("")


@pytest.fixture
def mock_results(mocker):
    return mocker.patch.object(demisto, "results")


@pytest.fixture(autouse=True)
def mock_demisto_version(mocker):
    return mocker.patch.object(demisto, "demistoVersion", return_value={"version": "6.5.0", "buildNumber": "12345"})


def patch_command_args_and_params(mocker, command, args):
    mocker.patch.object(demisto, "args", return_value=args)
    mocker.patch.object(demisto, "command", return_value=command)
    mocker.patch.object(demisto, "params", return_value={"credentials": {"password": ""}})


class TestE2E:
    def test_dossier_source_list_command(self, requests_mock, mocker, mock_results):
        patch_command_args_and_params(mocker, "bloxone-td-dossier-source-list", {})
        request_call = requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/sources",
            text=load_json_file("bloxone-td-dossier-source-list"),
        )
        res_list = ["dns", "geo", "ptr", "whois", "ssl_cert", "urlhaus"]
        main()
        assert mock_results.call_args[0][0]["EntryContext"]["BloxOneTD"]["DossierSource"] == res_list
        assert mock_results.call_args[0][0]["Contents"]["DossierSource"] == res_list
        assert request_call.called_once

    def test_lookalike_domain_list_command(self, requests_mock, mocker, mock_results):
        patch_command_args_and_params(mocker, "bloxone-td-lookalike-domain-list", {"target_domain": "test.com"})
        request_call = requests_mock.get(
            f"{BASE_URL}/api/tdlad/v1/lookalike_domains",
            text=load_json_file("bloxone-td-lookalike-domain-list"),
        )

        main()
        assert request_call.called_once
        assert request_call.request_history[0].qs["_filter"][0].startswith("target_domain")
        raw = mock_results.call_args[0][0]["Contents"]
        assert raw
        assert mock_results.call_args[0][0]["EntryContext"]["BloxOneTD.LookalikeDomain"] == raw

    def test_lookalike_domain_list_command_with_invalid_args(self, mocker, mock_results):
        patch_command_args_and_params(
            mocker,
            "bloxone-td-lookalike-domain-list",
            {"target_domain": "test.com", "filter": "test"},
        )
        with pytest.raises(SystemExit):
            main()
        assert mock_results.call_args[0][0]["Type"] == 4
        assert "Exactly one of them, more than one is argument is not accepted" in mock_results.call_args[0][0]["Contents"]

    def test_dossier_lookup_get_command(self, requests_mock, mocker, mock_results):
        job_id = "c924d233-ddeb-8877-1234-fedd6a9bb070"
        create_job_request_mock = requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/indicator/ip",
            text=load_json_file("bloxone-td-dossier-lookup-get_create-job"),
        )
        results_request_mock = requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/jobs/c924d233-ddeb-8877-1234-fedd6a9bb070/results",
            text=load_json_file("bloxone-td-dossier-lookup-get_results"),
        )
        pending_request_mock_data = [
            {"state": "created", "status": "pending"},
            {"state": "created", "status": "pending"},
            {"state": "completed", "status": "success"},
        ]
        pending_request_mock = requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/jobs/c924d233-ddeb-8877-1234-fedd6a9bb070/pending",
            text=lambda _x, _y: json.dumps(pending_request_mock_data.pop(0)),
        )

        patch_command_args_and_params(
            mocker,
            "bloxone-td-dossier-lookup-get",
            {
                "indicator_type": "ip",
                "value": "11.22.33.44",
                "sources": "urlhaus,atp,geo",
            },
        )
        # first time the command is running (creating the job + one poll)
        main()
        polling_args = mock_results.call_args[0][0]["PollingArgs"]
        assert mock_results.call_count == 1
        assert isinstance(mock_results.call_args[0][0]["HumanReadable"], str)
        assert polling_args["job_id"] == job_id
        assert polling_args["timeout"] == 590
        assert pending_request_mock.call_count == 1

        patch_command_args_and_params(mocker, "bloxone-td-dossier-lookup-get", polling_args)

        # second time the command is running (second poll)
        main()
        polling_args = mock_results.call_args[0][0]["PollingArgs"]
        assert mock_results.call_count == 2
        assert mock_results.call_args[0][0].get("HumanReadable") is None
        assert polling_args["job_id"] == job_id
        assert polling_args["timeout"] == 580
        assert pending_request_mock.call_count == 2

        # third time the command is running (third poll + get results)
        main()
        assert "PollingArgs" not in mock_results.call_args[0][0]
        assert mock_results.call_count == 3
        assert mock_results.call_args[0][0]["HumanReadable"]
        assert pending_request_mock.call_count == 3

        assert create_job_request_mock.called_once
        assert results_request_mock.called_once

    def test_command_test_module_401(self, requests_mock, mocker, mock_results):
        patch_command_args_and_params(mocker, "test-module", {})
        requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/sources",
            status_code=401,
            text="{}",
        )
        with pytest.raises(SystemExit):
            main()

        assert mock_results.call_args[0][0]["Type"] == 4
        assert "an error occurred while executing command test-module" in mock_results.call_args[0][0]["Contents"]
        assert (
            "Error in API call [401] - Encountered error while trying to get information from Infoblox Cloud: "
            "Invalid Service API Key configured." in mock_results.call_args[0][0]["Contents"]
        )

    def test_command_test_module(self, requests_mock, mocker, mock_results):
        patch_command_args_and_params(mocker, "test-module", {})
        request_call = requests_mock.get(f"{BASE_URL}/tide/api/services/intel/lookup/sources", text="{}")
        main()

        assert request_call.called_once
        assert mock_results.call_args[0][0] == "ok"

    def test_command_test_module_with_is_fetch(self, blox_client, requests_mock, mocker):
        """Test command_test_module function with isFetch parameter"""
        # Mock the dossier_source_list API call
        requests_mock.get(f"{BASE_URL}/tide/api/services/intel/lookup/sources", text="{}")

        # Test case 1: isFetch is False (default behavior)
        mock_params = mocker.patch.object(demisto, "params", return_value={"isFetch": False})
        mock_fetch_incidents = mocker.patch("InfobloxBloxOneThreatDefense.fetch_incidents")

        result = command_test_module(blox_client)

        assert result == "ok"
        mock_fetch_incidents.assert_not_called()

        # Test case 2: isFetch is True (should call fetch_incidents with is_test=True)
        mock_params.return_value = {"isFetch": True, "max_fetch": "10", "soc_insight_status": "Active"}

        # Mock the insights API call for fetch_incidents
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json={"insightList": []})

        result = command_test_module(blox_client)

        assert result == "ok"
        mock_fetch_incidents.assert_called_once_with(blox_client, mock_params.return_value, is_test=True)

    def test_command_test_module_with_fetch_validation_error(self, blox_client, requests_mock, mocker):
        """Test command_test_module when fetch_incidents raises validation error"""
        # Mock the dossier_source_list API call
        requests_mock.get(f"{BASE_URL}/tide/api/services/intel/lookup/sources", text="{}")

        # Mock params with invalid max_fetch to trigger validation error
        mocker.patch.object(
            demisto,
            "params",
            return_value={
                "isFetch": True,
                "max_fetch": "300",  # Invalid - exceeds 200
            },
        )

        # Mock the insights API call
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json={"insightList": []})
        with pytest.raises(ValueError, match="Invalid Max Fetch: 300"):
            command_test_module(blox_client)

    def test_not_implemented_command(self, mocker):
        patch_command_args_and_params(mocker, "not-implemented-command", {})
        with pytest.raises(SystemExit):
            main()


class TestBloxOneTDClient:
    def test_http_request_success(self, blox_client, requests_mock):
        """Test successful HTTP request with JSON response."""
        # Mock response
        mock_response = {"status": "success", "data": [1, 2, 3]}
        requests_mock.get(f"{BASE_URL}/test/endpoint", json=mock_response, status_code=200)

        # Call the method
        response = blox_client.http_request("GET", "/test/endpoint", params={"key": "value"})

        # Assertions
        assert response == mock_response
        assert requests_mock.last_request.method == "GET"
        assert requests_mock.last_request.path == "/test/endpoint"
        assert requests_mock.last_request.qs == {"key": ["value"]}

    def test_http_request_invalid_json(self, blox_client, requests_mock):
        """Test handling of non-JSON response."""
        # Mock non-JSON response
        requests_mock.get(f"{BASE_URL}/test/endpoint", text="Not a JSON response", status_code=200)

        # Call the method and expect an exception
        with pytest.raises(DemistoException) as excinfo:
            blox_client.http_request("GET", "/test/endpoint")

        # Assert the error message is as expected
        assert "Failed to parse json object from response" in str(excinfo.value)

    @pytest.mark.parametrize(
        "status_code, expected_error_msg",
        [
            (400, "Invalid argument value while trying to get information from Infoblox Cloud"),
            (401, "Invalid Service API Key configured"),
            (404, "No record found for given argument(s): Not Found"),
            (403, "Test connectivity failed. Please provide valid input parameters"),
            (521, "Test connectivity failed. Please provide valid input parameters"),
        ],
    )
    def test_http_request_error_status_codes(self, blox_client, requests_mock, status_code, expected_error_msg):
        """Test error handling for different HTTP status codes."""
        # Mock error response
        error_response = {"detail": "Detailed error message"}
        requests_mock.get(f"{BASE_URL}/test/endpoint", json=error_response, status_code=status_code)

        # Call the method and expect an exception
        with pytest.raises(DemistoException) as excinfo:
            blox_client.http_request("GET", "/test/endpoint")

        # Assert the error message contains the expected text
        assert expected_error_msg in str(excinfo.value)
        assert str(status_code) in str(excinfo.value)

    def test_http_request_with_json_data(self, blox_client, requests_mock):
        """Test HTTP request with JSON data in the body."""
        # Mock response
        test_data = {"key": "value", "nested": {"a": 1}}
        requests_mock.post(f"{BASE_URL}/test/endpoint", json={"status": "success"}, status_code=200)

        # Call the method
        response = blox_client.http_request("POST", "/test/endpoint", json_data=test_data)

        # Assertions
        assert response == {"status": "success"}
        assert requests_mock.last_request.method == "POST"
        assert requests_mock.last_request.json() == test_data

    def test_http_request_timeout_and_retry(self, blox_client, requests_mock, mocker):
        """Test timeout and retry behavior."""
        # Mock is_time_sensitive to control retry behavior
        is_time_sensitive_mock = mocker.patch(
            "InfobloxBloxOneThreatDefense.is_time_sensitive",
            side_effect=lambda: False,  # Always return False for this test
        )

        # Mock response
        requests_mock.get(f"{BASE_URL}/test/endpoint", json={"status": "success"})

        # Call the method
        response = blox_client.http_request("GET", "/test/endpoint")

        # Assert the request was made
        assert requests_mock.last_request is not None
        assert response == {"status": "success"}
        is_time_sensitive_mock.assert_called()

    def test_dossier_source_list(self, blox_client, requests_mock):
        requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/sources",
            text=load_json_file("bloxone-td-dossier-source-list"),
        )
        assert blox_client.dossier_source_list() == [
            "dns",
            "geo",
            "ptr",
            "whois",
            "ssl_cert",
            "urlhaus",
        ]
        assert "rlabs" not in blox_client.dossier_source_list()

    def test_lookalike_domain_list_with_filter(self, blox_client, requests_mock):
        lookalike_request_mock = requests_mock.get(
            f"{BASE_URL}/api/tdlad/v1/lookalike_domains",
            text=load_json_file("bloxone-td-lookalike-domain-list"),
        )
        blox_client.lookalike_domain_list(user_filter="test-filter")
        assert lookalike_request_mock.request_history[0].qs["_filter"][0] == "test-filter"

    def test_lookalike_domain_list_with_target_domain(self, blox_client, requests_mock):
        lookalike_request_mock = requests_mock.get(
            f"{BASE_URL}/api/tdlad/v1/lookalike_domains",
            text=load_json_file("bloxone-td-lookalike-domain-list"),
        )
        blox_client.lookalike_domain_list(target_domain="target.domain")
        assert lookalike_request_mock.request_history[0].qs["_filter"][0] == 'target_domain=="target.domain"'

    def test_lookalike_domain_list_with_detected_at(self, blox_client, requests_mock):
        lookalike_request_mock = requests_mock.get(
            f"{BASE_URL}/api/tdlad/v1/lookalike_domains",
            text=load_json_file("bloxone-td-lookalike-domain-list"),
        )
        blox_client.lookalike_domain_list(detected_at="2023-02-21T00:00:00Z")
        assert 'detected_at>="2023-02-21T00:00:00Z"'.lower() == lookalike_request_mock.request_history[0].qs["_filter"][0]

    def test_dossier_lookup_get_create(self, blox_client, requests_mock):
        lookup_get_create_request_mock = requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/indicator/ip",
            text=load_json_file("bloxone-td-dossier-lookup-get_create-job"),
        )
        job_id = blox_client.dossier_lookup_get_create(indicator_type="ip", value="11.22.33.44")
        assert "11.22.33.44" in lookup_get_create_request_mock.request_history[0].qs["value"]
        assert job_id == "c924d233-ddeb-8877-1234-fedd6a9bb070"

    def test_dossier_lookup_get_is_done_check_when_not_done(self, blox_client, requests_mock):
        requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/jobs/c924d233-ddeb-8877-1234-fedd6a9bb070/pending",
            text=json.dumps({"state": "created", "status": "pending"}),
        )
        is_done = blox_client.dossier_lookup_get_is_done("c924d233-ddeb-8877-1234-fedd6a9bb070")
        assert is_done is False

    def test_dossier_lookup_get_is_done_check_when_job_failed(self, blox_client, requests_mock):
        requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/jobs/c924d233-ddeb-8877-1234-fedd6a9bb070/pending",
            text=json.dumps({"state": "completed", "status": "error"}),
        )
        with pytest.raises(DemistoException):
            blox_client.dossier_lookup_get_is_done("c924d233-ddeb-8877-1234-fedd6a9bb070")

    def test_dossier_lookup_get_is_done_check_when_done(self, blox_client, requests_mock):
        requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/jobs/c924d233-ddeb-8877-1234-fedd6a9bb070/pending",
            text=json.dumps({"state": "completed", "status": "success"}),
        )
        is_done = blox_client.dossier_lookup_get_is_done("c924d233-ddeb-8877-1234-fedd6a9bb070")
        assert is_done is True

    def test_dossier_lookup_get_results(self, blox_client, requests_mock):
        dossier_lookup_get_results_request_mock = requests_mock.get(
            f"{BASE_URL}/tide/api/services/intel/lookup/jobs/c924d233-ddeb-8877-1234-fedd6a9bb070/results",
            text=load_json_file("bloxone-td-dossier-lookup-get_results"),
        )
        blox_client.dossier_lookup_get_results("c924d233-ddeb-8877-1234-fedd6a9bb070")
        assert dossier_lookup_get_results_request_mock.called_once


class TestUnitTests:
    def test_dossier_lookup_task_output(self):
        task_data = json.loads(load_json_file("bloxone-td-dossier-lookup-get_results"))["results"][0]
        expected_outputs = {
            "Source": "urlhaus",
            "Target": "11.22.33.44",
            "Task Id": "d4e24d99-1f98-4a1f-8434-cbf4c284c7d0",
            "Type": "ip",
        }
        assert dossier_lookup_task_output(task_data) == expected_outputs

    data_test_validate_and_format_lookalike_domain_list_args_with_multiple_filters = [
        {},
        {"filter": "filter", "target_domain": "target_domain"},
        {
            "filter": "filter",
            "target_domain": "target_domain",
            "detected_at": "detected_at",
        },
    ]

    @pytest.mark.parametrize(
        "args",
        data_test_validate_and_format_lookalike_domain_list_args_with_multiple_filters,
    )
    def test_validate_and_format_lookalike_domain_list_args_with_multiple_filters(self, args):
        with pytest.raises(DemistoException):
            validate_and_format_lookalike_domain_list_args(args)

    data_test_validate_and_format_lookalike_domain_list_args_with_a_single_filter = [
        {"filter": "filter"},
        {"target_domain": "target_domain"},
    ]

    @pytest.mark.parametrize(
        "args",
        data_test_validate_and_format_lookalike_domain_list_args_with_a_single_filter,
    )
    def test_validate_and_format_lookalike_domain_list_args_with_a_single_filter(self, args):
        assert validate_and_format_lookalike_domain_list_args(args) == args

    data_test_validate_and_format_lookalike_domain_list_args_with_detected_at_filter = [
        ("2023-02-20T00:00:00.000Z", "2023-02-20T00:00:00.000"),
        ("1 day", "2023-02-19T00:00:00.000"),
        ("1y", "2022-02-20T00:00:00.000"),
    ]

    @freeze_time("2023-02-20T00:00:00.000Z")
    @pytest.mark.parametrize(
        "detected_at, expected",
        data_test_validate_and_format_lookalike_domain_list_args_with_detected_at_filter,
    )
    def test_validate_and_format_lookalike_domain_list_args_with_detected_at_filter(self, detected_at, expected):
        out_args = validate_and_format_lookalike_domain_list_args({"detected_at": detected_at})
        assert out_args["detected_at"] == expected

    def test_validate_and_format_lookalike_domain_list_args_with_invalid_detected_at_filter(
        self,
    ):
        with pytest.raises(DemistoException):
            validate_and_format_lookalike_domain_list_args({"detected_at": "test"})

    def test_dossier_lookup_get_command_results(self):
        data = json.loads(load_json_file("bloxone-td-dossier-lookup-get_results"))
        command_results = dossier_lookup_get_command_results(data)
        assert command_results.outputs == data["results"]
        assert command_results.raw_response == data
        assert command_results.readable_output.count("11.22.33.44") == 4
        assert "\n|Task Id|Type|Target|Source|\n" in command_results.readable_output

    def test_dossier_lookup_get_schedule_polling_result_with_first_time_true(self):
        command_results = dossier_lookup_get_schedule_polling_result({"job_id": "1"}, first_time=True)
        assert command_results.readable_output

    def test_dossier_lookup_get_schedule_polling_result_without_first_time(self):
        command_results = dossier_lookup_get_schedule_polling_result({"job_id": "1"})
        assert command_results.readable_output is None

    def test_dossier_lookup_get_schedule_polling_result_polling_args_default(self):
        command_results = dossier_lookup_get_schedule_polling_result({"job_id": "1"})
        assert command_results.scheduled_command._args["timeout"] == 590
        assert command_results.scheduled_command._command == "bloxone-td-dossier-lookup-get"

    def test_dossier_lookup_get_schedule_polling_result_polling_args(self):
        command_results = dossier_lookup_get_schedule_polling_result({"job_id": "1", "interval_in_seconds": 30, "timeout": 300})
        assert command_results.scheduled_command._args["timeout"] == 270
        assert int(command_results.scheduled_command._next_run) == 30
        assert int(command_results.scheduled_command._timeout) == 300
        assert command_results.scheduled_command._command == "bloxone-td-dossier-lookup-get"


class TestIpCommand:
    @patch("InfobloxBloxOneThreatDefense.return_warning")
    def test_ip_command_success(self, mock_return_warning, blox_client, requests_mock, capfd):
        success_ip_address = "0.0.0.1"
        not_found_ip_address = "0001:0000:0000:0000:0000:0000:0000:0000"
        invalid_ip_address = "0.0.0.256"
        list_of_ip_addresses = ", ".join([success_ip_address, not_found_ip_address, invalid_ip_address])
        address_response = util_load_json("enrichment_ip_address_response.json")
        threat_response = util_load_json("enrichment_ip_threat_response.json")
        output = util_load_json("ip_command_context.json")
        ip_hr = util_load_text_data("ip_command_success_hr.md")
        ip_indicator = util_load_json("ip_command_indicator.json")

        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?ip={success_ip_address}&rlimit=1", json=threat_response, status_code=200
        )
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/ipam/address?_filter=address=='{success_ip_address}'&_limit=1",
            json=address_response,
            status_code=200,
        )

        requests_mock.get(f"{BASE_URL}/tide/api/data/threats?ip={not_found_ip_address}&rlimit=1", json={}, status_code=200)
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/ipam/address?_filter=address=='{not_found_ip_address}'&_limit=1", json={}, status_code=200
        )

        capfd.disabled()
        command_output = ip_command(blox_client, args={"ip": list_of_ip_addresses})

        # Ensure return_warning is called with the expected message
        mock_return_warning.assert_has_calls(
            [
                call(f"The following IP Addresses were found invalid: {invalid_ip_address}", exit=False),
                call(MESSAGES["NO_INFO_FOUND"].format("threat and address", "IP", not_found_ip_address)),
            ]
        )

        # Verify command outputs
        assert output == command_output[0].outputs
        assert command_output[0].raw_response == {"threat_data": threat_response, "address_data": address_response}
        assert ip_hr == command_output[0].readable_output
        assert command_output[0].outputs_key_field == "ip"
        assert OUTPUT_PREFIX["IP"] == command_output[0].outputs_prefix
        assert ip_indicator == command_output[0].indicator.to_context()

    @pytest.mark.parametrize("threat_level,expected_reputation", [(100, 3), (80, 3), (30, 2), (10, 1), (0, 0)])
    def test_ip_command_all_threat(self, blox_client, requests_mock, threat_level, expected_reputation):
        success_ip_address = "0.0.0.1"
        address_response = util_load_json("enrichment_ip_address_response.json")
        threat_response = util_load_json("enrichment_ip_threat_response.json")
        ip_indicator = util_load_json("ip_command_indicator.json")
        if threat_level < 80:
            del ip_indicator[list(ip_indicator.keys())[0]]["Malicious"]
        ip_indicator[list(ip_indicator.keys())[1]]["Score"] = expected_reputation

        threat_response["threat"][0]["threat_level"] = threat_level
        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?ip={success_ip_address}&rlimit=1", json=threat_response, status_code=200
        )
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/ipam/address?_filter=address=='{success_ip_address}'&_limit=1",
            json=address_response,
            status_code=200,
        )

        command_output = ip_command(blox_client, args={"ip": success_ip_address})

        # Verify indicator score
        assert ip_indicator == command_output[0].indicator.to_context()

    def test_ip_command_empty_input(self, blox_client):
        """Test command behavior with empty input"""
        with pytest.raises(ValueError, match=MESSAGES["REQUIRED_ARGUMENT"].format("ip")):
            ip_command(blox_client, args={"ip": ",,,"})

    @patch("InfobloxBloxOneThreatDefense.return_warning")
    def test_ip_command_invalid_input(self, mock_return_warning, blox_client):
        """Test command behavior with invalid input"""
        try:
            ip_command(blox_client, args={"ip": ",123,,"})
        except Exception:
            pass
        mock_return_warning.assert_has_calls(
            [
                call(MESSAGES["INVALID_IP_ADDRESS"].format("123"), exit=True),
            ]
        )


class TestUrlCommand:
    @patch("InfobloxBloxOneThreatDefense.return_warning")
    def test_url_command_success(self, mock_return_warning, blox_client, requests_mock, capfd):
        url = "https://test.com"
        not_found_url = "https://notfound.com"
        list_of_urls = ", ".join([url, not_found_url])
        threat_response = util_load_json("enrichment_url_threat_response.json")
        output = util_load_json("url_command_context.json")
        url_hr = util_load_text_data("url_command_success_hr.md")
        url_indicator = util_load_json("url_command_indicator.json")

        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?text_search={url}&type=url&rlimit=1", json=threat_response, status_code=200
        )

        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?text_search={not_found_url}&type=url&rlimit=1", json={}, status_code=200
        )

        capfd.disabled()
        command_output = url_command(blox_client, args={"url": list_of_urls})

        # Ensure return_warning is called with the expected message
        mock_return_warning.assert_has_calls(
            [
                call(MESSAGES["NO_INFO_FOUND"].format("threat", "URL", not_found_url)),
            ]
        )

        # Verify command outputs
        assert output == command_output[0].outputs
        assert command_output[0].raw_response == {"threat_data": threat_response}
        assert url_hr == command_output[0].readable_output
        assert command_output[0].outputs_key_field == "url"
        assert OUTPUT_PREFIX["URL"] == command_output[0].outputs_prefix
        assert url_indicator == command_output[0].indicator.to_context()

    @pytest.mark.parametrize("threat_level,expected_reputation", [(100, 3), (80, 3), (30, 2), (10, 1), (0, 0)])
    def test_url_command_all_threat(self, blox_client, requests_mock, threat_level, expected_reputation):
        success_url_address = "https://test.com"
        threat_response = util_load_json("enrichment_url_threat_response.json")
        url_indicator = util_load_json("url_command_indicator.json")
        if threat_level < 80:
            del url_indicator[list(url_indicator.keys())[0]]["Malicious"]
        url_indicator[list(url_indicator.keys())[1]]["Score"] = expected_reputation

        threat_response["threat"][0]["threat_level"] = threat_level
        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?text_search={success_url_address}&rlimit=1", json=threat_response, status_code=200
        )

        command_output = url_command(blox_client, args={"url": success_url_address})

        # Verify indicator score
        assert url_indicator == command_output[0].indicator.to_context()

    def test_url_command_invalid_args(self, blox_client, capfd):
        capfd.disabled()
        with pytest.raises(ValueError) as error_msg:
            url_command(blox_client, args={"url": ",,,"})

        assert str(error_msg.value) == MESSAGES["REQUIRED_ARGUMENT"].format("url")


class TestFetchIncidents:
    """Test cases for the fetch_incidents function"""

    @pytest.fixture
    def mock_demisto_methods(self, mocker):
        """Mock demisto methods used by fetch_incidents"""
        mock_get_last_run = mocker.patch.object(demisto, "getLastRun")
        mock_set_last_run = mocker.patch.object(demisto, "setLastRun")
        mock_incidents = mocker.patch.object(demisto, "incidents")
        return {"getLastRun": mock_get_last_run, "setLastRun": mock_set_last_run, "incidents": mock_incidents}

    def test_fetch_incidents_first_run_no_last_run(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents when no previous last_run exists (first run)"""
        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list"))

        # Mock no previous last run
        mock_demisto_methods["getLastRun"].return_value = None

        params = {
            "max_fetch": "10",
            "soc_insight_status": "Active",
            "soc_insight_priority_level": "HIGH",
            "soc_insight_threat_type": "Malware",
        }

        fetch_incidents(blox_client, params)

        # Verify API was called with correct parameters
        assert requests_mock.call_count == 1
        request = requests_mock.request_history[0]
        assert request.qs["status"] == ["active"]
        assert request.qs["priority"] == ["high"]
        assert request.qs["threat_type"] == ["malware"]

        # Verify incidents were created
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 3

        # Verify incident structure
        incident = incidents[0]
        assert "insightId" in incident["rawJSON"]
        assert incident["severity"] == 3  # HIGH priority maps to severity 3

        # Verify last run was set
        mock_demisto_methods["setLastRun"].assert_called_once()
        last_run_call = mock_demisto_methods["setLastRun"].call_args[0][0]
        assert "soc_insight_ids" in last_run_call
        assert "insight-001" in last_run_call["soc_insight_ids"]
        assert "insight-002" in last_run_call["soc_insight_ids"]
        assert "insight-003" in last_run_call["soc_insight_ids"]

    def test_fetch_incidents_with_existing_last_run(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents with existing last_run data"""
        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list"))

        # Mock existing last run with one insight already processed
        existing_last_run = {"soc_insight_ids": ["insight-001"]}
        mock_demisto_methods["getLastRun"].return_value = existing_last_run

        params = {"max_fetch": "10"}

        fetch_incidents(blox_client, params)

        # Verify only new incidents were created (insight-002 and insight-003)
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 2

        # Verify the skipped insight is not in the incidents
        incident_data = [json.loads(inc["rawJSON"]) for inc in incidents]
        soc_insight_ids = [data["insightId"] for data in incident_data]
        assert "insight-001" not in soc_insight_ids
        assert "insight-002" in soc_insight_ids
        assert "insight-003" in soc_insight_ids

    def test_fetch_incidents_max_fetch_limit(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents respects max_fetch limit"""
        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list"))

        mock_demisto_methods["getLastRun"].return_value = None

        params = {"max_fetch": "2"}  # Limit to 2 incidents

        fetch_incidents(blox_client, params)

        # Verify only 2 incidents were created despite 3 available
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 2

        # Verify last_run only contains the processed insights
        last_run_call = mock_demisto_methods["setLastRun"].call_args[0][0]
        assert len(last_run_call["soc_insight_ids"]) == 2

    def test_fetch_incidents_with_max_fetch_less_than_1(self, blox_client, requests_mock):
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json={"insightList": []})

        with pytest.raises(ValueError, match="Invalid Max Fetch: -1"):
            fetch_incidents(blox_client, {"max_fetch": -1})

    def test_fetch_incidents_empty_response(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents when API returns empty insight list"""
        # Mock empty API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json={"insightList": []})

        mock_demisto_methods["getLastRun"].return_value = None

        params = {"max_fetch": "10"}

        fetch_incidents(blox_client, params)

        # Verify no incidents were created
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 0

        # Verify empty last_run was set
        last_run_call = mock_demisto_methods["setLastRun"].call_args[0][0]
        assert "soc_insight_ids" not in last_run_call

    def test_fetch_incidents_empty_response_with_last_run(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents when API returns empty insight list"""
        # Mock empty API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json={"insightList": []})

        mock_demisto_methods["getLastRun"].return_value = {"soc_insight_ids": ["insight-001"]}

        params = {"max_fetch": "10"}

        fetch_incidents(blox_client, params)

        # Verify no incidents were created
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 0

        # Verify empty last_run was set
        last_run_call = mock_demisto_methods["setLastRun"].call_args[0][0]
        assert last_run_call["soc_insight_ids"] == ["insight-001"]

    def test_fetch_incidents_invalid_insights_skipped(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents skips insights with missing required fields"""
        # Mock API response with invalid insights
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list-invalid"))

        mock_demisto_methods["getLastRun"].return_value = None

        params = {"max_fetch": "10"}

        fetch_incidents(blox_client, params)

        # Verify only 1 incident was created (1 insight are invalid)
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 1

        # Verify empty last_run was set
        last_run_call = mock_demisto_methods["setLastRun"].call_args[0][0]
        assert last_run_call["soc_insight_ids"] == ["insight-004"]

    @pytest.mark.parametrize(
        "priority_text,expected_severity",
        [
            ("INFO", 1),
            ("MEDIUM", 2),
            ("HIGH", 3),
            ("CRITICAL", 4),
            ("UNKNOWN", 1),  # Default severity for unmapped priority
            (None, 1),  # Default severity for missing priority
        ],
    )
    def test_fetch_incidents_severity_mapping(
        self, blox_client, requests_mock, mock_demisto_methods, priority_text, expected_severity
    ):
        """Test fetch_incidents correctly maps priority to severity"""
        # Create custom response with specific priority
        insight_data = {
            "insightList": [
                {
                    "insightId": "test-insight",
                    "dateChanged": "2023-12-01T10:00:00Z",
                    "priorityText": priority_text,
                    "title": "Test Insight",
                    "description": "Test description",
                }
            ]
        }

        requests_mock.get(f"{BASE_URL}/api/v1/insights", json=insight_data)

        mock_demisto_methods["getLastRun"].return_value = None

        params = {"max_fetch": "10"}

        fetch_incidents(blox_client, params)

        # Verify correct severity mapping
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 1
        assert incidents[0]["severity"] == expected_severity

    def test_fetch_incidents_default_max_fetch(self, blox_client, requests_mock, mock_demisto_methods):
        """Test fetch_incidents uses default max_fetch of 50 when not specified"""
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list"))

        mock_demisto_methods["getLastRun"].return_value = None

        # Don't specify max_fetch parameter
        params = {}

        fetch_incidents(blox_client, params)

        # Verify function completes successfully (default max_fetch is used internally)
        mock_demisto_methods["incidents"].assert_called_once()
        incidents = mock_demisto_methods["incidents"].call_args[0][0]
        assert len(incidents) == 3  # All 3 test insights should be processed

    def test_fetch_incidents_through_main_function(self, requests_mock, mocker):
        """Test of fetch_incidents through main() function"""
        # Mock demisto methods
        mock_incidents = mocker.patch.object(demisto, "incidents")

        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list"))

        # Mock demisto command and params
        patch_command_args_and_params(mocker, "fetch-incidents", {})
        mocker.patch.object(
            demisto,
            "params",
            return_value={"credentials": {"password": "test-api-key"}, "max_fetch": "201", "soc_insight_status": "open"},
        )

        # Run main function
        main()

        # Verify fetch_incidents was executed successfully
        mock_incidents.assert_called_once()
        incidents = mock_incidents.call_args[0][0]
        assert len(incidents) == 3

    @patch("InfobloxBloxOneThreatDefense.return_results")
    def test_test_module_through_main_function_for_insight_fetch(self, mock_return, requests_mock, mocker):
        """Test of test_module through main() function for insight fetch"""

        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", text=load_json_file("soc-insights-list"))

        # Mock demisto command and params
        patch_command_args_and_params(mocker, "test-module", {})
        mocker.patch.object(
            demisto,
            "params",
            return_value={
                "credentials": {"password": "test-api-key"},
                "isFetch": True,
                "max_fetch": "10",
                "soc_insight_status": "open",
            },
        )

        # Run main function
        main()

        # Verify fetch_incidents was executed successfully
        assert mock_return.call_args.args[0] == "ok"

    @pytest.mark.parametrize(
        "max_fetch,expected_error",
        [
            ("0", ERRORS["INVALID_MAX_FETCH"].format("0")),
            ("201", ERRORS["INVALID_MAX_FETCH"].format("201")),
        ],
    )
    def test_fetch_invalid_max_fetch(self, blox_client, max_fetch, expected_error):
        """Test command behavior with error input"""
        with pytest.raises(ValueError, match=expected_error):
            fetch_incidents(blox_client, params={"max_fetch": max_fetch}, is_test=True)


class TestFetchDnsSecurityEvents:
    """Test cases for the fetch_dns_security_events function"""

    @pytest.fixture
    def dns_events_response(self):
        """Load DNS security events test data"""
        return util_load_json("dns-security-event-response-success.json")

    def test_fetch_dns_security_events_first_run_no_last_run(self, blox_client, requests_mock, dns_events_response):
        """Test fetch_dns_security_events when no previous last_run exists (first run)"""
        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": dns_events_response})

        params = {"first_fetch": "24 hours", "dns_events_queried_name": "example.com", "dns_events_threat_level": "HIGH,MEDIUM"}
        last_run = {}
        max_fetch = 50

        incidents, updated_last_run = fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Verify API was called with correct parameters
        assert requests_mock.call_count == 1
        request = requests_mock.request_history[0]
        assert "_limit" in request.qs
        assert request.qs["_limit"] == ["50"]
        assert "t0" in request.qs  # Should have start time
        assert "t1" in request.qs  # Should have end time
        assert request.qs["qname"] == ["example.com"]
        assert request.qs["threat_level"] == ["high,medium"]

        # Verify incident was created
        assert len(incidents) == 1
        incident = incidents[0]
        assert "Infoblox DNS Security Event - Data Exfiltration" in incident["name"]
        assert incident["severity"] == 3  # HIGH severity maps to 3
        assert "occurred" in incident
        assert "rawJSON" in incident

        # Verify last run was updated
        assert "dns_events_last_fetch" in updated_last_run
        assert "dns_events_ids" in updated_last_run
        assert len(updated_last_run["dns_events_ids"]) == 1

    def test_fetch_dns_security_events_with_existing_last_run(self, blox_client, requests_mock, dns_events_response):
        """Test fetch_dns_security_events with existing last_run data"""
        # Mock API response with same event
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": dns_events_response})

        # Create composite key from the test data event
        event = dns_events_response[0]
        event_time = event.get("event_time")
        qname_truncated = event.get("qname", "")[:20]
        composite_key = "|".join([event_time, qname_truncated, event.get("device", ""), event.get("feed_name", "")])

        # Mock existing last run with the event already processed
        existing_last_run = {"dns_events_last_fetch": "2025-09-17T07:45:30.000Z", "dns_events_ids": [composite_key]}

        params = {"first_fetch": "24 hours"}
        max_fetch = 50

        incidents, updated_last_run = fetch_dns_security_events(blox_client, params, existing_last_run, max_fetch)

        # Verify no incidents were created (event was already processed)
        assert len(incidents) == 0

        # Verify last run was updated
        assert updated_last_run["dns_events_last_fetch"] == event_time
        assert composite_key in updated_last_run["dns_events_ids"]

    def test_fetch_dns_security_events_max_fetch_limit(self, blox_client, requests_mock):
        """Test fetch_dns_security_events respects max_fetch limit"""
        # Create multiple events
        multiple_events = []
        base_event = util_load_json("dns-security-event-response-success.json")[0]
        for i in range(5):
            event = base_event.copy()
            event["event_time"] = f"2025-09-18T07:45:3{i}.000Z"
            event["qname"] = f"test{i}.example.com"
            multiple_events.append(event)

        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": multiple_events})

        params = {"first_fetch": "24 hours"}
        last_run = {}
        max_fetch = 5  # Limit to 5 events

        incidents, _ = fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Verify API was called with correct limit
        request = requests_mock.request_history[0]
        assert request.qs["_limit"] == ["5"]

        # Note: The function doesn't actually limit incidents in processing,
        # it relies on API _limit parameter
        assert len(incidents) == 5

    def test_fetch_dns_security_events_with_filters(self, blox_client, requests_mock, dns_events_response):
        """Test fetch_dns_security_events with various filter parameters"""
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": dns_events_response})

        params = {
            "first_fetch": "24 hours",
            "dns_events_queried_name": "example.com,test.com",
            "dns_events_policy_name": "Policy1,Policy2",
            "dns_events_threat_level": "HIGH,MEDIUM",
            "dns_events_threat_class": "Malware,Phishing",
            "dns_events_threat_family": "Family1,Family2",
            "dns_events_threat_indicator": "indicator1,indicator2",
            "dns_events_policy_action": "Block,Log",
            "dns_events_feed_name": "Feed1,Feed2",
            "dns_events_network": "Network1,Network2",
        }
        last_run = {}
        max_fetch = 50

        fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Verify API was called with all filter parameters
        request = requests_mock.request_history[0]
        assert request.qs["qname"] == ["example.com,test.com"]
        assert request.qs["policy_name"] == ["policy1,policy2"]
        assert request.qs["threat_level"] == ["high,medium"]
        assert request.qs["threat_class"] == ["malware,phishing"]
        assert request.qs["threat_family"] == ["family1,family2"]
        assert request.qs["threat_indicator"] == ["indicator1,indicator2"]
        assert request.qs["policy_action"] == ["block,log"]
        assert request.qs["feed_name"] == ["feed1,feed2"]
        assert request.qs["network"] == ["network1,network2"]

    def test_fetch_dns_security_events_empty_response(self, blox_client, requests_mock):
        """Test fetch_dns_security_events when API returns empty result"""
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": []})

        params = {"first_fetch": "24 hours"}
        last_run = {}
        max_fetch = 50

        incidents, updated_last_run = fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Verify no incidents were created
        assert len(incidents) == 0

        # Verify last_run is returned unchanged since no events
        assert updated_last_run == last_run

    def test_fetch_dns_security_events_test_mode(self, blox_client, requests_mock, dns_events_response):
        """Test fetch_dns_security_events in test mode"""
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": dns_events_response})

        params = {"first_fetch": "24 hours"}
        last_run = {}
        max_fetch = 50
        is_test = True

        incidents, updated_last_run = fetch_dns_security_events(blox_client, params, last_run, max_fetch, is_test)

        # In test mode, should return empty incidents and last_run
        assert incidents == []
        assert updated_last_run == {}

    @pytest.mark.parametrize(
        "severity, expected_severity_level",
        [
            ("HIGH", 3),
            ("MEDIUM", 2),
            ("INFO", 1),
            ("CRITICAL", 4),
            ("UNKNOWN", 1),  # Default for unmapped severity
            (None, 1),  # Default for missing severity
        ],
    )
    def test_fetch_dns_security_events_severity_mapping(self, blox_client, requests_mock, severity, expected_severity_level):
        """Test fetch_dns_security_events correctly maps severity to incident severity"""
        base_event = util_load_json("dns-security-event-response-success.json")[0]
        if severity is not None:
            base_event["severity"] = severity
        else:
            base_event.pop("severity", None)

        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": [base_event]})

        params = {"first_fetch": "24 hours"}
        last_run = {}
        max_fetch = 50

        incidents, _ = fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        assert len(incidents) == 1
        assert incidents[0]["severity"] == expected_severity_level

    def test_fetch_dns_security_events_response_format_variations(self, blox_client, requests_mock, dns_events_response):
        """Test fetch_dns_security_events handles different response formats"""
        # Test when response is directly a list (not wrapped in result key)
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json=dns_events_response)

        params = {"first_fetch": "24 hours"}
        last_run = {}
        max_fetch = 50

        incidents, _ = fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Should handle both response formats
        assert len(incidents) == 1

    def test_fetch_dns_security_events_time_handling(self, blox_client, requests_mock, dns_events_response, mocker):
        """Test fetch_dns_security_events properly handles time parameters"""
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": dns_events_response})

        # Mock datetime to control timestamp calculation
        mock_now = mocker.patch("InfobloxBloxOneThreatDefense.arg_to_datetime")
        mock_now.side_effect = lambda x: arg_to_datetime("2025-09-18T08:00:00.000Z") if x == "now" else arg_to_datetime(x)

        params = {"first_fetch": "1 day"}
        last_run = {"dns_events_last_fetch": "2025-09-17T08:00:00.000Z"}
        max_fetch = 50

        fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Verify time parameters were set correctly in API call
        request = requests_mock.request_history[0]
        assert "t0" in request.qs  # Start time from last fetch
        assert "t1" in request.qs  # End time (now)

    def test_fetch_dns_security_events_composite_key_generation(self, blox_client, requests_mock):
        """Test fetch_dns_security_events generates correct composite keys for deduplication"""
        # Create event with specific fields for key generation
        test_event = {
            "event_time": "2025-09-18T07:45:30.000Z",
            "qname": "test.example.com.with.very.long.domain.name.that.exceeds.twenty.characters",
            "device": "10.0.0.1",
            "feed_name": "Test Feed",
            "severity": "HIGH",
            "tclass": "Malware",
        }

        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": [test_event]})

        params = {"first_fetch": "24 hours"}
        last_run = {}
        max_fetch = 50

        _, updated_last_run = fetch_dns_security_events(blox_client, params, last_run, max_fetch)

        # Verify composite key format: event_time|qname_truncated|device|feed_name
        expected_composite_key = "2025-09-18T07:45:30.000Z|test.example.com.wit|10.0.0.1|Test Feed"
        assert expected_composite_key in updated_last_run["dns_events_ids"]

    def test_fetch_dns_security_events_integration_with_fetch_incidents(
        self, blox_client, requests_mock, dns_events_response, mocker
    ):
        """Test fetch_dns_security_events integration with main fetch_incidents function"""
        # Mock demisto methods
        mock_get_last_run = mocker.patch.object(demisto, "getLastRun", return_value={})
        mock_set_last_run = mocker.patch.object(demisto, "setLastRun")
        mock_incidents = mocker.patch.object(demisto, "incidents")

        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json={"result": dns_events_response})

        params = {"max_fetch": "50", "ingestion_type": "DNS Security Event", "first_fetch": "24 hours"}

        fetch_incidents(blox_client, params)

        # Verify demisto methods were called correctly
        mock_get_last_run.assert_called_once()
        mock_set_last_run.assert_called_once()
        mock_incidents.assert_called_once()

        # Verify incident was created
        incidents_call = mock_incidents.call_args[0][0]
        assert len(incidents_call) == 1
        assert incidents_call[0]["name"].startswith("Infoblox DNS Security Event")

    @patch("InfobloxBloxOneThreatDefense.return_results")
    def test_test_module_through_main_function_for_event_fetch(self, mock_return, requests_mock, mocker):
        """Test of test_module through main() function for DNS Security Events fetch"""

        # Mock API response
        requests_mock.get(f"{BASE_URL}/api/dnsdata/v2/dns_event", json=util_load_json("dns-security-event-response-success.json"))

        # Mock demisto command and params
        patch_command_args_and_params(mocker, "test-module", {})
        mocker.patch.object(
            demisto,
            "params",
            return_value={
                "credentials": {"password": "test-api-key"},
                "isFetch": True,
                "max_fetch": "10",
                "soc_insight_status": "open",
                "ingestion_type": "DNS Security Event",
            },
        )

        # Run main function
        main()

        # Verify fetch_incidents was executed successfully
        assert mock_return.call_args.args[0] == "ok"

    @pytest.mark.parametrize(
        "dns_events_threat_level,expected_error",
        [
            ("abc", MESSAGES["INVALID_DNS_EVENT_THREAT_LEVEL"].format("abc")),
            ("lower,high", MESSAGES["INVALID_DNS_EVENT_THREAT_LEVEL"].format("lower")),
        ],
    )
    def test_fetch_dns_security_events_error_input(self, blox_client, dns_events_threat_level, expected_error):
        """Test command behavior with error input"""
        with pytest.raises(ValueError, match=expected_error):
            fetch_dns_security_events(
                blox_client, params={"dns_events_threat_level": dns_events_threat_level}, last_run={}, max_fetch=50
            )


class TestMacEnrichCommand:
    def test_mac_enrich_command_success(self, blox_client, requests_mock):
        """Test successful MAC address enrichment with valid data"""
        test_mac = "00:00:00:00:00:01"

        # Load test data
        mac_response = util_load_json("enrichment_mac_address_response.json")
        mac_context = util_load_json("mac_command_context.json")
        mac_hr = util_load_text_data("mac_command_success_hr.md")

        # Mock API response
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/dhcp/lease?_filter=hardware=='{test_mac}'&_limit=1", json=mac_response, status_code=200
        )

        # Execute command
        command_result = mac_enrich_command(blox_client, args={"mac": test_mac})

        # Verify command outputs
        assert command_result.outputs_prefix == "InfobloxCloud.DHCPLease"
        assert command_result.outputs_key_field == "hardware"
        assert command_result.outputs == remove_empty_elements(mac_context)
        assert command_result.raw_response == mac_response
        assert command_result.readable_output == mac_hr

    @pytest.mark.parametrize("mac_address", ["00:00:00:00:00:00", "00-00-00-00-00-00", "0000.0000.0000", "000000000000"])
    def test_mac_enrich_command_valid_format(self, blox_client, requests_mock, mac_address):
        """Test successful MAC address enrichment with valid formats."""

        # Load test data
        mac_response = util_load_json("enrichment_mac_address_response.json")

        # Mock API response
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/dhcp/lease?_filter=hardware=='{mac_address}'&_limit=1", json=mac_response, status_code=200
        )

        # Execute command
        mac_enrich_command(blox_client, args={"mac": mac_address})

    @pytest.mark.parametrize(
        "mac,expected_error",
        [("", MESSAGES["REQUIRED_ARGUMENT"].format("mac")), ("123", MESSAGES["INVALID_VALUE"].format("123", "mac"))],
    )
    def test_mac_enrich_command_error_input(self, blox_client, mac, expected_error):
        """Test command behavior with error input"""
        with pytest.raises(ValueError, match=expected_error):
            mac_enrich_command(blox_client, args={"mac": mac})

    def test_mac_enrich_command_no_results(self, blox_client, requests_mock):
        """Test command behavior when no results are returned"""
        test_mac = "00:11:22:33:44:55"

        # Mock empty response
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/dhcp/lease?_filter=hardware=='{test_mac}'&_limit=1", json={"results": []}, status_code=200
        )

        command_result = mac_enrich_command(blox_client, args={"mac": test_mac})
        assert command_result.readable_output == MESSAGES["NO_INFO_FOUND"].format("DHCP lease", "MAC", test_mac)
        assert command_result.outputs is None

    def test_mac_enrich_command_options_parsing(self, blox_client, requests_mock):
        """Test command's options JSON parsing functionality"""
        test_mac = "00:00:00:00:00:01"

        # Create a modified response with valid options JSON
        options_response = deepcopy(util_load_json("enrichment_mac_address_response.json"))
        options_data = options_response["results"][0]
        options_data["options"] = '{"Options":[{"Code":"57","Value":"test"}]}'

        # Mock API response
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/dhcp/lease?_filter=hardware=='{test_mac}'&_limit=1", json=options_response, status_code=200
        )

        # Execute command
        mac_enrich_command(blox_client, args={"mac": test_mac})

        # Verify options were returned as a string
        clean_data = remove_empty_elements_for_hr(options_data)
        assert isinstance(clean_data.get("options"), str)
        assert '"Code":"57"' in clean_data.get("options")

    def test_mac_enrich_command_options_parsing_error(self, blox_client, requests_mock):
        """Test command's handling of invalid options JSON"""
        test_mac = "00:00:00:00:00:01"

        # Create a modified response with invalid options JSON
        invalid_options_response = deepcopy(util_load_json("enrichment_mac_address_response.json"))
        invalid_options_response["results"][0]["options"] = "{invalid json}"

        # Mock API response
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/dhcp/lease?_filter=hardware=='{test_mac}'&_limit=1",
            json=invalid_options_response,
            status_code=200,
        )

        # Execute command - should not raise exception for invalid JSON
        command_result = mac_enrich_command(blox_client, args={"mac": test_mac})

        # Verify command executed without error
        assert command_result.outputs_prefix == "InfobloxCloud.DHCPLease"
        assert command_result.outputs_key_field == "hardware"


class TestBlockUnblock:
    """Test cases for block_ip_command, unblock_ip_command, block_domain_command, unblock_domain_command and indicator_remove_command"""  # noqa: E501

    @pytest.mark.parametrize(
        "args,error_msg",
        [
            ({"ip": ""}, MESSAGES["REQUIRED_ARGUMENT"].format("ip")),
            ({"ip": "dummy", "custom_list_name": "test_name", "custom_list_type": "test_type"}, "Invalid IP or CIDR: dummy"),
            (
                {"ip": "0.0.0.0", "custom_list_name": "", "custom_list_type": "test_type"},
                MESSAGES["REQUIRED_ARGUMENT"].format("custom_list_name"),
            ),
            (
                {"ip": "0.0.0.1", "custom_list_type": "", "custom_list_name": "test_name"},
                MESSAGES["REQUIRED_ARGUMENT"].format("custom_list_type"),
            ),
            ({"ip": "0.0.0.0, 0"}, "Invalid IP or CIDR: 0"),
        ],
    )
    def test_block_ip_command_and_unblock_ip_command_when_empty_or_invalid_args_provided(self, blox_client, args, error_msg):
        """Test block_ip_command and unblock_ip_command when provided args are empty or invalid."""
        with pytest.raises(ValueError) as e:
            block_ip_command(blox_client, args)
        assert str(e.value) == error_msg

        with pytest.raises(ValueError) as e:
            unblock_ip_command(blox_client, args)
        assert str(e.value) == error_msg

    def test_block_ip_command_success(self, blox_client, requests_mock):
        """Test successful IP blocking"""
        # Load test data
        get_response = util_load_json("block-unblock-ip-command-response.json")
        readable_output = util_load_text_data("block-unblock-ip-command-readable.md")

        # Mock the three API calls that generic_named_list_method makes:

        # 1. Initial get_named_list call to get the list ID
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        # 2. update_named_list API call (POST to add items)
        requests_mock.post(
            f"{BASE_URL}/api/atcfw/v1/named_lists/{get_response['results']['id']}/items", json={"success": True}, status_code=200
        )

        # 3. Final get_named_list call to get updated results
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        result = block_ip_command(
            blox_client, {"ip": "0.0.0.0, 0.0.0.1", "custom_list_name": "Test Name", "custom_list_type": "test_type"}
        )

        assert result.readable_output == readable_output

    def test_unblock_ip_command_success(self, blox_client, requests_mock):
        """Test successful IP unblocking"""
        # Load test data
        get_response = util_load_json("block-unblock-ip-command-response.json")
        readable_output = util_load_text_data("block-unblock-ip-command-readable.md")

        # Mock the three API calls that generic_named_list_method makes for remove operation:

        # 1. Initial get_named_list call to get the list ID
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        # 2. remove_named_list_items API call (DELETE to remove items) - needs JSON response
        requests_mock.post(f"{BASE_URL}/api/atcfw/v1/named_lists/123456/items", json={"success": True}, status_code=200)

        # 3. Final get_named_list call to get updated results
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        result = unblock_ip_command(
            blox_client, {"ip": "0.0.0.0, 0.0.0.1", "custom_list_name": "Test Name", "custom_list_type": "test_type"}
        )

        assert result.readable_output == readable_output

    @pytest.mark.parametrize(
        "args,error_msg",
        [
            ({"domain": ""}, MESSAGES["REQUIRED_ARGUMENT"].format("domain")),
            (
                {"domain": "example.com", "custom_list_name": "", "custom_list_type": "test_type"},
                MESSAGES["REQUIRED_ARGUMENT"].format("custom_list_name"),
            ),
            (
                {"domain": "example.com", "custom_list_type": "", "custom_list_name": "test_name"},
                MESSAGES["REQUIRED_ARGUMENT"].format("custom_list_type"),
            ),
        ],
    )
    def test_block_domain_command_and_unblock_domain_command_when_empty_or_invalid_args_provided(
        self, blox_client, args, error_msg
    ):
        """Test block_domain_command and unblock_domain_command when provided args are empty or invalid."""
        with pytest.raises(ValueError) as e:
            block_domain_command(blox_client, args)
        assert str(e.value) == error_msg

        with pytest.raises(ValueError) as e:
            unblock_domain_command(blox_client, args)
        assert str(e.value) == error_msg

    def test_block_domain_command_success(self, blox_client, requests_mock):
        """Test successful domain blocking"""
        # Load test data
        get_response = util_load_json("block-unblock-domain-command-response.json")
        readable_output = util_load_text_data("block-unblock-domain-command-readable.md")

        # Mock the three API calls that generic_named_list_method makes:

        # 1. Initial get_named_list call to get the list ID
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        # 2. update_named_list API call (POST to add items)
        requests_mock.post(
            f"{BASE_URL}/api/atcfw/v1/named_lists/{get_response['results']['id']}/items", json={"success": True}, status_code=200
        )

        # 3. Final get_named_list call to get updated results
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        result = block_domain_command(
            blox_client, {"domain": "test.com, test.org", "custom_list_name": "Test Name", "custom_list_type": "test_type"}
        )

        assert result.readable_output == readable_output

    def test_unblock_domain_command_success(self, blox_client, requests_mock):
        """Test successful domain unblocking"""
        # Load test data
        get_response = util_load_json("block-unblock-domain-command-response.json")
        readable_output = util_load_text_data("block-unblock-domain-command-readable.md")

        # Mock the three API calls that generic_named_list_method makes for remove operation:

        # 1. Initial get_named_list call to get the list ID
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        # 2. remove_named_list_items API call (DELETE to remove items) - needs JSON response
        requests_mock.post(f"{BASE_URL}/api/atcfw/v1/named_lists/123456/items", json={"success": True}, status_code=200)

        # 3. Final get_named_list call to get updated results
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        result = unblock_domain_command(
            blox_client, {"domain": "test.com, test.org", "custom_list_name": "Test Name", "custom_list_type": "test_type"}
        )

        assert result.readable_output == readable_output

    @pytest.mark.parametrize(
        "args,error_msg",
        [
            ({"indicators": ""}, MESSAGES["REQUIRED_ARGUMENT"].format("indicators")),
            (
                {"indicators": "0.0.0.0", "custom_list_name": "", "custom_list_type": "test_type"},
                MESSAGES["REQUIRED_ARGUMENT"].format("custom_list_name"),
            ),
            (
                {"indicators": "0.0.0.1", "custom_list_type": "", "custom_list_name": "test_name"},
                MESSAGES["REQUIRED_ARGUMENT"].format("custom_list_type"),
            ),
        ],
    )
    def test_infobloxcloud_customlist_indicator_remove_when_empty_or_invalid_args_provided(self, blox_client, args, error_msg):
        """Test infobloxcloud_customlist_indicator_remove when provided args are empty or invalid."""
        with pytest.raises(ValueError) as e:
            infobloxcloud_customlist_indicator_remove(blox_client, args)
        assert str(e.value) == error_msg

    def test_infobloxcloud_customlist_indicator_remove_success(self, blox_client, requests_mock):
        """Test successful indicator removal"""
        get_response = util_load_json("infobloxcloud-customlist-indicator-remove-response.json")
        readable_output = util_load_text_data("infobloxcloud-customlist-indicator-remove-readable.md")

        # 1. Initial get_named_list call to get the list ID
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        # 2. update_named_list API call (POST to add items)
        requests_mock.delete(
            f"{BASE_URL}/api/atcfw/v1/named_lists/{get_response['results']['id']}/items", json={"success": True}, status_code=200
        )

        # 3. Final get_named_list call to get updated results
        requests_mock.get(f"{BASE_URL}/api/atcfw/v1/named_lists/0", json=get_response, status_code=200)

        result = infobloxcloud_customlist_indicator_remove(
            blox_client, {"indicators": "example.com", "custom_list_name": "Test Name", "custom_list_type": "test_type"}
        )

        assert result.readable_output == readable_output


class TestDomainCommand:
    @patch("InfobloxBloxOneThreatDefense.return_warning")
    def test_domain_command_success(self, mock_return_warning, blox_client, requests_mock, capfd, mocker):
        domain = "test.com"
        not_found_domain = "notfound.com"
        list_of_domains = ", ".join([domain, not_found_domain])
        threat_response = util_load_json("enrichment_domain_threat_response.json")
        address_response = util_load_json("enrichment_domain_address_response.json")
        output = util_load_json("domain_command_context.json")
        domain_hr = util_load_text_data("domain_command_success_hr.md")
        domain_indicator = util_load_json("domain_command_indicator.json")
        params = {"integrationReliability": DBotScoreReliability.B, "create_relationships": True}
        mocker.patch.object(demisto, "params", return_value=params)
        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?host={domain}&type=host&rlimit=1", json=threat_response, status_code=200
        )
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/ipam/host?_filter=name=='{domain}'&_limit=1",
            json=address_response,
            status_code=200,
        )

        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?host={not_found_domain}&type=host&rlimit=1", json={}, status_code=200
        )
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/ipam/host?_filter=name=='{not_found_domain}'&_limit=1", json={}, status_code=200
        )

        capfd.disabled()
        command_output = domain_command(blox_client, args={"domain": list_of_domains})

        # Ensure return_warning is called with the expected message
        mock_return_warning.assert_has_calls(
            [
                call(MESSAGES["NO_INFO_FOUND"].format("threat and address", "Domain", not_found_domain)),
            ]
        )

        # Verify command outputs
        assert output == command_output[0].outputs
        assert command_output[0].raw_response == {"threat_data": threat_response, "address_data": address_response}
        assert domain_hr == command_output[0].readable_output
        assert command_output[0].outputs_key_field == "domain"
        assert OUTPUT_PREFIX["Domain"] == command_output[0].outputs_prefix
        assert domain_indicator == command_output[0].indicator.to_context()

    @pytest.mark.parametrize("threat_level,expected_reputation", [(100, 3), (80, 3), (30, 2), (10, 1), (0, 0)])
    def test_domain_command_all_threat(self, blox_client, requests_mock, threat_level, expected_reputation, mocker):
        success_domain_address = "test.com"
        address_response = util_load_json("enrichment_domain_address_response.json")
        threat_response = util_load_json("enrichment_domain_threat_response.json")
        domain_indicator = util_load_json("domain_command_indicator.json")
        if threat_level < 80:
            del domain_indicator[list(domain_indicator.keys())[0]]["Malicious"]
        domain_indicator[list(domain_indicator.keys())[1]]["Score"] = expected_reputation

        threat_response["threat"][0]["threat_level"] = threat_level
        requests_mock.get(
            f"{BASE_URL}/tide/api/data/threats?host={success_domain_address}&type=host&rlimit=1",
            json=threat_response,
            status_code=200,
        )
        requests_mock.get(
            f"{BASE_URL}/api/ddi/v1/ipam/host?_filter=name=='{success_domain_address}'&_limit=1",
            json=address_response,
            status_code=200,
        )

        params = {"integrationReliability": DBotScoreReliability.B, "create_relationships": True}
        mocker.patch.object(demisto, "params", return_value=params)
        command_output = domain_command(blox_client, args={"domain": success_domain_address})

        # Verify indicator score
        assert domain_indicator == command_output[0].indicator.to_context()

    def test_domain_command_invalid_args(self, blox_client, capfd):
        capfd.disabled()
        with pytest.raises(ValueError) as error_msg:
            domain_command(blox_client, args={"domain": " "})

        assert str(error_msg.value) == MESSAGES["REQUIRED_ARGUMENT"].format("domain")


class TestListSOCInsights:
    """Tests for list_soc_insights command."""

    @pytest.fixture
    def return_data(self):
        """Returns test data for insights."""
        response = util_load_json("soc-insights-list.json")
        return response

    def test_list_soc_insights_with_no_filters(self, return_data, blox_client, requests_mock):
        """Test list_soc_insights command with no filters applied."""
        # Mock the soc_insights_list API call
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json=return_data, status_code=200)

        result = list_soc_insights_command(blox_client, {})

        assert result.outputs_prefix == "InfobloxCloud.SOCInsight"
        assert result.outputs_key_field == "insightId"
        assert len(result.outputs) == 3
        assert result.readable_output == util_load_text_data("soc-insights-list-readable.md")
        assert result.outputs == return_data.get("insightList")

    def test_list_soc_insights_with_filters(self, return_data, blox_client, requests_mock):
        """Test list_soc_insights command with filters applied."""
        args = {"status": "OPEN", "priority": "HIGH", "threat_type": "MALWARE"}

        # Mock the soc_insights_list API call
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json=return_data, status_code=200)

        list_soc_insights_command(blox_client, args)

        # Verify the parameters were passed correctly to the API
        request = requests_mock.request_history[0]
        assert request.qs["status"] == ["open"]
        assert request.qs["priority"] == ["high"]
        assert request.qs["threat_type"] == ["malware"]

    def test_list_soc_insights_with_empty_response(self, blox_client, requests_mock):
        """Test list_soc_insights command with empty response."""
        # Mock empty API response
        requests_mock.get(f"{BASE_URL}/api/v1/insights", json={"insightList": []}, status_code=200)

        result = list_soc_insights_command(blox_client, {})

        assert result.raw_response == []


class TestListSOCInsightIndicators:
    """Tests for list_soc_insight_indicators_command command."""

    @pytest.fixture
    def indicators_data(self):
        """Load test data for indicators."""
        return util_load_json("insight-indicators-list-command-response.json")

    def test_list_soc_insight_indicators_command_success(self, indicators_data, blox_client, requests_mock):
        """Test successful listing of insight indicators."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/indicators",
            json=indicators_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_indicators_command(blox_client, args)

        expected_readable = util_load_text_data("insight-indicators-list-command-readable.md")
        assert result.outputs_prefix == "InfobloxCloud.Indicator"
        assert result.readable_output == expected_readable

    def test_list_soc_insight_indicators_command_empty_insight_id(self, blox_client):
        """Test with empty insight ID."""

        args = {"soc_insight_id": ""}
        with pytest.raises(ValueError) as e:
            list_soc_insight_indicators_command(blox_client, args)
        assert str(e.value) == MESSAGES["REQUIRED_ARGUMENT"].format("soc_insight_id")

    def test_list_soc_insight_indicators_command_with_time_range(self, indicators_data, requests_mock, blox_client):
        """Test filtering indicators by time range."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/indicators",
            json=indicators_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "start_time": "2025-07-01T00:00:00Z", "end_time": "2025-07-31T23:59:59Z"}
        list_soc_insight_indicators_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("from") == ["2025-07-01t00:00:00.000"]
        assert request.qs.get("to") == ["2025-07-31t23:59:59.000"]

    def test_list_soc_insight_indicators_command_with_invalid_time_range(self, blox_client):
        """Test filtering indicators by time range."""

        args = {"soc_insight_id": "insight-123", "start_time": "invalid-time", "end_time": "invalid-time"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_indicators_command(blox_client, args)
        assert str(e.value) == 'Invalid date: "start_time"="invalid-time"'

    def test_list_soc_insight_indicators_command_empty_response(self, blox_client, requests_mock):
        """Test handling of empty response."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/indicators",
            json={"indicators": []},
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_indicators_command(blox_client, args)

        assert result.readable_output == "No indicators found."
        assert result.raw_response == []


class TestListSOCInsightEvents:
    """Tests for list_soc_insight_events_command command."""

    @pytest.fixture
    def events_data(self):
        """Load test data for events."""
        return util_load_json("insight-events-list-command-response.json")

    def test_list_soc_insight_events_command_success(self, events_data, blox_client, requests_mock):
        """Test successful listing of insight events."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/events",
            json=events_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_events_command(blox_client, args)

        expected_readable = util_load_text_data("insight-events-list-command-readable.md")
        assert result.readable_output == expected_readable
        assert result.outputs_prefix == "InfobloxCloud.Event"

    def test_list_soc_insight_events_command_with_device_ip(self, events_data, blox_client, requests_mock):
        """Test filtering events by device IP."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/events",
            json=events_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "device_ip": "0.0.0.0"}
        list_soc_insight_events_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("device_ip") == ["0.0.0.0"]

    def test_list_soc_insight_events_command_invalid_ip(self, blox_client):
        """Test validation of invalid IP address."""

        args = {"soc_insight_id": "insight-123", "device_ip": "invalid-ip"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_events_command(blox_client, args)

        assert str(e.value) == MESSAGES["INVALID_VALUE"].format("invalid-ip", "device_ip")

    def test_list_soc_insight_events_command_empty_insight_id(self, blox_client):
        """Test with empty insight ID."""

        args = {"soc_insight_id": ""}
        with pytest.raises(ValueError) as e:
            list_soc_insight_events_command(blox_client, args)
        assert str(e.value) == MESSAGES["REQUIRED_ARGUMENT"].format("soc_insight_id")

    def test_list_soc_insight_events_command_with_time_range(self, events_data, requests_mock, blox_client):
        """Test filtering events by time range."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/events",
            json=events_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "start_time": "2025-07-01T00:00:00Z", "end_time": "2025-07-31T23:59:59Z"}
        list_soc_insight_events_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("from") == ["2025-07-01t00:00:00.000"]
        assert request.qs.get("to") == ["2025-07-31t23:59:59.000"]

    def test_list_soc_insight_events_command_with_invalid_time_range(self, blox_client):
        """Test filtering events by time range."""

        args = {"soc_insight_id": "insight-123", "start_time": "invalid-time", "end_time": "invalid-time"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_events_command(blox_client, args)
        assert str(e.value) == 'Invalid date: "start_time"="invalid-time"'


class TestListSOCInsightAssets:
    """Tests for list_soc_insight_assets_command command."""

    @pytest.fixture
    def assets_data(self):
        """Load test data for assets."""
        return util_load_json("insight-assets-list-command-response.json")

    def test_list_soc_insight_assets_command_success(self, assets_data, requests_mock, blox_client):
        """Test successful listing of insight assets."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/assets",
            json=assets_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_assets_command(blox_client, args)

        expected_readable = util_load_text_data("insight-assets-list-command-readable.md")
        assert result.readable_output == expected_readable
        assert result.outputs_prefix == "InfobloxCloud.Asset"

    def test_list_soc_insight_assets_command_empty_insight_id(self, blox_client):
        """Test with empty insight ID."""

        args = {"soc_insight_id": ""}
        with pytest.raises(ValueError) as e:
            list_soc_insight_assets_command(blox_client, args)
        assert str(e.value) == MESSAGES["REQUIRED_ARGUMENT"].format("soc_insight_id")

    def test_list_soc_insight_assets_command_with_ip_filter(self, assets_data, requests_mock, blox_client):
        """Test filtering assets by IP address."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/assets",
            json=assets_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "qip": "0.0.0.0"}
        list_soc_insight_assets_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("qip") == ["0.0.0.0"]

    def test_list_soc_insight_assets_command_with_mac_filter(self, assets_data, requests_mock, blox_client):
        """Test filtering assets by MAC address."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/assets",
            json=assets_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "cmac": "00:00:00:00:00:00"}
        list_soc_insight_assets_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("cmac") == ["00:00:00:00:00:00"]

    def test_list_soc_insight_assets_command_with_time_range(self, assets_data, requests_mock, blox_client):
        """Test filtering assets by time range."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/assets",
            json=assets_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "start_time": "2025-07-01T00:00:00Z", "end_time": "2025-07-31T23:59:59Z"}
        list_soc_insight_assets_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("from") == ["2025-07-01t00:00:00.000"]
        assert request.qs.get("to") == ["2025-07-31t23:59:59.000"]

    def test_list_soc_insight_assets_command_with_invalid_time_range(self, blox_client):
        """Test filtering assets by time range."""

        args = {"soc_insight_id": "insight-123", "start_time": "invalid-time", "end_time": "invalid-time"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_assets_command(blox_client, args)
        assert str(e.value) == 'Invalid date: "start_time"="invalid-time"'

    def test_list_soc_insight_assets_command_empty_response(self, requests_mock, blox_client):
        """Test handling of empty response."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/assets",
            json={"assets": []},
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_assets_command(blox_client, args)

        assert result.readable_output == "No assets found."
        assert result.raw_response == []

    def test_list_soc_insight_assets_command_invalid_ip(self, blox_client):
        """Test validation of invalid IP address."""

        args = {"soc_insight_id": "insight-123", "qip": "invalid-ip"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_assets_command(blox_client, args)

        assert str(e.value) == MESSAGES["INVALID_VALUE"].format("invalid-ip", "qip")

    def test_list_soc_insight_assets_command_invalid_mac(self, blox_client):
        """Test validation of invalid MAC address."""

        args = {"soc_insight_id": "insight-123", "cmac": "invalid-mac"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_assets_command(blox_client, args)

        assert str(e.value) == MESSAGES["INVALID_VALUE"].format("invalid-mac", "cmac")


class TestListSOCInsightComments:
    """Tests for list_soc_insight_comments_command command."""

    @pytest.fixture
    def comments_data(self):
        """Load test data for comments."""
        return util_load_json("insight-comments-list-command-response.json")

    def test_list_soc_insight_comments_command_success(self, comments_data, requests_mock, blox_client):
        """Test successful listing of insight comments."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/comments",
            json=comments_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_comments_command(blox_client, args)

        expected_readable = util_load_text_data("insight-comments-list-command-readable.md")
        assert result.readable_output == expected_readable
        assert result.outputs_prefix == "InfobloxCloud.Comment"
        assert len(result.outputs) == 3

    def test_list_soc_insight_comments_command_with_limit(self, comments_data, requests_mock, blox_client):
        """Test limiting the number of comments returned."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/comments",
            json=comments_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "limit": "2"}
        result = list_soc_insight_comments_command(blox_client, args)

        assert len(result.outputs) == 2

    def test_list_soc_insight_comments_command_with_invalid_limit(self, blox_client):
        """Test invalid limit value."""

        args = {"soc_insight_id": "insight-123", "limit": "-1"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_comments_command(blox_client, args)
        assert str(e.value) == "Limit should not be less than 0."

    def test_list_soc_insight_comments_with_time_range(self, comments_data, requests_mock, blox_client):
        """Test filtering comments by time range."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/comments",
            json=comments_data,
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123", "start_time": "2025-07-01T00:00:00Z", "end_time": "2025-07-31T23:59:59Z"}
        list_soc_insight_comments_command(blox_client, args)

        request = requests_mock.request_history[0]
        assert request.qs.get("from") == ["2025-07-01t00:00:00.000"]
        assert request.qs.get("to") == ["2025-07-31t23:59:59.000"]

    def test_list_soc_insight_comments_command_with_invalid_time_range(self, blox_client):
        """Test filtering comments by time range."""

        args = {"soc_insight_id": "insight-123", "start_time": "invalid-time", "end_time": "invalid-time"}
        with pytest.raises(ValueError) as e:
            list_soc_insight_comments_command(blox_client, args)
        assert str(e.value) == 'Invalid date: "start_time"="invalid-time"'

    def test_list_soc_insight_comments_command_empty_response(self, requests_mock, blox_client):
        """Test handling of empty response."""

        requests_mock.get(
            f"{BASE_URL}/api/v1/insights/insight-123/comments",
            json={"comments": []},
            status_code=200,
        )

        args = {"soc_insight_id": "insight-123"}
        result = list_soc_insight_comments_command(blox_client, args)

        assert result.readable_output == "No comments found."
        assert result.raw_response == []

    def test_list_soc_insight_comments_command_empty_insight_id(self, blox_client):
        """Test with empty insight ID."""

        args = {"soc_insight_id": ""}
        with pytest.raises(ValueError) as e:
            list_soc_insight_comments_command(blox_client, args)
        assert str(e.value) == MESSAGES["REQUIRED_ARGUMENT"].format("soc_insight_id")