package rulevalidation import ( "reflect" "sort" "testing" kapi "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/util/sets" "github.com/openshift/origin/pkg/authorization/api" ) func TestCompactRules(t *testing.T) { testcases := map[string]struct { Rules []api.PolicyRule Expected []api.PolicyRule }{ "empty": { Rules: []api.PolicyRule{}, Expected: []api.PolicyRule{}, }, "simple": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("update", "patch"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("create"), APIGroups: []string{"extensions"}, Resources: sets.NewString("daemonsets")}, {Verbs: sets.NewString("delete"), APIGroups: []string{"extensions"}, Resources: sets.NewString("daemonsets")}, {Verbs: sets.NewString("educate"), APIGroups: []string{""}, Resources: sets.NewString("dolphins")}, // nil verbs are preserved in non-merge cases. // these are the pirates who don't do anything. {Verbs: nil, APIGroups: []string{""}, Resources: sets.NewString("pirates")}, // Test merging into a nil Verbs string set {Verbs: nil, APIGroups: []string{""}, Resources: sets.NewString("pods")}, {Verbs: sets.NewString("create"), APIGroups: []string{""}, Resources: sets.NewString("pods")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("create", "delete"), APIGroups: []string{"extensions"}, Resources: sets.NewString("daemonsets")}, {Verbs: sets.NewString("get", "list", "update", "patch"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("educate"), APIGroups: []string{""}, Resources: sets.NewString("dolphins")}, {Verbs: nil, APIGroups: []string{""}, Resources: sets.NewString("pirates")}, {Verbs: sets.NewString("create"), APIGroups: []string{""}, Resources: sets.NewString("pods")}, }, }, "complex multi-group": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("list"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("list"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, }, }, "complex multi-resource": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, }, }, "complex named-resource": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild2")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild2")}, }, }, "complex non-resource": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/")}, {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/foo")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/")}, {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/foo")}, }, }, "complex attributes": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, }, }, } for k, tc := range testcases { rules := tc.Rules originalRules, err := kapi.Scheme.DeepCopy(tc.Rules) if err != nil { t.Errorf("%s: couldn't copy rules: %v", k, err) continue } 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(api.SortableRuleSlice(compacted)) sort.Stable(api.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 api.PolicyRule Simple bool Resource unversioned.GroupResource }{ "simple, no verbs": { Rule: api.PolicyRule{Verbs: sets.NewString(), APIGroups: []string{""}, Resources: sets.NewString("builds")}, Simple: true, Resource: unversioned.GroupResource{Group: "", Resource: "builds"}, }, "simple, one verb": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, Simple: true, Resource: unversioned.GroupResource{Group: "", Resource: "builds"}, }, "simple, multi verb": { Rule: api.PolicyRule{Verbs: sets.NewString("get", "list"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, Simple: true, Resource: unversioned.GroupResource{Group: "", Resource: "builds"}, }, "complex, empty": { Rule: api.PolicyRule{}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, no group": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{}, Resources: sets.NewString("builds")}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, multi group": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{"a", "b"}, Resources: sets.NewString("builds")}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, no resource": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString()}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, multi resource": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, resource names": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("foo")}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, attribute restrictions": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, Simple: false, Resource: unversioned.GroupResource{}, }, "complex, non-resource urls": { Rule: api.PolicyRule{Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/")}, Simple: false, Resource: unversioned.GroupResource{}, }, } 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 } } }