From 9a2af6315d38ddecd0d414d74b087348014f7752 Mon Sep 17 00:00:00 2001 From: Pavan Karkun Date: Fri, 20 Dec 2024 01:26:25 -0800 Subject: [PATCH] Move iam package to workloadagentplatform PiperOrigin-RevId: 708230146 --- go.mod | 4 +- go.sum | 6 +- internal/onetime/status/status.go | 2 +- internal/onetime/status/status_test.go | 2 +- shared/iam/iam.go | 181 --------- shared/iam/iam_test.go | 534 ------------------------- 6 files changed, 5 insertions(+), 724 deletions(-) delete mode 100644 shared/iam/iam.go delete mode 100644 shared/iam/iam_test.go diff --git a/go.mod b/go.mod index d17cbed6..6293f7ce 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( cloud.google.com/go/monitoring v1.17.1 cloud.google.com/go/secretmanager v1.11.5 cloud.google.com/go/storage v1.36.0 - github.com/GoogleCloudPlatform/workloadagentplatform/integration/common v0.0.0-20241216220000-e80b9b366dbe + github.com/GoogleCloudPlatform/workloadagentplatform/integration/common v0.0.0-20241226073353-0b283b21f7a2 github.com/SAP/go-hdb v1.8.0 github.com/cenkalti/backoff/v4 v4.1.3 github.com/fsouza/fake-gcs-server v1.45.2 @@ -35,7 +35,7 @@ require ( go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/oauth2 v0.17.0 - golang.org/x/sys v0.18.0 + golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 google.golang.org/api v0.168.0 google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 diff --git a/go.sum b/go.sum index f716830f..53043e0d 100644 --- a/go.sum +++ b/go.sum @@ -239,11 +239,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/onetime/status/status.go b/internal/onetime/status/status.go index 3acc530f..4aa898e6 100644 --- a/internal/onetime/status/status.go +++ b/internal/onetime/status/status.go @@ -43,7 +43,7 @@ import ( "github.com/GoogleCloudPlatform/sapagent/internal/onetime/supportbundle" cpb "github.com/GoogleCloudPlatform/sapagent/protos/configuration" iipb "github.com/GoogleCloudPlatform/sapagent/protos/instanceinfo" - "github.com/GoogleCloudPlatform/sapagent/shared/iam" + "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/iam" "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/commandlineexecutor" "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/log" spb "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/protos/status" diff --git a/internal/onetime/status/status_test.go b/internal/onetime/status/status_test.go index c0b64380..f299484f 100644 --- a/internal/onetime/status/status_test.go +++ b/internal/onetime/status/status_test.go @@ -41,7 +41,7 @@ import ( "github.com/GoogleCloudPlatform/sapagent/internal/configuration" "github.com/GoogleCloudPlatform/sapagent/internal/databaseconnector" "github.com/GoogleCloudPlatform/sapagent/internal/iam" - "github.com/GoogleCloudPlatform/sapagent/shared/iam" + "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/iam" "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/commandlineexecutor" "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/gce/fake" "github.com/GoogleCloudPlatform/workloadagentplatform/integration/common/shared/log" diff --git a/shared/iam/iam.go b/shared/iam/iam.go deleted file mode 100644 index ad24645a..00000000 --- a/shared/iam/iam.go +++ /dev/null @@ -1,181 +0,0 @@ -/* -Copyright 2024 Google LLC - -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 - - https://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 iam provides a wrapper for IAM APIs offered by google cloud libraries. -package iam - -import ( - "context" - "fmt" - - iampb "cloud.google.com/go/iam/apiv1/iampb" - "cloud.google.com/go/secretmanager/apiv1" - "cloud.google.com/go/storage" - "github.com/googleapis/gax-go/v2" - "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/compute/v1" - "google.golang.org/api/option" -) - -// SecretManager is an interface for the Secret Manager client. -type SecretManager interface { - TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) -} - -// IAM is a wrapper for IAM APIs offered by google cloud libraries. -type IAM struct { - disksService *compute.DisksService - instancesService *compute.InstancesService - projectsService *cloudresourcemanager.ProjectsService - smClient SecretManager - storageClient *storage.Client -} - -// NewIAMClient creates a new IAM API wrapper. -func NewIAMClient(ctx context.Context, opts ...option.ClientOption) (*IAM, error) { - computeService, err := compute.NewService(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("error creating GCE client: %w", err) - } - smClient, err := secretmanager.NewClient(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("error creating secret manager client: %w", err) - } - crmService, err := cloudresourcemanager.NewService(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("error creating cloud resource manager client: %w", err) - } - storageClient, err := storage.NewClient(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("error creating storage client: %w", err) - } - return &IAM{ - instancesService: computeService.Instances, - disksService: computeService.Disks, - projectsService: crmService.Projects, - smClient: smClient, - storageClient: storageClient, - }, nil -} - -// CheckIAMPermissionsOnDisk checks if the required IAM permissions are present -// for the caller's identity (service account, etc) on a given disk. -// -// Returns the list of input permissions that are granted. -func (i *IAM) CheckIAMPermissionsOnDisk(ctx context.Context, project, zone, diskName string, permissions []string) (grantedPermissions []string, err error) { - if i.disksService == nil { - return nil, fmt.Errorf("disksService is not initialized") - } - if permissions == nil { - return nil, nil - } - req := &compute.TestPermissionsRequest{ - Permissions: permissions, - } - - resp, err := i.disksService.TestIamPermissions(project, zone, diskName, req).Do() - if err != nil { - return nil, fmt.Errorf("failed to test IAM permissions for disk: %w", err) - } - - return resp.Permissions, nil -} - -// CheckIAMPermissionsOnProject checks if the required IAM permissions are -// present for the caller's identity (service account, etc) on a given project. -// -// Returns the list of input permissions that are granted. -func (i *IAM) CheckIAMPermissionsOnProject(ctx context.Context, projectID string, permissions []string) (grantedPermissions []string, err error) { - if i.projectsService == nil { - return nil, fmt.Errorf("projectsService is not initialized") - } - if permissions == nil { - return nil, nil - } - req := &cloudresourcemanager.TestIamPermissionsRequest{ - Permissions: permissions, - } - resp, err := i.projectsService.TestIamPermissions(projectID, req).Do() - if err != nil { - return nil, fmt.Errorf("failed to test IAM permissions for project: %w", err) - } - - return resp.Permissions, nil -} - -// CheckIAMPermissionsOnBucket checks if the required IAM permissions are -// present for the caller's identity (service account, etc) on a given bucket, -// based on the connect params. -// -// Returns the list of input permissions that are granted. -func (i *IAM) CheckIAMPermissionsOnBucket(ctx context.Context, bucketName string, permissions []string) (grantedPermissions []string, err error) { - if i.storageClient == nil { - return nil, fmt.Errorf("storageClient is not initialized") - } - if permissions == nil { - return nil, nil - } - grantedPermissions, err = i.storageClient.Bucket(bucketName).IAM().TestPermissions(ctx, permissions) - if err != nil { - return nil, fmt.Errorf("failed to test IAM permissions for bucket: %w", err) - } - - return grantedPermissions, nil -} - -// CheckIAMPermissionsOnSecret checks if the required IAM permissions are -// present for the caller's identity (service account, etc) on a given secret. -// -// Returns the list of input permissions that are granted. -func (i *IAM) CheckIAMPermissionsOnSecret(ctx context.Context, projectID, secretID string, permissions []string) (grantedPermissions []string, err error) { - if i.smClient == nil { - return nil, fmt.Errorf("smClient is not initialized") - } - if permissions == nil { - return nil, nil - } - req := &iampb.TestIamPermissionsRequest{ - Resource: fmt.Sprintf("projects/%s/secrets/%s", projectID, secretID), - Permissions: permissions, - } - resp, err := i.smClient.TestIamPermissions(ctx, req) - if err != nil { - return nil, fmt.Errorf("failed to test IAM permissions for secret: %w", err) - } - return resp.GetPermissions(), nil -} - -// CheckIAMPermissionsOnInstance checks if the required IAM permissions are -// present for the caller's identity (service account, etc) on a given instance. -// -// Returns the list of input permissions that are granted. -func (i *IAM) CheckIAMPermissionsOnInstance(ctx context.Context, project, zone, instanceName string, permissions []string) (grantedPermissions []string, err error) { - if i.instancesService == nil { - return nil, fmt.Errorf("instancesService is not initialized") - } - if permissions == nil { - return nil, nil - } - req := &compute.TestPermissionsRequest{ - Permissions: permissions, - } - - resp, err := i.instancesService.TestIamPermissions(project, zone, instanceName, req).Do() - if err != nil { - return nil, fmt.Errorf("failed to test IAM permissions for instance: %w", err) - } - return resp.Permissions, nil -} diff --git a/shared/iam/iam_test.go b/shared/iam/iam_test.go deleted file mode 100644 index 2b94c567..00000000 --- a/shared/iam/iam_test.go +++ /dev/null @@ -1,534 +0,0 @@ -/* -Copyright 2024 Google LLC - -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 - - https://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 iam - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "testing" - - iampb "cloud.google.com/go/iam/apiv1/iampb" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - - gax "github.com/googleapis/gax-go/v2" - "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/compute/v1" - "google.golang.org/api/option" - "google.golang.org/protobuf/testing/protocmp" -) - -// Fake implementation of SecretManager interface -type fakeSecretManager struct { - fakeTestPermissions *iampb.TestIamPermissionsResponse - fakeError error -} - -func (f *fakeSecretManager) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { - return f.fakeTestPermissions, f.fakeError -} - -// resourceType represents the type of resource being tested. -type resourceType int - -const ( - resourceTypeProject resourceType = iota - resourceTypeBucket - resourceTypeInstance - resourceTypeDisk -) - -// createTestServer creates an HTTP test server with the specified response, -// status code, and the resource type -func createTestServer(t *testing.T, serverResp any, serverCode int, resourceType resourceType) (*httptest.Server, *[]string, *string) { - t.Helper() - var gotReqPerms []string - var gotPath string - var req any - switch resourceType { - case resourceTypeProject: - req = &cloudresourcemanager.TestIamPermissionsRequest{} - case resourceTypeInstance, resourceTypeDisk: - req = &compute.TestPermissionsRequest{} - case resourceTypeBucket: - req = &iampb.TestIamPermissionsRequest{} - default: - t.Fatalf("Unsupported resource type: %v", resourceType) - } - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if resourceType == resourceTypeBucket { - // For bucket tests, the request is in the query parameters - gotPath = r.URL.Path - gotReqPerms = r.URL.Query()["permissions"] // Extract permissions from query parameters - } else { - content, err := io.ReadAll(r.Body) - gotPath = r.URL.Path - r.Body.Close() - if err != nil { - t.Fatalf("Reading body: %v", err) - } - if err := json.Unmarshal(content, &req); err != nil { - t.Fatalf("Unmarshalling request: %v", err) - } - switch req.(type) { - case *cloudresourcemanager.TestIamPermissionsRequest: - gotReqPerms = req.(*cloudresourcemanager.TestIamPermissionsRequest).Permissions - case *compute.TestPermissionsRequest: - gotReqPerms = req.(*compute.TestPermissionsRequest).Permissions - case *iampb.TestIamPermissionsRequest: - gotReqPerms = req.(*iampb.TestIamPermissionsRequest).Permissions - default: - t.Fatalf("Unsupported request type: %v", req) - } - } - - code := http.StatusOK - if serverCode > 0 { - code = serverCode - } - w.WriteHeader(code) - w.Header().Set("Content-Type", "application/json") - - respContent, err := json.Marshal(serverResp) - if err != nil { - t.Fatalf("Error marshalling response: %v", err) - } - w.Write(respContent) - })) - - return server, &gotReqPerms, &gotPath -} - -func TestCheckIAMPermissionsOnSecret(t *testing.T) { - ctx := context.Background() - projectID := "test-project" - secretID := "test-secret" - - tests := []struct { - name string - permissions []string - fakeTestPermissions *iampb.TestIamPermissionsResponse - fakeError error - wantGranted []string - wantErr error - }{ - { - name: "Success", - permissions: []string{"secretmanager.secrets.get", "secretmanager.secrets.access"}, - fakeTestPermissions: &iampb.TestIamPermissionsResponse{ - Permissions: []string{"secretmanager.secrets.get"}, - }, - wantGranted: []string{"secretmanager.secrets.get"}, - }, - { - name: "Error", - permissions: []string{"secretmanager.secrets.get", "secretmanager.secrets.access"}, - fakeError: fmt.Errorf("test error"), - wantErr: cmpopts.AnyError, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - fakeSMClient := &fakeSecretManager{ - fakeTestPermissions: test.fakeTestPermissions, - fakeError: test.fakeError, - } - - iamClient := &IAM{ - smClient: fakeSMClient, - } - - gotGranted, err := iamClient.CheckIAMPermissionsOnSecret(ctx, projectID, secretID, test.permissions) - if !cmp.Equal(err, test.wantErr, cmpopts.EquateErrors()) { - t.Errorf("CheckIAMPermissionsOnSecret(%s) returned err: %v, wantErr: %v", test.name, err, test.wantErr) - } - if diff := cmp.Diff(test.wantGranted, gotGranted); diff != "" { - t.Errorf("CheckIAMPermissionsOnSecret(%s) returned unexpected granted permissions diff (-want +got):\n%s", test.name, diff) - } - }) - } -} - -func TestCheckIAMPermissionsOnProject(t *testing.T) { - cases := []struct { - name string - resource string - perms []string - serverResp *cloudresourcemanager.TestIamPermissionsResponse - serverCode int - wantPath string - wantReq *cloudresourcemanager.TestIamPermissionsRequest - want []string - wantErr error - }{ - { - name: "nil_list", - resource: "testproject", - }, - { - name: "AllPermissionsGranted", - resource: "testproject", - perms: []string{"compute.instances.list"}, - serverResp: &cloudresourcemanager.TestIamPermissionsResponse{ - Permissions: []string{"compute.instances.list"}, - }, - wantPath: "/v1/projects/testproject:testIamPermissions", - wantReq: &cloudresourcemanager.TestIamPermissionsRequest{ - Permissions: []string{"compute.instances.list"}, - }, - want: []string{"compute.instances.list"}, - }, - { - name: "SomePermissionsNotGranted", - resource: "testproject", - perms: []string{"compute.instances.list", "iam.serviceAccounts.actAs"}, - serverResp: &cloudresourcemanager.TestIamPermissionsResponse{ - Permissions: []string{"compute.instances.list"}, - }, - wantPath: "/v1/projects/testproject:testIamPermissions", - wantReq: &cloudresourcemanager.TestIamPermissionsRequest{ - Permissions: []string{"compute.instances.list", "iam.serviceAccounts.actAs"}, - }, - want: []string{"compute.instances.list"}, - }, - { - name: "ServerError", - resource: "testproject", - perms: []string{"compute.instances.list"}, - wantPath: "/v1/projects/testproject:testIamPermissions", - serverResp: nil, - serverCode: http.StatusInternalServerError, - want: nil, - wantReq: &cloudresourcemanager.TestIamPermissionsRequest{ - Permissions: []string{"compute.instances.list"}, - }, - wantErr: cmpopts.AnyError, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - ctx := context.Background() - - // Use createTestServer with resourceTypeProject - server, reqPerms, reqPath := createTestServer(t, tc.serverResp, tc.serverCode, resourceTypeProject) - defer server.Close() - - iamClient, err := NewIAMClient(ctx, option.WithEndpoint(server.URL), option.WithoutAuthentication()) - if err != nil { - t.Fatalf("NewIAMClient() failed: %v", err) - } - - got, err := iamClient.CheckIAMPermissionsOnProject(ctx, tc.resource, tc.perms) - gotPath := *reqPath - gotPerms := *reqPerms - - if !cmp.Equal(err, tc.wantErr, cmpopts.EquateErrors()) { - t.Fatalf("CheckIAMPermissionsOnProject(%s) returned err: %v, wantErr: %v", tc.name, err, tc.wantErr) - } - if diff := cmp.Diff(tc.want, got); diff != "" { - t.Errorf("Permissions mismatch (-want +got):\n%s", diff) - } - if len(tc.perms) > 0 { - if gotPath != tc.wantPath { - t.Errorf("Request resource mismatch got=%q want=%q", gotPath, tc.wantPath) - } - if diff := cmp.Diff(tc.wantReq.Permissions, gotPerms, protocmp.Transform()); diff != "" { - t.Errorf("Request diff (-want +got):\n%s", diff) - } - } - }) - } -} - -func TestCheckIAMPermissionsOnDisk(t *testing.T) { - cases := []struct { - name string - project string - zone string - diskName string - perms []string - serverResp *compute.TestPermissionsResponse - serverCode int - wantPath string - wantReq *compute.TestPermissionsRequest - want []string - wantErr error - }{ - { - name: "nil_list", - project: "testproject", - zone: "testzone", - diskName: "testdisk", - }, - { - name: "AllPermissionsGranted", - project: "testproject", - zone: "testzone", - diskName: "testdisk", - perms: []string{"compute.disks.create"}, - serverResp: &compute.TestPermissionsResponse{ - Permissions: []string{"compute.disks.create"}, - }, - wantPath: "/projects/testproject/zones/testzone/disks/testdisk/testIamPermissions", - wantReq: &compute.TestPermissionsRequest{ - Permissions: []string{"compute.disks.create"}, - }, - want: []string{"compute.disks.create"}, - }, - { - name: "SomePermissionsNotGranted", - project: "testproject", - zone: "testzone", - diskName: "testdisk", - perms: []string{"compute.disks.create", "compute.disks.use"}, - serverResp: &compute.TestPermissionsResponse{ - Permissions: []string{"compute.disks.create"}, - }, - wantPath: "/projects/testproject/zones/testzone/disks/testdisk/testIamPermissions", - wantReq: &compute.TestPermissionsRequest{ - Permissions: []string{"compute.disks.create", "compute.disks.use"}, - }, - want: []string{"compute.disks.create"}, - }, - { - name: "ServerError", - project: "testproject", - zone: "testzone", - diskName: "testdisk", - perms: []string{"compute.disks.create"}, - wantPath: "/projects/testproject/zones/testzone/disks/testdisk/testIamPermissions", - serverResp: nil, - serverCode: http.StatusInternalServerError, - want: nil, - wantReq: &compute.TestPermissionsRequest{ - Permissions: []string{"compute.disks.create"}, - }, - wantErr: cmpopts.AnyError, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - ctx := context.Background() - - server, reqPerms, reqPath := createTestServer(t, tc.serverResp, tc.serverCode, resourceTypeDisk) - defer server.Close() - - iamClient, err := NewIAMClient(ctx, option.WithEndpoint(server.URL), option.WithoutAuthentication()) - if err != nil { - t.Fatalf("NewIAMClient() failed: %v", err) - } - - got, err := iamClient.CheckIAMPermissionsOnDisk(ctx, tc.project, tc.zone, tc.diskName, tc.perms) - gotPath := *reqPath - gotPerms := *reqPerms - - if !cmp.Equal(err, tc.wantErr, cmpopts.EquateErrors()) { - t.Fatalf("CheckIAMPermissionsOnDisk(%s) returned err: %v, wantErr: %v", tc.name, err, tc.wantErr) - } - if diff := cmp.Diff(tc.want, got); diff != "" { - t.Errorf("Permissions mismatch (-want +got):\n%s", diff) - } - if len(tc.perms) > 0 { - if got, want := gotPath, tc.wantPath; got != want { - t.Errorf("Request resource mismatch got=%q want=%q", got, want) - } - if diff := cmp.Diff(tc.wantReq.Permissions, gotPerms, protocmp.Transform()); diff != "" { - t.Errorf("Request diff (-want +got):\n%s", diff) - } - } - }) - } -} - -func TestCheckIAMPermissionsOnInstance(t *testing.T) { - cases := []struct { - name string - project string - zone string - instance string - perms []string - serverResp *compute.TestPermissionsResponse - serverCode int - wantPath string - wantReq *compute.TestPermissionsRequest - want []string - wantErr error - }{ - { - name: "nil_list", - project: "testproject", - zone: "testzone", - instance: "testinstance", - }, - { - name: "AllPermissionsGranted", - project: "testproject", - zone: "testzone", - instance: "testinstance", - perms: []string{"compute.instances.get"}, - serverResp: &compute.TestPermissionsResponse{ - Permissions: []string{"compute.instances.get"}, - }, - wantPath: "/projects/testproject/zones/testzone/instances/testinstance/testIamPermissions", - wantReq: &compute.TestPermissionsRequest{ - Permissions: []string{"compute.instances.get"}, - }, - want: []string{"compute.instances.get"}, - }, - { - name: "SomePermissionsNotGranted", - project: "testproject", - zone: "testzone", - instance: "testinstance", - perms: []string{"compute.instances.get", "compute.instances.stop"}, - serverResp: &compute.TestPermissionsResponse{ - Permissions: []string{"compute.instances.get"}, - }, - wantPath: "/projects/testproject/zones/testzone/instances/testinstance/testIamPermissions", - wantReq: &compute.TestPermissionsRequest{ - Permissions: []string{"compute.instances.get", "compute.instances.stop"}, - }, - want: []string{"compute.instances.get"}, - }, - { - name: "ServerError", - project: "testproject", - zone: "testzone", - instance: "testinstance", - perms: []string{"compute.instances.get"}, - wantPath: "/projects/testproject/zones/testzone/instances/testinstance/testIamPermissions", - serverResp: nil, - serverCode: http.StatusInternalServerError, - want: nil, - wantReq: &compute.TestPermissionsRequest{ - Permissions: []string{"compute.instances.get"}, - }, - wantErr: cmpopts.AnyError, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - ctx := context.Background() - - server, reqPerms, reqPath := createTestServer(t, tc.serverResp, tc.serverCode, resourceTypeInstance) - defer server.Close() - - iamClient, err := NewIAMClient(ctx, option.WithEndpoint(server.URL), option.WithoutAuthentication()) - if err != nil { - t.Fatalf("NewIAMClient() failed: %v", err) - } - - got, err := iamClient.CheckIAMPermissionsOnInstance(ctx, tc.project, tc.zone, tc.instance, tc.perms) - gotPath := *reqPath - gotPerms := *reqPerms - - if !cmp.Equal(err, tc.wantErr, cmpopts.EquateErrors()) { - t.Fatalf("CheckIAMPermissionsOnInstance(%s) returned err: %v, wantErr: %v", tc.name, err, tc.wantErr) - } - if diff := cmp.Diff(tc.want, got); diff != "" { - t.Errorf("Permissions mismatch (-want +got):\n%s", diff) - } - if len(tc.perms) > 0 { - if got, want := gotPath, tc.wantPath; got != want { - t.Errorf("Request resource mismatch got=%q want=%q", got, want) - } - if diff := cmp.Diff(tc.wantReq.Permissions, gotPerms, protocmp.Transform()); diff != "" { - t.Errorf("Request diff (-want +got):\n%s", diff) - } - } - }) - } -} - -func TestCheckIAMPermissionsOnBucket(t *testing.T) { - cases := []struct { - name string - bucketName string - perms []string - serverResp *iampb.TestIamPermissionsResponse - serverCode int - wantPath string - want []string - wantErr error - }{ - { - name: "nil_list", - bucketName: "test-bucket", - }, - { - name: "AllPermissionsGranted", - bucketName: "test-bucket", - perms: []string{"storage.buckets.get, storage.buckets.update"}, - serverResp: &iampb.TestIamPermissionsResponse{Permissions: []string{"storage.buckets.get, storage.buckets.update"}}, - wantPath: "/b/test-bucket/iam/testPermissions", - want: []string{"storage.buckets.get, storage.buckets.update"}, - }, - { - name: "SomePermissionsNotGranted", - bucketName: "test-bucket", - perms: []string{"storage.buckets.get", "storage.objects.list"}, - serverResp: &iampb.TestIamPermissionsResponse{Permissions: []string{"storage.buckets.get"}}, - wantPath: "/b/test-bucket/iam/testPermissions", - want: []string{"storage.buckets.get"}, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - // t.Parallel() - ctx := context.Background() - - server, reqPerms, reqPath := createTestServer(t, tc.serverResp, tc.serverCode, resourceTypeBucket) - defer server.Close() - - iamClient, err := NewIAMClient(ctx, option.WithEndpoint(server.URL), option.WithoutAuthentication()) - if err != nil { - t.Fatalf("NewIAMClient() failed: %v", err) - } - - got, err := iamClient.CheckIAMPermissionsOnBucket(ctx, tc.bucketName, tc.perms) - gotPath := *reqPath - gotPerms := *reqPerms - - if !cmp.Equal(err, tc.wantErr, cmpopts.EquateErrors()) { - t.Fatalf("CheckIAMPermissionsOnBucket(%s) returned err: %v, wantErr: %v", tc.name, err, tc.wantErr) - } - if diff := cmp.Diff(tc.want, got); diff != "" { - t.Errorf("Permissions mismatch (-want +got):\n%s", diff) - } - if diff := cmp.Diff(tc.perms, gotPerms); diff != "" { - t.Errorf("Permissions mismatch (-want +got):\n%s", diff) - } - if len(tc.perms) > 0 { - if got, want := gotPath, tc.wantPath; got != want { - t.Errorf("Request resource mismatch got=%q want=%q", got, want) - } - } - }) - } -}