Validate iOS backup path before checks (#825)

* Validate iOS backup path before checks

* Fix iOS backup path mypy typing

* Fix custom module test backup fixture
This commit is contained in:
besendorf
2026-07-14 21:58:46 +02:00
committed by GitHub
parent f5b0a3cd91
commit 1532578b39
4 changed files with 71 additions and 1 deletions
+4 -1
View File
@@ -323,7 +323,10 @@ def check_backup(
cmd.list_modules()
return
log.info("Checking iTunes backup located at: %s", backup_path)
if not cmd.resolve_backup_path():
ctx.exit(1)
log.info("Checking iTunes backup located at: %s", cmd.target_path)
cmd.run()
cmd.show_alerts_brief()
+48
View File
@@ -4,6 +4,7 @@
# https://license.mvt.re/1.1/
import logging
import os
from typing import Optional
from mvt.common.command import Command
@@ -16,6 +17,12 @@ from .modules.mixed import MIXED_MODULES
log = logging.getLogger(__name__)
def is_ios_backup_folder(path: str) -> bool:
return os.path.isfile(os.path.join(path, "Manifest.db")) and os.path.isfile(
os.path.join(path, "Info.plist")
)
class CmdIOSCheckBackup(Command):
def __init__(
self,
@@ -52,5 +59,46 @@ class CmdIOSCheckBackup(Command):
self.name = "check-backup"
self.modules = BACKUP_MODULES + MIXED_MODULES
def resolve_backup_path(self) -> bool:
target_path = getattr(self, "target_path", None)
if not isinstance(target_path, str) or not target_path:
return False
if is_ios_backup_folder(target_path):
return True
if not os.path.isdir(target_path):
self.log.critical(
"%s does not appear to be an iTunes backup folder. "
"Expected Manifest.db and Info.plist.",
target_path,
)
return False
candidates = []
for entry_name in sorted(os.listdir(target_path)):
entry_path = os.path.join(target_path, entry_name)
if os.path.isdir(entry_path) and is_ios_backup_folder(entry_path):
candidates.append(entry_path)
if len(candidates) == 1:
self.log.info("Found iTunes backup in subfolder: %s", candidates[0])
self.target_path = candidates[0]
return True
if candidates:
self.log.critical(
"Found multiple iTunes backups in %s. Please specify one backup folder.",
target_path,
)
return False
self.log.critical(
"%s does not appear to be an iTunes backup folder. "
"Expected Manifest.db and Info.plist.",
target_path,
)
return False
def module_init(self, module):
module.is_backup = True
+17
View File
@@ -3,6 +3,8 @@
# 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
@@ -16,3 +18,18 @@ class TestCheckBackupCommand:
path = get_ios_backup_folder()
result = runner.invoke(check_backup, [path])
assert result.exit_code == 0
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
+2
View File
@@ -63,6 +63,8 @@ def test_load_module_appears_only_for_supported_cli_command(tmp_path):
def test_module_option_runs_supported_custom_module(tmp_path):
(tmp_path / "Manifest.db").touch()
(tmp_path / "Info.plist").touch()
module_path = _write_custom_module(
tmp_path / "custom.py",
"CustomRunModule",