Writing plugins¶
With Canopy 3, we’ve added the ability to use plugins in order to more easily extend functionality within Canopy. We’ve helped users previously write plugins, such as:
Custom tool format parsers, for use in importers (
plugin_type = 'parser'
).Customised finding rating systems (
plugin_type = 'custom-rating'
).XML post-processors for adding custom functions to XML generation for Word reports and/or SoWs (
plugin_type = 'xml-postprocessor'
).
The addition of the plugin system provides a standard interface for adding custom code to your Canopy instance.
Plugins are currently supported using the Python programming language.
Anatomy of a plugin¶
A plugin requires the following fields to ensure it is set up and registered by the plugin loader:
plugin_type = 'custom-rating'
name = 'Example Custom Rating'
The plugin_type
is used to register the type of the plugin. This is
arbitrary, although guidelines (e.g. custom-rating) will be provided
soon. The name registers the plugins name with the plugin system.
Caveats¶
The database cannot be assumed to be available during plugin load time. Therefore no module-level code in the plugin file should perform any action that requires database connectivity, directly or indirectly.
Example: Custom rating plugin¶
The following example shows the implementation of a custom findings rating system for use within Canopy:
from canopy.modules.common.models import Rating
__version__ = '0.0.1'
plugin_type = 'custom-rating'
name = 'Example Custom Rating'
RATINGS_EDITABLE = False
RATINGS = [
['Info', 'Info', 'Info', 'Info', 'Low', 'Low', 'Low', 'Low', 'Medium',
'Medium'],
['Info', 'Info', 'Info', 'Info', 'Low', 'Low', 'Low', 'Medium',
'Medium', 'Medium'],
['Info', 'Info', 'Info', 'Low', 'Low', 'Low', 'Low', 'Medium',
'Medium', 'High'],
['Info', 'Info', 'Info', 'Low', 'Low', 'Low', 'Medium', 'Medium',
'High', 'High'],
['Info', 'Info', 'Low', 'Low', 'Low', 'Medium', 'Medium', 'Medium',
'High', 'High'],
['Info', 'Low', 'Low', 'Low', 'Low', 'Medium', 'Medium', 'Medium',
'High', 'High'],
['Info', 'Low', 'Low', 'Low', 'Medium', 'Medium', 'Medium', 'High',
'High', 'Critical'],
['Low', 'Low', 'Low', 'Medium', 'Medium', 'Medium', 'High', 'High',
'Critical', 'Critical'],
['Low', 'Low', 'Medium', 'Medium', 'Medium', 'Medium', 'High', 'High',
'Critical', 'Critical'],
['Low', 'Low', 'Medium', 'Medium', 'Medium', 'High', 'High',
'Critical', 'Critical', 'Critical'],
]
OVERALL_RATINGS = {
'Info': 1,
'Low': 2,
'Medium': 3,
'High': 4,
'Critical': 5,
}
def calc_rating(finding):
score = 0
rating = finding.rating
custom_fields = {
fv.field.name: fv.value
for fv in finding.custom_fields.prefetch_related('field')
}
impact = int(custom_fields.get('impact', 0))
ease = int(custom_fields.get('ease', 0))
if impact and ease:
rating = Rating.objects.get(type=RATINGS[impact-1][ease-1])
score = OVERALL_RATINGS[RATINGS[impact-1][ease-1]]
return score, rating, None
Installing plugins¶
Once you’re ready to run your plugin, it needs to be installed. For further information on this, see Installing plugins and management commands.
Further improvements¶
The plugin framework will be improved over the coming releases. Identified areas of improvement include:
Making testing and validation of plugins easier.
Define a number of helper functions for certain types of plugins (e.g. markup formatting for tool importers).
User-interface plugins to support customisation of the UI.