Custom CLI Commands
MVT can load additional top-level commands into mvt-ios and mvt-android.
Custom commands are different from custom forensic modules:
commands add new CLI operations, while modules add analysis steps to existing
check-* commands.
Warning
Custom commands run as trusted Python code inside the MVT process. Install or load commands only from sources you trust. MVT does not sandbox third-party commands, and the MVT maintainers do not maintain them.
Install a Command Package
Python packages can register a Click command or group for either MVT CLI. A
minimal package can expose this command from my_mvt_plugin.py:
import click
@click.command()
@click.argument("path", type=click.Path(exists=True))
def summarize(path):
"""Summarize an acquisition."""
click.echo(f"Summarizing {path}")
Register the object in the package's pyproject.toml. The entry-point name is
the command users invoke:
[project.entry-points."mvt.ios.cli_plugins"]
summarize = "my_mvt_plugin:summarize"
[project.entry-points."mvt.android.cli_plugins"]
summarize = "my_mvt_plugin:summarize"
Use only the iOS or Android group if the command is platform-specific. After installing the package in the same environment as MVT, it appears directly in the appropriate CLI:
mvt-ios summarize ./ios-backup
mvt-android summarize ./androidqf-output
For a pipx installation of MVT, inject the plugin into MVT's environment:
pipx inject mvt my-mvt-plugin
When MVT is installed in an active virtual environment, install the plugin with
pip in that environment.
Load a Command File
For local commands that are not packaged, create a Python file that exports one
Click command or group named cli:
import click
@click.command("case-summary")
@click.argument("path", type=click.Path(exists=True))
def cli(path):
"""Summarize a case directory."""
click.echo(f"Summarizing {path}")
Pass the file before the custom command name:
mvt-ios --load-command ./case_summary.py case-summary ./ios-backup
--load-command can be repeated and also accepts a folder. MVT loads
non-hidden top-level *.py files in sorted order and skips __init__.py.
Every loaded file must export one cli object.
To load a file or folder on every invocation, set the platform-specific environment variable:
export MVT_IOS_CUSTOM_COMMANDS=./ios_commands
export MVT_ANDROID_CUSTOM_COMMANDS=./android_commands
Naming and Errors
Built-in MVT commands cannot be replaced. External command names must also be
unique; when installed packages or environment paths collide, MVT keeps the
first command and logs a warning. A collision from an explicit
--load-command is a usage error.
A package entry point or environment command that cannot be imported appears
as a marked broken command without preventing other MVT commands from working.
Invoke that command to see its package or file source and the underlying error.
An invalid command supplied explicitly with --load-command fails immediately
with a usage error.
Installed command packages use the entry-point name as the CLI command name.
The entry point must resolve to a click.Command or click.Group.