Forcepoint Security Management Center

Forcepoint SMC provides unified, centralized management of all models of Forcepoint engines whether physical, virtual or cloud—across large, geographically distributed enterprise environments.

Network Security · Forcepoint Security Management Center

Details

IDForcepoint Security Management Center
ProviderFrancisco Partners
CategoryNetwork Security
From Version6.8.0
Docker Imagedemisto/vendors-sdk:1.0.0.10120494
Supported ModulesAgentix XSIAM

README

Forcepoint SMC provides unified, centralized management of all models of Forcepoint engines whether physical, virtual or cloud—across large, geographically distributed enterprise environments.
This integration was integrated and tested with version 6.10 of Forcepoint Security Management Center

Configure Forcepoint Security Management Center in Cortex

Parameter Description Required
Server URL   True
API Key The API Key to use for connection True
Port   True
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.

forcepoint-smc-ip-list-create


Creates an IP list.

Base Command

forcepoint-smc-ip-list-create

Input

Argument Name Description Required
name The name of the IP list to create. Required
addresses A comma-separated list of IP addresses. Optional
comment The comment to add to the IP List. Optional

Context Output

Path Type Description
ForcepointSMC.IPList.Name String The name of the IP list.
ForcepointSMC.IPList.Addresses Unknown The list of addresses in the IP list.
ForcepointSMC.IPList.Comment String The comment for the IP list.

Command example

!forcepoint-smc-ip-list-create name="name" addresses="1.1.1.1" comment="test"

Context Example

{
    "ForcepointSMC": {
        "IPList": {
            "Addresses": [
                "1.1.1.1"
            ],
            "Comment": "test",
            "Name": "name"
        }
    }
}

Human Readable Output

IP List name was created successfully.

forcepoint-smc-ip-list-update


Updates an IP list.

Base Command

forcepoint-smc-ip-list-update

Input

Argument Name Description Required
name The name of the IP list. Required
addresses A comma-separated list of addresses to update. Optional
is_override If false, the list of addresses will be appended to the existing one. Else, the list will be overwritten. Default is False. Possible values are: False, True. Optional

Context Output

Path Type Description
ForcepointSMC.IPList.Name String The name of the IP list.
ForcepointSMC.IPList.Addresses Unknown The list of addresses in the IPList
ForcepointSMC.IPList.Comment String The comment for the IP list.

Command example

!forcepoint-smc-ip-list-update name="name" addresses="1.2.3.4" comment="test" is_override=True

Context Example

{
    "ForcepointSMC": {
        "IPList": {
            "Addresses": [
                "1.2.3.4"
            ],
            "Comment": "test",
            "Name": "name"
        }
    }
}

Human Readable Output

IP List name was updated successfully.

forcepoint-smc-ip-list-list


Lists the IP Lists in the system.

Base Command

forcepoint-smc-ip-list-list

Input

Argument Name Description Required
name The name of a specific IP list to fetch. Overrides the other arguments if used. Optional
limit The maximum number of IP lists to return. Default value is 50. Optional
all_results Whether to return all of the results or not. Default value is False. Optional

Context Output

Path Type Description
ForcepointSMC.IPList.Name String The name of the IP list.
ForcepointSMC.IPList.Addresses Unknown The list of addresses in the IP list.
ForcepointSMC.IPList.Comment String The comment of the IPList

Command example

!forcepoint-smc-ip-list-list name="name"

Context Example

{
    "ForcepointSMC": {
        "IPList": {
            "Addresses": [
                "1.2.3.4"
            ],
            "Comment": "test",
            "Name": "name"
        }
    }
}

Human Readable Output

IP Lists

Name Addresses Comment
name 1.2.3.4 test

forcepoint-smc-ip-list-delete


Deletes an IP list.

Base Command

forcepoint-smc-ip-list-delete

Input

Argument Name Description Required
name The name of the IP list to delete. Required

Context Output

Path Type Description
ForcepointSMC.IPList.Name String The name of the IP list.
ForcepointSMC.IPList.Deleted Boolean Whether the IP list was deleted.

Command example

!forcepoint-smc-ip-list-delete name="name"

Context Example

{
    "ForcepointSMC": {
        "IPList": {
            "Deleted": true,
            "Name": "name"
        }
    }
}

Human Readable Output

IP List name was deleted successfully.

forcepoint-smc-host-list


Lists the hosts in the system.

Base Command

forcepoint-smc-host-list

Input

Argument Name Description Required
name The name of a specific host to fetch. Optional
limit The maximum number of hosts to return. Default value is 50. Optional
all_results Whether to return all of the results. Overrides the other arguments if used. Default value is False. Optional

Context Output

Path Type Description
ForcepointSMC.Host.Name String The name of the host.
ForcepointSMC.Host.Address String The address of the host.
ForcepointSMC.Host.IPv6_address String The IPv6 address of the host.
ForcepointSMC.Host.Secondary_address String The secondary address of the host.
ForcepointSMC.Host.Comment String The comment for the host.

Command example

!forcepoint-smc-host-list name="name"

Context Example

{
    "ForcepointSMC": {
        "Host": {
            "Address": "1.1.1.1",
            "Comment": null,
            "IPv6_address": "",
            "Name": "name",
            "Secondary_address": []
        }
    }
}

Human Readable Output

Hosts

Name Address
name 1.1.1.1

forcepoint-smc-host-create


Creates a new host.

Base Command

forcepoint-smc-host-create

Input

Argument Name Description Required
name The name of a specific host to fetch. Required
address The address of the host. Cannot be combined with the ipv6_address argument. Optional
ipv6_address The IPv6 address of the host. Cannot be combined with the address argument. Optional
secondary_address A comma-separated list of secondary addresses of the host. Optional
comment The comment to add to the host. Optional

Context Output

Path Type Description
ForcepointSMC.Host.Name String The name of the host.
ForcepointSMC.Host.Address String The address of the host.
ForcepointSMC.Host.IPv6_address String The IPv6 address of the host.
ForcepointSMC.Host.Secondary_address Unknown The secondary address of the host.
ForcepointSMC.Host.Comment String The comment for the host.

