eigent/backend/tests/app/component/test_environment.py
bytecii 9c396ee015
tests: fix and refactor tests (#1262)
Co-authored-by: bytecii <bytecii@users.noreply.github.com>
Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com>
2026-02-13 23:16:14 -08:00

187 lines
6.3 KiB
Python

# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import os
import tempfile
from pathlib import Path
import pytest
from app.component.environment import env_base_dir, sanitize_env_path
def test_none_input_returns_none():
"""Test that None input returns None."""
assert sanitize_env_path(None) is None
def test_empty_string_returns_none():
"""Test that empty string returns None."""
assert sanitize_env_path("") is None
def test_valid_relative_path():
"""Test that valid relative path within base dir is accepted."""
result = sanitize_env_path("project1.env")
assert result is not None
assert result.startswith(env_base_dir)
assert result.endswith("project1.env")
def test_valid_absolute_path_within_base_dir():
"""Test that absolute path within base directory is accepted."""
valid_path = os.path.join(env_base_dir, "valid.env")
result = sanitize_env_path(valid_path)
assert result == os.path.abspath(valid_path)
def test_path_traversal_attack_rejected():
"""Test that path traversal attempts are rejected."""
malicious_paths = [
"../../../etc/passwd",
"../../.ssh/id_rsa.env",
"../outside.env",
"subdir/../../outside.env",
]
for path in malicious_paths:
result = sanitize_env_path(path)
# Path traversal should either be rejected
# or normalized within base_dir
if result:
assert result.startswith(env_base_dir), (
f"Path traversal not blocked: {path} -> {result}"
)
def test_absolute_path_outside_base_dir_rejected():
"""Test that absolute paths outside base directory are rejected."""
malicious_paths = [
"/etc/passwd",
"/tmp/evil.env",
"/root/.env",
str(Path.home() / "evil.env"),
]
for path in malicious_paths:
result = sanitize_env_path(path)
assert result is None, (
f"Absolute path outside base dir not rejected: {path}"
)
def test_non_env_extension_rejected():
"""Test that files without .env extension are rejected."""
invalid_paths = [
"config.txt",
"settings.json",
"environment",
".bashrc",
"script.py",
]
for path in invalid_paths:
result = sanitize_env_path(path)
assert result is None, f"Non-.env file not rejected: {path}"
def test_nested_valid_path():
"""Test that valid nested paths within base dir are accepted."""
result = sanitize_env_path("projects/project1/config.env")
assert result is not None
assert result.startswith(env_base_dir)
assert result.endswith("config.env")
def test_symlink_escape_attempt():
"""Test that symlinks cannot be used to escape base directory."""
with tempfile.TemporaryDirectory() as tmpdir:
# Create a symlink pointing outside base_dir
link_path = os.path.join(env_base_dir, "evil_link.env")
target_path = os.path.join(tmpdir, "outside.env")
# This test only makes sense if we can create symlinks
try:
if os.path.exists(link_path):
os.unlink(link_path)
os.symlink(target_path, link_path)
# The sanitized path should resolve the symlink
result = sanitize_env_path("evil_link.env")
# Either rejected or stays within base_dir after resolution
if result:
resolved = Path(result).resolve()
base_resolved = Path(env_base_dir).resolve()
# Check if resolved path is under base directory
try:
resolved.relative_to(base_resolved)
# If this succeeds, symlink stayed in base (acceptable)
except ValueError:
# Symlink escaped - should have been rejected
pytest.fail(f"Symlink escape not prevented: {result}")
except (OSError, NotImplementedError):
# Symlinks not supported on this system, skip test
pytest.skip("Symlinks not supported")
finally:
# Cleanup
if os.path.exists(link_path):
os.unlink(link_path)
def test_dot_env_in_filename():
"""Test that .env can appear in the middle of filename."""
result = sanitize_env_path("project.env.backup.env")
assert result is not None
assert result.endswith(".env")
def test_case_sensitivity():
"""Test handling of different case extensions."""
# Only .env (lowercase) should be accepted
assert sanitize_env_path("config.ENV") is None
assert sanitize_env_path("config.Env") is None
assert sanitize_env_path("config.env") is not None
def test_special_characters_in_path():
"""Test handling of special characters in valid paths."""
# These should be accepted if they end with .env and stay in base_dir
valid_special_chars = [
"my-project.env",
"project_name.env",
"project.2024.env",
]
for path in valid_special_chars:
result = sanitize_env_path(path)
assert result is not None, (
f"Valid path with special chars rejected: {path}"
)
assert result.startswith(env_base_dir)
def test_whitespace_handling():
"""Test handling of whitespace in paths."""
# Whitespace should be preserved in valid paths
result = sanitize_env_path("my project.env")
assert result is not None
assert "my project.env" in result
def test_current_directory_traversal():
"""Test that ./ and current directory references are handled."""
result = sanitize_env_path("./project.env")
assert result is not None
assert result.startswith(env_base_dir)
result = sanitize_env_path("././project.env")
assert result is not None
assert result.startswith(env_base_dir)