2021-01-20 13:01:57 +00:00
package remote
import (
"errors"
"testing"
2021-12-06 13:29:39 +00:00
"github.com/snyk/driftctl/pkg/remote/alerts"
"github.com/snyk/driftctl/pkg/remote/common"
remoteerr "github.com/snyk/driftctl/pkg/remote/error"
resourcegithub "github.com/snyk/driftctl/pkg/resource/github"
2021-08-04 15:17:27 +00:00
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
2021-01-20 13:01:57 +00:00
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws/awserr"
2021-12-06 13:29:39 +00:00
resourceaws "github.com/snyk/driftctl/pkg/resource/aws"
2021-01-20 13:01:57 +00:00
2021-12-06 13:29:39 +00:00
"github.com/snyk/driftctl/pkg/alerter"
2021-01-20 13:01:57 +00:00
)
2021-07-28 14:30:22 +00:00
func TestHandleAwsEnumerationErrors ( t * testing . T ) {
2021-01-20 13:01:57 +00:00
tests := [ ] struct {
name string
err error
wantAlerts alerter . Alerts
wantErr bool
} {
{
2021-02-11 11:21:49 +00:00
name : "Handled error 403" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "" , "" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsVpcResourceType ) ,
wantAlerts : alerter . Alerts { "aws_vpc" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( awserr . NewRequestFailure ( awserr . New ( "" , "" , errors . New ( "" ) ) , 403 , "" ) , "aws_vpc" , "aws_vpc" ) , alerts . EnumerationPhase ) } } ,
2021-01-20 13:01:57 +00:00
wantErr : false ,
} ,
2021-02-11 11:21:49 +00:00
{
name : "Handled error AccessDenied" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "AccessDeniedException" , "" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsDynamodbTableResourceType ) ,
wantAlerts : alerter . Alerts { "aws_dynamodb_table" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( awserr . NewRequestFailure ( awserr . New ( "AccessDeniedException" , "" , errors . New ( "" ) ) , 403 , "" ) , "aws_dynamodb_table" , "aws_dynamodb_table" ) , alerts . EnumerationPhase ) } } ,
2021-02-11 11:21:49 +00:00
wantErr : false ,
} ,
2021-01-20 13:01:57 +00:00
{
name : "Not Handled error code" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "" , "" , errors . New ( "" ) ) , 404 , "" ) , resourceaws . AwsVpcResourceType ) ,
2021-01-20 13:01:57 +00:00
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
{
name : "Not Handled error type" ,
err : errors . New ( "error" ) ,
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
{
name : "Not Handled root error type" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( errors . New ( "error" ) , resourceaws . AwsVpcResourceType ) ,
2021-01-20 13:01:57 +00:00
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
2021-07-28 14:30:22 +00:00
{
name : "Handle AccessDenied error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( errors . New ( "an error occured: AccessDenied: 403" ) , resourceaws . AwsVpcResourceType ) ,
wantAlerts : alerter . Alerts { "aws_vpc" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( errors . New ( "an error occured: AccessDenied: 403" ) , "aws_vpc" , "aws_vpc" ) , alerts . EnumerationPhase ) } } ,
2021-08-03 13:01:20 +00:00
wantErr : false ,
} ,
{
name : "Access denied error on a single resource" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceScanningError ( errors . New ( "Error: AccessDenied: 403 ..." ) , resourceaws . AwsS3BucketResourceType , "my-bucket" ) ,
wantAlerts : alerter . Alerts { "aws_s3_bucket.my-bucket" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( errors . New ( "Error: AccessDenied: 403 ..." ) , "aws_s3_bucket.my-bucket" , "aws_s3_bucket" ) , alerts . EnumerationPhase ) } } ,
2021-07-28 14:30:22 +00:00
wantErr : false ,
} ,
2021-01-20 13:01:57 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
alertr := alerter . NewAlerter ( )
gotErr := HandleResourceEnumerationError ( tt . err , alertr )
assert . Equal ( t , tt . wantErr , gotErr != nil )
retrieve := alertr . Retrieve ( )
assert . Equal ( t , tt . wantAlerts , retrieve )
} )
}
}
2021-03-02 10:39:14 +00:00
2021-07-28 14:30:22 +00:00
func TestHandleGithubEnumerationErrors ( t * testing . T ) {
2021-03-02 10:39:14 +00:00
tests := [ ] struct {
name string
err error
wantAlerts alerter . Alerts
wantErr bool
} {
{
name : "Handled graphql error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( errors . New ( "Your token has not been granted the required scopes to execute this query." ) , resourcegithub . GithubTeamResourceType ) ,
wantAlerts : alerter . Alerts { "github_team" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteGithubTerraform , remoteerr . NewResourceListingErrorWithType ( errors . New ( "Your token has not been granted the required scopes to execute this query." ) , "github_team" , "github_team" ) , alerts . EnumerationPhase ) } } ,
2021-03-02 10:39:14 +00:00
wantErr : false ,
} ,
{
name : "Not handled graphql error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( errors . New ( "This is a not handler graphql error" ) , resourcegithub . GithubTeamResourceType ) ,
2021-03-02 10:39:14 +00:00
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
{
name : "Not Handled error type" ,
err : errors . New ( "error" ) ,
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
alertr := alerter . NewAlerter ( )
gotErr := HandleResourceEnumerationError ( tt . err , alertr )
assert . Equal ( t , tt . wantErr , gotErr != nil )
retrieve := alertr . Retrieve ( )
assert . Equal ( t , tt . wantAlerts , retrieve )
} )
}
}
2021-08-04 15:17:27 +00:00
func TestHandleGoogleEnumerationErrors ( t * testing . T ) {
tests := [ ] struct {
name string
err error
wantAlerts alerter . Alerts
wantErr bool
} {
{
name : "Handled 403 error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( status . Error ( codes . PermissionDenied , "useless message" ) , "google_type" ) ,
wantAlerts : alerter . Alerts { "google_type" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteGoogleTerraform , remoteerr . NewResourceListingErrorWithType ( status . Error ( codes . PermissionDenied , "useless message" ) , "google_type" , "google_type" ) , alerts . EnumerationPhase ) } } ,
2021-08-04 15:17:27 +00:00
wantErr : false ,
} ,
{
name : "Not handled non 403 error" ,
err : status . Error ( codes . Unknown , "" ) ,
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
{
name : "Not Handled error type" ,
err : errors . New ( "error" ) ,
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
alertr := alerter . NewAlerter ( )
gotErr := HandleResourceEnumerationError ( tt . err , alertr )
assert . Equal ( t , tt . wantErr , gotErr != nil )
retrieve := alertr . Retrieve ( )
assert . Equal ( t , tt . wantAlerts , retrieve )
} )
}
}
2021-07-28 14:30:22 +00:00
func TestHandleAwsDetailsFetchingErrors ( t * testing . T ) {
tests := [ ] struct {
name string
err error
wantAlerts alerter . Alerts
wantErr bool
} {
{
name : "Handle AccessDeniedException error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "AccessDeniedException" , "test" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsVpcResourceType ) ,
wantAlerts : alerter . Alerts { "aws_vpc" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( awserr . NewRequestFailure ( awserr . New ( "AccessDeniedException" , "test" , errors . New ( "" ) ) , 403 , "" ) , "aws_vpc" , "aws_vpc" ) , alerts . DetailsFetchingPhase ) } } ,
2021-07-28 14:30:22 +00:00
wantErr : false ,
} ,
{
name : "Handle AccessDenied error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "test" , "error: AccessDenied" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsVpcResourceType ) ,
wantAlerts : alerter . Alerts { "aws_vpc" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( awserr . NewRequestFailure ( awserr . New ( "test" , "error: AccessDenied" , errors . New ( "" ) ) , 403 , "" ) , "aws_vpc" , "aws_vpc" ) , alerts . DetailsFetchingPhase ) } } ,
2021-07-28 14:30:22 +00:00
wantErr : false ,
} ,
{
2021-08-02 12:17:27 +00:00
name : "Handle AuthorizationError error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "test" , "error: AuthorizationError" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsVpcResourceType ) ,
wantAlerts : alerter . Alerts { "aws_vpc" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteAWSTerraform , remoteerr . NewResourceListingErrorWithType ( awserr . NewRequestFailure ( awserr . New ( "test" , "error: AuthorizationError" , errors . New ( "" ) ) , 403 , "" ) , "aws_vpc" , "aws_vpc" ) , alerts . DetailsFetchingPhase ) } } ,
2021-07-28 14:30:22 +00:00
wantErr : false ,
} ,
{
name : "Unhandled error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "test" , "error: dummy error" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsVpcResourceType ) ,
2021-07-28 14:30:22 +00:00
wantAlerts : alerter . Alerts { } ,
wantErr : true ,
} ,
2021-08-03 13:01:20 +00:00
{
name : "Not Handled error type" ,
err : errors . New ( "error" ) ,
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
2021-07-28 14:30:22 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
alertr := alerter . NewAlerter ( )
gotErr := HandleResourceDetailsFetchingError ( tt . err , alertr )
assert . Equal ( t , tt . wantErr , gotErr != nil )
retrieve := alertr . Retrieve ( )
assert . Equal ( t , tt . wantAlerts , retrieve )
} )
}
}
2021-08-04 15:17:27 +00:00
func TestHandleGoogleDetailsFetchingErrors ( t * testing . T ) {
tests := [ ] struct {
name string
err error
wantAlerts alerter . Alerts
wantErr bool
} {
{
name : "Handle 403 error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceScanningError (
2021-08-04 15:17:27 +00:00
errors . New ( "Error when reading or editing Storage Bucket \"driftctl-unittest-1\": googleapi: Error 403: driftctl@elie-dev.iam.gserviceaccount.com does not have storage.buckets.get access to the Google Cloud Storage bucket., forbidden" ) ,
"google_type" ,
"resource_id" ,
) ,
2021-09-06 15:00:38 +00:00
wantAlerts : alerter . Alerts { "google_type.resource_id" : [ ] alerter . Alert { alerts . NewRemoteAccessDeniedAlert ( common . RemoteGoogleTerraform , remoteerr . NewResourceListingErrorWithType ( errors . New ( "Error when reading or editing Storage Bucket \"driftctl-unittest-1\": googleapi: Error 403: driftctl@elie-dev.iam.gserviceaccount.com does not have storage.buckets.get access to the Google Cloud Storage bucket., forbidden" ) , "google_type.resource_id" , "google_type" ) , alerts . DetailsFetchingPhase ) } } ,
2021-08-04 15:17:27 +00:00
wantErr : false ,
} ,
{
name : "do not handle google unrelated error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceScanningError (
2021-08-04 15:17:27 +00:00
errors . New ( "this string does not contains g o o g l e a p i string and thus should not be matched" ) ,
"google_type" ,
"resource_id" ,
) , wantAlerts : alerter . Alerts { } ,
wantErr : true ,
} ,
{
name : "do not handle google error other than 403" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceScanningError (
2021-08-04 15:17:27 +00:00
errors . New ( "Error when reading or editing Storage Bucket \"driftctl-unittest-1\": googleapi: Error 404: not found" ) ,
"google_type" ,
"resource_id" ,
) , wantAlerts : alerter . Alerts { } ,
wantErr : true ,
} ,
{
name : "Not Handled error type" ,
err : errors . New ( "error" ) ,
wantAlerts : map [ string ] [ ] alerter . Alert { } ,
wantErr : true ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
alertr := alerter . NewAlerter ( )
gotErr := HandleResourceDetailsFetchingError ( tt . err , alertr )
assert . Equal ( t , tt . wantErr , gotErr != nil )
retrieve := alertr . Retrieve ( )
assert . Equal ( t , tt . wantAlerts , retrieve )
} )
}
}
2021-03-02 10:39:14 +00:00
func TestEnumerationAccessDeniedAlert_GetProviderMessage ( t * testing . T ) {
tests := [ ] struct {
name string
provider string
want string
} {
{
name : "test for unsupported provider" ,
provider : "foobar" ,
want : "" ,
} ,
{
name : "test for AWS" ,
2021-08-03 13:01:20 +00:00
provider : common . RemoteAWSTerraform ,
2021-05-12 09:31:00 +00:00
want : "It seems that we got access denied exceptions while listing resources.\nThe latest minimal read-only IAM policy for driftctl is always available here, please update yours: https://docs.driftctl.com/aws/policy" ,
2021-03-02 10:39:14 +00:00
} ,
{
name : "test for github" ,
2021-08-03 13:01:20 +00:00
provider : common . RemoteGithubTerraform ,
2021-05-12 09:31:00 +00:00
want : "It seems that we got access denied exceptions while listing resources.\nPlease be sure that your Github token has the right permissions, check the last up-to-date documentation there: https://docs.driftctl.com/github/policy" ,
2021-03-02 10:39:14 +00:00
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2021-09-06 15:00:38 +00:00
e := alerts . NewRemoteAccessDeniedAlert ( tt . provider , remoteerr . NewResourceListingErrorWithType ( errors . New ( "dummy error" ) , "supplier_type" , "listed_type_error" ) , alerts . EnumerationPhase )
2021-07-28 14:30:22 +00:00
if got := e . GetProviderMessage ( ) ; got != tt . want {
t . Errorf ( "GetProviderMessage() = %v, want %v" , got , tt . want )
}
} )
}
}
func TestDetailsFetchingAccessDeniedAlert_GetProviderMessage ( t * testing . T ) {
tests := [ ] struct {
name string
provider string
want string
} {
{
name : "test for unsupported provider" ,
provider : "foobar" ,
want : "" ,
} ,
{
name : "test for AWS" ,
2021-08-03 13:01:20 +00:00
provider : common . RemoteAWSTerraform ,
2021-07-28 14:30:22 +00:00
want : "It seems that we got access denied exceptions while reading details of resources.\nThe latest minimal read-only IAM policy for driftctl is always available here, please update yours: https://docs.driftctl.com/aws/policy" ,
} ,
{
name : "test for github" ,
2021-08-03 13:01:20 +00:00
provider : common . RemoteGithubTerraform ,
2021-07-28 14:30:22 +00:00
want : "It seems that we got access denied exceptions while reading details of resources.\nPlease be sure that your Github token has the right permissions, check the last up-to-date documentation there: https://docs.driftctl.com/github/policy" ,
} ,
2021-08-04 15:17:27 +00:00
{
name : "test for google" ,
provider : common . RemoteGoogleTerraform ,
want : "It seems that we got access denied exceptions while reading details of resources.\nPlease ensure that you have configured the required roles, please check our documentation at https://docs.driftctl.com/google/policy" ,
} ,
2021-07-28 14:30:22 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
2021-09-06 15:00:38 +00:00
e := alerts . NewRemoteAccessDeniedAlert ( tt . provider , remoteerr . NewResourceListingErrorWithType ( errors . New ( "dummy error" ) , "supplier_type" , "listed_type_error" ) , alerts . DetailsFetchingPhase )
2021-03-02 10:39:14 +00:00
if got := e . GetProviderMessage ( ) ; got != tt . want {
t . Errorf ( "GetProviderMessage() = %v, want %v" , got , tt . want )
}
} )
}
}
2021-08-03 13:01:20 +00:00
func TestResourceScanningErrorMethods ( t * testing . T ) {
tests := [ ] struct {
name string
2021-09-06 15:00:38 +00:00
err * remoteerr . ResourceScanningError
2021-08-03 13:01:20 +00:00
expectedError string
expectedResourceType string
} {
{
name : "Handled error AccessDenied" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( awserr . NewRequestFailure ( awserr . New ( "AccessDeniedException" , "" , errors . New ( "" ) ) , 403 , "" ) , resourceaws . AwsDynamodbTableResourceType ) ,
2021-08-03 13:01:20 +00:00
expectedError : "error scanning resource type aws_dynamodb_table: AccessDeniedException: \n\tstatus code: 403, request id: \ncaused by: " ,
expectedResourceType : resourceaws . AwsDynamodbTableResourceType ,
} ,
{
name : "Handle AccessDenied error" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceListingError ( errors . New ( "an error occured: AccessDenied: 403" ) , resourceaws . AwsVpcResourceType ) ,
2021-08-03 13:01:20 +00:00
expectedError : "error scanning resource type aws_vpc: an error occured: AccessDenied: 403" ,
expectedResourceType : resourceaws . AwsVpcResourceType ,
} ,
{
name : "Access denied error on a single resource" ,
2021-09-06 15:00:38 +00:00
err : remoteerr . NewResourceScanningError ( errors . New ( "Error: AccessDenied: 403 ..." ) , resourceaws . AwsS3BucketResourceType , "my-bucket" ) ,
2021-08-03 13:01:20 +00:00
expectedError : "error scanning resource aws_s3_bucket.my-bucket: Error: AccessDenied: 403 ..." ,
expectedResourceType : resourceaws . AwsS3BucketResourceType ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert . Equal ( t , tt . expectedError , tt . err . Error ( ) )
assert . Equal ( t , tt . expectedResourceType , tt . err . ResourceType ( ) )
} )
}
}