mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-03 16:41:05 +02:00
check-iocs takes its custom modules from load_custom_modules() like every check-* command and matches result files to modules by slug, so a plugin module's stored results are re-checked whenever it declares the check-iocs pair of its platform; nothing asserted it.
140 lines
4.2 KiB
Python
140 lines
4.2 KiB
Python
# Mobile Verification Toolkit (MVT)
|
|
# Copyright (c) 2021-2026 The MVT Authors.
|
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
|
# https://license.mvt.re/1.1/
|
|
|
|
import json
|
|
import logging
|
|
|
|
import pytest
|
|
from click.testing import CliRunner
|
|
|
|
from mvt.android.cli import cli as android_cli
|
|
from mvt.android.command_modules import ANDROID_CHECK_IOCS_MODULES
|
|
from mvt.common.cmd_check_iocs import CmdCheckIOCS
|
|
from mvt.common.module import MVTModule
|
|
from mvt.ios.cli import cli as ios_cli
|
|
from mvt.ios.command_modules import IOS_CHECK_IOCS_MODULES
|
|
|
|
# Keep the banner of the group callback from checking for updates online.
|
|
OFFLINE = ["--disable-update-check", "--disable-indicator-update-check"]
|
|
|
|
|
|
class CustomResultsModule(MVTModule):
|
|
"""A custom module which declares the check-iocs pair of both platforms."""
|
|
|
|
slug = "custom_results"
|
|
supported_commands = (
|
|
("ios", "check-backup"),
|
|
("ios", "check-iocs"),
|
|
("android", "check-iocs"),
|
|
)
|
|
|
|
checked: list = []
|
|
|
|
def run(self) -> None:
|
|
pass
|
|
|
|
def check_indicators(self) -> None:
|
|
self.checked.append(list(self.results))
|
|
|
|
|
|
class BackupOnlyModule(MVTModule):
|
|
"""A custom module which does not declare check-iocs."""
|
|
|
|
slug = "backup_only"
|
|
supported_commands = (("ios", "check-backup"),)
|
|
|
|
def check_indicators(self) -> None:
|
|
raise AssertionError("must not be re-checked")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"platform, builtin_modules",
|
|
[("ios", IOS_CHECK_IOCS_MODULES), ("android", ANDROID_CHECK_IOCS_MODULES)],
|
|
)
|
|
def test_check_iocs_rechecks_the_stored_results_of_custom_modules(
|
|
platform, builtin_modules, tmp_path, caplog
|
|
):
|
|
# check-iocs matches every <slug>.json in the results folder to the module
|
|
# with that slug, custom modules included, and runs its check_indicators()
|
|
# again over the stored results.
|
|
results = [{"domain": "example.org"}]
|
|
(tmp_path / "custom_results.json").write_text(json.dumps(results))
|
|
(tmp_path / "backup_only.json").write_text(json.dumps(results))
|
|
CustomResultsModule.checked.clear()
|
|
|
|
cmd = CmdCheckIOCS(
|
|
target_path=str(tmp_path),
|
|
custom_modules=[CustomResultsModule, BackupOnlyModule],
|
|
platform=platform,
|
|
)
|
|
cmd.modules = builtin_modules
|
|
|
|
with caplog.at_level(logging.INFO):
|
|
cmd.run()
|
|
|
|
assert CustomResultsModule.checked == [results]
|
|
assert (
|
|
'Loading results from "custom_results.json" with module CustomResultsModule'
|
|
in caplog.text
|
|
)
|
|
# A module declaring only check-backup is not part of check-iocs.
|
|
assert "backup_only.json" not in caplog.text
|
|
|
|
|
|
def test_check_iocs_lists_custom_modules_declaring_the_command(caplog):
|
|
cmd = CmdCheckIOCS(
|
|
custom_modules=[CustomResultsModule, BackupOnlyModule],
|
|
platform="ios",
|
|
)
|
|
cmd.modules = IOS_CHECK_IOCS_MODULES
|
|
|
|
with caplog.at_level(logging.INFO):
|
|
cmd.list_modules()
|
|
|
|
assert "CustomResultsModule" in caplog.text
|
|
assert "BackupOnlyModule" not in caplog.text
|
|
|
|
|
|
LOADED_MODULE = '''
|
|
from mvt.common.module import MVTModule
|
|
|
|
|
|
class LoadedResultsModule(MVTModule):
|
|
"""A module loaded from a file with --load-module."""
|
|
|
|
slug = "loaded_results"
|
|
supported_commands = (("ios", "check-iocs"), ("android", "check-iocs"))
|
|
|
|
def run(self) -> None:
|
|
pass
|
|
|
|
def check_indicators(self) -> None:
|
|
self.log.warning("loaded module checked %d results", len(self.results))
|
|
'''
|
|
|
|
|
|
@pytest.mark.parametrize("cli", [ios_cli, android_cli], ids=["mvt-ios", "mvt-android"])
|
|
def test_check_iocs_loads_custom_modules_from_a_file_on_each_cli(cli, tmp_path, caplog):
|
|
module_path = tmp_path / "loaded_module.py"
|
|
module_path.write_text(LOADED_MODULE)
|
|
results_folder = tmp_path / "results"
|
|
results_folder.mkdir()
|
|
(results_folder / "loaded_results.json").write_text(json.dumps([{"a": 1}]))
|
|
|
|
with caplog.at_level(logging.INFO):
|
|
result = CliRunner().invoke(
|
|
cli,
|
|
[
|
|
*OFFLINE,
|
|
"check-iocs",
|
|
"--load-module",
|
|
str(module_path),
|
|
str(results_folder),
|
|
],
|
|
)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert "loaded module checked 1 results" in caplog.text
|