Command example

!forcepoint-smc-host-create name="name" address="1.1.1.1"

Context Example

{
    "ForcepointSMC": {
        "Host": {
            "Address": "1.1.1.1",
            "Comment": "",
            "IPv6_address": "",
            "Name": "name",
            "Secondary_address": []
        }
    }
}

Human Readable Output

Host name was created successfully.

forcepoint-smc-host-update


Updates a host.

Base Command

forcepoint-smc-host-update

Input

Argument Name Description Required
name The name of the host to update. Required
address The address of the host. Cannot be combined with the ipv6_address argument. Optional
ipv6_address The IPv6 address of the host. Cannot be combined with the address argument. Optional
secondary_address comma-separated list of secondary addresses of the host. Optional
comment The comment to add to the host. Optional

Context Output

Path Type Description
ForcepointSMC.Host.Name String The name of the host.
ForcepointSMC.Host.Address String The address of the host.
ForcepointSMC.Host.IPv6_address String The IPv6 address of the host.
ForcepointSMC.Host.Secondary_address String The secondary address of the host.
ForcepointSMC.Host.Comment String The comment for the host.

Command example

!forcepoint-smc-host-update name="name" address="1.2.3.4"

Context Example

{
    "ForcepointSMC": {
        "Host": {
            "Address": "1.2.3.4",
            "Comment": null,
            "IPv6_address": "",
            "Name": "name",
            "Secondary_address": []
        }
    }
}

Human Readable Output

Host name was updated successfully.

forcepoint-smc-host-delete


Deletes a host.

Base Command

forcepoint-smc-host-delete

Input

Argument Name Description Required
name The name of the host to delete. Required

Context Output

Path Type Description
ForcepointSMC.Host.Name String The name of the host.
ForcepointSMC.Host.Deleted Boolean Whether the host was deleted.

Command example

!forcepoint-smc-host-delete name="name"

Context Example

{
    "ForcepointSMC": {
        "Host": {
            "Deleted": true,
            "Name": "name"
        }
    }
}

Human Readable Output

Host name was deleted successfully.

forcepoint-smc-domain-create


Creates a new domain.

Base Command

forcepoint-smc-domain-create

Input

Argument Name Description Required
name The name of the domain to create. Required
comment The comment to add to the domain. Optional

Context Output

Path Type Description
ForcepointSMC.Domain.Name String The name of the host.
ForcepointSMC.Domain.Comment String The comment of the host.

Command example

!forcepoint-smc-domain-create name="name"

Context Example

{
    "ForcepointSMC": {
        "Domain": {
            "Comment": "",
            "Name": "name"
        }
    }
}

Human Readable Output

Domain name was created successfully.

forcepoint-smc-domain-list


Lists the domains in the system.

Base Command

forcepoint-smc-domain-list

Input

Argument Name Description Required
name The name of a specific domain to fetch. Optional
limit The maximum number of hosts to return. Default value is 50. Optional
all_results Whether to return all of the results. Overrides the other arguments if used. Default value is False. Optional

Context Output

Path Type Description
ForcepointSMC.Domain.Name String The name of the domain.
ForcepointSMC.Domain.Comment String The comment for the domain.

Command example

!forcepoint-smc-domain-list name="name"

Context Example

{
    "ForcepointSMC": {
        "Domain": {
            "Comment": null,
            "Name": "name"
        }
    }
}

Human Readable Output

Domains

Name
name

forcepoint-smc-domain-delete


Deletes a domain.

Base Command

forcepoint-smc-domain-delete

Input

Argument Name Description Required
name The name of the domain to delete. Required

Context Output

Path Type Description
ForcepointSMC.Domain.Name String The name of the domain.
ForcepointSMC.Domain.Deleted Boolean Whether the domain was deleted.

Command example

!forcepoint-smc-domain-delete name="name"

Context Example

{
    "ForcepointSMC": {
        "Domain": {
            "Deleted": true,
            "Name": "name"
        }
    }
}

Human Readable Output

Domain name was deleted successfully.

forcepoint-smc-policy-template-list


Lists the policy templates in the system.

Base Command

forcepoint-smc-policy-template-list

Input

Argument Name Description Required
limit The maximum number of policy templates to return. Default value is 50. Optional
all_results Whether to return all of the results. Overrides the other arguments if used. Default value is False. Optional

Context Output

Path Type Description
ForcepointSMC.PolicyTemplate.Name String The name of the firewall policy template.
ForcepointSMC.PolicyTemplate.Comment String The comment for the firewall policy.

Command example

!forcepoint-smc-policy-template-list limit=1

Context Example

{
    "ForcepointSMC": {
        "PolicyTemplate": {
            "Comment": "Firewall Template Policy that uses Inspection rules from the No Inspection Policy.",
            "Name": "Firewall Template"
        }
    }
}

Human Readable Output

Policy template

Name Comment
Firewall Template Firewall Template Policy that uses Inspection rules from the No Inspection Policy.

forcepoint-smc-firewall-policy-list


Lists the firewall policies in the system.

Base Command

forcepoint-smc-firewall-policy-list

Input

Argument Name Description Required
limit The maximum number of firewall policies to return. Default value is 50. Optional
all_results Whether to return all of the results. Overrides the other arguments if used. Default value is False. Optional

Context Output

Path Type Description
ForcepointSMC.Policy.Name String The name of the firewall policy.
ForcepointSMC.Policy.Comment String The comment for the firewall policy.

Command example

!forcepoint-smc-firewall-policy-list limit=1

Context Example

{
    "ForcepointSMC": {
        "FirewallPolicy": {
            "Comment": null,
            "Name": "Policy For May To Test PC"
        }
    }
}

Human Readable Output

Firewall policies

Name
Policy For May To Test PC

forcepoint-smc-firewall-policy-create


Creates a firewall policy.

Base Command

forcepoint-smc-firewall-policy-create

Input

Argument Name Description Required
name The name of the firewall policy. Required
template The template name to use to create the firewall policy. Run the forcepoint-smc-policy-template-list command to get the list of policy templates. Required

