Coding considerations

The following sections provide advice and recommendations to consider when creating your function.

Data flow

Functions are blocking until results are returned. Returning Yielding a FunctionError() aborts the result of a workflow.

All functions are stateless. No persistence of data is retained between function calls.

Logging

Log information for debugging purposes. Sensitive information should never be logged, but can be obscured. For example, user.email@example.com can become us***@example.com.

To set the log to debug level, you can change the setting in the app.config file to loglevel=DEBUG or set the log level in the following command.
resilient-circuits run --loglevel DEBUG

Data results

Use yield FunctionResult(results) where results must be a Python Dictionary.

The code returns the results of the AppFunctionComponent to the SOAR Platform and can be accessed in the post-process script by using the results object.

The results are wrapped with details about the AppFunctionComponent execution. Specifically, the following example is the results of the URLHaus AppFunctionComponent.
{
    'version': 2.0,
    'success': True,
    'reason': None,
    'content': {
        'query_status': 'ok',
        'id': '438055',
        'urlhaus_reference': 'https://urlhaus.abuse.ch/url/438055/',
        'url': 'http://183.151.65.155:33955/Mozi.m',
        'url_status': 'offline',
        'host': '183.151.65.155',
        'date_added': '2020-08-21 08:51:10 UTC',
        'threat': 'malware_download'
    },
    'raw': None,
    'inputs': {
        'urlhaus_artifact_type': 'URL',
        'urlhaus_artifact_value': 'http://183.151.65.155:33955/Mozi.m'
    },
    'metrics': {
        'version': '1.0',
        'package': 'fn-urlhaus',
        'package_version': '1.0.0',
        'host': 'xxx.local',
        'execution_time_ms': 3301,
        'timestamp': '2021-11-16 11:40:25'
    }
}

Linking to 3rd party app objects

Perform the following to create a live URL link back to the integrated system, such as a ticketing system.
  1. Create a new incident custom field as a text area with Rich Text enabled.
  2. Add it to the summary section of an incident's layout.
  3. In the function’s post-process script, build the URL as an HTML anchor:
    incident.properties.pd_incident_url = "<a href='{}' target='blank'>Reference Link</
    a>".format(results.content.get('incident', {}).get('html_url', ''))
    

Rich text and temporary files

Rich text fields can contain HTML markup.

Rich text

Rich text fields can contain HTML markup. This format might be undesirable for the target app system. You can find a method to strip off the HTML elements, preserving some of the new line format in the library at: https://ibmresilient.github.io/resilient-python-api/pages/resilient-lib/resilient-lib.html#resilient_lib.components.resilient_common.clean_html.

Temporary files

To create a temporary file, see the helper in resilient-lib: https://ibmresilient.github.io/resilient-python-api/pages/resilient-lib/resilient-lib.html#resilient_lib.components.re[…]nt_common.write_to_tmp_file

Avoid using self.

self. is not threat-safe.

Using self. in functions is not thread-safe. This means that self. is shared by all functions (even though they are running in different threads). Therefore, a statement such as, self.connection = Connection will likely be overwritten when more than one function is invoked and running at the same time.

The better solution is to use Class level variables and only use self. for class function and static functions.

Functions in componentsdir

A function in the componentsdir directory requires a special message destination.

In your componentsdir you can have separate Python files and in these files you can extend the ResilientComponent from Resilient Circuits and create your own functions. In order to run these functions and for Resilient Circuits to register them properly, you need to create an associated message destination called components and then configure those functions to use that message destination.

If such a function is not configured to use the components message destination, users will see errors such as:
<Event[*] ('exception', 'Actions', 'User ad261c1f-f1cc-4115-bbce-a151f88bac5e is not authorized to read from queue://actions.201.components',