mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-12 12:49:13 +02:00
* Defer indicator loading until first use * Load indicators once at the start of a run The lazy property loads indicators wherever they are first read, which in Command.run() is inside the module loop, after init(). For check-androidqf that means the whole acquisition is walked before a missing --iocs file is reported, and the STIX parsing lines land between the module list and the first module. Read the indicators once after the module list is settled, so that a bad --module name still loads nothing, and hand the same object to every module. check-iocs reads them once too, so that a wrong --iocs path is reported even when no stored result matches a module. * Drop two test assertions the change does not need Retrying after a failed indicator load is incidental to the property rather than a requirement, so nothing should pin it. The exact wording of the check-backup rejection belongs to that command's own tests; exit code 1 already shows the path was rejected before indicators were loaded. * Create the output folder and command.log when a run starts Command.__init__ created the --output folder and attached the command.log handler, so `--list-modules -o out` or a rejected target path left an empty folder behind for a run that never happened. Do both at the top of run(), before the module list is resolved so that its warnings still reach the log. The nested commands run by check-androidqf re-attach the handler at the start of their runs, as they did at construction. Lines the CLI logs between construction and run(), such as the target path being checked, no longer reach command.log; info.json records the target path. This is the remaining part of #888. * Cache the indicators with functools.cached_property A property with a setter and a backing attribute does by hand what cached_property does: compute on first read, store the result on the instance, and accept assignment, which is how nested commands receive their parent's indicators. A failed load is still not cached. * Announce the target from the command so that it reaches command.log The CLI logged which backup, filesystem or acquisition it was about to check just before run(), which is now before command.log exists, so the line only reached the console. Each command logs it from init() instead, which runs once the log is attached, and run() logs the module list after init() so that the target still comes first. Nested commands without a target path log nothing, as before. * Log the Android backup path from the typed local mypy cannot determine the type of target_path in this command, which the surrounding lines already silence, so read the announced path from the local that carries the type instead of adding another ignore. --------- Co-authored-by: bitmeta69 <206962233+bitmeta69@users.noreply.github.com> Co-authored-by: besendorf <janik@besendorf.org> Co-authored-by: Donncha Ó Cearbhaill <donncha.ocearbhaill@amnesty.org>
44 lines
1.6 KiB
Python
44 lines
1.6 KiB
Python
# Mobile Verification Toolkit (MVT)
|
|
# Copyright (c) 2021-2023 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 shutil
|
|
|
|
from click.testing import CliRunner
|
|
|
|
from mvt.ios.cli import check_backup
|
|
|
|
from .utils import get_ios_backup_folder
|
|
|
|
|
|
class TestCheckBackupCommand:
|
|
def test_check(self):
|
|
runner = CliRunner()
|
|
path = get_ios_backup_folder()
|
|
result = runner.invoke(check_backup, [path])
|
|
assert result.exit_code == 0
|
|
|
|
def test_check_logs_the_backup_path_to_the_command_log(self, tmp_path):
|
|
path = get_ios_backup_folder()
|
|
output_path = tmp_path / "out"
|
|
result = CliRunner().invoke(check_backup, ["--output", str(output_path), path])
|
|
assert result.exit_code == 0
|
|
command_log = (output_path / "command.log").read_text(encoding="utf-8")
|
|
assert f"Checking iTunes backup located at: {path}" in command_log
|
|
|
|
def test_check_finds_backup_in_subfolder(self, tmp_path, caplog):
|
|
runner = CliRunner()
|
|
backup_path = tmp_path / "MobileSync" / "Backup" / "device-id"
|
|
shutil.copytree(get_ios_backup_folder(), backup_path)
|
|
|
|
result = runner.invoke(check_backup, [str(backup_path.parent)])
|
|
assert result.exit_code == 0
|
|
assert f"Found iTunes backup in subfolder: {backup_path}" in caplog.text
|
|
|
|
def test_check_rejects_non_backup_folder(self, tmp_path, caplog):
|
|
runner = CliRunner()
|
|
result = runner.invoke(check_backup, [str(tmp_path)])
|
|
assert result.exit_code == 1
|
|
assert "does not appear to be an iTunes backup folder" in caplog.text
|