123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- /*
- Copyright 2016 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"
- "testing"
- rbacv1 "k8s.io/api/rbac/v1"
- )
- type escalationTest struct {
- ownerRules []rbacv1.PolicyRule
- servantRules []rbacv1.PolicyRule
- expectedCovered bool
- expectedUncoveredRules []rbacv1.PolicyRule
- }
- func TestCoversExactMatch(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversSubresourceWildcard(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*/scale"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"foo/scale"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversMultipleRulesCoveringSingleRule(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
- {APIGroups: []string{"v1"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
- {APIGroups: []string{"v1"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversMultipleAPIGroupsCoveringSingleRule(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
- {APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
- {APIGroups: []string{"group1"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
- {APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
- {APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
- {APIGroups: []string{"group2"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"group1", "group2"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversSingleAPIGroupsCoveringMultiple(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"group1", "group2"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
- {APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
- {APIGroups: []string{"group1"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
- {APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
- {APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
- {APIGroups: []string{"group2"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversMultipleRulesMissingSingleVerbResourceCombination(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
- {APIGroups: []string{"v1"}, Verbs: []string{"delete"}, Resources: []string{"pods"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments", "pods"}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"update"}, Resources: []string{"pods"}},
- },
- }.test(t)
- }
- func TestCoversAPIGroupStarCoveringMultiple(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"group1", "group2"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversEnumerationNotCoveringAPIGroupStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"dummy-group"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- }.test(t)
- }
- func TestCoversAPIGroupStarCoveringStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversVerbStarCoveringMultiple(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"watch", "list"}, Resources: []string{"roles"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversEnumerationNotCoveringVerbStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get", "list", "watch", "create", "update", "delete", "exec"}, Resources: []string{"roles"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
- },
- }.test(t)
- }
- func TestCoversVerbStarCoveringStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversResourceStarCoveringMultiple(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"resourcegroup:deployments"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversEnumerationNotCoveringResourceStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"roles", "resourcegroup:deployments"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
- },
- }.test(t)
- }
- func TestCoversResourceStarCoveringStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversResourceNameEmptyCoveringMultiple(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{"foo", "bar"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversEnumerationNotCoveringResourceNameEmpty(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{"foo", "bar"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}},
- },
- }.test(t)
- }
- func TestCoversNonResourceURLs(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis"}, Verbs: []string{"*"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis"}, Verbs: []string{"*"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversNonResourceURLsStar(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"*"}, Verbs: []string{"*"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis", "/apis/v1", "/"}, Verbs: []string{"*"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversNonResourceURLsStarAfterPrefixDoesntCover(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis/*"}, Verbs: []string{"*"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis", "/apis/v1"}, Verbs: []string{"get"}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis"}, Verbs: []string{"get"}},
- },
- }.test(t)
- }
- func TestCoversNonResourceURLsStarAfterPrefix(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis/*"}, Verbs: []string{"*"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {NonResourceURLs: []string{"/apis/v1/foo", "/apis/v1"}, Verbs: []string{"get"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversNonResourceURLsWithOtherFields(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}, NonResourceURLs: []string{"/apis"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}, NonResourceURLs: []string{"/apis"}},
- },
- expectedCovered: true,
- expectedUncoveredRules: []rbacv1.PolicyRule{},
- }.test(t)
- }
- func TestCoversNonResourceURLsWithOtherFieldsFailure(t *testing.T) {
- escalationTest{
- ownerRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}},
- },
- servantRules: []rbacv1.PolicyRule{
- {APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}, NonResourceURLs: []string{"/apis"}},
- },
- expectedCovered: false,
- expectedUncoveredRules: []rbacv1.PolicyRule{{NonResourceURLs: []string{"/apis"}, Verbs: []string{"get"}}},
- }.test(t)
- }
- func (test escalationTest) test(t *testing.T) {
- actualCovered, actualUncoveredRules := Covers(test.ownerRules, test.servantRules)
- if actualCovered != test.expectedCovered {
- t.Errorf("expected %v, but got %v", test.expectedCovered, actualCovered)
- }
- if !rulesMatch(test.expectedUncoveredRules, actualUncoveredRules) {
- t.Errorf("expected %v, but got %v", test.expectedUncoveredRules, actualUncoveredRules)
- }
- }
- func rulesMatch(expectedRules, actualRules []rbacv1.PolicyRule) bool {
- if len(expectedRules) != len(actualRules) {
- return false
- }
- for _, expectedRule := range expectedRules {
- found := false
- for _, actualRule := range actualRules {
- if reflect.DeepEqual(expectedRule, actualRule) {
- found = true
- break
- }
- }
- if !found {
- return false
- }
- }
- return true
- }
- func TestNonResourceURLCovers(t *testing.T) {
- tests := []struct {
- owner string
- requested string
- want bool
- }{
- {"*", "", true},
- {"*", "/", true},
- {"*", "/api", true},
- {"/*", "", false},
- {"/*", "/", true},
- {"/*", "/foo", true},
- {"/api", "/api", true},
- {"/apis", "/api", false},
- {"/api/v1", "/api", false},
- {"/api/v1", "/api/v1", true},
- {"/api/*", "/api/v1", true},
- {"/api/*", "/api", false},
- {"/api/*/*", "/api/v1", false},
- {"/*/v1/*", "/api/v1", false},
- }
- for _, tc := range tests {
- got := nonResourceURLCovers(tc.owner, tc.requested)
- if got != tc.want {
- t.Errorf("nonResourceURLCovers(%q, %q): want=(%t), got=(%t)", tc.owner, tc.requested, tc.want, got)
- }
- }
- }
|