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 }