mirror of https://github.com/k3s-io/k3s
228 lines
9.4 KiB
Go
228 lines
9.4 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package validation
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
|
|
)
|
|
|
|
func TestCompactRules(t *testing.T) {
|
|
testcases := map[string]struct {
|
|
Rules []rbacv1.PolicyRule
|
|
Expected []rbacv1.PolicyRule
|
|
}{
|
|
"empty": {
|
|
Rules: []rbacv1.PolicyRule{},
|
|
Expected: []rbacv1.PolicyRule{},
|
|
},
|
|
"simple": {
|
|
Rules: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
{Verbs: []string{"update", "patch"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
|
|
{Verbs: []string{"create"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}},
|
|
{Verbs: []string{"delete"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}},
|
|
{Verbs: []string{"patch"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{""}},
|
|
{Verbs: []string{"get"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}},
|
|
|
|
{Verbs: []string{"educate"}, APIGroups: []string{""}, Resources: []string{"dolphins"}},
|
|
|
|
// nil verbs are preserved in non-merge cases.
|
|
// these are the pirates who don't do anything.
|
|
{Verbs: nil, APIGroups: []string{""}, Resources: []string{"pirates"}},
|
|
|
|
// Test merging into a nil Verbs string set
|
|
{Verbs: nil, APIGroups: []string{""}, Resources: []string{"pods"}},
|
|
{Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"pods"}},
|
|
},
|
|
Expected: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"create", "delete"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}},
|
|
{Verbs: []string{"patch"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{""}},
|
|
{Verbs: []string{"get", "list"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}},
|
|
{Verbs: []string{"get", "list", "update", "patch"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
{Verbs: []string{"educate"}, APIGroups: []string{""}, Resources: []string{"dolphins"}},
|
|
{Verbs: nil, APIGroups: []string{""}, Resources: []string{"pirates"}},
|
|
{Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"pods"}},
|
|
},
|
|
},
|
|
"complex multi-group": {
|
|
Rules: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
|
},
|
|
Expected: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
|
},
|
|
},
|
|
|
|
"complex multi-resource": {
|
|
Rules: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
|
},
|
|
Expected: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
|
},
|
|
},
|
|
|
|
"complex named-resource": {
|
|
Rules: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild2"}},
|
|
},
|
|
Expected: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild"}},
|
|
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild2"}},
|
|
},
|
|
},
|
|
|
|
"complex non-resource": {
|
|
Rules: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}},
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/foo"}},
|
|
},
|
|
Expected: []rbacv1.PolicyRule{
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}},
|
|
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/foo"}},
|
|
},
|
|
},
|
|
}
|
|
|
|
for k, tc := range testcases {
|
|
rules := tc.Rules
|
|
originalRules := make([]rbacv1.PolicyRule, len(tc.Rules))
|
|
for i := range tc.Rules {
|
|
originalRules[i] = *tc.Rules[i].DeepCopy()
|
|
}
|
|
compacted, err := CompactRules(tc.Rules)
|
|
if err != nil {
|
|
t.Errorf("%s: unexpected error: %v", k, err)
|
|
continue
|
|
}
|
|
if !reflect.DeepEqual(rules, originalRules) {
|
|
t.Errorf("%s: CompactRules mutated rules. Expected\n%#v\ngot\n%#v", k, originalRules, rules)
|
|
continue
|
|
}
|
|
if covers, missing := Covers(compacted, rules); !covers {
|
|
t.Errorf("%s: compacted rules did not cover original rules. missing: %#v", k, missing)
|
|
continue
|
|
}
|
|
if covers, missing := Covers(rules, compacted); !covers {
|
|
t.Errorf("%s: original rules did not cover compacted rules. missing: %#v", k, missing)
|
|
continue
|
|
}
|
|
|
|
sort.Stable(rbacv1helpers.SortableRuleSlice(compacted))
|
|
sort.Stable(rbacv1helpers.SortableRuleSlice(tc.Expected))
|
|
if !reflect.DeepEqual(compacted, tc.Expected) {
|
|
t.Errorf("%s: Expected\n%#v\ngot\n%#v", k, tc.Expected, compacted)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsSimpleResourceRule(t *testing.T) {
|
|
testcases := map[string]struct {
|
|
Rule rbacv1.PolicyRule
|
|
Simple bool
|
|
Resource simpleResource
|
|
}{
|
|
"simple, no verbs": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
Simple: true,
|
|
Resource: simpleResource{Group: "", Resource: "builds"},
|
|
},
|
|
"simple, one verb": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
Simple: true,
|
|
Resource: simpleResource{Group: "", Resource: "builds"},
|
|
},
|
|
"simple, one empty resource name": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{""}},
|
|
Simple: true,
|
|
Resource: simpleResource{Group: "", Resource: "builds", ResourceNameExist: true, ResourceName: ""},
|
|
},
|
|
"simple, one resource name": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"foo"}},
|
|
Simple: true,
|
|
Resource: simpleResource{Group: "", Resource: "builds", ResourceNameExist: true, ResourceName: "foo"},
|
|
},
|
|
"simple, multi verb": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get", "list"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
|
Simple: true,
|
|
Resource: simpleResource{Group: "", Resource: "builds"},
|
|
},
|
|
|
|
"complex, empty": {
|
|
Rule: rbacv1.PolicyRule{},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
"complex, no group": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{}, Resources: []string{"builds"}},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
"complex, multi group": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{"a", "b"}, Resources: []string{"builds"}},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
"complex, no resource": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{}},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
"complex, multi resource": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
"complex, resource names": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"foo", "bar"}},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
"complex, non-resource urls": {
|
|
Rule: rbacv1.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}},
|
|
Simple: false,
|
|
Resource: simpleResource{},
|
|
},
|
|
}
|
|
|
|
for k, tc := range testcases {
|
|
resource, simple := isSimpleResourceRule(&tc.Rule)
|
|
if simple != tc.Simple {
|
|
t.Errorf("%s: expected simple=%v, got simple=%v", k, tc.Simple, simple)
|
|
continue
|
|
}
|
|
if resource != tc.Resource {
|
|
t.Errorf("%s: expected resource=%v, got resource=%v", k, tc.Resource, resource)
|
|
continue
|
|
}
|
|
}
|
|
}
|