87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
import os
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
from services.temp_file_service import TEMP_FILE_SERVICE
|
|
|
|
|
|
@pytest.fixture
|
|
def managed_temp_dir(tmp_path, monkeypatch):
|
|
managed_dir = tmp_path / "presenton-temp"
|
|
managed_dir.mkdir()
|
|
monkeypatch.setattr(TEMP_FILE_SERVICE, "base_dir", str(managed_dir))
|
|
return managed_dir
|
|
|
|
|
|
def test_create_temp_file_path_uses_safe_basename(managed_temp_dir):
|
|
upload_dir = TEMP_FILE_SERVICE.create_temp_dir("upload-case")
|
|
|
|
created_path = TEMP_FILE_SERVICE.create_temp_file_path(
|
|
"../../etc/passwd", upload_dir
|
|
)
|
|
|
|
assert created_path == os.path.join(upload_dir, "passwd")
|
|
assert os.path.commonpath([created_path, str(managed_temp_dir)]) == str(
|
|
managed_temp_dir
|
|
)
|
|
|
|
|
|
def test_resolve_temp_path_rejects_paths_outside_managed_temp_dir(
|
|
managed_temp_dir, tmp_path
|
|
):
|
|
outside_file = tmp_path / "outside.txt"
|
|
outside_file.write_text("secret", encoding="utf-8")
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
TEMP_FILE_SERVICE.resolve_temp_path(str(outside_file), must_exist=True)
|
|
|
|
assert exc.value.status_code == 400
|
|
assert "temp directory" in exc.value.detail
|
|
|
|
|
|
def test_resolve_temp_path_rejects_symlink_escape(managed_temp_dir, tmp_path):
|
|
outside_file = tmp_path / "outside.txt"
|
|
outside_file.write_text("secret", encoding="utf-8")
|
|
symlink_path = managed_temp_dir / "linked-secret.txt"
|
|
|
|
try:
|
|
symlink_path.symlink_to(outside_file)
|
|
except OSError:
|
|
pytest.skip("symlinks are not available on this platform")
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
TEMP_FILE_SERVICE.resolve_temp_path(str(symlink_path), must_exist=True)
|
|
|
|
assert exc.value.status_code == 400
|
|
assert "temp directory" in exc.value.detail
|
|
|
|
|
|
def test_resolve_temp_path_accepts_symlinked_parent_of_managed_dir(
|
|
managed_temp_dir, tmp_path, monkeypatch
|
|
):
|
|
linked_parent = tmp_path / "linked-parent"
|
|
|
|
try:
|
|
linked_parent.symlink_to(managed_temp_dir.parent, target_is_directory=True)
|
|
except OSError:
|
|
pytest.skip("symlinks are not available on this platform")
|
|
|
|
linked_managed_dir = linked_parent / managed_temp_dir.name
|
|
temp_file = managed_temp_dir / "inside.txt"
|
|
temp_file.write_text("content", encoding="utf-8")
|
|
monkeypatch.setattr(TEMP_FILE_SERVICE, "base_dir", str(linked_managed_dir))
|
|
|
|
assert TEMP_FILE_SERVICE.resolve_temp_path(
|
|
str(linked_managed_dir / temp_file.name), must_exist=True
|
|
) == str(temp_file)
|
|
|
|
|
|
def test_resolve_temp_path_requires_existing_path(managed_temp_dir):
|
|
missing_file = managed_temp_dir / "missing.txt"
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
TEMP_FILE_SERVICE.resolve_temp_path(str(missing_file), must_exist=True)
|
|
|
|
assert exc.value.status_code == 404
|