2021-08-04 15:17:27 +00:00
package remote
import (
"context"
"testing"
asset "cloud.google.com/go/asset/apiv1"
2021-09-15 18:36:04 +00:00
"cloud.google.com/go/storage"
2021-08-04 15:17:27 +00:00
"github.com/cloudskiff/driftctl/mocks"
"github.com/cloudskiff/driftctl/pkg/filter"
"github.com/cloudskiff/driftctl/pkg/remote/alerts"
"github.com/cloudskiff/driftctl/pkg/remote/cache"
"github.com/cloudskiff/driftctl/pkg/remote/common"
2021-09-06 15:00:38 +00:00
remoteerr "github.com/cloudskiff/driftctl/pkg/remote/error"
2021-08-04 15:17:27 +00:00
"github.com/cloudskiff/driftctl/pkg/remote/google"
"github.com/cloudskiff/driftctl/pkg/remote/google/repository"
"github.com/cloudskiff/driftctl/pkg/resource"
googleresource "github.com/cloudskiff/driftctl/pkg/resource/google"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/goldenfile"
testgoogle "github.com/cloudskiff/driftctl/test/google"
testresource "github.com/cloudskiff/driftctl/test/resource"
terraform2 "github.com/cloudskiff/driftctl/test/terraform"
2021-09-15 18:36:04 +00:00
"github.com/pkg/errors"
2021-08-04 15:17:27 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestGoogleStorageBucket ( t * testing . T ) {
cases := [ ] struct {
test string
dirName string
response [ ] * assetpb . ResourceSearchResult
responseErr error
setupAlerterMock func ( alerter * mocks . AlerterInterface )
wantErr error
} {
{
test : "no storage buckets" ,
dirName : "google_storage_bucket_empty" ,
response : [ ] * assetpb . ResourceSearchResult { } ,
wantErr : nil ,
} ,
{
test : "multiples storage buckets" ,
dirName : "google_storage_bucket" ,
response : [ ] * assetpb . ResourceSearchResult {
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "driftctl-unittest-1" ,
} ,
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "driftctl-unittest-2" ,
} ,
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "driftctl-unittest-3" ,
} ,
} ,
wantErr : nil ,
} ,
{
test : "cannot list storage buckets" ,
dirName : "google_storage_bucket_empty" ,
responseErr : status . Error ( codes . PermissionDenied , "The caller does not have permission" ) ,
setupAlerterMock : func ( alerter * mocks . AlerterInterface ) {
alerter . On (
"SendAlert" ,
"google_storage_bucket" ,
alerts . NewRemoteAccessDeniedAlert (
common . RemoteGoogleTerraform ,
2021-09-06 15:00:38 +00:00
remoteerr . NewResourceListingError (
status . Error ( codes . PermissionDenied , "The caller does not have permission" ) ,
"google_storage_bucket" ,
) ,
2021-08-04 15:17:27 +00:00
alerts . EnumerationPhase ,
) ,
) . Once ( )
} ,
wantErr : nil ,
} ,
}
providerVersion := "3.78.0"
resType := resource . ResourceType ( googleresource . GoogleStorageBucketResourceType )
schemaRepository := testresource . InitFakeSchemaRepository ( "google" , providerVersion )
googleresource . InitResourcesMetadata ( schemaRepository )
factory := terraform . NewTerraformResourceFactory ( schemaRepository )
deserializer := resource . NewDeserializer ( factory )
for _ , c := range cases {
t . Run ( c . test , func ( tt * testing . T ) {
shouldUpdate := c . dirName == * goldenfile . Update
scanOptions := ScannerOptions { Deep : true }
providerLibrary := terraform . NewProviderLibrary ( )
remoteLibrary := common . NewRemoteLibrary ( )
// Initialize mocks
alerter := & mocks . AlerterInterface { }
if c . setupAlerterMock != nil {
c . setupAlerterMock ( alerter )
}
var assetClient * asset . Client
if ! shouldUpdate {
var err error
assetClient , err = testgoogle . NewFakeAssetServer ( c . response , c . responseErr )
if err != nil {
tt . Fatal ( err )
}
}
realProvider , err := terraform2 . InitTestGoogleProvider ( providerLibrary , providerVersion )
if err != nil {
tt . Fatal ( err )
}
provider := terraform2 . NewFakeTerraformProvider ( realProvider )
provider . WithResponse ( c . dirName )
// Replace mock by real resources if we are in update mode
if shouldUpdate {
ctx := context . Background ( )
assetClient , err = asset . NewClient ( ctx )
if err != nil {
tt . Fatal ( err )
}
err = realProvider . Init ( )
if err != nil {
tt . Fatal ( err )
}
provider . ShouldUpdate ( )
}
repo := repository . NewAssetRepository ( assetClient , realProvider . GetConfig ( ) , cache . New ( 0 ) )
remoteLibrary . AddEnumerator ( google . NewGoogleStorageBucketEnumerator ( repo , factory ) )
remoteLibrary . AddDetailsFetcher ( resType , common . NewGenericDetailsFetcher ( resType , provider , deserializer ) )
testFilter := & filter . MockFilter { }
testFilter . On ( "IsTypeIgnored" , mock . Anything ) . Return ( false )
s := NewScanner ( remoteLibrary , alerter , scanOptions , testFilter )
got , err := s . Resources ( )
assert . Equal ( tt , err , c . wantErr )
if err != nil {
return
}
alerter . AssertExpectations ( tt )
testFilter . AssertExpectations ( tt )
test . TestAgainstGoldenFile ( got , resType . String ( ) , c . dirName , provider , deserializer , shouldUpdate , tt )
} )
}
}
2021-09-15 18:36:04 +00:00
2021-10-04 17:03:44 +00:00
func TestGoogleStorageBucketIAMMember ( t * testing . T ) {
2021-09-15 18:36:04 +00:00
cases := [ ] struct {
test string
dirName string
assetRepositoryMock func ( assetRepository * repository . MockAssetRepository )
storageRepositoryMock func ( storageRepository * repository . MockStorageRepository )
responseErr error
setupAlerterMock func ( alerter * mocks . AlerterInterface )
wantErr error
} {
{
test : "no storage buckets" ,
2021-10-04 17:03:44 +00:00
dirName : "google_storage_bucket_member_empty" ,
2021-09-15 18:36:04 +00:00
assetRepositoryMock : func ( assetRepository * repository . MockAssetRepository ) {
assetRepository . On ( "SearchAllBuckets" ) . Return ( [ ] * assetpb . ResourceSearchResult { } , nil )
} ,
wantErr : nil ,
} ,
{
test : "multiples storage buckets, no bindings" ,
2021-10-04 17:03:44 +00:00
dirName : "google_storage_bucket_member_empty" ,
2021-09-15 18:36:04 +00:00
assetRepositoryMock : func ( assetRepository * repository . MockAssetRepository ) {
assetRepository . On ( "SearchAllBuckets" ) . Return ( [ ] * assetpb . ResourceSearchResult {
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "dctlgstoragebucketiambinding-1" ,
} ,
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "dctlgstoragebucketiambinding-2" ,
} ,
} , nil )
} ,
storageRepositoryMock : func ( storageRepository * repository . MockStorageRepository ) {
storageRepository . On ( "ListAllBindings" , "dctlgstoragebucketiambinding-1" ) . Return ( map [ string ] [ ] string { } , nil )
storageRepository . On ( "ListAllBindings" , "dctlgstoragebucketiambinding-2" ) . Return ( map [ string ] [ ] string { } , nil )
} ,
wantErr : nil ,
} ,
{
test : "Cannot list bindings" ,
2021-10-04 17:03:44 +00:00
dirName : "google_storage_bucket_member_listing_error" ,
2021-09-15 18:36:04 +00:00
assetRepositoryMock : func ( assetRepository * repository . MockAssetRepository ) {
assetRepository . On ( "SearchAllBuckets" ) . Return ( [ ] * assetpb . ResourceSearchResult {
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "dctlgstoragebucketiambinding-1" ,
} ,
} , nil )
} ,
storageRepositoryMock : func ( storageRepository * repository . MockStorageRepository ) {
storageRepository . On ( "ListAllBindings" , "dctlgstoragebucketiambinding-1" ) . Return (
map [ string ] [ ] string { } ,
errors . New ( "googleapi: Error 403: driftctl-acc-circle@driftctl-qa-1.iam.gserviceaccount.com does not have storage.buckets.getIamPolicy access to the Google Cloud Storage bucket., forbidden" ) )
} ,
setupAlerterMock : func ( alerter * mocks . AlerterInterface ) {
alerter . On (
"SendAlert" ,
2021-10-04 17:03:44 +00:00
"google_storage_bucket_iam_member" ,
2021-09-15 18:36:04 +00:00
alerts . NewRemoteAccessDeniedAlert (
common . RemoteGoogleTerraform ,
remoteerr . NewResourceListingError (
errors . New ( "googleapi: Error 403: driftctl-acc-circle@driftctl-qa-1.iam.gserviceaccount.com does not have storage.buckets.getIamPolicy access to the Google Cloud Storage bucket., forbidden" ) ,
2021-10-04 17:03:44 +00:00
"google_storage_bucket_iam_member" ,
2021-09-15 18:36:04 +00:00
) ,
alerts . EnumerationPhase ,
) ,
) . Once ( )
} ,
wantErr : nil ,
} ,
{
test : "multiples storage buckets, multiple bindings" ,
2021-10-04 17:03:44 +00:00
dirName : "google_storage_bucket_member_listing_multiple" ,
2021-09-15 18:36:04 +00:00
assetRepositoryMock : func ( assetRepository * repository . MockAssetRepository ) {
assetRepository . On ( "SearchAllBuckets" ) . Return ( [ ] * assetpb . ResourceSearchResult {
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "dctlgstoragebucketiambinding-1" ,
} ,
{
AssetType : "storage.googleapis.com/Bucket" ,
DisplayName : "dctlgstoragebucketiambinding-2" ,
} ,
} , nil )
} ,
storageRepositoryMock : func ( storageRepository * repository . MockStorageRepository ) {
storageRepository . On ( "ListAllBindings" , "dctlgstoragebucketiambinding-1" ) . Return ( map [ string ] [ ] string {
"roles/storage.admin" : { "user:elie.charra@cloudskiff.com" } ,
"roles/storage.objectViewer" : { "user:william.beuil@cloudskiff.com" } ,
} , nil )
storageRepository . On ( "ListAllBindings" , "dctlgstoragebucketiambinding-2" ) . Return ( map [ string ] [ ] string {
"roles/storage.admin" : { "user:william.beuil@cloudskiff.com" } ,
"roles/storage.objectViewer" : { "user:elie.charra@cloudskiff.com" } ,
} , nil )
} ,
wantErr : nil ,
} ,
}
providerVersion := "3.78.0"
2021-10-04 17:03:44 +00:00
resType := resource . ResourceType ( googleresource . GoogleStorageBucketIamMemberResourceType )
2021-09-15 18:36:04 +00:00
schemaRepository := testresource . InitFakeSchemaRepository ( "google" , providerVersion )
googleresource . InitResourcesMetadata ( schemaRepository )
factory := terraform . NewTerraformResourceFactory ( schemaRepository )
deserializer := resource . NewDeserializer ( factory )
for _ , c := range cases {
t . Run ( c . test , func ( tt * testing . T ) {
repositoryCache := cache . New ( 100 )
shouldUpdate := c . dirName == * goldenfile . Update
scanOptions := ScannerOptions { Deep : true }
providerLibrary := terraform . NewProviderLibrary ( )
remoteLibrary := common . NewRemoteLibrary ( )
// Initialize mocks
alerter := & mocks . AlerterInterface { }
if c . setupAlerterMock != nil {
c . setupAlerterMock ( alerter )
}
storageRepo := & repository . MockStorageRepository { }
if c . storageRepositoryMock != nil {
c . storageRepositoryMock ( storageRepo )
}
var storageRepository repository . StorageRepository = storageRepo
if shouldUpdate {
2021-09-27 09:29:47 +00:00
storageClient , err := storage . NewClient ( context . Background ( ) )
2021-09-15 18:36:04 +00:00
if err != nil {
panic ( err )
}
storageRepository = repository . NewStorageRepository ( storageClient , repositoryCache )
}
assetRepo := & repository . MockAssetRepository { }
if c . assetRepositoryMock != nil {
c . assetRepositoryMock ( assetRepo )
}
var assetRepository repository . AssetRepository = assetRepo
realProvider , err := terraform2 . InitTestGoogleProvider ( providerLibrary , providerVersion )
if err != nil {
tt . Fatal ( err )
}
provider := terraform2 . NewFakeTerraformProvider ( realProvider )
provider . WithResponse ( c . dirName )
2021-10-04 17:03:44 +00:00
remoteLibrary . AddEnumerator ( google . NewGoogleStorageBucketIamMemberEnumerator ( assetRepository , storageRepository , factory ) )
2021-09-15 18:36:04 +00:00
testFilter := & filter . MockFilter { }
testFilter . On ( "IsTypeIgnored" , mock . Anything ) . Return ( false )
s := NewScanner ( remoteLibrary , alerter , scanOptions , testFilter )
got , err := s . Resources ( )
assert . Equal ( tt , c . wantErr , err )
if err != nil {
return
}
alerter . AssertExpectations ( tt )
testFilter . AssertExpectations ( tt )
test . TestAgainstGoldenFile ( got , resType . String ( ) , c . dirName , provider , deserializer , shouldUpdate , tt )
} )
}
}