Splunk® Phantom (Legacy)

Python Playbook API Reference for Splunk Phantom

Acrobat logo Download manual as PDF


This documentation does not apply to the most recent version of Splunk® Phantom (Legacy). For documentation on the most recent version, go to the latest release.
Acrobat logo Download topic as PDF

Playbook automation API

Splunk Phantom's Automation API allows security operations teams to develop detailed and precise automation strategies. Playbooks can serve many purposes, ranging from automating minimal investigative tasks that can speed up analysis to large-scale response to a security breach. The following APIs are supported to leverage the capabilities of the platform using Playbooks.

act

 phantom.act(action, parameters=[], assets=None, tags=None,
            callback=None, reviewer=None, handle=None,
            start_time=None, name=None, asset_type=None,
            app=None)

phantom.act() call can be called from on_start() or any callback of any phantom.act() call. If multiple phantom.act() calls are called within the same function they will execute actions in parallel. Each action can take indefinite amount of time depending on what the action is. If the action is being executed on an asset that has primary approvers assigned then the action will generate approval requests and untill they are approved, the action will not be executed. Similarly if reviewer is specified, the action will not be executed unless the reviewer approves the action. Or the action can simply take a long time like detonation on a sandbox.

Parameter Required? Description
action Required The name of the action that the user intends to execute. These are actions like 'block ip', 'list vms', 'file reputation', etc. that are supported by the Apps installed on the Platform. The Platform can be used to carry out these actions generically across all Assets with the compatible Apps. Since Apps and Assets can be dynamically added to the system, the actions can automatically extend to these new Assets. The behavior can be more specific if the user specifies on which specific asset the action should be executed.
parameters Optional A list of dictionaries that contain the parameters expected by the action. The name of the keys are specific to the action being taken and can be found in the Phantom App Reference Guide section of this documentation.
assets Optional A list of Assets on which the action is to be executed. If the user intends to take the action on a specific asset, it must be specified in this parameter. This is a list of Asset IDs, as specified when an Asset is configured. If the assets have been configured with primary and secondary owners, they will be required to approve an action before it can be executed. Asset owners have the option to approve the action, alter the action parameters, delegate to other users, or deny the action.

If the asset is not specified, the action will be executed on ALL possible Assets on which the action can be executed. This is useful in case of the scenario where the user wants to take an action broadly across all applicable Assets, for example, if the user intends to 'block ip' across all firewall Assets, then the user can skip specifying this parameter and Phantom platform will block the IP on all firewalls.

Also, Playbooks may be designed, tested and deployed at any point in time. Later on, if new Assets and Apps are added that support the same action, and if the action did not specify the Assets, actions will automatically be executed across the newly added Assets as well.

If there are multiple Apps providing the same action for the same product, the system automatically uses the latest installed App.

While not deliberately specifying Assets is very powerful, it introduces an obvious risk. If new Assets or new Apps are added to the Phantom Platform, they may execute actions that you as the Playbook author had not intended. For example, if you begin your Phantom deployment with a simple network-based topology and configure a perimeter Firewall that supports block ip, and then add an Active Directory server which has an associated App that also understands block ip, then that action will be executed on both the firewall and AD server. Setting appropriate Approvals on Assets can help to minimize this risk. |- | tags || Optional || A list of asset tags which can help specify certain assets to be used for executing the action. Assets can be assigned a 'tag' when they are configured. For example if the asset is tagged critical and the Action is block ip, the action will only be executed on Assets that have been tagged as critical. If tags and assets are both specified then the action is only executed on assets tagged with the matching tag.

callback Optional The parameter where the user can specify a callback function (defined in the same Playbook) to be called upon completion of the action. Here the user has an opportunity to evaluate the outcome of one action and then take more actions. The facility can be used to either serialize actions where the user intends to execute the action one after the other or the subsequent action is dependent on the outcome or results of this one. The prototype of the callback function is specified below.
reviewer Optional A username, email address or group that will receive an approval request to review the action before it can be executed. The user receives an approval request with all of the details of the action and its parameters. If provided a comma separated list, or group, only one approval by any member of the list is required. SLA escalation settings affect how long the action will be held for approval. The approval request when using this parameter precedes the approvals generated by the Asset's configured primary and secondary approvers. For example: A response analyst reviews actions prior to the Asset owners.
handle Optional A string object that when specified is passed on to the callback. Users can save any Python object like a list, or dictionary that the user needs to access in the context of the callback from the action he had called. Handle is always saved with the action and passed to the callback.

We recommend using handles to pass objects from action to callbacks instead of using global variables. Global variables may or may not be accessible as actions can take an arbitrary period of time and may not be present across system or platform component restarts

Size of 'handle' object is limited to 4k. For objects bigger than 4k, please use save_data() and get_data() APIs instead.

