""" Behavioral tests for data_sanitizer module. Tests the DataSanitizer class which removes or redacts sensitive information from data structures. """ class TestSanitizeBasicDictionary: """Tests for sanitizing basic dictionaries.""" def test_removes_api_key(self): """api_key is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"username": "user", "api_key": "secret123"} result = DataSanitizer.sanitize(data) assert "api_key" not in result assert result["username"] == "user" def test_removes_password(self): """password is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"username": "user", "password": "secret123"} result = DataSanitizer.sanitize(data) assert "password" not in result assert result["username"] == "user" def test_removes_secret(self): """secret is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"name": "service", "secret": "abc123"} result = DataSanitizer.sanitize(data) assert "secret" not in result assert result["name"] == "service" def test_removes_access_token(self): """access_token is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"user_id": 1, "access_token": "token123"} result = DataSanitizer.sanitize(data) assert "access_token" not in result assert result["user_id"] == 1 def test_removes_refresh_token(self): """refresh_token is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"user_id": 1, "refresh_token": "refresh123"} result = DataSanitizer.sanitize(data) assert "refresh_token" not in result def test_removes_private_key(self): """private_key is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"key_id": "k1", "private_key": "-----BEGIN..."} result = DataSanitizer.sanitize(data) assert "private_key" not in result def test_removes_auth_token(self): """auth_token is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"session": "s1", "auth_token": "auth123"} result = DataSanitizer.sanitize(data) assert "auth_token" not in result def test_removes_session_token(self): """session_token is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"user": "u1", "session_token": "sess123"} result = DataSanitizer.sanitize(data) assert "session_token" not in result def test_removes_csrf_token(self): """csrf_token is removed from dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"form": "f1", "csrf_token": "csrf123"} result = DataSanitizer.sanitize(data) assert "csrf_token" not in result def test_removes_apikey_no_underscore(self): """apikey (without underscore) is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"service": "s1", "apikey": "key123"} result = DataSanitizer.sanitize(data) assert "apikey" not in result class TestSanitizeCaseInsensitive: """Tests for case-insensitive key matching.""" def test_removes_API_KEY_uppercase(self): """API_KEY in uppercase is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"name": "test", "API_KEY": "secret"} result = DataSanitizer.sanitize(data) assert "API_KEY" not in result def test_removes_Api_Key_mixed_case(self): """Api_Key in mixed case is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"name": "test", "Api_Key": "secret"} result = DataSanitizer.sanitize(data) assert "Api_Key" not in result def test_removes_PASSWORD_uppercase(self): """PASSWORD in uppercase is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"user": "u1", "PASSWORD": "secret"} result = DataSanitizer.sanitize(data) assert "PASSWORD" not in result def test_removes_Secret_capitalized(self): """Secret capitalized is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"id": 1, "Secret": "mysecret"} result = DataSanitizer.sanitize(data) assert "Secret" not in result class TestSanitizeNestedStructures: """Tests for nested dictionaries and lists.""" def test_removes_key_in_nested_dict(self): """api_key in nested dictionary is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"user": {"name": "test", "api_key": "secret"}} result = DataSanitizer.sanitize(data) assert "api_key" not in result["user"] assert result["user"]["name"] == "test" def test_removes_key_in_deeply_nested_dict(self): """api_key in deeply nested dictionary is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"a": {"b": {"c": {"password": "secret", "value": 1}}}} result = DataSanitizer.sanitize(data) assert "password" not in result["a"]["b"]["c"] assert result["a"]["b"]["c"]["value"] == 1 def test_removes_key_in_list_of_dicts(self): """api_key in list of dictionaries is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = [{"name": "a", "api_key": "k1"}, {"name": "b", "api_key": "k2"}] result = DataSanitizer.sanitize(data) assert all("api_key" not in item for item in result) assert result[0]["name"] == "a" assert result[1]["name"] == "b" def test_removes_key_in_mixed_nested_structure(self): """api_key in mixed nested structure is removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = { "users": [{"id": 1, "password": "p1"}, {"id": 2, "password": "p2"}], "config": {"api_key": "main_key"}, } result = DataSanitizer.sanitize(data) assert all("password" not in user for user in result["users"]) assert "api_key" not in result["config"] class TestSanitizePrimitives: """Tests for primitive values.""" def test_returns_string_unchanged(self): """String primitives are returned unchanged.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert DataSanitizer.sanitize("hello") == "hello" def test_returns_number_unchanged(self): """Number primitives are returned unchanged.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert DataSanitizer.sanitize(42) == 42 assert DataSanitizer.sanitize(3.14) == 3.14 def test_returns_boolean_unchanged(self): """Boolean primitives are returned unchanged.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert DataSanitizer.sanitize(True) is True assert DataSanitizer.sanitize(False) is False def test_returns_none_unchanged(self): """None is returned unchanged.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert DataSanitizer.sanitize(None) is None class TestSanitizeCustomKeys: """Tests for custom sensitive key sets.""" def test_custom_keys_are_removed(self): """Custom sensitive keys are removed.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"custom_secret": "value", "name": "test"} result = DataSanitizer.sanitize(data, sensitive_keys={"custom_secret"}) assert "custom_secret" not in result assert result["name"] == "test" def test_default_keys_not_removed_with_custom(self): """Default keys are not removed when custom set is provided.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"api_key": "value", "custom_key": "secret"} result = DataSanitizer.sanitize(data, sensitive_keys={"custom_key"}) # With custom keys, default keys are not removed assert "api_key" in result assert "custom_key" not in result def test_empty_custom_keys_removes_nothing(self): """Empty custom key set removes nothing.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"api_key": "value", "password": "secret"} result = DataSanitizer.sanitize(data, sensitive_keys=set()) assert "api_key" in result assert "password" in result class TestSanitizeEmptyInputs: """Tests for empty inputs.""" def test_empty_dict_returns_empty(self): """Empty dictionary returns empty dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert DataSanitizer.sanitize({}) == {} def test_empty_list_returns_empty(self): """Empty list returns empty list.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert DataSanitizer.sanitize([]) == [] class TestSanitizeOriginalUnmodified: """Tests that original data is not modified.""" def test_original_dict_unchanged(self): """Original dictionary is not modified.""" from local_deep_research.security.data_sanitizer import DataSanitizer original = {"name": "test", "api_key": "secret"} DataSanitizer.sanitize(original) assert "api_key" in original def test_original_nested_dict_unchanged(self): """Original nested dictionary is not modified.""" from local_deep_research.security.data_sanitizer import DataSanitizer original = {"user": {"name": "test", "password": "secret"}} DataSanitizer.sanitize(original) assert "password" in original["user"] class TestRedactBasicDictionary: """Tests for redacting basic dictionaries.""" def test_redacts_api_key(self): """api_key value is redacted.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"username": "user", "api_key": "secret123"} result = DataSanitizer.redact(data) assert result["api_key"] == "[REDACTED]" assert result["username"] == "user" def test_redacts_password(self): """password value is redacted.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"username": "user", "password": "secret123"} result = DataSanitizer.redact(data) assert result["password"] == "[REDACTED]" assert result["username"] == "user" def test_redacts_multiple_keys(self): """Multiple sensitive keys are redacted.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = { "api_key": "k1", "password": "p1", "secret": "s1", "name": "test", } result = DataSanitizer.redact(data) assert result["api_key"] == "[REDACTED]" assert result["password"] == "[REDACTED]" assert result["secret"] == "[REDACTED]" assert result["name"] == "test" class TestRedactCustomText: """Tests for custom redaction text.""" def test_custom_redaction_text(self): """Custom redaction text is used.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"api_key": "secret"} result = DataSanitizer.redact(data, redaction_text="***HIDDEN***") assert result["api_key"] == "***HIDDEN***" def test_empty_redaction_text(self): """Empty redaction text is used.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"api_key": "secret"} result = DataSanitizer.redact(data, redaction_text="") assert result["api_key"] == "" class TestRedactNestedStructures: """Tests for redacting nested structures.""" def test_redacts_nested_dict(self): """Nested dictionary values are redacted.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"config": {"api_key": "secret", "url": "http://example.com"}} result = DataSanitizer.redact(data) assert result["config"]["api_key"] == "[REDACTED]" assert result["config"]["url"] == "http://example.com" def test_redacts_list_of_dicts(self): """List of dictionaries values are redacted.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = [ {"name": "a", "password": "p1"}, {"name": "b", "password": "p2"}, ] result = DataSanitizer.redact(data) assert result[0]["password"] == "[REDACTED]" assert result[1]["password"] == "[REDACTED]" assert result[0]["name"] == "a" class TestRedactPreservesStructure: """Tests that redact preserves data structure.""" def test_preserves_key_in_result(self): """Redacted key is still present in result.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"api_key": "secret"} result = DataSanitizer.redact(data) assert "api_key" in result def test_preserves_nested_structure(self): """Nested structure is preserved.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"a": {"b": {"password": "secret"}}} result = DataSanitizer.redact(data) assert "a" in result assert "b" in result["a"] assert "password" in result["a"]["b"] class TestConvenienceFunctions: """Tests for convenience functions.""" def test_sanitize_data_function(self): """sanitize_data convenience function works.""" from local_deep_research.security.data_sanitizer import sanitize_data data = {"api_key": "secret", "name": "test"} result = sanitize_data(data) assert "api_key" not in result assert result["name"] == "test" def test_redact_data_function(self): """redact_data convenience function works.""" from local_deep_research.security.data_sanitizer import redact_data data = {"api_key": "secret", "name": "test"} result = redact_data(data) assert result["api_key"] == "[REDACTED]" assert result["name"] == "test" def test_sanitize_data_with_custom_keys(self): """sanitize_data works with custom keys.""" from local_deep_research.security.data_sanitizer import sanitize_data data = {"custom": "value", "other": "data"} result = sanitize_data(data, sensitive_keys={"custom"}) assert "custom" not in result assert result["other"] == "data" def test_redact_data_with_custom_text(self): """redact_data works with custom redaction text.""" from local_deep_research.security.data_sanitizer import redact_data data = {"password": "secret"} result = redact_data(data, redaction_text="") assert result["password"] == "" class TestDefaultSensitiveKeys: """Tests for the default sensitive keys constant.""" def test_default_keys_include_api_key(self): """Default keys include api_key.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert "api_key" in DataSanitizer.DEFAULT_SENSITIVE_KEYS def test_default_keys_include_password(self): """Default keys include password.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert "password" in DataSanitizer.DEFAULT_SENSITIVE_KEYS def test_default_keys_include_secret(self): """Default keys include secret.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert "secret" in DataSanitizer.DEFAULT_SENSITIVE_KEYS def test_default_keys_is_set(self): """Default keys is a set for O(1) lookup.""" from local_deep_research.security.data_sanitizer import DataSanitizer assert isinstance(DataSanitizer.DEFAULT_SENSITIVE_KEYS, set) class TestEdgeCases: """Tests for edge cases.""" def test_handles_none_values_in_dict(self): """Handles None values in dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"name": None, "api_key": "secret"} result = DataSanitizer.sanitize(data) assert result["name"] is None assert "api_key" not in result def test_handles_numeric_values(self): """Handles numeric values in dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"count": 42, "api_key": "secret"} result = DataSanitizer.sanitize(data) assert result["count"] == 42 assert "api_key" not in result def test_handles_boolean_values(self): """Handles boolean values in dictionary.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = {"enabled": True, "password": "secret"} result = DataSanitizer.sanitize(data) assert result["enabled"] is True assert "password" not in result def test_handles_mixed_types_in_list(self): """Handles mixed types in list.""" from local_deep_research.security.data_sanitizer import DataSanitizer data = [1, "string", {"api_key": "secret"}, None, True] result = DataSanitizer.sanitize(data) assert result[0] == 1 assert result[1] == "string" assert "api_key" not in result[2] assert result[3] is None assert result[4] is True