github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/rbac_test.go (about)

     1  package resolver
     2  
     3  import (
     4  	"math/rand"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  	"testing/quick"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	rbacv1 "k8s.io/api/rbac/v1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  
    15  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    16  )
    17  
    18  func TestGenerateName(t *testing.T) {
    19  	type args struct {
    20  		base string
    21  		o    interface{}
    22  	}
    23  	tests := []struct {
    24  		name string
    25  		args args
    26  		want string
    27  	}{
    28  		{
    29  			name: "generate",
    30  			args: args{
    31  				base: "myname",
    32  				o:    []string{"something"},
    33  			},
    34  			want: "myname-5L9sNXi3Y6mcOevFzYY3WOLIukKOeZwz1pfUlT",
    35  		},
    36  		{
    37  			name: "truncated",
    38  			args: args{
    39  				base: strings.Repeat("name", 100),
    40  				o:    []string{"something", "else"},
    41  			},
    42  			want: "namenamenamenamenamename-6XtefCelEzfYlFOD1fARIK5vhWVfWfGHja7H3q",
    43  		},
    44  	}
    45  	for _, tt := range tests {
    46  		t.Run(tt.name, func(t *testing.T) {
    47  			got, err := generateName(tt.args.base, tt.args.o)
    48  			require.NoError(t, err)
    49  			require.Equal(t, tt.want, got)
    50  			require.LessOrEqual(t, len(got), maxNameLength)
    51  		})
    52  	}
    53  }
    54  
    55  var runeSet = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-")
    56  
    57  type validKubeName string
    58  
    59  func (validKubeName) Generate(rand *rand.Rand, size int) reflect.Value {
    60  	b := make([]rune, size)
    61  	for i := range b {
    62  		b[i] = runeSet[rand.Intn(len(runeSet))]
    63  	}
    64  	return reflect.ValueOf(validKubeName(b))
    65  }
    66  
    67  func TestGeneratesWithinRange(t *testing.T) {
    68  	f := func(base validKubeName, o string) bool {
    69  		out, err := generateName(string(base), o)
    70  		return len(out) <= maxNameLength || err == nil
    71  	}
    72  	require.NoError(t, quick.Check(f, nil))
    73  }
    74  
    75  func TestRBACForClusterServiceVersion(t *testing.T) {
    76  	serviceAccount1 := "test-service-account"
    77  	serviceAccount2 := "second-service-account"
    78  	csvName := "test-csv.v1.1.0"
    79  
    80  	rules := []rbacv1.PolicyRule{
    81  		{
    82  			Verbs:     []string{"get"},
    83  			APIGroups: []string{""},
    84  			Resources: []string{"pods"},
    85  		},
    86  	}
    87  
    88  	// Note: two CSVs have same name and permissions for a cluster role, this is chosen intentionally,
    89  	// to verify that ClusterRole and ClusterRoleBinding have different names when the same CSV is installed
    90  	// twice in the same cluster, but in different namespaces.
    91  	tests := []struct {
    92  		name string
    93  		csv  v1alpha1.ClusterServiceVersion
    94  		want map[string]*OperatorPermissions
    95  	}{
    96  		{
    97  			name: "RoleBindings and one ClusterRoleBinding",
    98  			csv: v1alpha1.ClusterServiceVersion{
    99  				ObjectMeta: metav1.ObjectMeta{
   100  					Name:      csvName,
   101  					Namespace: "test-namespace",
   102  				},
   103  				Spec: v1alpha1.ClusterServiceVersionSpec{
   104  					InstallStrategy: v1alpha1.NamedInstallStrategy{
   105  						StrategyName: v1alpha1.InstallStrategyNameDeployment,
   106  						StrategySpec: v1alpha1.StrategyDetailsDeployment{
   107  							Permissions: []v1alpha1.StrategyDeploymentPermissions{
   108  								{
   109  									ServiceAccountName: serviceAccount1,
   110  									Rules:              rules,
   111  								},
   112  								{
   113  									ServiceAccountName: serviceAccount1,
   114  									Rules: []rbacv1.PolicyRule{
   115  										{
   116  											Verbs:     []string{"get"},
   117  											APIGroups: []string{""},
   118  											Resources: []string{"deployments"},
   119  										},
   120  									},
   121  								},
   122  								{
   123  									ServiceAccountName: serviceAccount2,
   124  									Rules:              rules,
   125  								},
   126  							},
   127  							ClusterPermissions: []v1alpha1.StrategyDeploymentPermissions{
   128  								{
   129  									ServiceAccountName: serviceAccount1,
   130  									Rules:              rules,
   131  								},
   132  							},
   133  						},
   134  					},
   135  				},
   136  			},
   137  			want: map[string]*OperatorPermissions{
   138  				serviceAccount1: {
   139  					RoleBindings:        []*rbacv1.RoleBinding{{}, {}},
   140  					ClusterRoleBindings: []*rbacv1.ClusterRoleBinding{{}},
   141  				},
   142  				serviceAccount2: {
   143  					RoleBindings: []*rbacv1.RoleBinding{{}},
   144  				},
   145  			},
   146  		},
   147  		{
   148  			name: "ClusterRoleBinding",
   149  			csv: v1alpha1.ClusterServiceVersion{
   150  				ObjectMeta: metav1.ObjectMeta{
   151  					Name:      csvName,
   152  					Namespace: "second-namespace",
   153  				},
   154  				Spec: v1alpha1.ClusterServiceVersionSpec{
   155  					InstallStrategy: v1alpha1.NamedInstallStrategy{
   156  						StrategyName: v1alpha1.InstallStrategyNameDeployment,
   157  						StrategySpec: v1alpha1.StrategyDetailsDeployment{
   158  							ClusterPermissions: []v1alpha1.StrategyDeploymentPermissions{
   159  								{
   160  									ServiceAccountName: serviceAccount1,
   161  									Rules:              rules,
   162  								},
   163  								{
   164  									ServiceAccountName: serviceAccount2,
   165  									Rules:              rules,
   166  								},
   167  							},
   168  						},
   169  					},
   170  				},
   171  			},
   172  			want: map[string]*OperatorPermissions{
   173  				serviceAccount1: {
   174  					ClusterRoleBindings: []*rbacv1.ClusterRoleBinding{{}},
   175  				},
   176  				serviceAccount2: {
   177  					ClusterRoleBindings: []*rbacv1.ClusterRoleBinding{{}},
   178  				},
   179  			},
   180  		},
   181  	}
   182  
   183  	// declared here to verify that names are unique when same csv is install in different namespaces
   184  	clusterRoleBindingNames := map[string]bool{}
   185  	clusterRolesNames := map[string]bool{}
   186  
   187  	for _, tt := range tests {
   188  		t.Run(tt.name, func(t *testing.T) {
   189  			result, err := RBACForClusterServiceVersion(&tt.csv)
   190  			require.NoError(t, err)
   191  
   192  			roleBindingNames := map[string]bool{}
   193  			rolesNames := map[string]bool{}
   194  			for serviceAccount, permissions := range tt.want {
   195  				// Check that correct number of bindings is created
   196  				require.Equal(t, len(permissions.RoleBindings), len(result[serviceAccount].RoleBindings))
   197  				require.Equal(t, len(permissions.ClusterRoleBindings), len(result[serviceAccount].ClusterRoleBindings))
   198  
   199  				// Check that testing ServiceAccount is the Subject of RoleBindings
   200  				for _, roleBinding := range result[serviceAccount].RoleBindings {
   201  					require.Len(t, roleBinding.Subjects, 1)
   202  					require.Equal(t, serviceAccount, roleBinding.Subjects[0].Name)
   203  
   204  					// Check that RoleBindings are created with unique names
   205  					_, rbWithNameExists := roleBindingNames[roleBinding.Name]
   206  					require.False(t, rbWithNameExists, "RoleBinding with the same name already generated")
   207  					roleBindingNames[roleBinding.Name] = true
   208  				}
   209  
   210  				// Check that testing ServiceAccount is the Subject of ClusterrRoleBindings
   211  				for _, clusterRoleBinding := range result[serviceAccount].ClusterRoleBindings {
   212  					require.Len(t, clusterRoleBinding.Subjects, 1)
   213  					require.Equal(t, serviceAccount, clusterRoleBinding.Subjects[0].Name)
   214  
   215  					// Check that ClusterRoleBindings are created with unique names
   216  					_, crbWithNameExists := clusterRoleBindingNames[clusterRoleBinding.Name]
   217  					require.False(t, crbWithNameExists, "ClusterRoleBinding with the same name already generated")
   218  					clusterRoleBindingNames[clusterRoleBinding.Name] = true
   219  				}
   220  
   221  				// Check that Roles are created with unique names
   222  				for _, role := range result[serviceAccount].Roles {
   223  					_, roleWithNameExists := rolesNames[role.Name]
   224  					require.False(t, roleWithNameExists, "Role with the same name already generated")
   225  					rolesNames[role.Name] = true
   226  				}
   227  
   228  				// Check that ClusterRoles are created with unique names
   229  				for _, clusterRole := range result[serviceAccount].ClusterRoles {
   230  					_, crWithNameExists := clusterRolesNames[clusterRole.Name]
   231  					require.False(t, crWithNameExists, "ClusterRole with the same name already generated")
   232  					clusterRolesNames[clusterRole.Name] = true
   233  				}
   234  			}
   235  		})
   236  	}
   237  }