start_time Optional The time in the future when the action should be scheduled for execution. For example 10 mins from now or at a specific time like Jan 01, 2020, 10:00 AM. This value is a datetime object. 'act_scheduled' playbook in the api category shows the usage of this parameter.
params=[]
params.append({'ip':'1.1.1.1'})

# schedule 'geolocate ip' 60 seconds from now
when = datetime.now()+timedelta(seconds=60)
phantom.act("geolocate ip",
    parameters=params,
    start_time=when)
name Optional A name the user can give to a instance of an action that gets executed.
asset_type Optional can be specified to limit the action on assets of the specified type. This can be a string or a list of strings. For example, asset_type = 'endpoint' or asset_type=['firewall','endpoint'].
app Optional Can be specified as the specific app which should be used to execute the action. App should be specified as a Python dictionary as {"name":"some_app_name", "version":"x.x.x"}. "name" is case insensitive. The names and versions of the app can be found on the Apps page of the product.
app_data={}
app_data['name']='MaxMind'
app_data['version']='1.1.0'
phantom.act('geolocate ip',
    parameters=[{ "ip" : "1.1.1.1" }],
    assets=["maxmind"],
    callback=geolocate_ip_cb,
    app=app_data)

or

phantom.act('geolocate ip',
    parameters=[{ "ip" : "1.1.1.1" }],
    assets=["maxmind"],
    callback=geolocate_ip_cb,
    app={'name':'MaxMind', 'version':'1.1.0' })

Here is a sample playbook that uses the phantom.act() API

import phantom.rules as phantom
import json

def geolocate_ip_cb(action, success, container, results, handle):
    phantom.debug(results)
    if not success:
        phantom.debug('Action '+json.dumps(action)+' : FAILED')
        return
    return

def on_start(container):
    ips = set(phantom.collect(container, 'artifact:*.cef.sourceAddress'))
    parameters = []
    for ip in ips:
        parameters.append({ "ip" : ip })

    if parameters:
        phantom.act('geolocate ip', parameters=parameters, assets=["maxmind"], callback=geolocate_ip_cb)

    return

def on_finish(container, summary):
    return

callback

Callback functions are specified as parameters in phantom.act():

phantom.act('geolocate ip', parameters=parameters, assets=["maxmind"], callback=geolocate_ip_cb)

NOTE: Callback functions are called when the phantom.act() action has completed, irrespective of action success or failure.

The phantom.act API takes a callback function, which should accept the following keyword arguments: action, success, container, results, and handle. Each of these parameters is discussed in greater detail in the table below.

The simplest no-op callback would look like this:

def do_nothing(action=None, success=None, container=None, results=None, handle=None):
    pass

Such a callback would be functionally equivalent to not providing a callback parameter to phantom.act at all.

Parameter Description
action This is a JSON object that specifies the action name and the action run id. The action run id, uniquely identifies that instance of action execution and can be used to fetch the details of the action execution any time from anywhere. Here is an example of action parameter from a callback:
{
    "action_run_id": 205,
    "action_name": "whois ip",
    "action" : "whois ip",
    "name": "my_whois_ip_action"
}

The 'action' field replaces the 'action_name' field. The 'action_name' field will be removed in a future release. success Either true or false. An action is considered failed only if the action has failed on all assets and with all specified parameters. If any part of the action succeeds, it is not considered failed. Use the utility functions like parse_errors() or parse_success() to get a flat listing of all errors and success. These utility functions simply parse the results to give the user a different view of the overall results.

container This is the container JSON object. Here is an example of container parameter from a callback:
{
    "sensitivity": "amber",
    "create_time": "2016-01-14 18:25:55.921199+00",
   "owner": "admin",
    "id": 7,
    "close_time": "",
    "severity": "medium",
    "label": "incident",
    "due_time": "2016-01-15 06:24:00+00",
    "version": "1",
    "current_rule_run_id": 1,
    "status": "open",
    "owner_name": "",
    "hash": "093d1d4d22cab1c5931bbfb1b16ce12c",
    "description": "this is my test incident",
    "tags": ["red-network"],
    "start_time": "2016-01-14 18:25:55.926468+00",
    "asset_name": "",
    "artifact_update_time": "2016-01-14 18:26:33.55643+00",
    "container_update_time": "2016-01-14 18:28:43.859814+00",
    "kill_chain": "",
    "name": "test",
    "ingest_app_id": "",
    "source_data_identifier":
        "48e4ab9c-2ec1-44a5-9d05-4e83bec05f87",
    "end_time": "",
    "artifact_count": 1
}
results This is a JSON object that has the full details and status of the complete action on all assets for each parameter. Here is an example where the 'geolocate ip' action is being executed:
parameters = []
parameters.append({ "ip" : '1.1.1.1' })
phantom.act('geolocate ip', parameters=parameters,
    assets=["maxmind"], callback=geolocate_ip_cb,
    name='my_geolocate_action')

