diff --git a/internal/sync/roles.go b/internal/sync/roles.go index 36957db..d54e628 100644 --- a/internal/sync/roles.go +++ b/internal/sync/roles.go @@ -73,6 +73,7 @@ func isLagoonGroup( // ID of the group's project. func projectGroupRoleName( group keycloak.Group, + projectNames map[int]string, groupProjectsMap map[string][]int, ) (string, error) { projectIDs, ok := groupProjectsMap[group.ID] @@ -80,24 +81,32 @@ func projectGroupRoleName( return "", fmt.Errorf("missing project group ID %s in groupProjectsMap", group.ID) } - if len(projectIDs) != 1 { - return "", fmt.Errorf("too many projects in group ID %s: %d", group.ID, - len(projectIDs)) + if len(projectIDs) == 0 { + return "", fmt.Errorf("missing project IDs in project group ID %s", group.ID) } - if projectIDs[0] < 0 { - return "", fmt.Errorf("invalid project ID in group ID %s: %d", group.ID, - projectIDs[0]) + for _, pid := range projectIDs { + if pid < 0 { + return "", fmt.Errorf("invalid project ID in group ID %s: %d", group.ID, pid) + } + if strings.TrimPrefix(group.Name, "project-") == projectNames[pid] { + return fmt.Sprintf("p%d", pid), nil + } } - return fmt.Sprintf("p%d", projectIDs[0]), nil + return "", fmt.Errorf( + "couldn't match project group ID %s to any member project IDs: %v", + group.ID, + projectIDs, + ) } // generateProjectGroupRole constructs an opensearch.Role from the given // keycloak group corresponding to a Lagoon project group. func generateProjectGroupRole( group keycloak.Group, + projectNames map[int]string, groupProjectsMap map[string][]int, ) (string, *opensearch.Role, error) { - name, err := projectGroupRoleName(group, groupProjectsMap) + name, err := projectGroupRoleName(group, projectNames, groupProjectsMap) if err != nil { return "", nil, fmt.Errorf("couldn't generate project group role name: %v", err) @@ -200,7 +209,8 @@ func generateRoles( var err error for _, group := range groups { if isProjectGroup(log, group) { - name, role, err = generateProjectGroupRole(group, groupProjectsMap) + name, role, err = + generateProjectGroupRole(group, projectNames, groupProjectsMap) if err != nil { log.Warn("couldn't generate role for project group", zap.String("group name", group.Name), zap.Error(err)) diff --git a/internal/sync/rolesmapping.go b/internal/sync/rolesmapping.go index cebcf6f..97b7847 100644 --- a/internal/sync/rolesmapping.go +++ b/internal/sync/rolesmapping.go @@ -62,13 +62,14 @@ func calculateRoleMappingDiff( func generateRolesMapping( log *zap.Logger, groups []keycloak.Group, + projectNames map[int]string, groupProjectsMap map[string][]int, ) map[string]opensearch.RoleMapping { rolesmapping := map[string]opensearch.RoleMapping{} for _, group := range groups { // figure out if this is a regular group or project group if isProjectGroup(log, group) { - name, err := projectGroupRoleName(group, groupProjectsMap) + name, err := projectGroupRoleName(group, projectNames, groupProjectsMap) if err != nil { log.Warn("couldn't generate project group role name", zap.Error(err), zap.String("group name", group.Name)) @@ -123,6 +124,7 @@ func syncRolesMapping( ctx context.Context, log *zap.Logger, groups []keycloak.Group, + projectNames map[int]string, roles map[string]opensearch.Role, groupProjectsMap map[string][]int, o OpensearchService, @@ -137,7 +139,7 @@ func syncRolesMapping( // ignore non-lagoon rolesmapping existing = filterRolesMapping(existing, roles) // generate the rolesmapping required by Lagoon - required := generateRolesMapping(log, groups, groupProjectsMap) + required := generateRolesMapping(log, groups, projectNames, groupProjectsMap) // calculate rolesmapping to add/remove toCreate, toDelete := calculateRoleMappingDiff(existing, required) for _, name := range toDelete { diff --git a/internal/sync/sync.go b/internal/sync/sync.go index 667ef92..a2469f3 100644 --- a/internal/sync/sync.go +++ b/internal/sync/sync.go @@ -112,7 +112,7 @@ func Sync(ctx context.Context, log *zap.Logger, l LagoonDBService, case "roles": syncRoles(ctx, log, groups, projectNames, roles, groupProjectsMap, o, dryRun) case "rolesmapping": - syncRolesMapping(ctx, log, groups, roles, groupProjectsMap, o, dryRun) + syncRolesMapping(ctx, log, groups, projectNames, roles, groupProjectsMap, o, dryRun) case "indexpatterns": syncIndexPatterns(ctx, log, groupsSansGlobal, projectNames, groupProjectsMap, o, d, dryRun, legacyIndexPatternDelimiter)