Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

354 lines
12 KiB
Python

"""
Behavioral tests for security/module_whitelist module.
Tests the whitelist validation logic, security error handling,
and module/class name filtering.
"""
import pytest
class TestAllowedModulePaths:
"""Tests for ALLOWED_MODULE_PATHS constant."""
def test_is_frozenset(self):
"""ALLOWED_MODULE_PATHS is a frozenset."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert isinstance(ALLOWED_MODULE_PATHS, frozenset)
def test_is_non_empty(self):
"""ALLOWED_MODULE_PATHS is non-empty."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert len(ALLOWED_MODULE_PATHS) > 0
def test_all_paths_start_with_dot(self):
"""All paths start with '.' (relative imports only)."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
for path in ALLOWED_MODULE_PATHS:
assert path.startswith("."), (
f"Path {path!r} does not start with '.'"
)
def test_all_paths_are_strings(self):
"""All paths are strings."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
for path in ALLOWED_MODULE_PATHS:
assert isinstance(path, str)
def test_contains_brave_engine(self):
"""Contains brave search engine module."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert ".engines.search_engine_brave" in ALLOWED_MODULE_PATHS
def test_contains_searxng_engine(self):
"""Contains SearXNG search engine module."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert ".engines.search_engine_searxng" in ALLOWED_MODULE_PATHS
def test_contains_base_engine(self):
"""Contains search_engine_base module."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert ".search_engine_base" in ALLOWED_MODULE_PATHS
def test_does_not_contain_os(self):
"""Does not contain 'os' module."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert "os" not in ALLOWED_MODULE_PATHS
def test_does_not_contain_subprocess(self):
"""Does not contain 'subprocess' module."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
)
assert "subprocess" not in ALLOWED_MODULE_PATHS
def test_legacy_alias_matches(self):
"""ALLOWED_MODULES is the same as ALLOWED_MODULE_PATHS."""
from local_deep_research.security.module_whitelist import (
ALLOWED_MODULE_PATHS,
ALLOWED_MODULES,
)
assert ALLOWED_MODULES is ALLOWED_MODULE_PATHS
class TestAllowedClassNames:
"""Tests for ALLOWED_CLASS_NAMES constant."""
def test_is_frozenset(self):
"""ALLOWED_CLASS_NAMES is a frozenset."""
from local_deep_research.security.module_whitelist import (
ALLOWED_CLASS_NAMES,
)
assert isinstance(ALLOWED_CLASS_NAMES, frozenset)
def test_is_non_empty(self):
"""ALLOWED_CLASS_NAMES is non-empty."""
from local_deep_research.security.module_whitelist import (
ALLOWED_CLASS_NAMES,
)
assert len(ALLOWED_CLASS_NAMES) > 0
def test_all_names_are_strings(self):
"""All class names are strings."""
from local_deep_research.security.module_whitelist import (
ALLOWED_CLASS_NAMES,
)
for name in ALLOWED_CLASS_NAMES:
assert isinstance(name, str)
def test_contains_brave_search_engine(self):
"""Contains BraveSearchEngine class."""
from local_deep_research.security.module_whitelist import (
ALLOWED_CLASS_NAMES,
)
assert "BraveSearchEngine" in ALLOWED_CLASS_NAMES
def test_contains_base_search_engine(self):
"""Contains BaseSearchEngine class."""
from local_deep_research.security.module_whitelist import (
ALLOWED_CLASS_NAMES,
)
assert "BaseSearchEngine" in ALLOWED_CLASS_NAMES
def test_does_not_contain_generic_names(self):
"""Does not contain generic dangerous class names."""
from local_deep_research.security.module_whitelist import (
ALLOWED_CLASS_NAMES,
)
assert "Popen" not in ALLOWED_CLASS_NAMES
assert "system" not in ALLOWED_CLASS_NAMES
class TestSecurityError:
"""Tests for SecurityError exception."""
def test_is_exception_subclass(self):
"""SecurityError is an Exception subclass."""
from local_deep_research.security.module_whitelist import SecurityError
assert issubclass(SecurityError, Exception)
def test_can_be_raised_and_caught(self):
"""SecurityError can be raised and caught."""
from local_deep_research.security.module_whitelist import SecurityError
with pytest.raises(SecurityError):
raise SecurityError("test")
def test_message_preserved(self):
"""Error message is preserved."""
from local_deep_research.security.module_whitelist import SecurityError
err = SecurityError("blocked import")
assert str(err) == "blocked import"
def test_legacy_alias(self):
"""ModuleNotAllowedError is same as SecurityError."""
from local_deep_research.security.module_whitelist import (
SecurityError,
ModuleNotAllowedError,
)
assert ModuleNotAllowedError is SecurityError
class TestValidateModuleImport:
"""Tests for validate_module_import function."""
def test_valid_module_and_class(self):
"""Returns True for whitelisted module and class."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(
".engines.search_engine_brave", "BraveSearchEngine"
)
assert result is True
def test_invalid_module_path(self):
"""Returns False for non-whitelisted module."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(
".engines.evil_module", "BraveSearchEngine"
)
assert result is False
def test_invalid_class_name(self):
"""Returns False for non-whitelisted class."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(
".engines.search_engine_brave", "EvilClass"
)
assert result is False
def test_both_invalid(self):
"""Returns False when both module and class are invalid."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(".evil.module", "EvilClass")
assert result is False
def test_empty_module_path(self):
"""Returns False for empty module path."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import("", "BraveSearchEngine")
assert result is False
def test_empty_class_name(self):
"""Returns False for empty class name."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(".engines.search_engine_brave", "")
assert result is False
def test_none_module_path(self):
"""Returns False for None module path."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(None, "BraveSearchEngine")
assert result is False
def test_none_class_name(self):
"""Returns False for None class name."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(".engines.search_engine_brave", None)
assert result is False
def test_rejects_absolute_import_os(self):
"""Rejects absolute import of 'os' module."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import("os", "system")
assert result is False
def test_rejects_absolute_import_subprocess(self):
"""Rejects absolute import of 'subprocess' module."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import("subprocess", "Popen")
assert result is False
def test_rejects_non_relative_whitelisted_path(self):
"""Rejects non-relative path even if it looks similar to whitelisted one."""
from local_deep_research.security.module_whitelist import (
validate_module_import,
)
result = validate_module_import(
"engines.search_engine_brave", "BraveSearchEngine"
)
assert result is False
class TestGetSafeModuleClass:
"""Tests for get_safe_module_class function security validation."""
def test_raises_for_non_whitelisted_module(self):
"""Raises SecurityError for non-whitelisted module."""
from local_deep_research.security.module_whitelist import (
get_safe_module_class,
SecurityError,
)
with pytest.raises(SecurityError) as exc_info:
get_safe_module_class(".evil.module", "EvilClass")
assert "not in the security whitelist" in str(exc_info.value)
def test_raises_for_non_whitelisted_class(self):
"""Raises SecurityError for non-whitelisted class name."""
from local_deep_research.security.module_whitelist import (
get_safe_module_class,
SecurityError,
)
with pytest.raises(SecurityError) as exc_info:
get_safe_module_class(".engines.search_engine_brave", "EvilClass")
assert "not in the security whitelist" in str(exc_info.value)
def test_raises_for_absolute_import(self):
"""Raises SecurityError for absolute import path."""
from local_deep_research.security.module_whitelist import (
get_safe_module_class,
SecurityError,
)
with pytest.raises(SecurityError):
get_safe_module_class("os", "system")
def test_error_message_includes_module_path(self):
"""Error message includes the rejected module path."""
from local_deep_research.security.module_whitelist import (
get_safe_module_class,
SecurityError,
)
with pytest.raises(SecurityError) as exc_info:
get_safe_module_class(".evil.module", "EvilClass")
assert ".evil.module" in str(exc_info.value)
def test_error_message_includes_class_name(self):
"""Error message includes the rejected class name."""
from local_deep_research.security.module_whitelist import (
get_safe_module_class,
SecurityError,
)
with pytest.raises(SecurityError) as exc_info:
get_safe_module_class(".evil.module", "EvilClass")
assert "EvilClass" in str(exc_info.value)