Context Output

Path Type Description
ForcepointSMC.Policy.Name String The name of the firewall policy.
ForcepointSMC.Policy.Comment String The comment for the firewall policy.

Command example

!forcepoint-smc-firewall-policy-create name="name" template="Firewall Template"

Context Example

{
    "ForcepointSMC": {
        "Policy": {
            "Comment": null,
            "Name": "name"
        }
    }
}

Human Readable Output

Firewall policy name was created successfully.

forcepoint-smc-firewall-policy-delete


Deletes a firewall policy.

Base Command

forcepoint-smc-firewall-policy-delete

Input

Argument Name Description Required
name The name of the policy to delete. Required

Context Output

Path Type Description
ForcepointSMC.Policy.Name String The name of the firewall policy.
ForcepointSMC.Policy.Deleted Boolean Whether the policy was deleted.

Command example

!forcepoint-smc-firewall-policy-delete name="name"

Context Example

{
    "ForcepointSMC": {
        "Policy": {
            "Deleted": true,
            "Name": "name"
        }
    }
}

Human Readable Output

Firewall policy name was deleted successfully.

forcepoint-smc-rule-create


Creates a rule.

Base Command

forcepoint-smc-rule-create

Input

Argument Name Description Required
policy_name The name of the firewall policy. Required
rule_name The name of the rule to create. Required
ip_version The ip_version of the rule. Possible values are: V4, V6. Required
source_ip_list A comma-separated list of source ip-list names to use to create the rule. Run the forcepoint-ip-list-list command to get the list of ip lists. Optional
source_host A comma-separated list of source host names to use to create the rule. Run the forcepoint-host-list command to get the list of hosts. Optional
source_domain A comma-separated list of source domain names to use to create the rule. Run the forcepoint-domain-list command to get the list of domains. Optional
destination_ip_list A comma-separated list of destination ip-list names to use to create the rule. Run the forcepoint-ip-list-list command to get the list of ip lists. Optional
destination_host A comma-separated list of destination host names to use to create the rule. Run the forcepoint-host-list command to get the list of hosts. Optional
destination_domain A comma-separated list of destination domain names to use to create the rule. Run the forcepoint-domain-list command to get the list of domains. Optional
action The action of the rule. Possible values are: allow, continue, discard, refuse, enforce_vpn, apply_vpn, forward_vpn, blacklist, forced_next_hop. Required
comment The comment to add to the rule. Optional

Context Output

Path Type Description
ForcepointSMC.Rule.Name String The name of the rule.
ForcepointSMC.Rule.ID String The ID of the rule.
ForcepointSMC.Rule.IP_version String The IP version of the rule.
ForcepointSMC.Rule.Action String The action of the rule.
ForcepointSMC.Rule.Comment String The comment for the rule.

Command example

!forcepoint-smc-rule-create policy_name="name" action=allow rule_name="test" destination_ip_list="test" ip_version="V4"

Context Example

{
    "ForcepointSMC": {
        "Rule": {
            "Action": [
                "allow"
            ],
            "Comment": "",
            "Destinations": [
                "test"
            ],
            "ID": "2097186.0",
            "IP_version": "V4",
            "Name": "test",
            "Services": [],
            "Sources": []
        }
    }
}

Human Readable Output

The rule test to the policy name was created successfully.

forcepoint-smc-rule-update


Updates a rule.

Base Command

forcepoint-smc-rule-update

Input

Argument Name Description Required
policy_name The name of the firewall policy. Required
rule_name The name of the rule to update. Required
is_override Whether to override the existing values. Default value is False. Possible values are: False, True. Optional
ip_version The ip_version of the rule. Possible values are: V4, V6. Required
source_ip_list A comma-separated list of source ip-list names to use to update the rule. Run the forcepoint-ip-list-list command to get the list of ip lists. Optional
source_host A comma-separated list of source host names to use to update the rule. Run the forcepoint-host-list command to get the list of hosts. Optional
source_domain A comma-separated list of source domain names to use to update the rule. Run the forcepoint-domain-list command to get the list of domains. Optional
destination_ip_list A comma-separated list of destination ip-list names to use to update the rule. Run the forcepoint-ip-list-list command to get the list of ip lists. Optional
destination_host A comma-separated list of destination host names to use to update the rule. Run the forcepoint-host-list command to get the list of hosts. Optional
destination_domain A comma-separated list of destination domain names to use to update the rule. Run the forcepoint-domain-list command to get the list of domains. Optional
action The action of the rule. Possible values are: allow, continue, discard, refuse, enforce_vpn, apply_vpn, forward_vpn, blacklist, forced_next_hop. Optional
comment The comment to add to the rule. Optional

Context Output

There is no context output for this command.

Command example

!forcepoint-smc-rule-update policy_name="name" action=continue rule_name="test" source_ip_list="test" ip_version="V4"

Human Readable Output

The rule test to the policy name was updated successfully.

forcepoint-smc-rule-list


Lists the rules in a specific policy.

Base Command

forcepoint-smc-rule-list

Input

Argument Name Description Required
policy_name The name of the firewall policy. Required

Context Output

Path Type Description
ForcepointSMC.Rule.Name String The name of the rule.
ForcepointSMC.Rule.ID String The ID of the rule.
ForcepointSMC.Rule.IP_version String The IP version of the rule.
ForcepointSMC.Rule.Sources Unknown The sources of the rule.
ForcepointSMC.Rule.Destinations Unknown The destinations of the rule.
ForcepointSMC.Rule.Services Unknown The services of the rule.
ForcepointSMC.Rule.Actions Unknown The actions of the rule.
ForcepointSMC.Rule.Comment String The comment of the rule.

Command example

!forcepoint-smc-rule-list policy_name="name"

Context Example

{
    "ForcepointSMC": {
        "Rule": {
            "Actions": [
                "continue"
            ],
            "Comment": "",
            "Destinations": [
                "test"
            ],
            "ID": "2097186.1",
            "IP_version": "V4",
            "Name": "test",
            "Services": [],
            "Sources": [
                "test"
            ]
        }
    }
}

Human Readable Output

