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 }