Files
mvt/tests/common/test_cmd_check_iocs.py
Donncha Ó Cearbhaill 1b163749b2 Pin that check-iocs re-checks the results of custom modules
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.
2026-08-26 13:52:10 +02:00

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