k8s.io/kubernetes@v1.29.3/pkg/registry/rbac/validation/policy_compact_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package validation 18 19 import ( 20 "reflect" 21 "sort" 22 "testing" 23 24 rbacv1 "k8s.io/api/rbac/v1" 25 "k8s.io/component-helpers/auth/rbac/validation" 26 rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1" 27 ) 28 29 func TestCompactRules(t *testing.T) { 30 testcases := map[string]struct { 31 Rules []rbacv1.PolicyRule 32 Expected []rbacv1.PolicyRule 33 }{ 34 "empty": { 35 Rules: []rbacv1.PolicyRule{}, 36 Expected: []rbacv1.PolicyRule{}, 37 }, 38 "simple": { 39 Rules: []rbacv1.PolicyRule{ 40 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}}, 41 {Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}}, 42 {Verbs: []string{"update", "patch"}, APIGroups: []string{""}, Resources: []string{"builds"}}, 43 44 {Verbs: []string{"create"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}}, 45 {Verbs: []string{"delete"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}}, 46 {Verbs: []string{"patch"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{""}}, 47 {Verbs: []string{"get"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}}, 48 {Verbs: []string{"list"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}}, 49 50 {Verbs: []string{"educate"}, APIGroups: []string{""}, Resources: []string{"dolphins"}}, 51 52 // nil verbs are preserved in non-merge cases. 53 // these are the pirates who don't do anything. 54 {Verbs: nil, APIGroups: []string{""}, Resources: []string{"pirates"}}, 55 56 // Test merging into a nil Verbs string set 57 {Verbs: nil, APIGroups: []string{""}, Resources: []string{"pods"}}, 58 {Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"pods"}}, 59 }, 60 Expected: []rbacv1.PolicyRule{ 61 {Verbs: []string{"create", "delete"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}}, 62 {Verbs: []string{"patch"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{""}}, 63 {Verbs: []string{"get", "list"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}}, 64 {Verbs: []string{"get", "list", "update", "patch"}, APIGroups: []string{""}, Resources: []string{"builds"}}, 65 {Verbs: []string{"educate"}, APIGroups: []string{""}, Resources: []string{"dolphins"}}, 66 {Verbs: nil, APIGroups: []string{""}, Resources: []string{"pirates"}}, 67 {Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"pods"}}, 68 }, 69 }, 70 "complex multi-group": { 71 Rules: []rbacv1.PolicyRule{ 72 {Verbs: []string{"get"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}}, 73 {Verbs: []string{"list"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}}, 74 }, 75 Expected: []rbacv1.PolicyRule{ 76 {Verbs: []string{"get"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}}, 77 {Verbs: []string{"list"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}}, 78 }, 79 }, 80 81 "complex multi-resource": { 82 Rules: []rbacv1.PolicyRule{ 83 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}}, 84 {Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}}, 85 }, 86 Expected: []rbacv1.PolicyRule{ 87 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}}, 88 {Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}}, 89 }, 90 }, 91 92 "complex named-resource": { 93 Rules: []rbacv1.PolicyRule{ 94 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild"}}, 95 {Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild2"}}, 96 }, 97 Expected: []rbacv1.PolicyRule{ 98 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild"}}, 99 {Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild2"}}, 100 }, 101 }, 102 103 "complex non-resource": { 104 Rules: []rbacv1.PolicyRule{ 105 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}}, 106 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/foo"}}, 107 }, 108 Expected: []rbacv1.PolicyRule{ 109 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}}, 110 {Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/foo"}}, 111 }, 112 }, 113 } 114 115 for k, tc := range testcases { 116 rules := tc.Rules 117 originalRules := make([]rbacv1.PolicyRule, len(tc.Rules)) 118 for i := range tc.Rules { 119 originalRules[i] = *tc.Rules[i].DeepCopy() 120 } 121 compacted, err := CompactRules(tc.Rules) 122 if err != nil { 123 t.Errorf("%s: unexpected error: %v", k, err) 124 continue 125 } 126 if !reflect.DeepEqual(rules, originalRules) { 127 t.Errorf("%s: CompactRules mutated rules. Expected\n%#v\ngot\n%#v", k, originalRules, rules) 128 continue 129 } 130 if covers, missing := validation.Covers(compacted, rules); !covers { 131 t.Errorf("%s: compacted rules did not cover original rules. missing: %#v", k, missing) 132 continue 133 } 134 if covers, missing := validation.Covers(rules, compacted); !covers { 135 t.Errorf("%s: original rules did not cover compacted rules. missing: %#v", k, missing) 136 continue 137 } 138 139 sort.Stable(rbacv1helpers.SortableRuleSlice(compacted)) 140 sort.Stable(rbacv1helpers.SortableRuleSlice(tc.Expected)) 141 if !reflect.DeepEqual(compacted, tc.Expected) { 142 t.Errorf("%s: Expected\n%#v\ngot\n%#v", k, tc.Expected, compacted) 143 continue 144 } 145 } 146 } 147 148 func TestIsSimpleResourceRule(t *testing.T) { 149 testcases := map[string]struct { 150 Rule rbacv1.PolicyRule 151 Simple bool 152 Resource simpleResource 153 }{ 154 "simple, no verbs": { 155 Rule: rbacv1.PolicyRule{Verbs: []string{}, APIGroups: []string{""}, Resources: []string{"builds"}}, 156 Simple: true, 157 Resource: simpleResource{Group: "", Resource: "builds"}, 158 }, 159 "simple, one verb": { 160 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}}, 161 Simple: true, 162 Resource: simpleResource{Group: "", Resource: "builds"}, 163 }, 164 "simple, one empty resource name": { 165 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{""}}, 166 Simple: true, 167 Resource: simpleResource{Group: "", Resource: "builds", ResourceNameExist: true, ResourceName: ""}, 168 }, 169 "simple, one resource name": { 170 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"foo"}}, 171 Simple: true, 172 Resource: simpleResource{Group: "", Resource: "builds", ResourceNameExist: true, ResourceName: "foo"}, 173 }, 174 "simple, multi verb": { 175 Rule: rbacv1.PolicyRule{Verbs: []string{"get", "list"}, APIGroups: []string{""}, Resources: []string{"builds"}}, 176 Simple: true, 177 Resource: simpleResource{Group: "", Resource: "builds"}, 178 }, 179 180 "complex, empty": { 181 Rule: rbacv1.PolicyRule{}, 182 Simple: false, 183 Resource: simpleResource{}, 184 }, 185 "complex, no group": { 186 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{}, Resources: []string{"builds"}}, 187 Simple: false, 188 Resource: simpleResource{}, 189 }, 190 "complex, multi group": { 191 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{"a", "b"}, Resources: []string{"builds"}}, 192 Simple: false, 193 Resource: simpleResource{}, 194 }, 195 "complex, no resource": { 196 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{}}, 197 Simple: false, 198 Resource: simpleResource{}, 199 }, 200 "complex, multi resource": { 201 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}}, 202 Simple: false, 203 Resource: simpleResource{}, 204 }, 205 "complex, resource names": { 206 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"foo", "bar"}}, 207 Simple: false, 208 Resource: simpleResource{}, 209 }, 210 "complex, non-resource urls": { 211 Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}}, 212 Simple: false, 213 Resource: simpleResource{}, 214 }, 215 } 216 217 for k, tc := range testcases { 218 resource, simple := isSimpleResourceRule(&tc.Rule) 219 if simple != tc.Simple { 220 t.Errorf("%s: expected simple=%v, got simple=%v", k, tc.Simple, simple) 221 continue 222 } 223 if resource != tc.Resource { 224 t.Errorf("%s: expected resource=%v, got resource=%v", k, tc.Resource, resource) 225 continue 226 } 227 } 228 }