mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-03 00:21:07 +02:00
Plugin packages need somewhere to keep their own settings, but MVT rewrites its config.yaml with only the fields it knows about, so any foreign section is dropped. Add MVTPluginSettings, a pydantic-settings base class that gives each plugin its own file under the MVT config folder and its own MVT_PLUGIN_<NAME>_ environment variable namespace. Settings resolve from constructor arguments, then the environment, then the plugin file, then the field defaults. Saving skips the values the environment currently supplies, so credentials passed as environment variables are not copied to disk, and writes through a private temporary file so a settings file is never partially written or briefly readable by other users.
112 lines
3.4 KiB
Markdown
112 lines
3.4 KiB
Markdown
# Custom CLI Commands
|
|
|
|
MVT can load additional top-level commands into `mvt-ios` and `mvt-android`.
|
|
Custom commands are different from [custom forensic modules](index.md#custom-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`:
|
|
|
|
```python
|
|
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:
|
|
|
|
```toml
|
|
[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:
|
|
|
|
```bash
|
|
mvt-ios summarize ./ios-backup
|
|
mvt-android summarize ./androidqf-output
|
|
```
|
|
|
|
For a `pipx` installation of MVT, inject the plugin into MVT's environment:
|
|
|
|
```bash
|
|
pipx inject mvt my-mvt-plugin
|
|
```
|
|
|
|
When MVT is installed in an active virtual environment, install the plugin with
|
|
`pip` in that environment.
|
|
|
|
Command packages that need their own settings, such as an API key, should store
|
|
them in a namespaced [plugin configuration file](plugin_configuration.md)
|
|
rather than in MVT's own `config.yaml`.
|
|
|
|
## Load a Command File
|
|
|
|
For local commands that are not packaged, create a Python file that exports one
|
|
Click command or group named `cli`:
|
|
|
|
```python
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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`.
|