Skip to content

Load installed module packages via entry points - #883

Merged
DonnchaC merged 4 commits into
mainfrom
feature/installed-module-packages
Aug 19, 2026
Merged

Load installed module packages via entry points#883
DonnchaC merged 4 commits into
mainfrom
feature/installed-module-packages

Conversation

@DonnchaC

Copy link
Copy Markdown
Collaborator

Summary

Python packages can already register custom CLI commands which MVT loads automatically through the mvt.ios.cli_plugins and mvt.android.cli_plugins entry-point groups. Custom forensic modules however still have to be loaded explicitly on every invocation, either with --load-module or through the MVT_CUSTOM_MODULES environment variable.

This PR extends the plugin system to modules: packages can register modules in a new mvt.modules entry-point group, and MVT loads them automatically into every module-running check-* command.

[project.entry-points."mvt.modules"]
my-mvt-modules = "my_mvt_modules:get_modules"

An entry point must resolve to an iterable of MVTModule subclasses, or to a callable returning one.

Details

  • load_installed_modules() in mvt/common/module_loader.py discovers and loads the entry points; load_custom_modules() prepends the installed modules ahead of any environment/--load-module paths, with deduplication.
  • Installed modules follow the same rules as other custom modules: they must declare supported_commands, and dependencies are resolved with the standard topological ordering.
  • Mirroring the CLI plugin loader, a broken entry point is skipped with a warning so a faulty package cannot break MVT. Entry points load in a deterministic (sorted) order.
  • Documented in docs/development.md under a new "Installed module packages" section.

Testing

  • New tests cover entry-point loading, broken entry-point handling, and deduplication against path-loaded modules.
  • Full test suite passes: 238 passed, 1 skipped. ruff and mypy clean.

Python packages can already register custom CLI commands which load
automatically, but custom modules still require --load-module or the
MVT_CUSTOM_MODULES environment variable on every invocation.

Add an mvt.modules entry-point group so installed packages can register
forensic modules which load automatically into every module-running
check-* command. An entry point resolves to an iterable of MVTModule
subclasses, or a callable returning one. Broken entry points are
skipped with a warning so a faulty package cannot break MVT.
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Coverage

Tests Skipped Failures Errors Time
255 1 💤 0 ❌ 0 🔥 13.204s ⏱️

Now that installed module packages load automatically, record where every
module came from:

- --list-modules groups the available modules by source, one line per
  source with the modules comma-separated: MVT itself with its version,
  each installed package with its version and VCS commit when recorded
  (PEP 610 direct_url.json), and each --load-module/MVT_CUSTOM_MODULES
  file with its SHA-256 hash.
- Commands log one line per module source with its version or hash and
  the modules loaded from it, so command.log records exactly which
  modules ran and where they came from.
- Make init_logging() idempotent: a loaded module package importing an
  MVT CLI module would previously add a second console handler and
  duplicate every console log line.
Modules loaded from installed packages or file paths live outside the
mvt logger hierarchy, so their log records never reach MVT's console
and file handlers and instead fall through to logging.lastResort:
alerts print as bare unformatted lines and INFO messages are dropped
entirely.

Add get_module_logger() and use it everywhere module loggers are
created. Built-in mvt.* modules keep their existing logger names, and
everything external is parented under a dedicated mvt.ext namespace so
records reach the handlers and external names can never collide with
MVT's internal logger tree. File-path modules are named after their
file (mvt.ext.<stem>) instead of the mangled internal import name.

Document a naming convention for community module packages:
distribute as mvt-plugin-<name> with import package mvt_plugin_<name>,
including the publishing organization in the name. The prefix is
advisory (loading is by entry point, and it is no mark of
authenticity), but conforming packages get a cleaner logger namespace:
the mvt_plugin_ prefix is stripped, so mvt_plugin_amnesty_custom logs
as mvt.ext.amnesty_custom.
@DonnchaC
DonnchaC marked this pull request as ready for review August 19, 2026 21:13
@DonnchaC
DonnchaC merged commit dac4acb into main Aug 19, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant