Playbook components

Before you write your app code, create the playbook components on a SOAR Platform.

You create playbook components at a SOAR organization. For detailed procedures to create each component, see SOAR Playbook designer.

For a SOAR Platform at V44 or later, you can package playbooks with your app instead of rules and workflows.

Alternately, you can copy existing playbook components or playbooks by using the clone command. You can also use the command to change the object type of cloned workflows, scripts, and playbooks.

Consider the following conventions for naming your app and its associated components.
  • Make the name of your app meaningful and unique. For example, LDAP Query, Machine Learning for SOAR, and ElasticSearch Functions for SOAR.
  • Ideally, the components you create reflect the app name and are unique. The following example names are based on the LDAP Query app.
    • Function name: ldap_query
    • Message destination name: ldap_query
    • Input field: ldap_query_inputname
    • Data table: ldap_query_datatable
    • Custom field: ldap_query_fieldname
    • If you include rules or workflows that are meant as examples, you can use the prefix, Example, such as “Example: Query LDAP”. If you use a function, use the API name of the workflow, such as "example_ldap_query_workflow_name".

    You do not need to add the app name prefix to commonly used fields, such as incident_id, task_id, attachment_id, and artifact_id.

    IBM Security® has a common library of these fields that you can use.

You can test each function individually on the SOAR Platform before you package the app to ensure that the components are working as expected. The Testing a function topic in the Playbook Designer Guide includes an example of how to test functions.

If you use functions, see Function input field considerations and Function post-process script considerations.

Function input field considerations

Consider the following when defining input fields.
  • Input fields are referenced via the inputs object, for example inputs.id.
  • For any ID input field, you must define the corresponding input field type as Number. Frequently used ID input fields include:
    • incident_id
    • artifact_id
    • task_id
    • attachment_id
  • When sending an ID field to an input field, you must define the input field as Numeric.
  • Text Areas, such as incident.description, must be passed to input fields using the 'content' property. For example: inputs.fn_description = incident.description.content
  • In the SOAR Platform, use the Tooltip field to provide extra information about the input. Use an example if helpful.
  • Use care when processing TextArea fields, which can contain rich text. Rich text is passed to your function as HTML tags. For example, a bold word is passed as '<b>word</b>'. This can be confusing to apps that do not anticipate this tagging. In most cases, it makes sense to strip out these tags.
  • An alternative to naming individual input fields for each parameter to pass to an app, use a single input field containing a JSON string:
    inputs.test_details = """{{ "incidentId": "{0}", 
    "name": "{1}", 
    "description": "{2}" }}""".format(str(incident.id), incident.name, incident.description.content)
    
  • Decoding this input field may require the removal of control characters:
    test_details = kwargs.get("test_details")  # text
    
    mpa = {}.fromkeys(range(32))
    dict = json.loads(test_details.translate(mpa))
    log.info("incidentId: "+dict['incidentId'])
    
  • Binary format, such as an attachment, is not supported. If a function needs the content of an attachment, do not send it through input fields. Instead, the app needs to call the resilient_client of its super class to get the file content. For example:
    resilientClient = self.rest_client();
    """ 
         Example of call:
        /incidents/2095/artifacts/13/contents 
    """
    api = "/incidents/{}/artifacts/{}/contents".format(incidentID, artifactID)
    response = resilientClient.get_content(api)
    

    NOTE: IBM Security provides a helper library of common functions such as reading attachments from the SOAR Platform. The library is resilient-lib and is found in Github. It is also pip installable.

  • Input fields can be a composite of multiple SOAR Platform fields, for example:
    inputs.jira_description = 
    "Incident types: {}\nNIST Attack Vectors: {}\n\nAdditional Information: {}"
       .format(incident.incident_type_ids, incident.nist_attack_vectors, 
               incident.description)
    
You should test all required input parameters for a valid entry. You can also enforce this when defining the input field (Requirement: Always). Pre-process scripts are needed for field assignment. Another common function available in resilient-lib: validate_fields()
incident_id = kwargs.get('incident_id')
if not incident_id:
     raise FunctionError('incident_id is required')

NOTE: Another common function available in resilient-lib: validate_fields()

Function post-process script considerations

Consider the following when defining post-process scripts.
  • Use the results object to access the data returned from an app. Due to limitations in the way Python scripts can be written, the syntax to access the JSON data can vary:
    • results.matched_list should be used rather than results['matched_list']
    • results.matched_list['file'] should be used for the next level item
  • Failed post-process scripts may cause a workflow to remain in the running state. For a given incident, click the Actions button then select Action Status to verify the successful completion of a function. Click the Actions button then select Workflow status to terminate any workflow with failed actions.
  • Use dict.get("key") when testing whether data exists for that key. The dict["key"] may cause the script to fail if "key" does not exist.