From 71ef2dda8bf7dcd22edde42ff3322af2206840ba Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Tue, 5 Nov 2024 17:03:32 +0100 Subject: [PATCH 1/8] Replicate system role assignments for custom roles in migrator --- .../relation_replicator.py | 1 + rbac/migration_tool/migrate.py | 66 +++++++++++++---- tests/migration_tool/tests_migrate.py | 70 +++++++++++++++++-- 3 files changed, 118 insertions(+), 19 deletions(-) diff --git a/rbac/management/relation_replicator/relation_replicator.py b/rbac/management/relation_replicator/relation_replicator.py index 006dff986..9e973840f 100644 --- a/rbac/management/relation_replicator/relation_replicator.py +++ b/rbac/management/relation_replicator/relation_replicator.py @@ -52,6 +52,7 @@ class ReplicationEventType(str, Enum): MIGRATE_CUSTOM_ROLE = "migrate_custom_role" MIGRATE_TENANT_GROUPS = "migrate_tenant_groups" CUSTOMIZE_DEFAULT_GROUP = "customize_default_group" + MIGRATE_SYSTEM_ROLE_ASSIGMENT = "migrate_system_role_assignment" class ReplicationEvent: diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index db9d857e8..be37244b2 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -18,7 +18,10 @@ import logging from typing import Iterable +from django.db import transaction from kessel.relations.v1beta1 import common_pb2 +from management.group.model import Group +from management.group.relation_api_dual_write_group_handler import RelationApiDualWriteGroupHandler from management.models import Workspace from management.principal.model import Principal from management.relation_replicator.logging_replicator import LoggingReplicator @@ -94,31 +97,66 @@ def migrate_role( return relationships, v2_role_bindings -def migrate_users_for_groups(tenant: Tenant) -> list[common_pb2.Relationship]: - """Write users relationship to groups.""" - relationships: list[common_pb2.Relationship] = [] - for group in tenant.group_set.exclude(platform_default=True): - user_set: Iterable[Principal] = group.principals.all() - for user in user_set: - if (relationship := group.relationship_to_principal(user)) is not None: - relationships.append(relationship) +def migrate_system_role_assignments_for_groups(groups: list[Group]) -> list[common_pb2.Relationship]: + """Generate system role assignments for groups.""" + with transaction.atomic(): + dual_write_handler = None + relationships: list[common_pb2.Relationship] = [] + for group in groups: + if group.system is False and group.admin_default is False: + if dual_write_handler is None: + dual_write_handler = RelationApiDualWriteGroupHandler(group, None) + else: + dual_write_handler.group = group + system_roles = group.roles().filter(system=True) + if system_roles.exists() > 0: + dual_write_handler.generate_relations_to_add_roles(system_roles) + relationships.extend(dual_write_handler.group_relations_to_add) return relationships -def migrate_data_for_tenant(tenant: Tenant, exclude_apps: list, replicator: RelationReplicator): - """Migrate all data for a given tenant.""" - logger.info("Migrating relations of group and user.") - - tuples = migrate_users_for_groups(tenant) +def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator): + """Generate user relationships and system role assignments for groups in a tenant.""" + groups = tenant.group_set.all() + user_relationships = migrate_user_relationships_for_groups(groups) replicator.replicate( ReplicationEvent( event_type=ReplicationEventType.MIGRATE_TENANT_GROUPS, info={"tenant": tenant.org_id}, partition_key=PartitionKey.byEnvironment(), - add=tuples, + add=user_relationships, + ) + ) + + system_role_relationships = migrate_system_role_assignments_for_groups(groups) + replicator.replicate( + ReplicationEvent( + event_type=ReplicationEventType.MIGRATE_SYSTEM_ROLE_ASSIGMENT, + info={"tenant": tenant.org_id}, + partition_key=PartitionKey.byEnvironment(), + add=system_role_relationships, ) ) + +def migrate_user_relationships_for_groups(groups: list[Group]) -> list[common_pb2.Relationship]: + """Write user relationships to groups.""" + relationships: list[common_pb2.Relationship] = [] + for group in groups: + if not group.platform_default: + user_set: Iterable[Principal] = group.principals.all() + for user in user_set: + if (relationship := group.relationship_to_principal(user)) is not None: + relationships.append(relationship) + return relationships + + +def migrate_data_for_tenant(tenant: Tenant, exclude_apps: list, replicator: RelationReplicator): + """Migrate all data for a given tenant.""" + logger.info("Migrating relations of group and user.") + + migrate_groups_for_tenant(tenant, replicator) + logger.info("Finished migrating relations of group and user.") default_workspace = Workspace.objects.get(type=Workspace.Types.DEFAULT, tenant=tenant) diff --git a/tests/migration_tool/tests_migrate.py b/tests/migration_tool/tests_migrate.py index 788ba47f7..f6a98227c 100644 --- a/tests/migration_tool/tests_migrate.py +++ b/tests/migration_tool/tests_migrate.py @@ -15,13 +15,18 @@ # along with this program. If not, see . # """Test the utils module.""" +from platform import system from unittest.mock import Mock, call, patch -from django.test import TestCase +from uuid import uuid4 + +from django.test import TestCase, override_settings from api.models import Tenant from management.models import * from migration_tool.migrate import migrate_data +from management.utils import clear_pk +from setuptools.command.easy_install import sys_executable class MigrateTests(TestCase): @@ -31,7 +36,7 @@ def setUp(self): """Set up the utils tests.""" super().setUp() public_tenant = Tenant.objects.get(tenant_name="public") - Group.objects.create(name="default", tenant=public_tenant, platform_default=True) + default_group = Group.objects.create(name="default", tenant=public_tenant, platform_default=True, system=True) # This would be skipped permission1 = Permission.objects.create(permission="app1:hosts:read", tenant=public_tenant) permission2 = Permission.objects.create(permission="inventory:hosts:write", tenant=public_tenant) @@ -82,19 +87,47 @@ def setUp(self): self.group_a2.principals.add(self.principal1, self.principal2) self.policy_a2 = Policy.objects.create(name="System Policy_a2", group=self.group_a2, tenant=self.tenant) self.policy_a2.roles.add(self.role_a2) + + self.system_role_1 = Role.objects.create( + name="System Role 1", platform_default=True, tenant=public_tenant, system=True + ) + self.policy_a2.roles.add(self.system_role_1) self.policy_a2.save() # setup data for another tenant 7654321 self.role_b = Role.objects.create(name="role_b", tenant=another_tenant) self.access_b = Access.objects.create(permission=permission2, role=self.role_b, tenant=another_tenant) - self.system_role = Role.objects.create(name="system_role", system=True, tenant=public_tenant) + self.system_role_2 = Role.objects.create(name="System Role 2", system=True, tenant=public_tenant) Access.objects.bulk_create( [ - Access(permission=permission1, role=self.system_role, tenant=public_tenant), - Access(permission=permission2, role=self.system_role, tenant=public_tenant), + Access(permission=permission1, role=self.system_role_2, tenant=public_tenant), + Access(permission=permission2, role=self.system_role_2, tenant=public_tenant), ] ) + # create custom default group + group = default_group + default_policy = Policy.objects.create( + system=True, name=f"System Policy for Group {group.uuid}", group=group, tenant=self.tenant + ) + group.policies.add(default_policy) + tenant_default_policy = group.policies.get(system=True) + group.name = "Custom default access" + group.system = False + group.tenant = self.tenant + group.uuid = uuid4() + clear_pk(group) + clear_pk(tenant_default_policy) + tenant_default_policy.uuid = uuid4() + tenant_default_policy.name = "System Policy for Group {}".format(group.uuid) + tenant_default_policy.tenant = self.tenant + group.save() + tenant_default_policy.group = group + tenant_default_policy.save() + tenant_default_policy.roles.add(self.system_role_2) + self.custom_default_group = group + + @override_settings(REPLICATION_TO_RELATION_ENABLED=True, PRINCIPAL_USER_DOMAIN="redhat") @patch("management.relation_replicator.logging_replicator.logger") def test_migration_of_data(self, logger_mock): """Test that we get the correct access for a principal.""" @@ -134,6 +167,25 @@ def test_migration_of_data(self, logger_mock): ): workspace_1, workspace_2 = workspace_2, workspace_1 + binding_mapping_system_role_1 = BindingMapping.objects.filter( + role=self.system_role_1, + resource_type_name="workspace", + resource_type_namespace="rbac", + resource_id=self.default_workspace.id, + ).get() + self.assertEqual(binding_mapping_system_role_1.mappings["groups"][0], str(self.group_a2.uuid)) + + role_binding_system_role_1_uuid = binding_mapping_system_role_1.mappings["id"] + + binding_mapping_system_role_2 = BindingMapping.objects.filter( + role=self.system_role_2, + resource_type_name="workspace", + resource_type_namespace="rbac", + resource_id=self.default_workspace.id, + ).get() + self.assertEqual(binding_mapping_system_role_2.mappings["groups"][0], str(self.custom_default_group.uuid)) + + role_binding_system_role_2_uuid = binding_mapping_system_role_2.mappings["id"] tuples = [ # Org relationships of self.tenant # the other org is not included since it is not specified in the orgs parameter @@ -155,5 +207,13 @@ def test_migration_of_data(self, logger_mock): call(f"role:{v2_role_a32}#inventory_hosts_write@principal:*"), call(f"workspace:{workspace_2}#parent@workspace:{default_workspace_id}"), call(f"workspace:{workspace_2}#binding@role_binding:{rolebinding_a32}"), + ## System role 1 assigment to custom group + call(f"workspace:{self.default_workspace.id}#binding@role_binding:{role_binding_system_role_1_uuid}"), + call(f"role_binding:{role_binding_system_role_1_uuid}#subject@group:{self.group_a2.uuid}"), + call(f"role_binding:{role_binding_system_role_1_uuid}#role@role:{self.system_role_1.uuid}"), + ## System role 2 assigment to custom default group + call(f"workspace:{self.default_workspace.id}#binding@role_binding:{role_binding_system_role_2_uuid}"), + call(f"role_binding:{role_binding_system_role_2_uuid}#subject@group:{self.custom_default_group.uuid}"), + call(f"role_binding:{role_binding_system_role_2_uuid}#role@role:{self.system_role_2.uuid}"), ] logger_mock.info.assert_has_calls(tuples, any_order=True) From cffae105df4abd496a3e9f26ad54cad7044b01f8 Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Thu, 7 Nov 2024 18:53:56 +0100 Subject: [PATCH 2/8] Leverage replication for user-groups membership from dual write handler --- .../relation_api_dual_write_group_handler.py | 10 ++- rbac/migration_tool/migrate.py | 61 ++++--------------- 2 files changed, 18 insertions(+), 53 deletions(-) diff --git a/rbac/management/group/relation_api_dual_write_group_handler.py b/rbac/management/group/relation_api_dual_write_group_handler.py index 23653fb8d..9fafb7569 100644 --- a/rbac/management/group/relation_api_dual_write_group_handler.py +++ b/rbac/management/group/relation_api_dual_write_group_handler.py @@ -93,13 +93,17 @@ def _generate_member_relations(self): return relations + def generate_relations_to_add_principals(self, principals: list[Principal]): + """Generate relations to add principals.""" + logger.info("[Dual Write] Generate new relations from Group(%s): '%s'", self.group.uuid, self.group.name) + self.principals = principals + self.group_relations_to_add = self._generate_member_relations() + def replicate_new_principals(self, principals: list[Principal]): """Replicate new principals into group.""" if not self.replication_enabled(): return - logger.info("[Dual Write] Generate new relations from Group(%s): '%s'", self.group.uuid, self.group.name) - self.principals = principals - self.group_relations_to_add = self._generate_member_relations() + self.generate_relations_to_add_principals(principals) self._replicate() def replicate_removed_principals(self, principals: list[Principal]): diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index be37244b2..8a695c0cf 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -20,10 +20,8 @@ from django.db import transaction from kessel.relations.v1beta1 import common_pb2 -from management.group.model import Group from management.group.relation_api_dual_write_group_handler import RelationApiDualWriteGroupHandler from management.models import Workspace -from management.principal.model import Principal from management.relation_replicator.logging_replicator import LoggingReplicator from management.relation_replicator.outbox_replicator import OutboxReplicator from management.relation_replicator.relation_replicator import ( @@ -97,58 +95,21 @@ def migrate_role( return relationships, v2_role_bindings -def migrate_system_role_assignments_for_groups(groups: list[Group]) -> list[common_pb2.Relationship]: - """Generate system role assignments for groups.""" - with transaction.atomic(): - dual_write_handler = None - relationships: list[common_pb2.Relationship] = [] - for group in groups: - if group.system is False and group.admin_default is False: - if dual_write_handler is None: - dual_write_handler = RelationApiDualWriteGroupHandler(group, None) - else: - dual_write_handler.group = group - system_roles = group.roles().filter(system=True) - if system_roles.exists() > 0: - dual_write_handler.generate_relations_to_add_roles(system_roles) - relationships.extend(dual_write_handler.group_relations_to_add) - return relationships - - def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator): """Generate user relationships and system role assignments for groups in a tenant.""" groups = tenant.group_set.all() - user_relationships = migrate_user_relationships_for_groups(groups) - replicator.replicate( - ReplicationEvent( - event_type=ReplicationEventType.MIGRATE_TENANT_GROUPS, - info={"tenant": tenant.org_id}, - partition_key=PartitionKey.byEnvironment(), - add=user_relationships, - ) - ) - - system_role_relationships = migrate_system_role_assignments_for_groups(groups) - replicator.replicate( - ReplicationEvent( - event_type=ReplicationEventType.MIGRATE_SYSTEM_ROLE_ASSIGMENT, - info={"tenant": tenant.org_id}, - partition_key=PartitionKey.byEnvironment(), - add=system_role_relationships, - ) - ) - - -def migrate_user_relationships_for_groups(groups: list[Group]) -> list[common_pb2.Relationship]: - """Write user relationships to groups.""" - relationships: list[common_pb2.Relationship] = [] for group in groups: - if not group.platform_default: - user_set: Iterable[Principal] = group.principals.all() - for user in user_set: - if (relationship := group.relationship_to_principal(user)) is not None: - relationships.append(relationship) - return relationships + with transaction.atomic(): + dual_write_handler = RelationApiDualWriteGroupHandler( + group, ReplicationEventType.MIGRATE_TENANT_GROUPS, replicator=replicator + ) + if not group.platform_default: + dual_write_handler.generate_relations_to_add_principals(group.principals.all()) + if group.system is False and group.admin_default is False: + system_roles = group.roles().filter(system=True) + if system_roles.exists() > 0: + dual_write_handler.generate_relations_to_add_roles(system_roles) + dual_write_handler.replicate() def migrate_data_for_tenant(tenant: Tenant, exclude_apps: list, replicator: RelationReplicator): From 4618398bb87bfe615b98cd29b24bd41283a69c4b Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Thu, 7 Nov 2024 18:58:58 +0100 Subject: [PATCH 3/8] Allow migration only on read only mode --- rbac/migration_tool/migrate.py | 5 +++++ tests/migration_tool/tests_migrate.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index 8a695c0cf..bb11301a1 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -18,6 +18,7 @@ import logging from typing import Iterable +from django.conf import settings from django.db import transaction from kessel.relations.v1beta1 import common_pb2 from management.group.relation_api_dual_write_group_handler import RelationApiDualWriteGroupHandler @@ -154,6 +155,10 @@ def migrate_data_for_tenant(tenant: Tenant, exclude_apps: list, replicator: Rela def migrate_data(exclude_apps: list = [], orgs: list = [], write_relationships: str = "False"): """Migrate all data for all tenants.""" + if not settings.READ_ONLY_API_MODE: + logger.info("Read-only API mode is required. READ_ONLY_API_MODE must be set to true.") + return + count = 0 tenants = Tenant.objects.exclude(tenant_name="public") replicator = _get_replicator(write_relationships) diff --git a/tests/migration_tool/tests_migrate.py b/tests/migration_tool/tests_migrate.py index f6a98227c..2a18baae9 100644 --- a/tests/migration_tool/tests_migrate.py +++ b/tests/migration_tool/tests_migrate.py @@ -127,7 +127,7 @@ def setUp(self): tenant_default_policy.roles.add(self.system_role_2) self.custom_default_group = group - @override_settings(REPLICATION_TO_RELATION_ENABLED=True, PRINCIPAL_USER_DOMAIN="redhat") + @override_settings(REPLICATION_TO_RELATION_ENABLED=True, PRINCIPAL_USER_DOMAIN="redhat", READ_ONLY_API_MODE=True) @patch("management.relation_replicator.logging_replicator.logger") def test_migration_of_data(self, logger_mock): """Test that we get the correct access for a principal.""" From 33771a7616dd2429b2ed93a8e416073295f0cbf9 Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Fri, 8 Nov 2024 09:40:24 +0100 Subject: [PATCH 4/8] Update rbac/migration_tool/migrate.py Co-authored-by: Alec Henninger --- rbac/migration_tool/migrate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index bb11301a1..eb4acee80 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -100,6 +100,8 @@ def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator): """Generate user relationships and system role assignments for groups in a tenant.""" groups = tenant.group_set.all() for group in groups: + # The migrator does not generally deal with concurrency control, + # but we require an atomic block due to use of select_for_update in the dual write handler. with transaction.atomic(): dual_write_handler = RelationApiDualWriteGroupHandler( group, ReplicationEventType.MIGRATE_TENANT_GROUPS, replicator=replicator From 5e35fbe0a92428381107d21e8019d818ee405d55 Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Fri, 8 Nov 2024 09:45:27 +0100 Subject: [PATCH 5/8] Update rbac/migration_tool/migrate.py Co-authored-by: Alec Henninger --- rbac/migration_tool/migrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index eb4acee80..e3aba72ae 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -158,7 +158,7 @@ def migrate_data_for_tenant(tenant: Tenant, exclude_apps: list, replicator: Rela def migrate_data(exclude_apps: list = [], orgs: list = [], write_relationships: str = "False"): """Migrate all data for all tenants.""" if not settings.READ_ONLY_API_MODE: - logger.info("Read-only API mode is required. READ_ONLY_API_MODE must be set to true.") + logger.fatal("Read-only API mode is required. READ_ONLY_API_MODE must be set to true.") return count = 0 From 663b08b37ffc36b3ef78d2e659d915253f08888a Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Fri, 8 Nov 2024 10:15:49 +0100 Subject: [PATCH 6/8] Use check in memory for existence of system relations Co-authored-by: Alec Henninger --- rbac/migration_tool/migrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index e3aba72ae..2f46314ff 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -110,7 +110,7 @@ def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator): dual_write_handler.generate_relations_to_add_principals(group.principals.all()) if group.system is False and group.admin_default is False: system_roles = group.roles().filter(system=True) - if system_roles.exists() > 0: + if any(True for _ in system_roles): dual_write_handler.generate_relations_to_add_roles(system_roles) dual_write_handler.replicate() From 2346391679be95c76739d78429f62896bd0ecf7b Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Fri, 8 Nov 2024 10:35:24 +0100 Subject: [PATCH 7/8] Don't call replicate method for group assigment if it is not needed --- rbac/migration_tool/migrate.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/rbac/migration_tool/migrate.py b/rbac/migration_tool/migrate.py index 2f46314ff..194844616 100644 --- a/rbac/migration_tool/migrate.py +++ b/rbac/migration_tool/migrate.py @@ -23,6 +23,7 @@ from kessel.relations.v1beta1 import common_pb2 from management.group.relation_api_dual_write_group_handler import RelationApiDualWriteGroupHandler from management.models import Workspace +from management.principal.model import Principal from management.relation_replicator.logging_replicator import LoggingReplicator from management.relation_replicator.outbox_replicator import OutboxReplicator from management.relation_replicator.relation_replicator import ( @@ -100,19 +101,22 @@ def migrate_groups_for_tenant(tenant: Tenant, replicator: RelationReplicator): """Generate user relationships and system role assignments for groups in a tenant.""" groups = tenant.group_set.all() for group in groups: - # The migrator does not generally deal with concurrency control, - # but we require an atomic block due to use of select_for_update in the dual write handler. - with transaction.atomic(): - dual_write_handler = RelationApiDualWriteGroupHandler( - group, ReplicationEventType.MIGRATE_TENANT_GROUPS, replicator=replicator - ) - if not group.platform_default: - dual_write_handler.generate_relations_to_add_principals(group.principals.all()) - if group.system is False and group.admin_default is False: - system_roles = group.roles().filter(system=True) - if any(True for _ in system_roles): - dual_write_handler.generate_relations_to_add_roles(system_roles) - dual_write_handler.replicate() + principals: list[Principal] = [] + system_roles: list[Role] = [] + if not group.platform_default: + principals = group.principals.all() + if group.system is False and group.admin_default is False: + system_roles = group.roles().filter(system=True) + if any(True for _ in system_roles) or any(True for _ in principals): + # The migrator does not generally deal with concurrency control, + # but we require an atomic block due to use of select_for_update in the dual write handler. + with transaction.atomic(): + dual_write_handler = RelationApiDualWriteGroupHandler( + group, ReplicationEventType.MIGRATE_TENANT_GROUPS, replicator=replicator + ) + dual_write_handler.generate_relations_to_add_principals(principals) + dual_write_handler.generate_relations_to_add_roles(system_roles) + dual_write_handler.replicate() def migrate_data_for_tenant(tenant: Tenant, exclude_apps: list, replicator: RelationReplicator): From e22761e1e992ce951c5e989194be9601dc71a3cb Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Fri, 8 Nov 2024 14:04:38 +0100 Subject: [PATCH 8/8] Reorder migration tests; Use clone_default_group_in_public_schema and seed_group methods --- tests/migration_tool/tests_migrate.py | 75 +++++++++++++-------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/tests/migration_tool/tests_migrate.py b/tests/migration_tool/tests_migrate.py index 2a18baae9..396b7b57b 100644 --- a/tests/migration_tool/tests_migrate.py +++ b/tests/migration_tool/tests_migrate.py @@ -25,8 +25,7 @@ from api.models import Tenant from management.models import * from migration_tool.migrate import migrate_data -from management.utils import clear_pk -from setuptools.command.easy_install import sys_executable +from management.group.definer import seed_group, clone_default_group_in_public_schema class MigrateTests(TestCase): @@ -35,12 +34,31 @@ class MigrateTests(TestCase): def setUp(self): """Set up the utils tests.""" super().setUp() + # public tenant public_tenant = Tenant.objects.get(tenant_name="public") - default_group = Group.objects.create(name="default", tenant=public_tenant, platform_default=True, system=True) + + # system roles + self.system_role_1 = Role.objects.create( + name="System Role 1", platform_default=True, tenant=public_tenant, system=True + ) + self.system_role_2 = Role.objects.create( + name="System Role 2", platform_default=True, system=True, tenant=public_tenant + ) + # default group + default_group, _ = seed_group() + # permissions # This would be skipped permission1 = Permission.objects.create(permission="app1:hosts:read", tenant=public_tenant) permission2 = Permission.objects.create(permission="inventory:hosts:write", tenant=public_tenant) - # Two organization + Access.objects.bulk_create( + [ + Access(permission=permission1, role=self.system_role_2, tenant=public_tenant), + Access(permission=permission2, role=self.system_role_2, tenant=public_tenant), + ] + ) + + # two organizations + # tenant 1 - org_id=1234567 self.tenant = Tenant.objects.create(org_id="1234567", tenant_name="tenant") self.root_workspace = Workspace.objects.create( type=Workspace.Types.ROOT, tenant=self.tenant, name="Root Workspace" @@ -48,12 +66,10 @@ def setUp(self): self.default_workspace = Workspace.objects.create( type=Workspace.Types.DEFAULT, tenant=self.tenant, name="Default Workspace", parent=self.root_workspace ) - - another_tenant = Tenant.objects.create(org_id="7654321") - # setup data for organization 1234567 self.workspace_id_1 = "123456" self.workspace_id_2 = "654321" + # This role will be skipped because it contains permission with skipping application self.role_a1 = Role.objects.create(name="role_a1", tenant=self.tenant) self.access_a11 = Access.objects.create(permission=permission1, role=self.role_a1, tenant=self.tenant) @@ -88,44 +104,18 @@ def setUp(self): self.policy_a2 = Policy.objects.create(name="System Policy_a2", group=self.group_a2, tenant=self.tenant) self.policy_a2.roles.add(self.role_a2) - self.system_role_1 = Role.objects.create( - name="System Role 1", platform_default=True, tenant=public_tenant, system=True - ) - self.policy_a2.roles.add(self.system_role_1) - self.policy_a2.save() + # tenant 2 - org_id=7654321 + another_tenant = Tenant.objects.create(org_id="7654321") # setup data for another tenant 7654321 self.role_b = Role.objects.create(name="role_b", tenant=another_tenant) self.access_b = Access.objects.create(permission=permission2, role=self.role_b, tenant=another_tenant) - self.system_role_2 = Role.objects.create(name="System Role 2", system=True, tenant=public_tenant) - Access.objects.bulk_create( - [ - Access(permission=permission1, role=self.system_role_2, tenant=public_tenant), - Access(permission=permission2, role=self.system_role_2, tenant=public_tenant), - ] - ) + + self.policy_a2.roles.add(self.system_role_1) + self.policy_a2.save() # create custom default group - group = default_group - default_policy = Policy.objects.create( - system=True, name=f"System Policy for Group {group.uuid}", group=group, tenant=self.tenant - ) - group.policies.add(default_policy) - tenant_default_policy = group.policies.get(system=True) - group.name = "Custom default access" - group.system = False - group.tenant = self.tenant - group.uuid = uuid4() - clear_pk(group) - clear_pk(tenant_default_policy) - tenant_default_policy.uuid = uuid4() - tenant_default_policy.name = "System Policy for Group {}".format(group.uuid) - tenant_default_policy.tenant = self.tenant - group.save() - tenant_default_policy.group = group - tenant_default_policy.save() - tenant_default_policy.roles.add(self.system_role_2) - self.custom_default_group = group + self.custom_default_group = clone_default_group_in_public_schema(default_group, self.tenant) @override_settings(REPLICATION_TO_RELATION_ENABLED=True, PRINCIPAL_USER_DOMAIN="redhat", READ_ONLY_API_MODE=True) @patch("management.relation_replicator.logging_replicator.logger") @@ -173,7 +163,11 @@ def test_migration_of_data(self, logger_mock): resource_type_namespace="rbac", resource_id=self.default_workspace.id, ).get() - self.assertEqual(binding_mapping_system_role_1.mappings["groups"][0], str(self.group_a2.uuid)) + + self.assertEqual( + binding_mapping_system_role_1.mappings["groups"], + [str(self.custom_default_group.uuid), str(self.group_a2.uuid)], + ) role_binding_system_role_1_uuid = binding_mapping_system_role_1.mappings["id"] @@ -183,6 +177,7 @@ def test_migration_of_data(self, logger_mock): resource_type_namespace="rbac", resource_id=self.default_workspace.id, ).get() + self.assertEqual(binding_mapping_system_role_2.mappings["groups"][0], str(self.custom_default_group.uuid)) role_binding_system_role_2_uuid = binding_mapping_system_role_2.mappings["id"]