go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/config_service/internal/acl/project_test.go (about)

     1  // Copyright 2023 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package acl
    16  
    17  import (
    18  	"testing"
    19  
    20  	"go.chromium.org/luci/auth/identity"
    21  	cfgcommonpb "go.chromium.org/luci/common/proto/config"
    22  	"go.chromium.org/luci/server/auth"
    23  	"go.chromium.org/luci/server/auth/authtest"
    24  	"go.chromium.org/luci/server/auth/realms"
    25  	"google.golang.org/protobuf/proto"
    26  
    27  	"go.chromium.org/luci/config_service/internal/common"
    28  	"go.chromium.org/luci/config_service/testutil"
    29  
    30  	. "github.com/smartystreets/goconvey/convey"
    31  )
    32  
    33  func TestProjectConfig(t *testing.T) {
    34  	t.Parallel()
    35  
    36  	Convey("Project Config ACL Check", t, func() {
    37  		ctx := testutil.SetupContext()
    38  		fakeAuthDB := authtest.NewFakeDB()
    39  		const requester = identity.Identity("user:requester@example.com")
    40  		const lProject = "example-project"
    41  		realm := realms.Join(lProject, realms.RootRealm)
    42  		ctx = auth.WithState(ctx, &authtest.FakeState{
    43  			Identity: requester,
    44  			FakeDB:   fakeAuthDB,
    45  		})
    46  		const accessGroup = "access-group"
    47  		const validationGroup = "validate-group"
    48  		const reimportGroup = "reimport-group"
    49  		testutil.InjectSelfConfigs(ctx, map[string]proto.Message{
    50  			common.ACLRegistryFilePath: &cfgcommonpb.AclCfg{
    51  				ProjectAccessGroup:     accessGroup,
    52  				ProjectValidationGroup: validationGroup,
    53  				ProjectReimportGroup:   reimportGroup,
    54  			},
    55  		})
    56  
    57  		Convey("CanReadProject", func() {
    58  			Convey("Access Denied", func() {
    59  				allowed, err := CanReadProject(ctx, lProject)
    60  				So(err, ShouldBeNil)
    61  				So(allowed, ShouldBeFalse)
    62  			})
    63  			Convey("allowed in Acl.cfg", func() {
    64  				fakeAuthDB.AddMocks(authtest.MockMembership(requester, accessGroup))
    65  				allowed, err := CanReadProject(ctx, lProject)
    66  				So(err, ShouldBeNil)
    67  				So(allowed, ShouldBeTrue)
    68  			})
    69  			Convey("allowed in realm", func() {
    70  				fakeAuthDB.AddMocks(authtest.MockPermission(requester, realm, ReadPermission))
    71  				allowed, err := CanReadProject(ctx, lProject)
    72  				So(err, ShouldBeNil)
    73  				So(allowed, ShouldBeTrue)
    74  			})
    75  		})
    76  
    77  		Convey("CanReadProjects", func() {
    78  			const (
    79  				project1 = "project1"
    80  				project2 = "project2"
    81  				project3 = "project3"
    82  			)
    83  			// can read project 1 and 3.
    84  			fakeAuthDB.AddMocks(
    85  				authtest.MockPermission(requester, realms.Join(project1, realms.RootRealm), ReadPermission),
    86  				authtest.MockPermission(requester, realms.Join(project3, realms.RootRealm), ReadPermission),
    87  			)
    88  			result, err := CanReadProjects(ctx, []string{project1, project2, project3})
    89  			So(err, ShouldBeNil)
    90  			So(result, ShouldResemble, []bool{true, false, true})
    91  		})
    92  
    93  		Convey("CanValidateProject", func() {
    94  			Convey("Denied because of no read access", func() {
    95  				// This should allow validate
    96  				fakeAuthDB.AddMocks(authtest.MockMembership(requester, validationGroup))
    97  				allowed, err := CanValidateProject(ctx, lProject)
    98  				So(err, ShouldBeNil)
    99  				So(allowed, ShouldBeFalse)
   100  			})
   101  			Convey("Denied even with read access", func() {
   102  				fakeAuthDB.AddMocks(authtest.MockPermission(requester, realm, ReadPermission))
   103  				allowed, err := CanValidateProject(ctx, lProject)
   104  				So(err, ShouldBeNil)
   105  				So(allowed, ShouldBeFalse)
   106  			})
   107  			Convey("Allowed by Acl.cfg", func() {
   108  				fakeAuthDB.AddMocks(authtest.MockPermission(requester, realm, ReadPermission))
   109  				fakeAuthDB.AddMocks(authtest.MockMembership(requester, validationGroup))
   110  				allowed, err := CanValidateProject(ctx, lProject)
   111  				So(err, ShouldBeNil)
   112  				So(allowed, ShouldBeTrue)
   113  			})
   114  			Convey("Allowed by Realm", func() {
   115  				fakeAuthDB.AddMocks(
   116  					authtest.MockPermission(requester, realm, ReadPermission),
   117  					authtest.MockPermission(requester, realm, ValidatePermission),
   118  				)
   119  				allowed, err := CanValidateProject(ctx, lProject)
   120  				So(err, ShouldBeNil)
   121  				So(allowed, ShouldBeTrue)
   122  			})
   123  		})
   124  
   125  		Convey("CanReimportProject", func() {
   126  			Convey("Denied because of no read access", func() {
   127  				// This should allow reimport
   128  				fakeAuthDB.AddMocks(authtest.MockMembership(requester, reimportGroup))
   129  				allowed, err := CanReimportProject(ctx, lProject)
   130  				So(err, ShouldBeNil)
   131  				So(allowed, ShouldBeFalse)
   132  			})
   133  			Convey("Denied even with read access", func() {
   134  				fakeAuthDB.AddMocks(authtest.MockPermission(requester, realm, ReadPermission))
   135  				allowed, err := CanReimportProject(ctx, lProject)
   136  				So(err, ShouldBeNil)
   137  				So(allowed, ShouldBeFalse)
   138  			})
   139  			Convey("Allowed by Acl.cfg", func() {
   140  				fakeAuthDB.AddMocks(authtest.MockPermission(requester, realm, ReadPermission))
   141  				fakeAuthDB.AddMocks(authtest.MockMembership(requester, reimportGroup))
   142  				allowed, err := CanReimportProject(ctx, lProject)
   143  				So(err, ShouldBeNil)
   144  				So(allowed, ShouldBeTrue)
   145  			})
   146  			Convey("Allowed by Realm", func() {
   147  				fakeAuthDB.AddMocks(
   148  					authtest.MockPermission(requester, realm, ReadPermission),
   149  					authtest.MockPermission(requester, realm, ReimportPermission),
   150  				)
   151  				allowed, err := CanReimportProject(ctx, lProject)
   152  				So(err, ShouldBeNil)
   153  				So(allowed, ShouldBeTrue)
   154  			})
   155  		})
   156  	})
   157  }