go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/acls/run_read_test.go (about)

     1  // Copyright 2021 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 acls
    16  
    17  import (
    18  	"testing"
    19  
    20  	"google.golang.org/grpc/codes"
    21  
    22  	"go.chromium.org/luci/auth/identity"
    23  	"go.chromium.org/luci/gae/service/datastore"
    24  	"go.chromium.org/luci/grpc/appstatus"
    25  	"go.chromium.org/luci/server/auth"
    26  	"go.chromium.org/luci/server/auth/authtest"
    27  
    28  	cfgpb "go.chromium.org/luci/cv/api/config/v2"
    29  	"go.chromium.org/luci/cv/internal/common"
    30  	"go.chromium.org/luci/cv/internal/configs/prjcfg/prjcfgtest"
    31  	"go.chromium.org/luci/cv/internal/configs/validation"
    32  	"go.chromium.org/luci/cv/internal/cvtesting"
    33  	"go.chromium.org/luci/cv/internal/run"
    34  
    35  	. "github.com/smartystreets/goconvey/convey"
    36  	. "go.chromium.org/luci/common/testing/assertions"
    37  )
    38  
    39  func TestRunReadChecker(t *testing.T) {
    40  	t.Parallel()
    41  
    42  	Convey("NewRunReadChecker works", t, func() {
    43  		ct := cvtesting.Test{}
    44  		ctx, cancel := ct.SetUp(t)
    45  		defer cancel()
    46  
    47  		const projectPublic = "infra"
    48  		const projectInternal = "infra-internal"
    49  
    50  		prjcfgtest.Create(ctx, projectPublic, &cfgpb.Config{
    51  			// TODO(crbug/1233963): update this test to stop relying on legacy-based
    52  			// ACL.
    53  			CqStatusHost: validation.CQStatusHostPublic,
    54  			ConfigGroups: []*cfgpb.ConfigGroup{{
    55  				Name: "first",
    56  			}},
    57  		})
    58  		prjcfgtest.Create(ctx, projectInternal, &cfgpb.Config{
    59  			// TODO(crbug/1233963): update this test to stop relying on legacy-based
    60  			// ACL.
    61  			CqStatusHost: validation.CQStatusHostInternal,
    62  			ConfigGroups: []*cfgpb.ConfigGroup{{
    63  				Name: "first",
    64  			}},
    65  		})
    66  
    67  		publicRun := &run.Run{
    68  			ID:            common.RunID(projectPublic + "/123-visible"),
    69  			EVersion:      5,
    70  			ConfigGroupID: prjcfgtest.MustExist(ctx, projectPublic).ConfigGroupIDs[0],
    71  		}
    72  		internalRun := &run.Run{
    73  			ID:            common.RunID(projectInternal + "/456-invisible"),
    74  			EVersion:      5,
    75  			ConfigGroupID: prjcfgtest.MustExist(ctx, projectInternal).ConfigGroupIDs[0],
    76  		}
    77  		So(datastore.Put(ctx, publicRun, internalRun), ShouldBeNil)
    78  
    79  		ctx = auth.WithState(ctx, &authtest.FakeState{
    80  			Identity: identity.AnonymousIdentity,
    81  		})
    82  
    83  		Convey("Loading individual Runs", func() {
    84  			Convey("Run doesn't exist", func() {
    85  				_, err1 := run.LoadRun(ctx, common.RunID("foo/bar"), NewRunReadChecker())
    86  				So(err1, ShouldHaveAppStatus, codes.NotFound)
    87  
    88  				Convey("No access must be indistinguishable from not existing Run", func() {
    89  					_, err2 := run.LoadRun(ctx, internalRun.ID, NewRunReadChecker())
    90  					So(err2, ShouldHaveAppStatus, codes.NotFound)
    91  
    92  					st1, _ := appstatus.Get(err1)
    93  					st2, _ := appstatus.Get(err2)
    94  					So(st1.Message(), ShouldResemble, st2.Message())
    95  					So(st1.Details(), ShouldBeEmpty)
    96  					So(st2.Details(), ShouldBeEmpty)
    97  				})
    98  			})
    99  
   100  			Convey("OK public", func() {
   101  				r, err := run.LoadRun(ctx, publicRun.ID, NewRunReadChecker())
   102  				So(err, ShouldBeNil)
   103  				So(r, cvtesting.SafeShouldResemble, publicRun)
   104  			})
   105  
   106  			Convey("OK internal", func() {
   107  				// TODO(crbug/1233963): add a test once non-legacy ACLs are working.
   108  				ctx = auth.WithState(ctx, &authtest.FakeState{
   109  					Identity:       "user:googler@example.com",
   110  					IdentityGroups: []string{"googlers"},
   111  				})
   112  				r, err := run.LoadRun(ctx, internalRun.ID, NewRunReadChecker())
   113  				So(err, ShouldBeNil)
   114  				So(r, cvtesting.SafeShouldResemble, internalRun)
   115  			})
   116  
   117  			Convey("OK v0 API users", func() {
   118  				ctx = auth.WithState(ctx, &authtest.FakeState{
   119  					Identity:       "user:v0-api-users@example.com",
   120  					IdentityGroups: []string{V0APIAllowGroup},
   121  				})
   122  				r, err := run.LoadRun(ctx, publicRun.ID, NewRunReadChecker())
   123  				So(err, ShouldBeNil)
   124  				So(r, cvtesting.SafeShouldResemble, publicRun)
   125  				r, err = run.LoadRun(ctx, internalRun.ID, NewRunReadChecker())
   126  				So(err, ShouldBeNil)
   127  				So(r, cvtesting.SafeShouldResemble, internalRun)
   128  			})
   129  
   130  			Convey("PermissionDenied", func() {
   131  				ctx = auth.WithState(ctx, &authtest.FakeState{
   132  					Identity:       "user:public-user@example.com",
   133  					IdentityGroups: []string{"insufficient"},
   134  				})
   135  				_, err := run.LoadRun(ctx, internalRun.ID, NewRunReadChecker())
   136  				So(err, ShouldHaveAppStatus, codes.NotFound)
   137  			})
   138  		})
   139  	})
   140  }