Rules

Name ID IP_version Sources Destinations Actions
test 2097186.1 V4 test test continue

forcepoint-smc-rule-delete


Deletes a rule.

Base Command

forcepoint-smc-rule-delete

Input

Argument Name Description Required
policy_name The name of the firewall policy. Required
rule_name The name of the rule to delete. Required
ip_version The ip_version of the rule. Possible values are: V4, V6. Required

Context Output

Path Type Description
ForcepointSMC.Rule.ID String The ID of the rule.
ForcepointSMC.Rule.Deleted Boolean Whether the rule was deleted.

Command example

!forcepoint-smc-rule-delete policy_name="name" rule_name="test" ip_version=V4

Context Example

{
    "ForcepointSMC": {
        "Rule": {
            "Deleted": true,
            "Name": "test"
        }
    }
}

Human Readable Output

Rule test was deleted successfully.

forcepoint-smc-engine-list


Lists the engines in the system.

Base Command

forcepoint-smc-engine-list

Input

Argument Name Description Required
limit The maximum number of engines to return. Default value is 50. Optional
all_results Whether to return all of the results or not, overrides the other arguments if used. Default value is False. Optional

Context Output

Path Type Description
ForcepointSMC.Engine.Name String The name of the engine.
ForcepointSMC.Engine.Comment String The comment for the engine.

Command example

!forcepoint-smc-engine-list limit=1

Context Example

{
    "ForcepointSMC": {
        "Engine": {
            "Comment": "Forcepoint Engine element pre-populated by installer",
            "Name": "Forcepoint Engine"
        }
    }
}

Human Readable Output

Engines

Name Comment
Forcepoint Engine Forcepoint Engine element pre-populated by installer

forcepoint-smc-engine-refresh


Refreshes the specified engines. Use the forcepoint-smc-engine-list command to list the engines in the system.

Base Command

forcepoint-smc-engine-refresh

Input

Argument Name Description Required
engine_name A comma-separated list of engine names to refresh. Required
interval_in_seconds The interval in seconds between polling attempts. To prevent search timeouts, set this value within the 60-90 second range. Default is 60. Optional
timeout_in_seconds The timeout for polling in seconds. Default is 600. Optional

Context Output

There is no context output for this command.

