package service import ( "context" "go.infratographer.com/x/events" "go.infratographer.com/x/gidx" ) func (s *service) processRelationships(ctx context.Context, subjectType string, relationships []Relationship) { var err error for _, rel := range relationships { err = s.publisher.PublishChange(ctx, subjectType, events.ChangeMessage{ SubjectID: rel.Resource.PrefixedID(), EventType: string(events.CreateChangeType), AdditionalSubjectIDs: []gidx.PrefixedID{ rel.RelatedResource.PrefixedID(), }, }) if err != nil { s.logger.Errorw("error publishing change", "subject_type", subjectType, "resource.id", rel.Resource.PrefixedID(), "related_resource.id", rel.RelatedResource.PrefixedID(), "error", err, ) } } } func (s *service) processMemberships(ctx context.Context, memberships []ResourceMemberships) { resourceRoleID := make(map[gidx.PrefixedID]map[string]gidx.PrefixedID) resourceRoleMembers := make(map[gidx.PrefixedID]map[string]map[gidx.PrefixedID]bool) roleActions := make(map[string][]string) for _, membership := range memberships { resourceID := membership.Resource.PrefixedID() role := membership.Role memberID := membership.Member.PrefixedID() if _, ok := resourceRoleMembers[resourceID]; !ok { resourceRoleID[resourceID] = make(map[string]gidx.PrefixedID) resourceRoleMembers[resourceID] = make(map[string]map[gidx.PrefixedID]bool) } if _, ok := resourceRoleMembers[resourceID][role]; !ok { resourceRoleMembers[resourceID][role] = make(map[gidx.PrefixedID]bool) roleActions[role] = s.roles[role] } resourceRoleID[resourceID][role] = gidx.NullPrefixedID resourceRoleMembers[resourceID][role][memberID] = true } resourceRoleAssignments := make(map[gidx.PrefixedID]map[gidx.PrefixedID]map[gidx.PrefixedID]bool) for resourceID, roles := range resourceRoleID { resourceRoleAssignments[resourceID] = make(map[gidx.PrefixedID]map[gidx.PrefixedID]bool) for role := range roles { actions := roleActions[role] resourceRole, err := s.perms.FindResourceRoleByActions(ctx, resourceID, actions) if err != nil { s.logger.Warnw("failed to find role by actions for resource", "resource.id", resourceID, "role", role, "actions", actions, "error", err) continue } resourceRoleID[resourceID][role] = resourceRole.ID resourceRoleAssignments[resourceID][resourceRole.ID] = make(map[gidx.PrefixedID]bool) assignments, err := s.perms.ListRoleAssignments(ctx, resourceRole.ID) if err != nil { s.logger.Warnw("failed to get role assignments for resource", "resource.id", resourceID, "role", role, "error", err) continue } for _, assignment := range assignments { resourceRoleAssignments[resourceID][resourceRole.ID][assignment] = true } } } for resourceID, roles := range resourceRoleMembers { for role, members := range roles { roleID := resourceRoleID[resourceID][role] actions := roleActions[role] logger := s.logger.With("resource.id", resourceID, "role.name", role, "actions", actions) var createdRole bool if roleID == gidx.NullPrefixedID { logger.Infow("creating role for resource") resourceRoleID, err := s.perms.CreateRole(ctx, resourceID, actions) if err != nil { logger.Errorw("failed to create role for resource", "error", err) continue } createdRole = true roleID = resourceRoleID } logger = logger.With("role.id", roleID) assignments := make(map[gidx.PrefixedID]bool) if !createdRole { assignments = resourceRoleAssignments[resourceID][roleID] } for memberID := range members { mlogger := logger.With("member.id", memberID) if _, ok := assignments[memberID]; ok { mlogger.Infow("skipping already assigned member") continue } if err := s.perms.AssignRole(ctx, roleID, memberID); err != nil { mlogger.Errorw("failed to assign member to role", "error", err) continue } mlogger.Infow("role assigned to member") } } } }