Skip to main content
Glama
test_security_permissions.py46.7 kB
"""Comprehensive tests for security.permissions module.""" import os import stat import tempfile from pathlib import Path import pytest from mnemex.security.permissions import ( DIR_PERMISSIONS, FILE_PERMISSIONS, check_permissions, ensure_secure_storage, secure_config_file, secure_directory, secure_file, ) IS_POSIX = os.name != "nt" class TestSecureFile: """Tests for secure_file function.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_set_permissions_on_existing_file(self): """Test setting permissions on an existing file.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("test content") secure_file(test_file) file_stat = test_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == FILE_PERMISSIONS assert actual_perms == 0o600 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_create_file_with_create_if_missing_true(self): """Test creating a file with create_if_missing=True.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "new_file.txt" assert not test_file.exists() secure_file(test_file, create_if_missing=True) assert test_file.exists() file_stat = test_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == FILE_PERMISSIONS def test_file_not_found_when_create_if_missing_false(self): """Test FileNotFoundError when file doesn't exist and create_if_missing=False.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "nonexistent.txt" with pytest.raises(FileNotFoundError, match="File not found"): secure_file(test_file, create_if_missing=False) def test_value_error_when_path_is_directory(self): """Test ValueError when path is a directory not a file.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "directory" test_dir.mkdir() with pytest.raises(ValueError, match="Path is not a file"): secure_file(test_dir) @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_custom_permissions(self): """Test setting custom permissions (not just default).""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") custom_perms = 0o640 secure_file(test_file, permissions=custom_perms) file_stat = test_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == custom_perms @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_verify_actual_permissions_after_setting(self): """Test verifying actual file permissions after setting.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o777) initial_perms = stat.S_IMODE(test_file.stat().st_mode) assert initial_perms == 0o777 secure_file(test_file) final_perms = stat.S_IMODE(test_file.stat().st_mode) assert final_perms == FILE_PERMISSIONS assert final_perms == 0o600 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_file_with_string_path(self): """Test secure_file accepts string paths.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") secure_file(str(test_file)) file_stat = test_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == FILE_PERMISSIONS class TestSecureDirectory: """Tests for secure_directory function.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_set_permissions_on_existing_directory(self): """Test setting permissions on an existing directory.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() secure_directory(test_dir) dir_stat = test_dir.stat() actual_perms = stat.S_IMODE(dir_stat.st_mode) assert actual_perms == DIR_PERMISSIONS assert actual_perms == 0o700 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_create_directory_with_create_if_missing_true(self): """Test creating a directory with create_if_missing=True.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "new_dir" assert not test_dir.exists() secure_directory(test_dir, create_if_missing=True) assert test_dir.exists() dir_stat = test_dir.stat() actual_perms = stat.S_IMODE(dir_stat.st_mode) assert actual_perms == DIR_PERMISSIONS @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_create_nested_directory_with_create_if_missing_true(self): """Test creating nested directories with create_if_missing=True.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "level1" / "level2" / "level3" assert not test_dir.exists() secure_directory(test_dir, create_if_missing=True) assert test_dir.exists() dir_stat = test_dir.stat() actual_perms = stat.S_IMODE(dir_stat.st_mode) assert actual_perms == DIR_PERMISSIONS def test_directory_not_found_when_create_if_missing_false(self): """Test FileNotFoundError when directory doesn't exist and create_if_missing=False.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "nonexistent" with pytest.raises(FileNotFoundError, match="Directory not found"): secure_directory(test_dir, create_if_missing=False) def test_value_error_when_path_is_file(self): """Test ValueError when path is a file not a directory.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "file.txt" test_file.write_text("content") with pytest.raises(ValueError, match="Path is not a directory"): secure_directory(test_file) @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_custom_permissions(self): """Test setting custom permissions on a directory.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() custom_perms = 0o750 secure_directory(test_dir, permissions=custom_perms) dir_stat = test_dir.stat() actual_perms = stat.S_IMODE(dir_stat.st_mode) assert actual_perms == custom_perms @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_recursive_mode_secures_subdirectories(self): """Test recursive mode secures all subdirectories.""" with tempfile.TemporaryDirectory() as tmpdir: base_dir = Path(tmpdir) / "base" base_dir.mkdir() sub1 = base_dir / "sub1" sub1.mkdir() sub2 = base_dir / "sub2" sub2.mkdir() nested = sub1 / "nested" nested.mkdir() os.chmod(sub1, 0o755) os.chmod(sub2, 0o755) os.chmod(nested, 0o755) secure_directory(base_dir, recursive=True) assert stat.S_IMODE(base_dir.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(sub1.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(sub2.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(nested.stat().st_mode) == DIR_PERMISSIONS @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_recursive_mode_does_not_affect_files(self): """Test recursive mode doesn't modify file permissions.""" with tempfile.TemporaryDirectory() as tmpdir: base_dir = Path(tmpdir) / "base" base_dir.mkdir() test_file = base_dir / "file.txt" test_file.write_text("content") os.chmod(test_file, 0o644) secure_directory(base_dir, recursive=True) assert stat.S_IMODE(test_file.stat().st_mode) == 0o644 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_verify_actual_permissions_after_setting(self): """Test verifying actual directory permissions after setting.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() os.chmod(test_dir, 0o777) initial_perms = stat.S_IMODE(test_dir.stat().st_mode) assert initial_perms == 0o777 secure_directory(test_dir) final_perms = stat.S_IMODE(test_dir.stat().st_mode) assert final_perms == DIR_PERMISSIONS assert final_perms == 0o700 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_directory_with_string_path(self): """Test secure_directory accepts string paths.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() secure_directory(str(test_dir)) dir_stat = test_dir.stat() actual_perms = stat.S_IMODE(dir_stat.st_mode) assert actual_perms == DIR_PERMISSIONS class TestCheckPermissionsAsIsSecureFile: """Tests for check_permissions as is_secure_file validator.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_secure_permissions_0o600(self): """Test files with secure permissions (0o600).""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "secure.txt" test_file.write_text("content") os.chmod(test_file, 0o600) result = check_permissions(test_file) assert result["is_secure"] is True assert result["current"] == "0o600" assert result["expected"] == "0o600" assert result["world_readable"] is False assert result["group_readable"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_insecure_permissions_0o644(self): """Test files with insecure permissions (0o644).""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "insecure.txt" test_file.write_text("content") os.chmod(test_file, 0o644) result = check_permissions(test_file) assert result["is_secure"] is False assert result["current"] == "0o644" assert result["world_readable"] is True assert result["group_readable"] is True @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_insecure_permissions_0o666(self): """Test files with insecure permissions (0o666).""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "insecure.txt" test_file.write_text("content") os.chmod(test_file, 0o666) result = check_permissions(test_file) assert result["is_secure"] is False assert result["current"] == "0o666" assert result["world_readable"] is True assert result["world_writable"] is True assert result["group_readable"] is True assert result["group_writable"] is True @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_insecure_permissions_0o777(self): """Test files with insecure permissions (0o777).""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "insecure.txt" test_file.write_text("content") os.chmod(test_file, 0o777) result = check_permissions(test_file) assert result["is_secure"] is False assert result["current"] == "0o777" assert result["world_readable"] is True assert result["world_writable"] is True def test_nonexistent_file_raises_error(self): """Test non-existent files raise FileNotFoundError.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "nonexistent.txt" with pytest.raises(FileNotFoundError, match="Path not found"): check_permissions(test_file) @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_directory_detected_as_insecure_for_file_check(self): """Test directories are detected as insecure when expecting file permissions.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "directory" test_dir.mkdir() os.chmod(test_dir, 0o700) result = check_permissions(test_dir, expected_permissions=FILE_PERMISSIONS) assert result["is_secure"] is False assert result["expected"] == "0o600" class TestCheckPermissionsAsIsSecureDirectory: """Tests for check_permissions as is_secure_directory validator.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_directory_with_secure_permissions_0o700(self): """Test directories with secure permissions (0o700).""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "secure_dir" test_dir.mkdir() os.chmod(test_dir, 0o700) result = check_permissions(test_dir) assert result["is_secure"] is True assert result["current"] == "0o700" assert result["expected"] == "0o700" assert result["world_readable"] is False assert result["group_readable"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_directory_with_insecure_permissions_0o755(self): """Test directories with insecure permissions (0o755).""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "insecure_dir" test_dir.mkdir() os.chmod(test_dir, 0o755) result = check_permissions(test_dir) assert result["is_secure"] is False assert result["current"] == "0o755" assert result["world_readable"] is True assert result["group_readable"] is True @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_directory_with_insecure_permissions_0o777(self): """Test directories with insecure permissions (0o777).""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "insecure_dir" test_dir.mkdir() os.chmod(test_dir, 0o777) result = check_permissions(test_dir) assert result["is_secure"] is False assert result["current"] == "0o777" assert result["world_readable"] is True assert result["world_writable"] is True def test_nonexistent_directory_raises_error(self): """Test non-existent directories raise FileNotFoundError.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "nonexistent" with pytest.raises(FileNotFoundError, match="Path not found"): check_permissions(test_dir) @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_detected_as_insecure_for_directory_check(self): """Test files are detected as insecure when expecting directory permissions.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "file.txt" test_file.write_text("content") os.chmod(test_file, 0o600) result = check_permissions(test_file, expected_permissions=DIR_PERMISSIONS) assert result["is_secure"] is False assert result["expected"] == "0o700" class TestCheckPermissionsGroupAndOtherAccess: """Tests for check_permissions detecting group and other access.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_group_read_access(self): """Test files with group read access.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o640) result = check_permissions(test_file) assert result["group_readable"] is True assert result["group_writable"] is False assert result["world_readable"] is False assert result["is_secure"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_group_write_access(self): """Test files with group write access.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o620) result = check_permissions(test_file) assert result["group_readable"] is False assert result["group_writable"] is True assert result["is_secure"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_other_read_access(self): """Test files with other (world) read access.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o604) result = check_permissions(test_file) assert result["world_readable"] is True assert result["world_writable"] is False assert result["group_readable"] is False assert result["is_secure"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_other_write_access(self): """Test files with other (world) write access.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o602) result = check_permissions(test_file) assert result["world_readable"] is False assert result["world_writable"] is True assert result["is_secure"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_file_with_only_owner_access(self): """Test files with only owner access (secure).""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o600) result = check_permissions(test_file) assert result["group_readable"] is False assert result["group_writable"] is False assert result["world_readable"] is False assert result["world_writable"] is False assert result["is_secure"] is True @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_directory_with_group_and_other_access(self): """Test directories with both group and other access.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() os.chmod(test_dir, 0o755) result = check_permissions(test_dir) assert result["group_readable"] is True assert result["world_readable"] is True assert result["is_secure"] is False @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_various_permission_combinations(self): """Test various permission combinations.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") test_cases = [ (0o700, False, False, False, False), (0o750, True, False, False, False), (0o705, False, False, True, False), (0o777, True, True, True, True), (0o644, True, False, True, False), (0o664, True, True, True, False), ] for perms, grp_r, grp_w, wld_r, wld_w in test_cases: os.chmod(test_file, perms) result = check_permissions(test_file) assert result["group_readable"] == grp_r, f"Failed for {oct(perms)}" assert result["group_writable"] == grp_w, f"Failed for {oct(perms)}" assert result["world_readable"] == wld_r, f"Failed for {oct(perms)}" assert result["world_writable"] == wld_w, f"Failed for {oct(perms)}" class TestSecureConfigFile: """Tests for secure_config_file function.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_existing_config_file(self): """Test securing an existing config file.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = Path(tmpdir) / ".env" config_file.write_text("API_KEY=secret") secure_config_file(config_file) file_stat = config_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == 0o600 def test_config_file_not_found(self): """Test FileNotFoundError when config file doesn't exist.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = Path(tmpdir) / "nonexistent.env" with pytest.raises(FileNotFoundError, match="Config file not found"): secure_config_file(config_file) def test_config_path_is_directory_raises_error(self): """Test ValueError when config path is a directory.""" with tempfile.TemporaryDirectory() as tmpdir: config_dir = Path(tmpdir) / "config" config_dir.mkdir() with pytest.raises(ValueError, match="Config path is not a file"): secure_config_file(config_dir) @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_config_file_with_string_path(self): """Test secure_config_file accepts string paths.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = Path(tmpdir) / ".env" config_file.write_text("SECRET=value") secure_config_file(str(config_file)) file_stat = config_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == 0o600 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_config_file_with_tilde_expansion(self): """Test secure_config_file handles tilde expansion.""" import tempfile with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as tf: tf.write("TEST=value") temp_path = Path(tf.name) try: secure_config_file(temp_path) file_stat = temp_path.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == 0o600 finally: temp_path.unlink() class TestEnsureSecureStorage: """Tests for ensure_secure_storage function.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_storage_directory_and_files(self): """Test securing storage directory and all contained files.""" with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "storage" storage_dir.mkdir() file1 = storage_dir / "mem1.jsonl" file1.write_text("data1") file2 = storage_dir / "mem2.jsonl" file2.write_text("data2") os.chmod(file1, 0o644) os.chmod(file2, 0o644) stats = ensure_secure_storage(storage_dir) assert stats["files"] == 2 assert stats["directories"] == 1 assert stats["errors"] == 0 assert stat.S_IMODE(storage_dir.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(file1.stat().st_mode) == FILE_PERMISSIONS assert stat.S_IMODE(file2.stat().st_mode) == FILE_PERMISSIONS @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_secure_storage_with_subdirectories(self): """Test securing storage with nested subdirectories.""" with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "storage" storage_dir.mkdir() subdir1 = storage_dir / "sub1" subdir1.mkdir() subdir2 = storage_dir / "sub2" subdir2.mkdir() nested = subdir1 / "nested" nested.mkdir() file1 = storage_dir / "file1.txt" file1.write_text("data") file2 = subdir1 / "file2.txt" file2.write_text("data") file3 = nested / "file3.txt" file3.write_text("data") stats = ensure_secure_storage(storage_dir) assert stats["files"] == 3 assert stats["directories"] >= 3 assert stats["errors"] == 0 assert stat.S_IMODE(storage_dir.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(subdir1.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(subdir2.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(nested.stat().st_mode) == DIR_PERMISSIONS assert stat.S_IMODE(file1.stat().st_mode) == FILE_PERMISSIONS assert stat.S_IMODE(file2.stat().st_mode) == FILE_PERMISSIONS assert stat.S_IMODE(file3.stat().st_mode) == FILE_PERMISSIONS def test_storage_path_not_found(self): """Test FileNotFoundError when storage path doesn't exist.""" with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "nonexistent" with pytest.raises(FileNotFoundError, match="Storage path not found"): ensure_secure_storage(storage_dir) def test_storage_path_is_file_raises_error(self): """Test ValueError when storage path is a file.""" with tempfile.TemporaryDirectory() as tmpdir: storage_file = Path(tmpdir) / "file.txt" storage_file.write_text("content") with pytest.raises(ValueError, match="Storage path is not a directory"): ensure_secure_storage(storage_file) @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_custom_file_and_directory_permissions(self): """Test ensure_secure_storage with custom permissions.""" with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "storage" storage_dir.mkdir() file1 = storage_dir / "file.txt" file1.write_text("data") custom_file_perms = 0o640 custom_dir_perms = 0o750 stats = ensure_secure_storage( storage_dir, file_permissions=custom_file_perms, dir_permissions=custom_dir_perms ) assert stats["files"] == 1 assert stats["directories"] == 1 assert stat.S_IMODE(storage_dir.stat().st_mode) == custom_dir_perms assert stat.S_IMODE(file1.stat().st_mode) == custom_file_perms @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_empty_storage_directory(self): """Test securing an empty storage directory.""" with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "storage" storage_dir.mkdir() stats = ensure_secure_storage(storage_dir) assert stats["files"] == 0 assert stats["directories"] == 1 assert stats["errors"] == 0 assert stat.S_IMODE(storage_dir.stat().st_mode) == DIR_PERMISSIONS class TestCheckPermissions: """Tests for check_permissions function.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_check_permissions_secure_file(self): """Test check_permissions on a secure file.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "secure.txt" test_file.write_text("content") os.chmod(test_file, 0o600) result = check_permissions(test_file) assert result["current"] == "0o600" assert result["expected"] == "0o600" assert result["is_secure"] is True assert "secure" in result["recommendation"].lower() @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_check_permissions_insecure_file(self): """Test check_permissions on an insecure file.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "insecure.txt" test_file.write_text("content") os.chmod(test_file, 0o644) result = check_permissions(test_file) assert result["current"] == "0o644" assert result["is_secure"] is False assert "0o600" in result["recommendation"] @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_check_permissions_with_custom_expected_permissions(self): """Test check_permissions with custom expected permissions.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o640) result = check_permissions(test_file, expected_permissions=0o640) assert result["current"] == "0o640" assert result["expected"] == "0o640" assert result["is_secure"] is True @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_check_permissions_auto_detects_directory(self): """Test check_permissions auto-detects directory type.""" with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() os.chmod(test_dir, 0o700) result = check_permissions(test_dir) assert result["expected"] == "0o700" assert result["is_secure"] is True @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_check_permissions_returns_all_fields(self): """Test check_permissions returns all expected fields.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o644) result = check_permissions(test_file) required_fields = [ "current", "expected", "is_secure", "world_readable", "world_writable", "group_readable", "group_writable", "recommendation", ] for field in required_fields: assert field in result @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_check_permissions_with_string_path(self): """Test check_permissions accepts string paths.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o600) result = check_permissions(str(test_file)) assert result["is_secure"] is True def test_check_permissions_nonexistent_path(self): """Test check_permissions raises error for nonexistent path.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "nonexistent.txt" with pytest.raises(FileNotFoundError, match="Path not found"): check_permissions(test_file) class TestMain: """Tests for the main() CLI function.""" @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_main_check_secure_file(self, monkeypatch, capsys): """Test main with --check flag on a secure file.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "secure.txt" test_file.write_text("content") os.chmod(test_file, 0o600) monkeypatch.setattr("sys.argv", ["prog", str(test_file), "--check"]) result = main() assert result == 0 captured = capsys.readouterr() assert "Secure: True" in captured.out @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_main_check_insecure_file(self, monkeypatch, capsys): """Test main with --check flag on an insecure file.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "insecure.txt" test_file.write_text("content") os.chmod(test_file, 0o644) monkeypatch.setattr("sys.argv", ["prog", str(test_file), "--check"]) result = main() assert result == 1 captured = capsys.readouterr() assert "Secure: False" in captured.out assert "⚠️" in captured.out @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_main_secure_config_file(self, monkeypatch, capsys): """Test main with --config flag.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: config_file = Path(tmpdir) / ".env" config_file.write_text("API_KEY=secret") monkeypatch.setattr("sys.argv", ["prog", str(config_file), "--config"]) result = main() assert result == 0 captured = capsys.readouterr() assert "Secured config file" in captured.out file_stat = config_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == 0o600 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_main_secure_single_file(self, monkeypatch, capsys): """Test main securing a single file.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") os.chmod(test_file, 0o644) monkeypatch.setattr("sys.argv", ["prog", str(test_file)]) result = main() assert result == 0 captured = capsys.readouterr() assert "Secured file" in captured.out file_stat = test_file.stat() actual_perms = stat.S_IMODE(file_stat.st_mode) assert actual_perms == 0o600 @pytest.mark.skipif(not IS_POSIX, reason="Unix permissions not applicable on Windows") def test_main_secure_directory_non_recursive(self, monkeypatch, capsys): """Test main securing a directory without --recursive.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() os.chmod(test_dir, 0o755) monkeypatch.setattr("sys.argv", ["prog", str(test_dir)]) result = main() assert result == 0 captured = capsys.readouterr() assert "Secured directory" in captured.out dir_stat = test_dir.stat() actual_perms = stat.S_IMODE(dir_stat.st_mode) assert actual_perms == 0o700 def test_main_secure_directory_recursive(self, monkeypatch, capsys): """Test main securing a directory with --recursive.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() subdir = test_dir / "subdir" subdir.mkdir() file1 = test_dir / "file1.txt" file1.write_text("data") monkeypatch.setattr("sys.argv", ["prog", str(test_dir), "--recursive"]) result = main() assert result == 0 captured = capsys.readouterr() assert "Secured directory" in captured.out assert "Files secured:" in captured.out assert "Directories secured:" in captured.out def test_main_recursive_with_errors(self, monkeypatch, capsys): """Test main with --recursive when there are permission errors.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() file1 = test_dir / "file1.txt" file1.write_text("data") monkeypatch.setattr("sys.argv", ["prog", str(test_dir), "--recursive"]) result = main() if result == 1: captured = capsys.readouterr() assert "Errors:" in captured.out else: assert result == 0 def test_main_nonexistent_path(self, monkeypatch, capsys): """Test main with a nonexistent path.""" from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: nonexistent = Path(tmpdir) / "nonexistent" monkeypatch.setattr("sys.argv", ["prog", str(nonexistent)]) result = main() assert result == 1 captured = capsys.readouterr() assert "Error" in captured.err or "Error" in captured.out def test_main_exception_handling(self, monkeypatch, capsys): """Test main exception handling.""" from mnemex.security.permissions import main monkeypatch.setattr("sys.argv", ["prog", "/nonexistent/path/that/does/not/exist"]) result = main() assert result == 1 class TestPermissionErrors: """Tests for PermissionError exception handling.""" def test_secure_file_permission_error(self, monkeypatch): """Test PermissionError when securing a file.""" import os with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / "test.txt" test_file.write_text("content") original_chmod = os.chmod def mock_chmod(path, mode): if str(path) == str(test_file): raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) with pytest.raises(PermissionError, match="Unable to set permissions"): secure_file(test_file) def test_secure_directory_permission_error(self, monkeypatch): """Test PermissionError when securing a directory.""" import os with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() original_chmod = os.chmod def mock_chmod(path, mode): if str(path) == str(test_dir): raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) with pytest.raises(PermissionError, match="Unable to set permissions"): secure_directory(test_dir) def test_secure_directory_recursive_subdirectory_permission_error(self, monkeypatch, capsys): """Test PermissionError warning on subdirectory in recursive mode.""" import os with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() subdir = test_dir / "subdir" subdir.mkdir() original_chmod = os.chmod def mock_chmod(path, mode): if str(path) == str(subdir): raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) secure_directory(test_dir, recursive=True) captured = capsys.readouterr() assert "Warning: Unable to secure subdirectory" in captured.out @pytest.mark.skipif( not IS_POSIX or os.uname().sysname == "Darwin", reason="Permission error behavior differs on macOS/Windows", ) def test_secure_config_file_permission_error(self, monkeypatch): """Test PermissionError when securing a config file.""" import os with tempfile.TemporaryDirectory() as tmpdir: config_file = Path(tmpdir) / ".env" config_file.write_text("SECRET=value") original_chmod = os.chmod def mock_chmod(path, mode): if str(path) == str(config_file): raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) with pytest.raises(PermissionError, match="Unable to secure config file"): secure_config_file(config_file) @pytest.mark.skipif( not IS_POSIX or os.uname().sysname == "Darwin", reason="Permission error behavior differs on macOS/Windows", ) def test_ensure_secure_storage_directory_permission_error(self, monkeypatch, capsys): """Test PermissionError on storage directory in ensure_secure_storage.""" import os with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "storage" storage_dir.mkdir() original_chmod = os.chmod def mock_chmod(path, mode): if str(path) == str(storage_dir): raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) stats = ensure_secure_storage(storage_dir) assert stats["errors"] > 0 captured = capsys.readouterr() assert "Warning: Unable to secure storage directory" in captured.out @pytest.mark.skipif( not IS_POSIX or os.uname().sysname == "Darwin", reason="Permission error behavior differs on macOS/Windows", ) def test_ensure_secure_storage_file_permission_error(self, monkeypatch, capsys): """Test PermissionError on files in ensure_secure_storage.""" import os with tempfile.TemporaryDirectory() as tmpdir: storage_dir = Path(tmpdir) / "storage" storage_dir.mkdir() test_file = storage_dir / "file.txt" test_file.write_text("data") original_chmod = os.chmod call_count = [0] def mock_chmod(path, mode): call_count[0] += 1 if call_count[0] > 1 and str(path) == str(test_file): raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) stats = ensure_secure_storage(storage_dir) assert stats["errors"] > 0 captured = capsys.readouterr() assert "Warning: Unable to secure" in captured.out def test_main_with_storage_errors_returns_1(self, monkeypatch, capsys): """Test main returns 1 when ensure_secure_storage has errors.""" import os from mnemex.security.permissions import main with tempfile.TemporaryDirectory() as tmpdir: test_dir = Path(tmpdir) / "test_dir" test_dir.mkdir() test_file = test_dir / "file.txt" test_file.write_text("data") original_chmod = os.chmod call_count = [0] def mock_chmod(path, mode): call_count[0] += 1 if call_count[0] > 1: raise PermissionError("Permission denied") return original_chmod(path, mode) monkeypatch.setattr(os, "chmod", mock_chmod) monkeypatch.setattr("sys.argv", ["prog", str(test_dir), "--recursive"]) result = main() assert result == 1 captured = capsys.readouterr() assert "Errors:" in captured.out

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mnemexai/mnemex'

If you have feedback or need assistance with the MCP directory API, please join our Discord server