From a6639ba405081b7748e5a30d216ec71a9e1ffac0 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Thu, 2 Oct 2025 16:33:26 -0500 Subject: [PATCH] windows compatibility fixes --- src/core/platform_tools.py | 5 ++++- tests/core/test_file_transfer.py | 28 ++++++++++++++++------------ tests/utils/test_security_utils.py | 4 +++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/core/platform_tools.py b/src/core/platform_tools.py index a42c85c..98cef9b 100644 --- a/src/core/platform_tools.py +++ b/src/core/platform_tools.py @@ -132,8 +132,11 @@ def ensure_platform_tools_in_user_dir(version_tag: Optional[str] = "latest") -> # Check for path traversal in zip entries for info in zf.infolist(): # Normalize the path and ensure it doesn't escape + # Use realpath to resolve any symlinks and get absolute path normalized = os.path.normpath(os.path.join(tmp_dir, info.filename)) - if not normalized.startswith(tmp_dir): + # On Windows, tmp_dir might not have a trailing separator, so add it + tmp_dir_with_sep = tmp_dir if tmp_dir.endswith(os.sep) else tmp_dir + os.sep + if not (normalized.startswith(tmp_dir_with_sep) or normalized == tmp_dir): raise RuntimeError(f"Zip contains path traversal: {info.filename}") zf.extractall(tmp_dir) diff --git a/tests/core/test_file_transfer.py b/tests/core/test_file_transfer.py index 8e6c557..f507680 100644 --- a/tests/core/test_file_transfer.py +++ b/tests/core/test_file_transfer.py @@ -43,12 +43,13 @@ class TestADBFileTransfer: mock_runner = MagicMock() mock_runner.run_adb_command.return_value = ("", "", 0) mock_command_runner.return_value = mock_runner - + transfer = ADBFileTransfer() result = transfer.pull_file("/sdcard/test.txt", "/local/test.txt") - + assert result is True - expected_local_path = os.path.normpath('/local/test.txt') + # sanitize_local_path converts to absolute path, so we need to match that + expected_local_path = os.path.abspath(os.path.normpath('/local/test.txt')) mock_runner.run_adb_command.assert_called_with(['pull', '/sdcard/test.txt', expected_local_path]) @patch('src.core.file_transfer.ADBCommandRunner') @@ -89,12 +90,13 @@ class TestADBFileTransfer: mock_runner = MagicMock() mock_runner.run_adb_command.return_value = ("", "", 0) mock_command_runner.return_value = mock_runner - + transfer = ADBFileTransfer() result = transfer.push_file("/local/test.txt", "/sdcard/test.txt") - + assert result is True - expected_local_path = os.path.normpath('/local/test.txt') + # sanitize_local_path converts to absolute path + expected_local_path = os.path.abspath(os.path.normpath('/local/test.txt')) mock_runner.run_adb_command.assert_called_with(['push', expected_local_path, '/sdcard/test.txt']) @patch('src.core.file_transfer.ADBCommandRunner') @@ -137,12 +139,13 @@ class TestADBFileTransfer: mock_runner = MagicMock() mock_runner.run_adb_command.return_value = ("", "", 0) mock_command_runner.return_value = mock_runner - + transfer = ADBFileTransfer() result = transfer.pull_folder("/sdcard/Documents", "/local/Documents") - + assert result is True - expected_local_path = os.path.normpath('/local/Documents') + # sanitize_local_path converts to absolute path + expected_local_path = os.path.abspath(os.path.normpath('/local/Documents')) mock_runner.run_adb_command.assert_called_with(['pull', '/sdcard/Documents', expected_local_path]) @patch('src.core.file_transfer.ADBCommandRunner') @@ -169,12 +172,13 @@ class TestADBFileTransfer: mock_runner = MagicMock() mock_runner.run_adb_command.return_value = ("", "", 0) mock_command_runner.return_value = mock_runner - + transfer = ADBFileTransfer() result = transfer.push_folder("/local/Documents", "/sdcard/Documents") - + assert result is True - expected_local_path = os.path.normpath('/local/Documents') + # sanitize_local_path converts to absolute path + expected_local_path = os.path.abspath(os.path.normpath('/local/Documents')) mock_runner.run_adb_command.assert_called_with(['push', expected_local_path, '/sdcard/Documents']) @patch('src.core.file_transfer.ADBCommandRunner') diff --git a/tests/utils/test_security_utils.py b/tests/utils/test_security_utils.py index 51ac65a..c46bff7 100644 --- a/tests/utils/test_security_utils.py +++ b/tests/utils/test_security_utils.py @@ -120,7 +120,9 @@ class TestSanitizeLocalPath: """Test that paths within base_dir are accepted.""" base = "/tmp/safe" result = sanitize_local_path("/tmp/safe/subdir", base_dir=base) - assert result.startswith(base) + # result is an absolute path, so we need to compare absolute versions + base_abs = os.path.abspath(base) + assert result.startswith(base_abs) def test_path_normalization(self): """Test that paths with .. are normalized."""