// SPDX-License-Identifier: MPL-2.0 package organizations import ( "context" "errors" "slices" "time" ) var ErrRoleInvitationUnsupported = errors.New("organizations: atomic role-set invitations are unsupported") // RoleInvitationRepository must preserve the entire role set and its required // owner authority, then commit acceptance, membership, grants and audit together. type RoleInvitationRepository interface { CreateInvitationWithRoles(context.Context, Invitation, string, AuditEvent) error AcceptInvitationWithRoles(context.Context, [32]byte, string, string, time.Time, AuditEvent) error } // RoleNames returns a validated copy of the invitation's direct roles. The older // DirectRole remains supported; supplying both forms is an error, not a union. func (invitation Invitation) RoleNames() ([]string, error) { if invitation.DirectRole != "" && len(invitation.DirectRoles) > 0 || len(invitation.DirectRoles) > 16 { return nil, errors.New("organizations: invalid invitation roles") } roles := append([]string(nil), invitation.DirectRoles...) if invitation.DirectRole != "" { roles = append(roles, invitation.DirectRole) } slices.Sort(roles) for i, role := range roles { if !safeNamePattern.MatchString(role) || i > 0 && role == roles[i-1] { return nil, errors.New("organizations: invalid invitation role") } } return roles, nil }