mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(paths): accept filesystem roots in containment checks
This commit is contained in:
parent
02199b670b
commit
c8cf19e9d7
2 changed files with 25 additions and 3 deletions
|
|
@ -33,7 +33,7 @@ def safe_join(base_dir: str, *parts: str) -> str:
|
|||
raise ValueError("Path contains null byte")
|
||||
base: Final = os.path.realpath(base_dir)
|
||||
resolved: Final = os.path.realpath(os.path.join(base, *parts))
|
||||
if not (resolved.startswith(base + os.sep) or resolved == base):
|
||||
if not (resolved.startswith(os.path.join(base, "")) or resolved == base):
|
||||
raise ValueError(f"Path {resolved!r} escapes base directory {base!r}")
|
||||
return resolved
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ def is_within(path: str, base_dir: str) -> bool:
|
|||
"""True when path, with symlinks resolved, is base_dir or sits inside it."""
|
||||
base: Final = os.path.realpath(base_dir)
|
||||
resolved: Final = os.path.realpath(path)
|
||||
return resolved.startswith(base + os.sep) or resolved == base
|
||||
return resolved.startswith(os.path.join(base, "")) or resolved == base
|
||||
|
||||
|
||||
def join_within(base_dir: str, *parts: str) -> str | None:
|
||||
|
|
@ -65,7 +65,7 @@ def join_within(base_dir: str, *parts: str) -> str | None:
|
|||
return None
|
||||
base: Final = os.path.normpath(os.path.abspath(base_dir))
|
||||
joined: Final = os.path.normpath(os.path.join(base, *parts))
|
||||
if not joined.startswith(base + os.sep):
|
||||
if joined == base or not joined.startswith(os.path.join(base, "")):
|
||||
return None
|
||||
return joined
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,32 @@
|
|||
import os
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.litellm_core_utils.path_utils import is_within, join_within, safe_filename, safe_join, try_safe_join
|
||||
|
||||
|
||||
@pytest.mark.parametrize("join", (safe_join, try_safe_join, join_within))
|
||||
def test_join_accepts_filesystem_root(join: Callable[[str, str], str | None], tmp_path: Path) -> None:
|
||||
root: Final = tmp_path.anchor
|
||||
relative: Final = os.path.relpath(str(tmp_path / "file.yaml"), root)
|
||||
assert join(root, relative) == str(tmp_path / "file.yaml")
|
||||
|
||||
|
||||
def test_is_within_accepts_filesystem_root(tmp_path: Path) -> None:
|
||||
assert is_within(str(tmp_path / "file.yaml"), tmp_path.anchor)
|
||||
assert is_within(tmp_path.anchor, tmp_path.anchor)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("use_root", (True, False))
|
||||
@pytest.mark.parametrize("parts", ((), (".",), ("subdir", "..")))
|
||||
def test_join_within_rejects_base_itself(tmp_path: Path, use_root: bool, parts: tuple[str, ...]) -> None:
|
||||
base: Final = tmp_path.anchor if use_root else str(tmp_path)
|
||||
assert join_within(base, *parts) is None
|
||||
|
||||
|
||||
class TestSafeJoin:
|
||||
def test_normal_path(self, tmp_path):
|
||||
result = safe_join(str(tmp_path), "subdir", "file.yaml")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue