Error Handling
Introduction¶
This section covers error handling in PSEngine. While not every module is discussed individually, the error handling concepts are consistent across all modules. The examples below illustrate how to recognize, interpret, and handle errors generated by PSEngine.
The first examples show errors as they appear without handling, followed by examples demonstrating proper error handling.
Examples¶
Warning
The following examples demonstrate how to use this module. Be sure to add appropriate error handling as needed; all possible errors for each method or function are listed in the API Reference page.
Additionally, you must configure the RF_TOKEN
environment variable before getting started. For instructions, see Learn.
1: Handling missing or wrong token¶
In this4: example, we set the RF_TOKEN
environment variable to an empty string before importing psengine
. This is just a workaround to make the example reproducible, to show what happens if you run PSEngine without the variable configured.
The whole exception traceback is:
The ValueError
at the bottom indicates that the API token is missing.
Another instance of ValueError
regarding the token is a first level of validation that PSEngine performs when a token is passed. Recorded Future tokens have 32 alphanumeric characters, all lowercase, from a
to f
and from 0
to 9
. If you pass a token with invalid syntax, PSEngine will error out.
In this case the traceback will be:
Showing that the token provided does not conform to the properties described above.
2: Handling missing token permissions¶
In this example, we perform a lookup of a password using the IdentityMgr
. We removed the Identity module from the token permissions.
After running it, the error we get is:
This is an IdentityLookupError
, which is defined within the identity
module. It shows an HTTP 403 error with the forbidden URL that was called. The fact that it's a 403 and the "Cause: User does not have access to this API" indicates that the token has not been configured properly.
3: Understanding ValidationError
on wrong fields¶
Another common error you might see in PSEngine is the ValidationError
. This can be generated from two locations:
- A method call
- A method return value
The example below shows case 1, where you supply an incorrect parameter. Case 2 is rarer and you cannot do anything to solve it, since it comes from an error during validation of what is sent by the Recorded Future API to PSEngine and can either mean an issue in the Recorded Future API or a bug in PSEngine. In this scenario, raise a support ticket to Recorded Future with the code sample you ran and the error.
The LookupMgr.lookup
method expects as the entity_type
parameter (the second one) a string that must be one of the entity types defined in PSEngine. In this example, we pass an invalid string: an ip address
.
The ValidationError
raised will be:
It has a couple of parts to be aware of:
- The first line tells you the method that raised the error:
LookupMgr.lookup
. - The
2
on the second line indicates the second parameter. - The third line shows all the possible literal values you are allowed to enter.
4: Proper error handling¶
When writing code with PSEngine, it is good practice to surround PSEngine calls with the related error handling. You can find which exception a method will raise in three ways:
- Via the API reference in the "Errors" section of each module.
- Via the API reference in the manager section; in each method there is a "Raises" table showing which exceptions will be raised.
- Via the method docstring. In any editor, you should be able to see a method's docstring if you hover over the method. The docstring shows the exception it will raise.
Generally speaking, the exception names are intuitive. For example, the ClassicAlertMgr.fetch
method raises AlertFetchError
; LookupMgr.lookup
raises EnrichmentLookupError
. The structure of the name is <Functionality><Method>Error
.
Every manager (except for stix2
) will have some scenarios where it raises a ValidationError
.
Given the above, we can write a safe enrichment the following way:
In this example, we first catch any potential ValueError
from the LookupMgr
initialization. If there is a missing token or a wrong token, print a message along with the ve
exception and interrupt the script.
If everything is correct, we start the lookup of entities. In this example, we purposefully show the lookup
of each entity instead of using lookup_bulk
to make the example clearer.
The third entity that we need to enrich has two issues:
- The type of the key is incorrect;
1
should be a string. - The
entity_type
value is incorrect; it should be one of the supportedentity_type
values.
This raises a ValidationError
, but we decide to skip any entity that is not enrichable.
An error with the API or the response raises an EnrichmentLookupError
, which we do not want to ignore; hence we print a message, the exception, and exit with error code 2
. This error code is not required but is useful to understand at what point the script failed.
Lastly, if the entity has been enriched, we print the details. The output should be:
This way, the script does not crash if some scenarios can be handled more gracefully.