Files
wehub-resource-sync 25576b0be6
Checks (magui2.0) / python-lint (push) Failing after 1s
Checks (magui2.0) / python-test (push) Failing after 0s
Checks (magui2.0) / frontend-lint (push) Failing after 0s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
Checks (magui2.0) / python-format (push) Failing after 1s
CodeQL Advanced / Analyze (python) (push) Failing after 0s
Checks (magui2.0) / python-pyright (push) Failing after 1s
Checks (magui2.0) / frontend-format (push) Failing after 1s
Checks (magui2.0) / frontend-typecheck (push) Failing after 0s
Checks (magui2.0) / frontend-test (push) Failing after 2s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:24:32 +08:00

86 lines
3.1 KiB
Python

"""Tests for filesystem route path validation."""
from pathlib import Path
from unittest.mock import patch
import pytest
from fastapi import HTTPException
from magentic_ui.backend.web.routes.filesystem import _resolve_path
@pytest.fixture(autouse=True)
def _mock_home(tmp_path: Path):
"""Mock get_home to return a temp directory for safe testing."""
# Create some test directories
(tmp_path / "Documents").mkdir()
(tmp_path / "Documents" / "project").mkdir()
(tmp_path / "Desktop").mkdir()
with patch(
"magentic_ui.backend.web.routes.filesystem.get_home",
return_value=tmp_path,
):
yield tmp_path
class TestResolvePath:
"""Tests for _resolve_path — validates and resolves filesystem paths."""
def test_valid_subdirectory(self, _mock_home: Path):
result = _resolve_path(str(_mock_home / "Documents"))
assert result == _mock_home / "Documents"
def test_nested_subdirectory(self, _mock_home: Path):
result = _resolve_path(str(_mock_home / "Documents" / "project"))
assert result == _mock_home / "Documents" / "project"
def test_home_itself(self, _mock_home: Path):
result = _resolve_path(str(_mock_home))
assert result == _mock_home
def test_rejects_path_traversal(self, _mock_home: Path):
with pytest.raises(HTTPException) as exc_info:
_resolve_path(str(_mock_home / ".." / "etc"))
assert exc_info.value.status_code == 403
def test_rejects_path_outside_home(self):
with pytest.raises(HTTPException) as exc_info:
_resolve_path("/etc/passwd")
assert exc_info.value.status_code == 403
def test_rejects_empty_path(self):
with pytest.raises(HTTPException) as exc_info:
_resolve_path("")
assert exc_info.value.status_code == 400
def test_rejects_null_bytes(self, _mock_home: Path):
with pytest.raises(HTTPException) as exc_info:
_resolve_path(str(_mock_home) + "/foo\x00bar")
assert exc_info.value.status_code == 400
def test_rejects_nonexistent_path(self, _mock_home: Path):
with pytest.raises(HTTPException) as exc_info:
_resolve_path(str(_mock_home / "nonexistent"))
assert exc_info.value.status_code == 404
def test_rejects_file_not_directory(self, _mock_home: Path):
(file := _mock_home / "file.txt").write_text("hello")
with pytest.raises(HTTPException) as exc_info:
_resolve_path(str(file))
assert exc_info.value.status_code == 400
def test_symlink_within_home(self, _mock_home: Path):
link = _mock_home / "link_to_docs"
link.symlink_to(_mock_home / "Documents")
result = _resolve_path(str(link))
assert result == _mock_home / "Documents"
def test_symlink_escaping_home(self, _mock_home: Path, tmp_path_factory):
outside = tmp_path_factory.mktemp("outside")
link = _mock_home / "escape"
link.symlink_to(outside)
with pytest.raises(HTTPException) as exc_info:
_resolve_path(str(link))
assert exc_info.value.status_code == 403