Files
cleveragents-core/tests/test_file_tools_security.py
HAL9000 d646288142
CI / push-validation (pull_request) Successful in 34s
CI / helm (pull_request) Successful in 37s
CI / build (pull_request) Successful in 48s
CI / lint (pull_request) Successful in 1m8s
CI / typecheck (pull_request) Successful in 1m14s
CI / quality (pull_request) Successful in 1m7s
CI / security (pull_request) Successful in 1m15s
CI / integration_tests (pull_request) Successful in 3m7s
CI / unit_tests (pull_request) Successful in 4m54s
CI / docker (pull_request) Successful in 1m26s
CI / coverage (pull_request) Successful in 11m59s
CI / status-check (pull_request) Successful in 3s
fix(lint): replace EN DASH with hyphen-minus in comment; apply ruff format
2026-05-28 00:24:29 -04:00

147 lines
5.9 KiB
Python

"""Tests for ``validate_path`` security fixes.
Covers:
- Absolute path rejection (pathlib ``/`` join bypass)
- Path traversal via ``..`` components
- Empty and whitespace-only paths
- Valid relative paths continue to function normally
"""
from __future__ import annotations
import tempfile
from pathlib import Path
import pytest
class ValidatePathTests:
"""Security-focused tests for the ``validate_path`` function."""
@staticmethod
def _make_sandbox() -> str:
"""Create a temporary sandbox directory and return its path."""
return tempfile.mkdtemp()
# ------------------------------------------------------------------
# Absolute path rejection (CVE-style bypass prevention)
# ------------------------------------------------------------------
def test_absolute_leading_slash_rejected(self):
"""An absolute path like ``/etc/passwd`` must be rejected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Absolute paths"):
validate_path("/etc/passwd", sandbox_root=sandbox)
def test_absolute_slash_only_rejected(self):
"""Root path ``/`` is absolute and must be rejected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Absolute paths"):
validate_path("/", sandbox_root=sandbox)
def test_absolute_nested_rejected(self):
"""A deeply nested absolute path must be rejected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Absolute paths"):
validate_path("/var/lib/../../etc/shadow", sandbox_root=sandbox)
def test_absolute_double_slash_rejected(self):
"""Paths starting with ``//`` are treated as absolute."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Absolute paths"):
validate_path("//etc/passwd", sandbox_root=sandbox)
# ------------------------------------------------------------------
# Path traversal via ``..`` components
# ------------------------------------------------------------------
def test_double_dot_traversal_rejected(self):
"""A single ``..`` at the top level escapes the sandbox."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Path traversal"):
validate_path("../outside", sandbox_root=sandbox)
def test_double_dot_traversal_multiple_rejected(self):
"""Multiple ``..`` components that escape the sandbox are rejected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Path traversal"):
validate_path("../../../etc/passwd", sandbox_root=sandbox)
def test_traversal_inside_subdirs_rejected(self):
"""Traversal after entering a subdirectory is detected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
# First go into a subdir, then escape up twice (exceeds root)
with pytest.raises(ValueError, match="Path traversal"):
validate_path("a/b/../../..", sandbox_root=sandbox)
def test_double_dot_last_component_rejected(self):
"""A path ending in ``..`` that escapes root is rejected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Path traversal"):
validate_path("..", sandbox_root=sandbox)
# ------------------------------------------------------------------
# Empty and whitespace handling
# ------------------------------------------------------------------
def test_empty_string_rejected(self):
"""An empty path string must be rejected."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
with pytest.raises(ValueError, match="Empty file path"):
validate_path("", sandbox_root=sandbox)
# ------------------------------------------------------------------
# Valid relative paths still work
# ------------------------------------------------------------------
def test_simple_relative_file_accepted(self):
"""A normal relative path inside the sandbox is accepted."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
result = validate_path("myfile.txt", sandbox_root=sandbox)
assert str(result).startswith(sandbox)
def test_nested_relative_accepted(self):
"""A nested relative path inside the sandbox is accepted."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
result = validate_path("subdir/nested/file.txt", sandbox_root=sandbox)
assert str(result).startswith(sandbox)
def test_dot_self_reference_accepted(self):
"""``./`` prefix paths are accepted as valid relative paths."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
result = validate_path("./myfile.txt", sandbox_root=sandbox)
assert str(result).startswith(sandbox)
def test_traversal_within_sandbox_accepted(self):
"""``..`` components that stay inside the sandbox are valid."""
from cleveragents.tool.builtins.file_tools import validate_path
sandbox = self._make_sandbox()
# Go into a subdir and back out stays within root
result = validate_path("subdir/..", sandbox_root=sandbox)
assert str(result).startswith(sandbox)