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.
Error handling
Any Exception that is raised in your AppFunctionComponent code, is excepted by the Resilient® Circuits framework, which then sends the error back to the SOAR Platform. The error can be viewed in the Action Status.
To raise your own custom error, use resilient-lib’s IntegrationError: https://ibmresilient.github.io/resilient-python-api/pages/resilient-lib/resilient-lib.html#resilient_lib.components.in[…]ion_errors.IntegrationError.
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.
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.
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
- Create a new incident custom field as a text area with Rich Text enabled.
- Add it to the summary section of an incident's layout.
- 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.
<Event[*] ('exception', 'Actions', 'User ad261c1f-f1cc-4115-bbce-a151f88bac5e is not authorized to read from queue://actions.201.components',