| Index: scheduler/appengine/acl/acl_test.go
|
| diff --git a/scheduler/appengine/acl/acl_test.go b/scheduler/appengine/acl/acl_test.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9ec1629bac73313e8a00a2ce356d5ae119170cdb
|
| --- /dev/null
|
| +++ b/scheduler/appengine/acl/acl_test.go
|
| @@ -0,0 +1,218 @@
|
| +// Copyright 2017 The LUCI 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 acl
|
| +
|
| +import (
|
| + "fmt"
|
| + "testing"
|
| +
|
| + "github.com/luci/luci-go/appengine/gaetesting"
|
| + "github.com/luci/luci-go/scheduler/appengine/messages"
|
| + "github.com/luci/luci-go/server/auth"
|
| + "github.com/luci/luci-go/server/auth/authtest"
|
| + . "github.com/smartystreets/goconvey/convey"
|
| +)
|
| +
|
| +func TestAclsValidation(t *testing.T) {
|
| + t.Parallel()
|
| +
|
| + validGrant := &messages.Acl{Role: messages.Acl_READER, GrantedTo: "group:all"}
|
| + validGrants := []*messages.Acl{validGrant}
|
| +
|
| + Convey("grant validation", t, func() {
|
| + So(validateGrants(validGrants), ShouldBeNil)
|
| +
|
| + call := func(acls ...*messages.Acl) error {
|
| + return validateGrants(acls)
|
| + }
|
| + So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "e@example.com"}), ShouldBeNil)
|
| +
|
| + So(call(&messages.Acl{Role: 3}).Error(), ShouldResemble, "invalid role \"3\"")
|
| + So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: ""}).Error(),
|
| + ShouldResemble, "missing granted_to for role OWNER")
|
| + So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "group:"}).Error(),
|
| + ShouldResemble, "invalid granted_to \"group:\" for role OWNER: needs a group name")
|
| + So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "not-email"}).Error(),
|
| + ShouldStartWith, "invalid granted_to \"not-email\" for role OWNER: ")
|
| + So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "bot:"}).Error(),
|
| + ShouldStartWith, "invalid granted_to \"bot:\" for role OWNER: ")
|
| + })
|
| +
|
| + validAclSet := &messages.AclSet{Name: "public", Acls: validGrants}
|
| +
|
| + Convey("Validate AclSets", t, func() {
|
| + as, err := ValidateAclSets([]*messages.AclSet{validAclSet})
|
| + So(err, ShouldBeNil)
|
| + So(len(as), ShouldEqual, 1)
|
| + So(as["public"], ShouldResemble, validGrants)
|
| +
|
| + shouldError := func(sets ...*messages.AclSet) {
|
| + _, err := ValidateAclSets(sets)
|
| + So(err, ShouldNotBeNil)
|
| + }
|
| +
|
| + shouldError(&messages.AclSet{Name: "one"})
|
| + shouldError(&messages.AclSet{Name: "?bad i'd", Acls: validGrants})
|
| + shouldError(validAclSet, validAclSet)
|
| + })
|
| +
|
| + Convey("Task Acls", t, func() {
|
| + Convey("Without AclSets", func() {
|
| + jobAcls, err := ValidateTaskAcls(nil, []string{}, validGrants)
|
| + So(err, ShouldBeNil)
|
| + So(jobAcls.Owners, ShouldResemble, []string{})
|
| + So(jobAcls.Readers, ShouldResemble, []string{"group:all"})
|
| + })
|
| +
|
| + Convey("Without AclSets but with bad ACLs", func() {
|
| + _, err := ValidateTaskAcls(nil, []string{}, []*messages.Acl{
|
| + {Role: messages.Acl_OWNER, GrantedTo: ""}})
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("Many ACLs", func() {
|
| + taskGrants := make([]*messages.Acl, maxGrantsPerJob)
|
| + for i := 0; i < maxGrantsPerJob; i++ {
|
| + taskGrants[i] = &messages.Acl{Role: messages.Acl_OWNER, GrantedTo: fmt.Sprintf("group:%d", i)}
|
| + }
|
| + Convey("Hitting max is OK", func() {
|
| + r, err := ValidateTaskAcls(nil, []string{}, taskGrants)
|
| + So(err, ShouldBeNil)
|
| + So(len(r.Owners), ShouldEqual, maxGrantsPerJob)
|
| + })
|
| + Convey("1 too many", func() {
|
| + aclSets := map[string][]*messages.Acl{
|
| + "public": {{Role: messages.Acl_READER, GrantedTo: "group:all"}},
|
| + }
|
| + _, err := ValidateTaskAcls(aclSets, []string{"public"}, taskGrants)
|
| + So(err.Error(), ShouldResemble, "Job or Trigger can have at most 32 acls, but 33 given")
|
| + })
|
| + })
|
| +
|
| + protoAclSets := []*messages.AclSet{
|
| + {Name: "public", Acls: []*messages.Acl{
|
| + {Role: messages.Acl_READER, GrantedTo: "group:all"},
|
| + {Role: messages.Acl_OWNER, GrantedTo: "group:owners"},
|
| + }},
|
| + {Name: "power-owners", Acls: []*messages.Acl{
|
| + {Role: messages.Acl_OWNER, GrantedTo: "group:power"},
|
| + }},
|
| + {Name: "private", Acls: []*messages.Acl{
|
| + {Role: messages.Acl_READER, GrantedTo: "group:internal"},
|
| + }},
|
| + }
|
| + aclSets, err := ValidateAclSets(protoAclSets)
|
| + So(err, ShouldBeNil)
|
| + So(len(aclSets), ShouldEqual, 3)
|
| +
|
| + Convey("Bad acl_set reference in a task definition", func() {
|
| + _, err := ValidateTaskAcls(aclSets, []string{"typo"}, validGrants)
|
| + So(err.Error(), ShouldResemble, "referencing AclSet 'typo' which doesn't exist")
|
| + })
|
| +
|
| + Convey("Merging", func() {
|
| + jobAcls, err := ValidateTaskAcls(
|
| + aclSets, []string{"public", "power-owners"},
|
| + []*messages.Acl{
|
| + {Role: messages.Acl_OWNER, GrantedTo: "me@example.com"},
|
| + {Role: messages.Acl_READER, GrantedTo: "you@example.com"},
|
| + })
|
| + So(err, ShouldBeNil)
|
| + So(jobAcls.Owners, ShouldResemble, []string{"group:owners", "group:power", "me@example.com"})
|
| + So(jobAcls.Readers, ShouldResemble, []string{"group:all", "you@example.com"})
|
| +
|
| + jobAcls, err = ValidateTaskAcls(
|
| + aclSets, []string{"private"},
|
| + []*messages.Acl{
|
| + {Role: messages.Acl_OWNER, GrantedTo: "me@example.com"},
|
| + })
|
| + So(err, ShouldBeNil)
|
| + So(jobAcls.Owners, ShouldResemble, []string{"me@example.com"})
|
| + So(jobAcls.Readers, ShouldResemble, []string{"group:internal"})
|
| + })
|
| + })
|
| +}
|
| +
|
| +func TestAclsChecks(t *testing.T) {
|
| + t.Parallel()
|
| + ctx := gaetesting.TestingContext()
|
| +
|
| + basicGroups := GrantsByRole{Owners: []string{"group:owners"}, Readers: []string{"group:readers"}}
|
| +
|
| + Convey("Admins are owners and readers", t, func() {
|
| + ctx = auth.WithState(ctx, &authtest.FakeState{
|
| + Identity: "user:admin@example.com",
|
| + IdentityGroups: []string{"administrators"},
|
| + })
|
| + yup, err := basicGroups.IsOwner(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(yup, ShouldBeTrue)
|
| + yup, err = basicGroups.IsReader(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(yup, ShouldBeTrue)
|
| + })
|
| + Convey("Owners", t, func() {
|
| + ctx = auth.WithState(ctx, &authtest.FakeState{
|
| + Identity: "user:owner@example.com",
|
| + IdentityGroups: []string{"owners"},
|
| + })
|
| + yup, err := basicGroups.IsReader(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(yup, ShouldBeTrue)
|
| + yup, err = basicGroups.IsReader(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(yup, ShouldBeTrue)
|
| + })
|
| + Convey("Readers", t, func() {
|
| + ctx = auth.WithState(ctx, &authtest.FakeState{
|
| + Identity: "user:reader@example.com",
|
| + IdentityGroups: []string{"readers"},
|
| + })
|
| + nope, err := basicGroups.IsOwner(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(nope, ShouldBeFalse)
|
| + yup, err := basicGroups.IsReader(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(yup, ShouldBeTrue)
|
| + })
|
| + Convey("By email", t, func() {
|
| + ctx = auth.WithState(ctx, &authtest.FakeState{
|
| + Identity: "user:reader@example.com",
|
| + IdentityGroups: []string{"all"},
|
| + })
|
| + g := GrantsByRole{
|
| + Owners: []string{"group:owners"},
|
| + Readers: []string{"group:some", "reader@example.com"},
|
| + }
|
| + nope, err := g.IsOwner(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(nope, ShouldBeFalse)
|
| + yup, err := g.IsReader(ctx)
|
| + So(err, ShouldBeNil)
|
| + So(yup, ShouldBeTrue)
|
| + })
|
| +}
|
| +
|
| +func TestAclsEqual(t *testing.T) {
|
| + t.Parallel()
|
| + Convey("GrantsByRole.Equal", t, func() {
|
| + x1 := GrantsByRole{Readers: []string{"a"}, Owners: []string{"b", "c"}}
|
| + x2 := GrantsByRole{Readers: []string{"a"}, Owners: []string{"b", "c"}}
|
| + So(x1.Equal(&x2), ShouldBeTrue)
|
| + y := GrantsByRole{Readers: []string{"e", "g"}, Owners: []string{"b", "d"}}
|
| + z := GrantsByRole{Readers: []string{"e", "g"}, Owners: []string{"b", "c", "d"}}
|
| + So(x1.Equal(&y), ShouldBeFalse)
|
| + So(y.Equal(&z), ShouldBeFalse)
|
| + })
|
| +}
|
|
|