Feature Category
Related issue #36
Describe the problem
Plugins don't identify themselves in Malwarecage. They doesn't inform about the status and plugin version.
Plugin can deliver both backend and frontend extension. Some plugins are frontend-only. Frontend extensions are built into the frontend bundle at compile time. Backend extensions are loaded run-time.
Backend plugin entrypoint (__init__.py
) usually looks like this:
from plugin_engine import PluginAppContext
from .resources import MQueryResource
from .schema import MQueryYaraJobSchema
def entrypoint(app_context: PluginAppContext):
# Initialization code which also could be "first installation" code
app_context.register_resource(MQueryResource, "/mquery/search")
app_context.register_schema_spec("MQueryYaraJobSchema", MQueryYaraJobSchema)
...
__plugin_entrypoint__ = entrypoint
Describe the solution you'd like
Plugin should provide its author/version/docstring information via module-level dunder names (__author__
, __version__
and __doc__
like in __plugin_entrypoint__
case)
"""MQuery integration plugin"""
from plugin_engine import PluginAppContext
from .resources import MQueryResource
from .schema import MQueryYaraJobSchema
__author__ = "CERT Polska"
__version__ = "1.0.0"
def entrypoint(app_context: PluginAppContext):
# Initialization code which also could be "first installation" code
app_context.register_resource(MQueryResource, "/mquery/search")
app_context.register_schema_spec("MQueryYaraJobSchema", MQueryYaraJobSchema)
...
__plugin_entrypoint__ = entrypoint
Frontend-only plugins should also deliver the information stub in __init__.py
(e.g. plugins/certInfo/__init__.py
customizing the logo and adding our Terms of Service)
"""mwdb.cert.pl logo and Terms of Service plugin"""
__author__ = "CERT Polska"
__version__ = "1.0.0"
It means that __init__.py
is now mandatory and __plugin_entrypoint__
is optional
These information should be gathered by backend plugin loader plugin_engine.load_plugins
https://github.com/CERT-Polska/malwarecage/blob/master/plugin_engine.py#L97 and exposed via global dictionary plugin_engine.loaded_plugins
(due to current code structure it would be difficult to expose it other way, good topic for future code refactor)
loaded_plugins = {
"<module name>": {
"active": bool
"author":
"description":
"version": ...
}
}
When __author__
, __description__
or __version__
is missing, None should be placed instead.
When plugin is successfully loaded, active
should be set to True
. False
otherwise. The reason of inactivity should stay visible only in logs (the most common case will be probably a lack of configuration).
Complete plugin information (from plugin_engine.loaded_plugins
should be exposed via /server
endpoint (ServerInfoResource
, https://github.com/CERT-Polska/malwarecage/blob/master/resources/server.py#L28)
The plugin information should be exposed in web app's /about
view under the banner.
![image](https://user-images.githubusercontent.com/8720367/86149721-a7534a80-bafc-11ea-8a28-ecca470abcd0.png)
Keep in mind that /server
is already loaded into the Redux state as "client-side config" (https://github.com/CERT-Polska/malwarecage/blob/master/malwarefront/src/commons/config/config.js) and used to fetch Malwarecage version.
https://github.com/CERT-Polska/malwarecage/blob/20d4b2a25345d22ce10a2b0a336dcf8d43036159/malwarefront/src/components/About.js#L31-L37