Plugin Best Practices
This guide provides best practices for developing ASH plugins.
General Best Practices
- Follow the Plugin Interface: Implement all required methods for your plugin type
- Use Pydantic Models: For configuration and data validation
- Handle Errors Gracefully: Use try/except blocks and provide meaningful error messages
- Document Your Plugin: Add docstrings and comments to explain your plugin's functionality
- Test Thoroughly: Create unit tests for your plugins
- Version Your Plugins: Use semantic versioning for your plugins
- Respect the Plugin Context: Use the provided directories for outputs
- Clean Up After Yourself: Remove temporary files when done
Scanner Plugin Best Practices
- Generate SARIF Reports: SARIF is the standard format for security findings
- Handle Ignore Paths: Skip files that are in the global ignore paths
- Use Subprocess Utilities: Use the provided
_run_subprocess
method for running external commands - Add Metadata: Add useful metadata to the results container
- Support Both File and Directory Scanning: Handle both individual files and directories
Reporter Plugin Best Practices
- Validate Dependencies: Implement the
validate
method to check dependencies - Output to Files: Write reports to the
reports
directory - Return Content: Return the report content as a string
- Use Model Methods: Use the model's helper methods like
to_simple_dict()
andto_flat_vulnerabilities()
- Handle Large Reports: Be mindful of memory usage when generating large reports
Converter Plugin Best Practices
- Preserve Line Numbers: Try to preserve line numbers for better mapping of findings back to original files
- Handle Directories: Support converting both individual files and directories
- Return Paths: Return the path to the converted file or directory
- Skip Unsupported Files: Only convert files with supported extensions
- Maintain File Structure: Preserve the directory structure when converting directories
Plugin Dependencies
You can specify dependencies for your plugins:
from automated_security_helper.base.plugin_dependency import PluginDependency, CustomCommand
from automated_security_helper.plugins.decorators import ash_scanner_plugin
from automated_security_helper.base.scanner_plugin import ScannerPluginBase
@ash_scanner_plugin
class MyCustomScanner(ScannerPluginBase):
name = "my-custom-scanner"
description = "My custom security scanner"
version = "1.0.0"
dependencies = [
PluginDependency(
name="my-scanner-tool",
commands=[
CustomCommand(
platform="linux",
arch="amd64",
command=["pip", "install", "my-scanner-tool"]
),
CustomCommand(
platform="darwin",
arch="amd64",
command=["pip", "install", "my-scanner-tool"]
)
]
)
]
Plugin Event Subscribers
ASH supports event subscribers for reacting to events during the scan process. Event subscribers are registered using the ASH_EVENT_HANDLERS
dictionary pattern:
# my_ash_plugins/__init__.py
from automated_security_helper.plugins.events import AshEventType
def handle_scan_complete(**kwargs):
"""Handle scan complete event"""
scanner = kwargs.get('scanner', 'Unknown')
remaining_count = kwargs.get('remaining_count', 0)
remaining_scanners = kwargs.get('remaining_scanners', [])
print(f"Scanner '{scanner}' completed!")
if remaining_count > 0:
print(f"{remaining_count} scanners remaining: {', '.join(remaining_scanners)}")
else:
print("All scanners completed!")
return True
def handle_report_complete(**kwargs):
"""Handle report complete event"""
phase = kwargs.get('phase', 'Unknown')
print(f"Report phase '{phase}' completed!")
return True
# Event callback registry following the same pattern as ASH_SCANNERS, ASH_REPORTERS, etc.
ASH_EVENT_HANDLERS = {
AshEventType.SCAN_COMPLETE: [handle_scan_complete],
AshEventType.REPORT_COMPLETE: [handle_report_complete],
}
Available Event Types
AshEventType.SCAN_START
: Fired when the scan phase beginsAshEventType.SCAN_COMPLETE
: Fired when each individual scanner completesAshEventType.CONVERT_START
: Fired when the convert phase beginsAshEventType.CONVERT_COMPLETE
: Fired when the convert phase completesAshEventType.REPORT_START
: Fired when the report phase beginsAshEventType.REPORT_COMPLETE
: Fired when the report phase completesAshEventType.ERROR
: Fired when errors occurAshEventType.WARNING
: Fired for warning conditionsAshEventType.INFO
: Fired for informational events
Event Data
Event subscribers receive keyword arguments with relevant data. For example, SCAN_COMPLETE
events include:
scanner
: Name of the completed scannercompleted_count
: Number of scanners completed so fartotal_count
: Total number of scannersremaining_count
: Number of scanners still runningremaining_scanners
: List of remaining scanner namesmessage
: Human-readable summary messagephase
: The phase name ("scan")plugin_context
: The current plugin context
Common Pitfalls
- Not Handling Errors: Always catch and handle exceptions to prevent the entire scan from failing
- Ignoring Configuration: Always respect the plugin configuration options
- Hard-coding Paths: Use the paths provided in the plugin context
- Not Validating Dependencies: Always check that required dependencies are available
- Returning Incorrect Types: Make sure to return the expected types from plugin methods
Security Considerations
- Validate User Input: Never trust user input without validation
- Avoid Shell Injection: Use lists for subprocess commands instead of strings
- Handle Secrets Securely: Never log or expose sensitive information
- Limit Resource Usage: Be mindful of memory and CPU usage
- Clean Up Temporary Files: Always clean up temporary files after use