This simple action can result in various execution strategies and outcomes, depending on how the system is configured.

In the most simplistic form, there is one app that supports the geolocate ip action and there is one 'Maxmind' asset that is configured which results in one ip being queried once on one asset.

In a more complex example, if there are 2 Apps, both of which support file reputation (for example VirusTotal and ReversingLabs, and 2 Assets (one for VirusTotal and one for ReversingLabs), then this one simple action will result in a file hash being queried on both the assets.

The single action file reputation will result in the hash being queried twice, once on each asset. The two queries still constitute one action, therefore the callback 'file_reputation_cb' will be called only once when both the queries have completed.

The parameters as seen in the above example is a list of dictionaries and contains one ip. However, in one action call the user can specify many different ips.

These parameters are the original input parameters. For actions like prompt, tasks, approvals, and reviews these parameters include and therefore allow a user to see who the intended user was for the action.

The results JSON object provides full visibility into the execution of the action on all matching assets using all matching apps for all specified parameters.

Here are the results of the above geolocate ip action (Single parameter, single asset, single app):

       [
            {
                "asset_id": 63,
                "status": "success",
                "name": "geolocate_ip_1",
                "app": "MaxMind",
                "action_results": [
                    {
                        "status": "success",
                        "data": [
                            {
                                "state_name": "Victoria",
                                "latitude": -37.7,
                                "country_iso_code": "AU",
                                "time_zone": "Australia/Melbourne",
                                "longitude": 145.1833,
                                "state_iso_code": "VIC",
                                "city_name": "Research",
                                "country_name": "Australia",
                                "continent_name": "Oceania",
                                "postal_code": "3095"
                            }
                        ],
                        "message": "City: Research, State: VIC,
                                    Country: Australia",
                        "parameter": {
                            "ip": "1.1.1.1",
                            "context": {
                                "guid": "f42fd73f-...-8194aaa9bc11",
                                "artifact_id": 0,
                                "parent_action_run": []
                            }
                        },
                        "summary": {
                            "city": "Research",
                            "state": "VIC",
                            "country": "Australia"
                        }
                    }
                ],
                "app_id": 83,
                "summary": {
                    "total_objects": 1,
                    "total_objects_successful": 1
                },
                "asset": "maxmind",
                "action": "geolocate ip",
                "message": "'geolocate_ip_1' on asset 'maxmind': 1
                            action succeeded. (1)For Parameter:
                            {\"ip\":\"1.1.1.1\"} Message: \"City:
                            Research, State: VIC, Country: Australia\"",
                "app_run_id": 51,
                "action_run_id": 11
            }
      ]
handle A string object that was specified in the action phantom.act() call for passing data between action and callbacks. Please see the description of this parameter in the phantom.act() call.

condition

 phantom.condition(container=None,
                  action_results=None,
                  conditions=[],
                  logical_operator='or',
                  scope='new',
                  filtered_artifacts=[],
                  filtered_results=[],
                  limit=100,
                  name=None,
                  trace=False,
                  case_sensitive=True)

This API implements the decision block in the visual playbook editor. It evaluates expressions and returns matching artifacts and actions results that evaluate as true. The code for this API is autogenerated via the use of condition blocks on the new 2.0 Playbook editor.

Parameter Required? Description
container Required This is the container dictionary object that is passed into the calling function.
action_results Required These are the action results passed into any callback function or a subset of action results that had been filtered from a phantom.condition() call.
conditions Required Conditions are a list of one or more 'and' or 'or' expressions that are to be evaulated. Matching artifacts or matching action results are returned.

Expression format:

[ [ LHS, OPERATOR, RHS ], [ LHS, OPERATOR, RHS ], ..]

OPERATOR can be any one of the following:

==, !=, <, >, <=, >=, in, not in

LHS/RHS values can be a value, artifact datapath, or action result datapath. Please see below for the various types and examples of datapath that can be used.

logical_operator Optional Valid logical operators are 'and' or 'or' and expresses the relationship between conditions. Defaults to 'or'.
scope Optional Please refer to the phantom.collect() API documentation.
filtered_artifacts Optional Filtered artifacts that were returned from an immediately preceding phantom.condition() block.
filtered_results Optional Filtered results that were returned from an immediately preceding phantom.condition() block.
limit Optional Please refer to phantom.collect() API documentation.
name Optional Specify a unique name to save the filtered results (filtered action results and filtered artifacts) which can then be later retrieved using either collect2() API or phantom.get_filtered_data() API.
trace Optional Set this parameter to 'True' for verbose debugging of the API call.
case_sensitive Optional Default is 'True'. Set to 'False' for evaluating conditions in a case-insensitive manner.

phantom.condition() returns a list of artifact ids and a list of action result objects. These are the artifacts and actions results that matched the conditions expressed. If there is no filter statement specified that is about action results there will be no filtered action results returned and the playbook editor UI will not show that as a selectable option in subsequent blocks.

When using the Playbook Editor, users can select to connect various UI blocks. Each of these blocks implements a function in the auto generated Python code. These functions have various parameters like container, results, filtered_artifacts and filtered_results. The expressions used for the conditions can be either a constant or a datapath that allows the users to specify what they need to fetch and operate on. These datapaths could point to either a field in the artifact, action_result, filtered-artifacts, filtered results or a constant.

Here are the various examples of the datapaths

Datapath Description
artifact: This datapath type refers to a field in the artifact. These datapaths begin with "artifact:" For example: "artifact:*.cef.bytesIn"
action-name:artifact: This datapath type refers to a field in the artifact whose one or more CEF fields were used as an input parameter of an action. "geolocate_ip_1:artifact:*.cef.bytesIn" In the phantom.act() API, when specifying parameters, the auto-generated code (or users) uses context which is a hidden parameter that helps identify which artifact was used to execute the action such that users can access it from the results and this access fields of this artifact for subsequent actions or decision making. context is a means to attach a "reference" to the parameter that can then later be retrieved from the results. Each instance of a context has a unique GUID and optionally parent_action that refers to the action that launched this action. Hence "geolocate_ip_1:artifact" implies the artifact_id whose field was used as an input parameter to a particular action.
filtered-artifact: This datapath type refers to a field in the artifact that was filtered from a previous decision block. Example: "filtered-artifact:*.cef.bytesIn"
action_result. This datapath type refers to a field in the action result object. Example: "action_result.data.*.latitude". When this type of datapath is used, the condition API expects the action_results parameter to provide the action result list object. This is the same object that is passed into the function via the "results" parameter or obtained via the "phantom.get_action_results()" API.
action_name:action_result. This datapath type refers to a field in the action result object of an action called with a name parameter. This can be any of the actions that may have been executed in the path that leads to this action. For example: "geolocate_ip_1:action_result.data.*.latitude" thus the datapath "action_result.data.*.latitude" is to be used to extract data from the action named "geolocate_ip_1"
action_name:filtered-action_result. This datapath type refers to a field in the action result object of a named action that has been filtered. As mentioned earlier, phantom.condition() statement returns those action_result objects or artifact ids that match the condition. When this type of datapath is used it requires that the filtered results be provided as the parameter. For example: "geolocate_ip_1:filtered-action_result.data.*.latitude" thus the datapath "action_result.data.*.latitude" is to be used to extract data from the previous conditions filtered named "geolocate_ip_1"s filtered results

Generally, CEF fields that are passed into phantom.condition, if they have commas in the value, will cause the value to be treated as a list. One specific exception that has been defined is that if the CEF field is "toEmail" or "fromEmail", commas will not trigger the list behavior. This is because commas frequently appear in the displayname portion of an email address.

If two strings which can be converted to a numeric type are being compared with one of the following operators, they will be converted to numeric types before the comparison occurs.

==, !=, <, >, <=, >=

format

 phantom.format(container=None,
               template=None,
               parameters=None,
               scope='new',
               name=None,
               trace=False,
               separator=None,
               drop_none=False):

This is an API supported for the purposes of formatting text with values that are extracted using datapaths for other complex objects like artifacts or action results.

Parameter Required? Description
container The container object passed into the action callback or on_start or any other method.
template The format string where positional arguments are substituted with their values. The arguments are expressed and passed as list of datapaths in the 'parameters' argument. If the datapath returns a 'list' of items, the positional argument is replaced by a comma separated value of the items. The format string uses positional arguments same as Python string formatting. {0} for first argument, {1} for second etc.
parameters This is a list of datapaths with a datapath for each positional format argument used in the template string.
scope Optional For this parameter, refer to phantom.collect() API. The value of this API can be 'all' or 'new'. Default value is 'new'.
name Optional This parameter is the name used to save the resulting formatted data, to be later retrieved via get_format_data() API. Internally this API uses save_run_data() API to save the formatted data in the context of playbook run. If this parameter is not specified, the data is not saved.
trace Optional This boolean parameter is used for detailed debugging. Default value is False.
separator Optional If a datapath response contains a list (ie, strings or numbers, but not python objects), the default output separator is ', '. Specify an alternate separator via this parameter.
drop_none Optional Default value for this boolean parameter is False. By default None values are included in the resulting string, but the user can filter NoneType values in the resulting string via this parameter.

Example:

def on_start(container):

    template = "Host '{0}' transferred in '{1}' bytes"

    datapaths = ['artifact:*.cef.sourceAddress','artifact:*.cef.bytesIn']

    formatted_data = phantom.format(container=container,
                                    template=template,
                                    parameters=datapaths,
                                    name='formatted_1')

    phantom.debug("Formatted data is: {}".format(formatted_data))

    # use the same name that was provided for key in phantom.format()
    formatted_data = phantom.get_format_data(name="format_1")

    phantom.debug("Retrieved formatted data is: {}".format(formatted_data))

    return

Sample result:

Starting playbook 'format_test' on 'incident' id '13' with playbook run id '7'.
calling on_start() on incident 'test_incident'(id: 13).
phantom.collect2(): called for datapath['artifact:*.cef.sourceAddress']
phantom.collect2(): called for datapath['artifact:*.cef.bytesIn']
save_run_data() called
Formatted data is: Host '1.1.1.1' transferred in '999' bytes
get_run_data() called
Retrieved formatted data is: Host '1.1.1.1' transferred in '999' bytes
No actions were executed
calling on_finish()


Playbook 'format_test' (playbook id: 6) executed (playbook run id: 7) on
	incident 'test_incident'(container id: 13).
   	Playbook execution status is 'success'
	Total actions executed: 0

{"message":"No actions were executed","playbook_run_id":7,"result":[],
	"status":"success"}

In the above example, if there are multiple artifacts artifact:*.cef.sourceAddress effectively is referencing a list of IPs. If you use this same format block as above, and there are multiple artifacts in the container, the output would look something like this:

Retrieved formatted data is: Host '1.1.1.1', '8.8.8.8', '8.8.4.4' transferred in '999', '888', '777' bytes

It may be more desirirable for each pair of sourceAddress and bytesIn to have their own line in this output. By wrapping sections of the format text in '%%' you can accomplish this behavior. We could change the above Python code to the following:

def on_start(container):

    template = """\
%%
Host '{0}' transferred in '{1}' bytes"
%%"""

    datapaths = ['artifact:*.cef.sourceAddress','artifact:*.cef.bytesIn']

    formatted_data = phantom.format(container=container,
                                    template=template,
                                    parameters=datapaths,
                                    name='formatted_1')

    phantom.debug("Formatted data is: {}".format(formatted_data))

    # use the same name that was provided for key in phantom.format()
    formatted_data = phantom.get_format_data(name="format_1")

    phantom.debug("Retrieved formatted data is: {}".format(formatted_data))

    return

This will create the following string:

Retrieved formatted data is: Host '1.1.1.1' transferred in '999' bytes
Host '8.8.8.8' transferred in '888' bytes
Host '8.8.4.4' transferred in '777' bytes

When creating this string, each section will be saved into a list. When you are using the VPE, you can get this list for the format block, instead of the string, and then each item in this list will be passed a parameter to the action.

def on_start(container):

    template = """\
%%
Host '{0}' transferred in '{1}' bytes"
%%"""

    datapaths = ['artifact:*.cef.sourceAddress','artifact:*.cef.bytesIn']

    # formatted_data will always be a string
    formatted_data = phantom.format(container=container,
                                    template=template,
                                    parameters=datapaths,
                                    name='formatted_1')

    # Add __as_list to the end of the name to retrieve the list instead of the string
    formatted_data_list = phantom.get_format_data(name="format_1__as_list")
    return

render_template

phantom.render_template(template, context)

This API accepts a Django 1.11 template and fills the variable fields with contexual information from a provided dictionary. Common uses of the template are for user prompts or case management updates. Additional information about Django 1.11 templates can be found on the Django Project homepage at https://docs.djangoproject.com/en/1.11/ref/templates/language/

Parameter Required? Description
template Required The Django 1.11 template.
context Required Dictionary of values used to populate variable fields in the Django template.

The following is an example code snippet that demonstrates the addition and population of a template in a playbook.

phantom.render_template(
        "<html>
            <head>
                <title>Report for {{ report_name }}</title>
            </head>
            <body>Hi {{ subject }}, here are a list of IPs you should look at! <ul>{% for ip in ip_list %}
                <li>{{ ip }}</li>
                {% endfor %} </ul>
            </body>
        </html>",
        {
        'report_name': 'Task for {}: {}'.format(container['id'],
        container['name']),
        'subject': container['owner_name'],
        'ip_list': ips_affected
        }
    )

playbook

 phantom.playbook(playbook=None,
		container=None,
		handle=None,
		show_debug=False,
		callback=None,
		inherit_scope=True,
		name=None)

This is an API that allows the users to call another playbook from within the current playbook. If there are 2 or more playbooks by the same name from different repos, the call will fail. In such cases, the playbook name should be very specific i.e. repo_name/playbook_name.

It returns the playbook_run_id that can be used to query corresponding playbook execution details / report.

Parameter Required? Description
playbook Required The playbook name that needs to be executed. It should follow the format "repo name/playbook name" to avoid ambiguity of which playbook to run from which repo.
container Required The container json object that needs to be passed to execute the playbook on. This is the same container JSON object that you get in on_start() or any other callback function.
handle Optional This is a object that you can pass to the API which will be passed back to the callback when the playbook finishes execution.
show_debug Optional This parameter is defaulted to False, however if you set this to True, the debug messages of the launched/callee playbook will be shown in the debug window when you debug the parent/caller playbook.
callback Optional If this parameter is specified, the playbook is launched in a synchronous fashion. When the callee (child) playbook finishes, the specified callback function is called with playbook execution results. When callee(child) playbooks are launched synchronously, the caller (parent) playbook is not considered completed till the called child playbook has finished executing. If this parameter is specified, you must also specify the name parameter.
inherit_scope Optional Default is True. This implies that the child playbook will inherit the scope settings from the parent when called. If set to false, the child playbook will run with default playbook scope i.e. 'new'.
name Required This is an optional parameter unless the callback parameter is specified. This parameter uniquely identifies the execution instance of the called playbook. If the code for calling the child playbook is auto generated, the name of the function is the recommended value to be used for this parameter.

Example:

"""
This sample playbook shows calling a playbook from a playbook
"""
import json
import phantom.rules as phantom

def on_start(container):
    playbook_run_id = phantom.playbook(playbook='local/test1', container=container)
    return


def on_finish(container, summary):
    return

prompt

 phantom.prompt(user=None,
               message='',
               respond_in_mins=30,
               callback=None,
               name=None,
               options=None,
               parameters=None,
               container=None,
               scope='new',
               trace=False,
               separator=None,
               drop_none=False)
Parameter Required? Description
container Required The container object that is associated with the current playbook execution. This object is available to all action callbacks and other playbook execution functions like on_start().
user Required The recipient in the form of a user email address, username, or a role. Must be a valid user/role on Phantom.
message Required The message content to send.
respond_in_mins Optional The time the user is given to respond. If the user does not respond in the specified time, the prompt fails and the 'failed' status is sent to the callback. Default is 30 mins.
callback Optional This has the same prototype as action callbacks. Status indicates success when the user has responded to the action and is failure only when the user does not respond in the specified time. The results JSON has the same format as any action results. Handle is not used and hence is an empty object.
name Optional The name of the 'prompt' action to be able to distinguish various prompt blocks if there are more than one prompts used in the playbook.
options Optional This parameter is a JSON dictionary. This allows the user response to display with programmed choices. See Option Parameter Examples below.
parameters Optional A list of datapaths whose values are used to format the message. Recognized datapaths will be used to retrieve data, and the data will be used to populate the curly brackets in the message. The first parameter will replace {0}, the second will replace {1} and so on.
scope Optional Scope can either be "new" or "all". Default value is 'new'. Please refer to phantom.collect() API for more details.
trace Optional This parameter is used for detailed debugging. Default value is False.
separator Optional If a datapath response contains a list (ie, strings or numbers, but not python objects), the default output separator is ', '. Specify an alternate separator via this parameter.
drop_none Optional By default None values are included in the resulting string, but user can choose to not have None be included in the resulting string via this parameter.

Using phantom.prompt() results in a message sent to the specified user or users.

  • A notification is sent to the notifications bell icon in the upper right corner of the screen.
  • If Splunk Phantom has been configured with an SMTP asset, and the specified user or user have valid email addresses in their account settings, the user or users are sent an email.

    An email notification sent using phantom.prompt or phantom.prompt2 cannot be disabled by users by disabling notifications in their account settings.

Pending notifications can be accessed by clicking the bell icon in the top right corner of the UI. Delegation for approvals is possible. Either the user or delegated user can complete the task. When the task is completed, the prompt() callback is called with the final response in the action results.

The structure of the callback function and all the parameters is consistent with an action callback. Using prompt only allows the user to complete a task. The playbook can contain a callback function and use the prompt response, found in the result object in the callback, to change playbook behavior.

Example:

"""
This sample playbook shows calling a phantom.prompt() from a playbook
"""
import phantom.rules as phantom
import json
 
 
def on_start(container):
    phantom.prompt(container=container,
                   user="user@company.com",
                   message="proceed with blocking these ips on FW?",
                   respond_in_mins=10,
                   callback=prompt_cb,
                   options={ 'type': 'list', 'choices': ['yes', 'no', 'maybe'] },
                   name="prompt_to_block_ips")
    return
 
def prompt_cb(action, success, container, results, handle):
    phantom.debug(results)
    return


def on_finish(container, summary):
    return

The output of the playbook is as shown below:

Fri Apr 29 2016 19:38:25 GMT-0700 (PDT): Starting playbook 'manual_action' testing on 'incident' id: '215'...
Fri Apr 29 2016 19:38:25 GMT-0700 (PDT): calling on_start(): on incident 'test', id: 215.
Fri Apr 29 2016 19:38:25 GMT-0700 (PDT): phantom.act(): Warning: For action 'prompt' no assets were specified. The action shall execute on all assets the app (supporting the action) can be executed on
Fri Apr 29 2016 19:38:25 GMT-0700 (PDT): phantom.act(): action 'prompt' shall be executed with parameters: '[{"to": "user@company.com", "message": "please make sure xyz is ok ...", "mins_to_act": 10}]', assets: '', callback function: 'prompt_cb', with no action approver, no delay to execute the action, no user provided name for the action, no tags, no asset type
Fri Apr 29 2016 19:38:25 GMT-0700 (PDT): Request sent  for action'automated action 'prompt' of 'manual_action' playbook'
Fri Apr 29 2016 19:38:50 GMT-0700 (PDT): Manual action was completed by the user. User message: yes I am OK..
Fri Apr 29 2016 19:38:50 GMT-0700 (PDT): calling action callback function: prompt_cb
Fri Apr 29 2016 19:38:50 GMT-0700 (PDT):

[
    {
        "asset_id": 0,
        "status": "success",
        "name": "prompt_to_block_ips",
        "app": "",
        "action_results": [
            {
                "status": "success",
                "data": [
                    {
                        "response": "maybe"
                    }
                ],
                "message": "proceed with blocking these ips on FW?",
                "parameter": {
                    "message": "proceed with blocking these ips on FW?"
                },
                "summary": {
                    "response": "maybe"
                }
            }
        ],
        "app_id": 0,
        "app_run_id": 0,
        "asset": "",
        "action": "prompt",
        "message": "1 action succeeded",
        "summary": {},
        "action_run_id": 57
    }
]

Fri Apr 29 2016 19:38:50 GMT-0700 (PDT): successfully called action callback 'prompt_cb()' in rule: manual_action(id:182)
Fri Apr 29 2016 19:38:50 GMT-0700 (PDT): calling on_finish()
Fri Apr 29 2016 19:38:50 GMT-0700 (PDT):
Playbook 'manual_action (id: 182)' executed (playbook_run_id: 195) on incident 'test'(id: 215).
Playbook execution status is:'success'
	No actions were executed for this playbook and 'incident'
Fri Apr 29 2016 19:38:50 GMT-0700 (PDT): *** Playbook execution has completed with status: SUCCESS ***
Fri Apr 29 2016 19:38:51 GMT-0700 (PDT): Playbook execution report:
{"message":"","playbook_run_id":195,"result":[{"action":"prompt","app_runs":null,"close_time":"2016-04-30T02:38:50.844839+00:00","create_time":"2016-04-30T02:38:25.731+00:00","id":156,"message":"yes I am OK.. ","name":"automated action 'prompt' of 'manual_action' playbook","status":"success","type":"manual"}],"status":"success"}

Option Parameter Examples

Type: list
Shows the items in choices as the availabe responses.
{ 'type': 'list', 'choices': ['High', 'Medium', 'Low'] }

Type: range
Shows an input that requires a response within the given range of integers, i.e. 1-10.
{ 'type': 'range', 'min': 1, 'max': 100 }

Type: message
Shows a text area input in which a free form response can be entered.
{ 'type': 'message'}

prompt2

 phantom.prompt2(user=None,
                message='',
                respond_in_mins=30,
                response_types=None,
                callback=None,
                name=None,
                parameters=None,
                container=None,
                scope='new',
                trace=False,
                separator=None,
                drop_none=False)

This API is similar to phantom.prompt, with some changes made to more easily allow creating a prompt with multiple user input fields. Notice the "options" parameter has been replaced by "response_types". The other parameters behave the same as phantom.prompt.

Parameter Required? Description
container Required The container object that is associated with the current playbook execution. This object is available to all action callbacks and other playbook execution functions like on_start().
user Required The recipient in the form of a user email address, username, or a role. Must be a valid user/role on Phantom.

message [required] the message content to send.

response_types Required The list of JSON dictionaries describing each input field in the prompt which will be created.
respond_in_mins Optional The time the user is given to respond. If the user does not respond in the specified time, the prompt fails and the 'failed' status is sent to the callback. Default is 30 mins.
callback Optional This has the same prototype as action callbacks. Status indicates success when the user has responded to the action and is failure only when the user does not respond in the specified time. The results JSON has the same format as any action results. Handle is not used and hence is an empty object.
name Optional This parameter allows you to name the 'prompt' action to be able to distinguish various prompt blocks if there are more than one prompts used in the playbook.
parameters Optional A list of datapaths whose values are used to format the message. Recognized datapaths will be used to retrieve data, and the data will be used to populate the curly brackets in the message. The first parameter will replace {0}, the second will replace {1} and so on.
scope Optional Scope can either be "new" or "all". Default value is 'new'. Please refer to phantom.collect() API for more details.
trace Optional This parameter is used for detailed debugging. Default value is False.
separator Optional If a datapath response contains a list (ie, strings or numbers, but not python objects), the default output separator is ', '. Specify an alternate separator via this parameter.
drop_none Optional By default None values are included in the resulting string, but user can choose to not have None be included in the resulting string via this parameter.

Response Types Example:

Response types is a list of JSON objects. Each object represents one input field in the prompt which will be created. Each object will need to have a value with the key 'prompt', and has an optional key, 'options'. 'prompt' is a message for that input field. 'options' is a dictionary with the same structure as a dictionary for the 'options' in phantom.prompt. No options being specified will result in a normal message type prompt.

[
  {'prompt': 'Select a number in this range', 'options': {'type': 'range', 'min': 1, 'max': 50}},
  {'prompt': 'Describe the event'}
]

The 'message' parameter is still used in phantom.prompt2. The message will be displayed at the top of the created prompt, above the input fields.

task

phantom.task(user=None, message=None, respond_in_mins=0, callback=None, name=None)

This API is a specialization of a manual action that can be used to ask a user or a role to do some work in the course of a response workflow or playbook

Parameter Required? Description
user Required The person or a role to whom the task is assigned
message Required The text that has the information or details of the task to be performed.
respond_in_mins Required The time given to the user to be able to perform the task, after which the task fails and the status is expressed in the callback if callback was specified.
callback Optional A callback function to be called when the task completes i.e. succeeds, fails or expires.
name Required A unique name for the user to be able to identify and distinguish this action from other actions

error

phantom.error(message)

This is an API supported for the purposes of letting the author debug or print log messages as the Playbook is being executed with logging disabled. This is an equivalent of a print() statement. The parameter for the call is a 'string' type object and the contents are shown in the playbook debug console in red text color so that the user can distinguish his/her text from the system text.

Example:

def on_start(container):
    phantom.error('in on_start() of playbook')
    return

Response:

2016-02-13T01:32:52.583000+00:00: calling on_start(): on incident 'test', id: 107.
2016-02-13T01:32:52.608695+00:00: in on_start() of playbook

debug

phantom.debug(message)

This is an API supported for the purposes of letting the author debug as the Playbook is being developed and tested, when logging is enabled. This is an equivalent of a print() statement. The parameter for the call is a 'string' type object and the contents are shown in the debug console in cyan text color so that the user can distinguish his/her text from the system text.

Example:

def on_start(container):
    phantom.debug('in on_start() of playbook')
    return

Response:

2016-02-13T01:32:52.583000+00:00: calling on_start(): on incident 'test', id: 107.
2016-02-13T01:32:52.608695+00:00: in on_start() of playbook

discontinue

phantom.discontinue()

This is an API that allows the users to stop executing any more active playbooks when a container is being processed against "Active" playbooks.

Example:

def on_start(container):
    phantom.discontinue()

completed

phantom.completed(action_names=None, playbook_names=None, trace=False)

This API checks to see if all of the actions and child playbooks (synchronously launched) in the the given list of action_names and playbook names have finished executing or not. Succeeded or Failed implies 'Done'. Returns True if and only if all the actions and playbooks are done or else returns False. This API is used primarily in the join function where certain blocks are being executed in parallel but the next block has to be called only when all the joining blocks have completed executing.

Parameter Required? Description
action_names Required A list of names given to an action via phantom.act() API in the parameter 'name'.
playbook_names Required A list of names given to a playbook execution via phantom.playbook() API in the parameter 'name'.

Example:

def join_add_tag_1(action=None, success=None, container=None, results=None,
                   handle=None, filtered_artifacts=None, filtered_results=None):
    # this is a "join" function. It is a callback for 2 separate actions
    # check if all connected incoming actions are done i.e. have succeeded or failed
    # only invoke add_tag_1 when both have completed

    if phantom.completed(action_names=[ 'whois_ip_1'], playbook_names=['playbook_local_child_basic_1']):

        # call connected block "add_tag_1"
        add_tag_1(container=container, handle=handle)

    return
Last modified on 15 October, 2020
PREVIOUS
Understanding apps and assets
  NEXT
Container automation API

This documentation applies to the following versions of Splunk® Phantom (Legacy): 4.8


Was this documentation topic helpful?


You must be logged into splunk.com in order to post comments. Log in now.

Please try to keep this discussion focused on the content covered in this documentation topic. If you have a more general question about Splunk functionality or are experiencing a difficulty with Splunk, consider posting a question to Splunkbase Answers.

0 out of 1000 Characters