# #region Test.SecurityBadgeService [C:3] [TYPE Module] [SEMANTICS test,profile,security,permissions,badges] # @BRIEF Tests for security_badge_service.py — role extraction, permission pairs, security summary. # @RELATION BINDS_TO -> [SecurityBadgeService] from pathlib import Path import sys sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from unittest.mock import MagicMock, patch import pytest def make_user(**kwargs): """Helper to create a mock User with roles.""" from src.models.auth import User user = MagicMock(spec=User) for k, v in kwargs.items(): setattr(user, k, v) return user def make_role(name, permissions=None): role = MagicMock() role.name = name role.permissions = permissions or [] return role def make_permission(resource, action): perm = MagicMock() perm.resource = resource perm.action = action return perm class TestCollectUserPermissionPairs: """_collect_user_permission_pairs — extract (resource, ACTION) tuples.""" def test_no_roles_returns_empty(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() user = make_user(roles=[]) result = svc._collect_user_permission_pairs(user) assert result == set() def test_role_with_permissions(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() perms = [make_permission("dashboard", "read"), make_permission("dataset", "write")] role = make_role("Editor", perms) user = make_user(roles=[role]) result = svc._collect_user_permission_pairs(user) assert ("dashboard", "READ") in result assert ("dataset", "WRITE") in result def test_permission_without_resource_skipped(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() perms = [make_permission("", "read"), make_permission(None, "write")] role = make_role("Viewer", perms) user = make_user(roles=[role]) result = svc._collect_user_permission_pairs(user) assert result == set() def test_multiple_roles_dedup(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() p1 = make_permission("dashboard", "read") role1 = make_role("Admin", [p1]) role2 = make_role("Editor", [p1]) user = make_user(roles=[role1, role2]) result = svc._collect_user_permission_pairs(user) assert len(result) == 1 class TestBuildSecuritySummary: """build_security_summary — full security snapshot.""" def test_no_roles(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() user = make_user(roles=[], auth_source="database") summary = svc.build_security_summary(user) assert summary.read_only is True assert summary.roles == [] assert summary.current_role is None assert summary.auth_source == "database" def test_single_role(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() role = make_role("Viewer") user = make_user(roles=[role], auth_source="ldap") summary = svc.build_security_summary(user) assert summary.roles == ["Viewer"] assert summary.current_role == "Viewer" def test_admin_role_detected(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() role = make_role("Admin") user = make_user(roles=[role], auth_source="database") summary = svc.build_security_summary(user) assert "Admin" in summary.roles assert summary.current_role == "Admin" def test_roles_sorted(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() role_z = make_role("ZViewer") role_a = make_role("AAdmin") user = make_user(roles=[role_z, role_a]) summary = svc.build_security_summary(user) assert summary.roles == ["AAdmin", "ZViewer"] def test_discover_permissions_fallback(self): """When discover_declared_permissions raises, fallback to user permissions.""" from src.services.security_badge_service import SecurityBadgeService perms = [make_permission("dashboard", "read")] role = make_role("Editor", perms) user = make_user(roles=[role]) with patch("src.services.security_badge_service.discover_declared_permissions", side_effect=RuntimeError("Plugin load failed")): svc = SecurityBadgeService(plugin_loader=MagicMock()) summary = svc.build_security_summary(user) # Should still produce permission states assert len(summary.permissions) >= 0 def test_is_admin_allows_all(self): """Admin user sees all declared permissions as allowed.""" from src.services.security_badge_service import SecurityBadgeService perms = [make_permission("dashboard", "read")] role = make_role("Admin", perms) user = make_user(roles=[role]) with patch("src.services.security_badge_service.discover_declared_permissions", return_value={("dashboard", "READ"), ("dataset", "WRITE")}): svc = SecurityBadgeService() summary = svc.build_security_summary(user) admin_perm = next((p for p in summary.permissions if p.key == "dashboard"), None) assert admin_perm is not None assert admin_perm.allowed is True def test_permission_key_format_read(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() key = svc._format_permission_key("dashboard", "READ") assert key == "dashboard" def test_permission_key_format_write(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() key = svc._format_permission_key("dataset", "WRITE") assert key == "dataset:write" class TestFormatPermissionKey: """_format_permission_key — compact UI key format.""" def test_read_omits_action(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() assert svc._format_permission_key("dashboard", "READ") == "dashboard" def test_write_includes_action(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() assert svc._format_permission_key("dataset", "WRITE") == "dataset:write" def test_empty_resource(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() result = svc._format_permission_key("", "READ") assert result is not None assert isinstance(result, str) class TestPermissionEdgeCases: """Edge cases for permission processing.""" def test_empty_role_name_skipped(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() role_empty = make_role("") role_none = make_role(None) user = make_user(roles=[role_empty, role_none]) summary = svc.build_security_summary(user) assert summary.roles == [] def test_role_name_with_whitespace_sanitized(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() role = make_role(" Editor ") user = make_user(roles=[role]) summary = svc.build_security_summary(user) assert "Editor" in summary.roles def test_collect_with_none_permissions(self): from src.services.security_badge_service import SecurityBadgeService svc = SecurityBadgeService() role = make_role("Viewer", permissions=None) user = make_user(roles=[role]) result = svc._collect_user_permission_pairs(user) assert result == set() # #endregion Test.SecurityBadgeService