Configuration parameters

  • url — Server URL (required)
  • credentials — (required)
  • port — Port (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (21)

  • forcepoint-smc-domain-create

    Creates a new domain.

  • forcepoint-smc-domain-delete

    Deletes a domain.

  • forcepoint-smc-domain-list

    Lists the domains in the system.

  • forcepoint-smc-engine-list

    Lists the engines in the system.

  • forcepoint-smc-engine-refresh

    Refreshes the specified engines. Use the forcepoint-smc-engine-list command to list the engines in the system.

  • forcepoint-smc-firewall-policy-create

    Creates a firewall policy.

  • forcepoint-smc-firewall-policy-delete

    Deletes a firewall policy.

  • forcepoint-smc-firewall-policy-list

    Lists the firewall policies in the system.

  • forcepoint-smc-host-create

    Creates a new host.

  • forcepoint-smc-host-delete

    Deletes a host.

  • forcepoint-smc-host-list

    Lists the hosts in the system.

  • forcepoint-smc-host-update

    Updates a host.

  • forcepoint-smc-ip-list-create

    Creates an IP list.

  • forcepoint-smc-ip-list-delete

    Deletes an IP list.

  • forcepoint-smc-ip-list-list

    Lists the IP Lists in the system.

  • forcepoint-smc-ip-list-update

    Updates an IP list.

  • forcepoint-smc-policy-template-list

    Lists the policy templates in the system.

  • forcepoint-smc-rule-create

    Creates a rule.

  • forcepoint-smc-rule-delete

    Deletes a rule.

  • forcepoint-smc-rule-list

    Lists the rules in a specific policy.

  • forcepoint-smc-rule-update

    Updates a rule.

# pylint: disable=E1101
import demistomock as demisto
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import
from CommonServerUserPython import *  # noqa
from smc import session
from smc.administration.tasks import Task
from smc.elements.network import IPList, DomainName, Host
from smc.core.engine import Engine
from smc.base.model import Element
from smc.policy.layer3 import FirewallTemplatePolicy, FirewallPolicy
from smc.policy.rule import IPv6Rule, Rule
from smc.api.exceptions import ElementNotFound, TaskRunFailed
import urllib3
from typing import Any

# Disable insecure warnings
urllib3.disable_warnings()

""" CONSTANTS """

DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"  # ISO8601 format with UTC, default in XSOAR
DEFAULT_LIMIT = 50
API_VERSION = "6.10"

DEFAULT_POLLING_INTERVAL_IN_SECONDS = 30
DEFAULT_POLLING_TIMEOUT_IN_SECONDS = 600
""" CLIENT CLASS """


class Client:
    """Client class to interact with the service API

    This Client implements API calls, and does not contain any XSOAR logic.
    Should only do requests and return data.
    It inherits from BaseClient defined in CommonServer Python.
    Most calls use _http_request() that handles proxy, SSL verification, etc.
    For this  implementation, no special attributes defined
    """

    def __init__(self, url: str, api_key: str, verify: bool, proxy: bool, port: str):
        self.url = url + ":" + port
        self.api_key = api_key
        self.verify = verify
        self.proxy = proxy

    def login(self):
        """Logs into a session of smc"""
        handle_proxy()
        session.login(url=self.url, api_key=self.api_key, verify=self.verify, api_version=API_VERSION)

    def logout(self):
        """logs out of a session in smc"""
        session.logout()


def extract_host_address(host: Host):
    """extracts the ip address or the ipv6 address"""
    address = ""
    try:
        address = host.address
    except AttributeError:
        pass

    ipv6_address = ""
    try:
        ipv6_address = host.ipv6_address
    except AttributeError:
        pass

    return address, ipv6_address


def handle_rule_entities(ip_lists: list, host_list: list, domain_list: list):
    """Returns a unified list of all of entities for rule creation.
    Args:
        ip_list (list): A list of IP List names
        host_list (list):  A list of Host names
        domain_list (list):  A list of Domain names

    """
    entities: List[Element] = []

    for ip_list in ip_lists:
        entities.extend(list(IPList.objects.filter(name=ip_list, exact_match=True)))

    for host in host_list:
        entities.extend(list(Host.objects.filter(name=host, exact_match=True)))

    for domain in domain_list:
        entities.extend(list(DomainName.objects.filter(name=domain, exact_match=True)))

    return entities


def get_rule_from_policy(policy: FirewallPolicy, rule_name: str, ip_version: str = "", all_rules: bool = True):
    """Gets a rule from a policy based on its ID"""

    rules = get_policy_rules(policy, ip_version, all_rules)
    for rule in rules:
        if rule.name == rule_name:
            return rule

    raise DemistoException(f"Rule with name {rule_name} was not found in policy {policy.name}.")


def get_policy_rules(policy: FirewallPolicy, ip_version: str = "", all_rules: bool = True):
    """Gets rules from a specific policy"""

    ipv4_rules = list(policy.fw_ipv4_access_rules.all())
    ipv6_rules = list(policy.fw_ipv6_access_rules.all())

    if all_rules:
        return ipv4_rules + ipv6_rules
    else:
        if ip_version == "V4":
            return ipv4_rules
        else:
            return ipv6_rules


def get_rule_ip_version(rule: Rule):
    """Gets the rule ip version"""
    if isinstance(rule, IPv6Rule):
        return "V6"
    else:
        return "V4"


""" COMMAND FUNCTIONS """


def test_module(client: Client) -> str:
    """Tests API connectivity and authentication'

    Returning 'ok' indicates that the integration works like it is supposed to.
    Connection to the service is successful.
    Raises exceptions if something goes wrong.

    :type client: ``Client``
    :param Client: client to use

    :return: 'ok' if test passed, anything else will fail the test.
    :rtype: ``str``
    """

    try:
        client.login()
        IPList.objects.limit(1)
    except Exception as e:
        if "Login failed, HTTP status code:" in str(e):
            raise DemistoException("Login failed, please check your API key or your server URL.")
        else:
            raise e
    return "ok"


def create_iplist_command(args: dict[str, Any]) -> CommandResults:
    """Creating IP List with a list of addresses.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")
    addresses = argToList(args.get("addresses", []))
    comment = args.get("comment", "")

    ip_list = IPList.create(name=name, iplist=addresses, comment=comment)

    outputs = {"Name": ip_list.name, "Addresses": ip_list.iplist, "Comment": ip_list.comment}
    return CommandResults(
        outputs_prefix="ForcepointSMC.IPList",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=f"IP List {name} was created successfully.",
    )


def update_iplist_command(args: dict[str, Any]) -> CommandResults:
    """Updating an IP List.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")
    addresses = argToList(args.get("addresses", []))
    is_override = argToBoolean(args.get("is_override", False))

    if not list(IPList.objects.filter(name=name, exact_match=True)):
        return CommandResults(readable_output=f"IP List {name} was not found.")

    ip_list = IPList.update_or_create(name=name, append_lists=not is_override, iplist=addresses)

    outputs = {"Name": ip_list.name, "Addresses": ip_list.iplist, "Comment": ip_list.comment}

    return CommandResults(
        outputs_prefix="ForcepointSMC.IPList",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=f"IP List {name} was updated successfully.",
    )


def list_iplist_command(args: dict[str, Any]) -> CommandResults:  # noqa:
    """Lists the IP Lists in the system.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name", "")
    limit = arg_to_number(args.get("limit", DEFAULT_LIMIT))
    all_results = argToBoolean(args.get("all_results", False))

    ip_lists = []
    if name:
        ip_lists = list(IPList.objects.filter(name=name, exact_match=True))
    elif all_results:
        ip_lists = list(IPList.objects.all())
    else:
        ip_lists = list(IPList.objects.limit(limit))

    outputs = []
    for ip_list in ip_lists:
        outputs.append({"Name": ip_list.name, "Addresses": ip_list.iplist, "Comment": ip_list.comment})

    return CommandResults(
        outputs_prefix="ForcepointSMC.IPList",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=tableToMarkdown(name="IP Lists:", t=outputs, removeNull=True, sort_headers=False),
    )


def delete_iplist_command(args: dict[str, Any]) -> CommandResults:
    """Deleting IP List with a list of addresses.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")

    try:
        IPList(name).delete()

    except ElementNotFound:
        return CommandResults(readable_output=f"IP List {name} was not found.")

    outputs = {"Name": name, "Deleted": True}

    return CommandResults(
        outputs_prefix="ForcepointSMC.IPList",
        outputs_key_field="Name",
        outputs=outputs,
        readable_output=f"IP List {name} was deleted successfully.",
    )


def list_host_command(args: dict[str, Any]) -> CommandResults:
    """Lists the Hosts in the system.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name", "")
    limit = arg_to_number(args.get("limit", DEFAULT_LIMIT))
    all_results = argToBoolean(args.get("all_results", False))

    hosts = []
    if name:
        hosts = list(Host.objects.filter(name=name, exact_match=True))
    elif all_results:
        hosts = list(Host.objects.all())
    else:
        hosts = list(Host.objects.limit(limit))

    outputs = []
    for host in hosts:
        address, ipv6_address = extract_host_address(host)
        outputs.append(
            {
                "Name": host.name,
                "Address": address,
                "IPv6_address": ipv6_address,
                "Secondary_address": host.secondary,
                "Comment": host.comment,
            }
        )

    return CommandResults(
        outputs_prefix="ForcepointSMC.Host",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=tableToMarkdown(name="Hosts:", t=outputs, removeNull=True, sort_headers=False),
    )


def create_host_command(args: dict[str, Any]) -> CommandResults:
    """Creating a Host.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")
    address = args.get("address", "")
    ipv6_address = args.get("ipv6_address", "")
    secondary = argToList(args.get("secondary_address", ""))
    comment = args.get("comment", "")

    if address and ipv6_address:
        return CommandResults(readable_output="Both address and ipv6_address were provided, choose just one.")

    host = Host.create(name=name, address=address, ipv6_address=ipv6_address, secondary=secondary, comment=comment)
    address, ipv6_address = extract_host_address(host)
    outputs = {
        "Name": host.name,
        "Address": address,
        "IPv6_address": ipv6_address,
        "Secondary_address": host.secondary,
        "Comment": host.comment,
    }

    return CommandResults(
        outputs_prefix="ForcepointSMC.Host",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=f"Host {name} was created successfully.",
    )


def update_host_command(args: dict[str, Any]) -> CommandResults:
    """Updating an Host.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")
    kwargs = {
        "name": name,
        "address": args.get("address", ""),
        "ipv6_address": args.get("ipv6_address", ""),
        "secondary": argToList(args.get("secondary_address", "")),
        "comment": args.get("comment", ""),
    }
    remove_nulls_from_dictionary(kwargs)

    if not list(Host.objects.filter(name=name, exact_match=True)):
        return CommandResults(readable_output=f"Host {name} was not found.")

    host = Host.update_or_create(**kwargs)

    address, ipv6_address = extract_host_address(host)
    outputs = {
        "Name": host.name,
        "Address": address,
        "IPv6_address": ipv6_address,
        "Secondary_address": host.secondary,
        "Comment": host.comment,
    }

    return CommandResults(
        outputs_prefix="ForcepointSMC.Host",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=f"Host {name} was updated successfully.",
    )


def delete_host_command(args: dict[str, Any]) -> CommandResults:
    """Deleting Host.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")

    try:
        Host(name).delete()

    except ElementNotFound:
        return CommandResults(readable_output=f"Host {name} was not found.")

    outputs = {"Name": name, "Deleted": True}

    return CommandResults(
        outputs_prefix="ForcepointSMC.Host",
        outputs_key_field="Name",
        outputs=outputs,
        readable_output=f"Host {name} was deleted successfully.",
    )


def create_domain_command(args: dict[str, Any]) -> CommandResults:
    """Creating a Domain.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")
    comment = args.get("comment", "")

    domain = DomainName.create(name=name, comment=comment)

    outputs = {"Name": domain.name, "Comment": domain.comment}

    return CommandResults(
        outputs_prefix="ForcepointSMC.Domain",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=f"Domain {name} was created successfully.",
    )


def list_domain_command(args: dict[str, Any]) -> CommandResults:
    """Lists the Domains in the system.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name", "")
    limit = arg_to_number(args.get("limit", DEFAULT_LIMIT))
    all_results = argToBoolean(args.get("all_results", False))

    domains = []
    if name:
        domains = list(DomainName.objects.filter(name=name, exact_match=True))
    elif all_results:
        domains = list(DomainName.objects.all())
    else:
        domains = list(DomainName.objects.limit(limit))

    outputs = []
    for domain in domains:
        outputs.append({"Name": domain.name, "Comment": domain.comment})

    return CommandResults(
        outputs_prefix="ForcepointSMC.Domain",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=tableToMarkdown(name="Domains:", t=outputs, removeNull=True, sort_headers=False),
    )


def delete_domain_command(args: dict[str, Any]) -> CommandResults:
    """Deleting domain.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")

    try:
        DomainName(name).delete()

    except ElementNotFound:
        return CommandResults(readable_output=f"Domain {name} was not found.")

    outputs = {"Name": name, "Deleted": True}

    return CommandResults(
        outputs_prefix="ForcepointSMC.Domain",
        outputs_key_field="Name",
        outputs=outputs,
        readable_output=f"Domain {name} was deleted successfully.",
    )


def list_policy_template_command(args: dict[str, Any]) -> CommandResults:
    """Lists the policy templates in the system.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    limit = arg_to_number(args.get("limit", DEFAULT_LIMIT))
    all_results = argToBoolean(args.get("all_results", False))

    policy_templates = []
    if all_results:
        policy_templates = list(FirewallTemplatePolicy.objects.all())
    else:
        policy_templates = list(FirewallTemplatePolicy.objects.limit(limit))

    outputs = []
    for policy_template in policy_templates:
        outputs.append({"Name": policy_template.name, "Comment": policy_template.comment})

    return CommandResults(
        outputs_prefix="ForcepointSMC.PolicyTemplate",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=tableToMarkdown(name="Policy template:", t=outputs, removeNull=True, sort_headers=False),
    )


def list_firewall_policy_command(args: dict[str, Any]) -> CommandResults:
    """Lists the policy templates in the system.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    limit = arg_to_number(args.get("limit", DEFAULT_LIMIT))
    all_results = argToBoolean(args.get("all_results", False))

    firewall_policies = []
    if all_results:
        firewall_policies = list(FirewallPolicy.objects.all())
    else:
        firewall_policies = list(FirewallPolicy.objects.limit(limit))

    outputs = []
    for firewall_policy in firewall_policies:
        outputs.append({"Name": firewall_policy.name, "Comment": firewall_policy.comment})

    return CommandResults(
        outputs_prefix="ForcepointSMC.FirewallPolicy",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=tableToMarkdown(name="Firewall policies:", t=outputs, removeNull=True, sort_headers=False),
    )


def create_firewall_policy_command(args: dict[str, Any]) -> CommandResults:
    """Creating a Domain.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")
    template = args.get("template", "")

    firewall_policy = FirewallPolicy.create(name=name, template=template)

    outputs = {"Name": firewall_policy.name, "Comment": firewall_policy.comment}

    return CommandResults(
        outputs_prefix="ForcepointSMC.Policy",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=f"Firewall policy {name} was created successfully.",
    )


def delete_firewall_policy_command(args: dict[str, Any]) -> CommandResults:
    """Deleting domain.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    name = args.get("name")

    try:
        FirewallPolicy(name).delete()

    except ElementNotFound:
        return CommandResults(readable_output=f"Firewall policy {name} was not found.")

    outputs = {"Name": name, "Deleted": True}

    return CommandResults(
        outputs_prefix="ForcepointSMC.Policy",
        outputs_key_field="Name",
        outputs=outputs,
        readable_output=f"Firewall policy {name} was deleted successfully.",
    )


def create_rule_command(args: dict[str, Any]) -> CommandResults:
    """Creating a rule.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    policy_name = args.get("policy_name")
    rule_name = args.get("rule_name")
    ip_version = args.get("ip_version", "V4")
    source_ip_list = argToList(args.get("source_ip_list", []))
    source_host = argToList(args.get("source_host", []))
    source_domain = argToList(args.get("source_domain", []))
    dest_ip_list = argToList(args.get("destination_ip_list", []))
    dest_host = argToList(args.get("destination_host", []))
    dest_domain = argToList(args.get("destination_domain", []))
    action = args.get("action", "")
    comment = args.get("comment", "")

    if not any([source_ip_list, source_host, source_domain, dest_ip_list, dest_host, dest_domain]):
        return CommandResults(readable_output="No sources or destinations were provided, provide at least one.")

    firewall_policy = FirewallPolicy(policy_name)
    sources = handle_rule_entities(source_ip_list, source_host, source_domain)
    destinations = handle_rule_entities(dest_ip_list, dest_host, dest_domain)

    if ip_version == "V4":
        rule = firewall_policy.fw_ipv4_access_rules.create(
            name=rule_name, sources=sources, destinations=destinations, action=action, comment=comment
        )
    else:
        rule = firewall_policy.fw_ipv6_access_rules.create(
            name=rule_name, sources=sources, destinations=destinations, action=action, comment=comment
        )

    outputs = {
        "Name": rule.name,
        "ID": rule.tag,
        "Action": rule.action.action,
        "Sources": [source.name for source in rule.sources.all()],
        "Destinations": [dest.name for dest in rule.destinations.all()],
        "Services": [service.name for service in rule.services.all()],
        "IP_version": ip_version,
        "Comment": rule.comment,
    }

    return CommandResults(
        outputs_prefix="ForcepointSMC.Rule",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="ID",
        readable_output=f"The rule {rule_name} to the policy {policy_name} was created successfully.",
    )


def update_rule_command(args: dict[str, Any]) -> CommandResults:
    """Updating a Rule.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    policy_name = args.get("policy_name", "")
    rule_name = args.get("rule_name", "")
    ip_version = args.get("ip_version", "")
    is_override = argToBoolean(args.get("is_override", False))
    source_ip_list = argToList(args.get("source_ip_list", []))
    source_host = argToList(args.get("source_host", []))
    source_domain = argToList(args.get("source_domain", []))
    dest_ip_list = argToList(args.get("destination_ip_list", []))
    dest_host = argToList(args.get("destination_host", []))
    dest_domain = argToList(args.get("destination_domain", []))
    action = args.get("action", "")
    comment = args.get("comment", "")

    policy = FirewallPolicy(policy_name)
    rule = get_rule_from_policy(policy, rule_name, ip_version, all_rules=False)
    sources = handle_rule_entities(source_ip_list, source_host, source_domain)
    destinations = handle_rule_entities(dest_ip_list, dest_host, dest_domain)

    prev_dest = list(rule.destinations.all())
    prev_source = list(rule.sources.all())
    if action:
        rule.action.update(action=[action])

    if comment:
        rule.update(comment=comment)

    if sources:
        if not is_override:
            sources = sources + prev_source
        rule.sources.add_many(sources)
        rule.save()

    if destinations:
        if not is_override:
            destinations = destinations + prev_dest
        rule.destinations.add_many(destinations)
        rule.save()

    return CommandResults(readable_output=f"The rule {rule.name} to the policy {policy_name} was updated successfully.")


def list_rule_command(args: dict[str, Any]) -> CommandResults:
    """Lists the rules in a policy.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    policy_name = args.get("policy_name", "")
    policy = FirewallPolicy(policy_name)

    rules = []
    policy_rules = get_policy_rules(policy)
    for rule in policy_rules:
        rules.append(
            {
                "Name": rule.name,
                "ID": rule.tag,
                "IP_version": get_rule_ip_version(rule),
                "Sources": [source.name for source in rule.sources.all()],
                "Destinations": [dest.name for dest in rule.destinations.all()],
                "Services": [service.name for service in rule.services.all()],
                "Actions": rule.action.action,
                "Comment": rule.comment,
            }
        )

    return CommandResults(
        outputs_prefix="ForcepointSMC.Rule",
        outputs=rules,
        raw_response=rules,
        outputs_key_field="ID",
        readable_output=tableToMarkdown(name="Rules:", t=rules, removeNull=True, sort_headers=False),
    )


def delete_rule_command(args: dict[str, Any]) -> CommandResults:
    """Deleting a rule.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    policy_name = args.get("policy_name", "")
    rule_name = args.get("rule_name", "")
    ip_version = args.get("ip_version", "")

    if not list(FirewallPolicy.objects.filter(name=policy_name, exact_match=True)):
        return CommandResults(readable_output=f"Firewall policy {policy_name} was not found.")

    policy = FirewallPolicy(policy_name)
    rule = get_rule_from_policy(policy, rule_name, ip_version)
    rule.delete()

    outputs = {"Name": rule_name, "Deleted": True}

    return CommandResults(
        outputs_prefix="ForcepointSMC.Rule",
        outputs_key_field="Name",
        outputs=outputs,
        readable_output=f"Rule {rule_name} was deleted successfully.",
    )


def list_engine_command(args: dict[str, Any]) -> CommandResults:
    """Lists the policy templates in the system.

    Args:
        args (dict[str, Any]): The command args.

    Returns:
        CommandResults
    """
    limit = arg_to_number(args.get("limit", DEFAULT_LIMIT))
    all_results = argToBoolean(args.get("all_results", False))

    engines = []
    if all_results:
        engines = list(Engine.objects.all())
    else:
        engines = list(Engine.objects.limit(limit))

    outputs = []
    for engine in engines:
        outputs.append({"Name": engine.name, "Comment": engine.comment})

    return CommandResults(
        outputs_prefix="ForcepointSMC.Engine",
        outputs=outputs,
        raw_response=outputs,
        outputs_key_field="Name",
        readable_output=tableToMarkdown(name="Engines:", t=outputs, removeNull=True, sort_headers=False),
    )


@polling_function(
    "forcepoint-smc-engine-refresh",
    poll_message="Refreshing engines:",
    requires_polling_arg=False,
    interval=arg_to_number(demisto.args().get("interval_in_seconds")) or DEFAULT_POLLING_INTERVAL_IN_SECONDS,
    timeout=arg_to_number(demisto.args().get("timeout_in_seconds")) or DEFAULT_POLLING_TIMEOUT_IN_SECONDS,
)
def engine_refresh_command(args: dict) -> PollResult:
    """
    Refresh the specified engines.

    This command initiates refresh tasks and polls for status until complete.

    Args:
        args: Command arguments including engine names.

    Returns:
        PollResult: Contains the refresh status or indicates to continue polling.
    """
    task_ids = argToList(args.get("task_ids", []))
    engine_names = argToList(args.get("engine_name", []))

    if not task_ids:
        # first call - initiate refresh tasks
        failed_engines = []

        demisto.debug("Creating refresh tasks:")
        for engine_name in engine_names:
            try:
                engine = Engine(engine_name)
                poller = engine.refresh()
                task_ids.append(poller.task.href)
                demisto.debug(f"\t- (Engine: {engine_name}, Task: {poller.task.href})")
            except TaskRunFailed:
                failed_engines.append(engine_name)

        if failed_engines:
            raise DemistoException(
                f"Failed to initiate refresh tasks for engines ({', '.join(failed_engines)}), refresh policy is locked."
            )

        demisto.debug("Completed task initiation.")
        demisto.debug(f"Initiated refresh tasks for engines {', '.join(engine_names)}.")
        demisto.debug(f"Tasks IDs: {task_ids}")
        args["task_ids"] = task_ids

    # poll for refresh status
    completed_tasks = []
    pending_tasks = []

    demisto.debug("Restoring refresh tasks, assignments are expected to be the same as during creation:")
    for task_id, engine_name in zip(task_ids, engine_names):
        task = Task({"follower": task_id})
        demisto.debug(f"\t- (Engine: {engine_name}, Task: {task_id})")
        task = task.update_status()
        if not task.in_progress:
            completed_tasks.append(engine_name)
        else:
            pending_tasks.append((task_id, engine_name))

    demisto.debug(f"Refresh status:\n{pending_tasks=}\n{completed_tasks=}")

    if not pending_tasks:
        demisto.debug("All refresh tasks are complete.")
        return PollResult(
            response=CommandResults(
                readable_output=f"Existing policy on specified devices ({', '.join(engine_names)}) were refreshed successfully."
            ),
            continue_to_poll=False,
        )

    demisto.info(f"Refresh tasks {pending_tasks} are still in progress, continuing to poll...")

    return PollResult(
        response=CommandResults(readable_output="Refresh tasks are still in progress, continuing to poll..."),
        continue_to_poll=True,
        args_for_next_run=args,
    )


""" MAIN FUNCTION """


def main():
    """main function, parses params and runs command functions"""
    params = demisto.params()
    url = params.get("url")
    api_key = params.get("credentials", {}).get("password")
    port = params.get("port")
    verify = not argToBoolean(params.get("insecure", False))
    proxy = argToBoolean(params.get("proxy", False))
    client = Client(url=url, api_key=api_key, verify=verify, proxy=proxy, port=port)

    command = demisto.command()
    demisto.debug(f"Command being called is {command}")
    try:
        if command == "test-module":
            result = test_module(client)
            return_results(result)

        client.login()

        if command == "forcepoint-smc-ip-list-create":
            return_results(create_iplist_command(demisto.args()))
        elif command == "forcepoint-smc-ip-list-update":
            return_results(update_iplist_command(demisto.args()))
        elif command == "forcepoint-smc-ip-list-list":
            return_results(list_iplist_command(demisto.args()))
        elif command == "forcepoint-smc-ip-list-delete":
            return_results(delete_iplist_command(demisto.args()))
        elif command == "forcepoint-smc-host-list":
            return_results(list_host_command(demisto.args()))
        elif command == "forcepoint-smc-host-create":
            return_results(create_host_command(demisto.args()))
        elif command == "forcepoint-smc-host-update":
            return_results(update_host_command(demisto.args()))
        elif command == "forcepoint-smc-host-delete":
            return_results(delete_host_command(demisto.args()))
        elif command == "forcepoint-smc-domain-create":
            return_results(create_domain_command(demisto.args()))
        elif command == "forcepoint-smc-domain-list":
            return_results(list_domain_command(demisto.args()))
        elif command == "forcepoint-smc-domain-delete":
            return_results(delete_domain_command(demisto.args()))
        elif command == "forcepoint-smc-policy-template-list":
            return_results(list_policy_template_command(demisto.args()))
        elif command == "forcepoint-smc-firewall-policy-list":
            return_results(list_firewall_policy_command(demisto.args()))
        elif command == "forcepoint-smc-firewall-policy-create":
            return_results(create_firewall_policy_command(demisto.args()))
        elif command == "forcepoint-smc-firewall-policy-delete":
            return_results(delete_firewall_policy_command(demisto.args()))
        elif command == "forcepoint-smc-rule-create":
            return_results(create_rule_command(demisto.args()))
        elif command == "forcepoint-smc-rule-update":
            return_results(update_rule_command(demisto.args()))
        elif command == "forcepoint-smc-rule-list":
            return_results(list_rule_command(demisto.args()))
        elif command == "forcepoint-smc-rule-delete":
            return_results(delete_rule_command(demisto.args()))
        elif command == "forcepoint-smc-engine-list":
            return_results(list_engine_command(demisto.args()))
        elif command == "forcepoint-smc-engine-refresh":
            return_results(engine_refresh_command(demisto.args()))
    # Log exceptions and return errors
    except Exception as e:
        return_error(f"Failed to execute {command} command.\nError:\n{str(e)}")
    finally:
        client.logout()


""" ENTRY POINT """


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()