@@ -107,7 +107,11 @@ func NewClient(ctx context.Context, l log.Logger, config *ExtendedRemoteStateCon
107107// CreateS3BucketIfNecessary prompts the user to create the given bucket if it doesn't already exist and if the user
108108// confirms, creates the bucket and enables versioning for it.
109109func (client * Client ) CreateS3BucketIfNecessary (ctx context.Context , l log.Logger , bucketName string , opts * options.TerragruntOptions ) error {
110- cfg := & client .RemoteStateConfigS3
110+ if client .ExtendedRemoteStateConfigS3 == nil {
111+ return errors .Errorf ("client configuration is nil - cannot create S3 bucket if necessary" )
112+ }
113+
114+ cfg := & client .ExtendedRemoteStateConfigS3 .RemoteStateConfigS3
111115
112116 if exists , err := client .DoesS3BucketExistWithLogging (ctx , l , cfg .Bucket ); err != nil || exists {
113117 return err
@@ -252,9 +256,13 @@ func (client *Client) UpdateS3BucketIfNecessary(ctx context.Context, l log.Logge
252256
253257// configureAccessLogBucket - configure access log bucket.
254258func (client * Client ) configureAccessLogBucket (ctx context.Context , l log.Logger , opts * options.TerragruntOptions ) error {
255- cfg := & client .RemoteStateConfigS3
259+ if client .ExtendedRemoteStateConfigS3 == nil {
260+ return errors .Errorf ("client configuration is nil - cannot configure access log bucket" )
261+ }
256262
257- l .Debugf ("Enabling bucket-wide Access Logging on AWS S3 bucket %s - using as TargetBucket %s" , client .RemoteStateConfigS3 .Bucket , client .AccessLoggingBucketName )
263+ cfg := & client .ExtendedRemoteStateConfigS3 .RemoteStateConfigS3
264+
265+ l .Debugf ("Enabling bucket-wide Access Logging on AWS S3 bucket %s - using as TargetBucket %s" , cfg .Bucket , client .AccessLoggingBucketName )
258266
259267 if err := client .CreateLogsS3BucketIfNecessary (ctx , l , client .AccessLoggingBucketName , opts ); err != nil {
260268 l .Errorf ("Could not create logs bucket %s for AWS S3 bucket %s\n %s" , client .AccessLoggingBucketName , cfg .Bucket , err .Error ())
@@ -435,7 +443,11 @@ func (client *Client) CheckIfVersioningEnabled(ctx context.Context, l log.Logger
435443
436444// CreateS3BucketWithVersioningSSEncryptionAndAccessLogging creates the given S3 bucket and enable versioning for it.
437445func (client * Client ) CreateS3BucketWithVersioningSSEncryptionAndAccessLogging (ctx context.Context , l log.Logger , opts * options.TerragruntOptions ) error {
438- cfg := & client .RemoteStateConfigS3
446+ if client .ExtendedRemoteStateConfigS3 == nil {
447+ return errors .Errorf ("client configuration is nil - cannot create S3 bucket" )
448+ }
449+
450+ cfg := & client .ExtendedRemoteStateConfigS3 .RemoteStateConfigS3
439451
440452 l .Debugf ("Create S3 bucket %s with versioning, SSE encryption, and access logging." , cfg .Bucket )
441453
@@ -565,7 +577,11 @@ func (client *Client) TagS3BucketAccessLogging(ctx context.Context, l log.Logger
565577
566578// TagS3Bucket tags the S3 bucket with the tags specified in the config.
567579func (client * Client ) TagS3Bucket (ctx context.Context , l log.Logger ) error {
568- cfg := & client .RemoteStateConfigS3
580+ if client .ExtendedRemoteStateConfigS3 == nil {
581+ return errors .Errorf ("client configuration is nil - cannot tag S3 bucket" )
582+ }
583+
584+ cfg := & client .ExtendedRemoteStateConfigS3 .RemoteStateConfigS3
569585
570586 if len (client .S3BucketTags ) == 0 {
571587 l .Debugf ("No tags to apply to S3 bucket %s" , cfg .Bucket )
@@ -612,7 +628,11 @@ func convertTags(tags map[string]string) []types.Tag {
612628// AWS is eventually consistent, so after creating an S3 bucket, this method can be used to wait until the information
613629// about that S3 bucket has propagated everywhere.
614630func (client * Client ) WaitUntilS3BucketExists (ctx context.Context , l log.Logger ) error {
615- cfg := & client .RemoteStateConfigS3
631+ if client .ExtendedRemoteStateConfigS3 == nil {
632+ return errors .Errorf ("client configuration is nil - cannot wait for S3 bucket" )
633+ }
634+
635+ cfg := & client .ExtendedRemoteStateConfigS3 .RemoteStateConfigS3
616636
617637 l .Debugf ("Waiting for bucket %s to be created" , cfg .Bucket )
618638
@@ -634,6 +654,10 @@ func (client *Client) WaitUntilS3BucketExists(ctx context.Context, l log.Logger)
634654
635655// CreateS3Bucket creates the S3 bucket specified in the given config.
636656func (client * Client ) CreateS3Bucket (ctx context.Context , l log.Logger , bucket string ) error {
657+ if client .s3Client == nil {
658+ return errors .Errorf ("S3 client is nil - cannot create S3 bucket %s" , bucket )
659+ }
660+
637661 l .Debugf ("Creating S3 bucket %s" , bucket )
638662
639663 input := & s3.CreateBucketInput {
@@ -684,18 +708,42 @@ func isBucketErrorRetriable(err error) bool {
684708
685709// EnableRootAccesstoS3Bucket adds a policy to allow root access to the bucket.
686710func (client * Client ) EnableRootAccesstoS3Bucket (ctx context.Context , l log.Logger ) error {
687- bucket := client .RemoteStateConfigS3 .Bucket
711+ if client .ExtendedRemoteStateConfigS3 == nil {
712+ return errors .Errorf ("client configuration is nil - cannot enable root access to S3 bucket" )
713+ }
714+
715+ if client .s3Client == nil {
716+ return errors .Errorf ("S3 client is nil - cannot enable root access to S3 bucket" )
717+ }
718+
719+ // Access bucket name safely through defensive checking
720+ config := client .ExtendedRemoteStateConfigS3
721+ bucket := config .RemoteStateConfigS3 .Bucket
722+ if bucket == "" {
723+ return errors .Errorf ("S3 bucket name is empty - cannot enable root access to S3 bucket" )
724+ }
725+
688726 l .Debugf ("Enabling root access to S3 bucket %s" , bucket )
689727
728+ if client .awsConfig .Region == "" {
729+ return errors .Errorf ("AWS config region is empty - cannot enable root access to S3 bucket %s" , bucket )
730+ }
731+
690732 accountID , err := awshelper .GetAWSAccountID (ctx , client .awsConfig )
691733 if err != nil {
692734 return errors .Errorf ("error getting AWS account ID %s for bucket %s: %w" , accountID , bucket , err )
693735 }
736+ if accountID == "" {
737+ return errors .Errorf ("AWS account ID is empty - cannot enable root access to S3 bucket %s" , bucket )
738+ }
694739
695740 partition , err := awshelper .GetAWSPartition (ctx , client .awsConfig )
696741 if err != nil {
697742 return errors .Errorf ("error getting AWS partition %s for bucket %s: %w" , partition , bucket , err )
698743 }
744+ if partition == "" {
745+ return errors .Errorf ("AWS partition is empty - cannot enable root access to S3 bucket %s" , bucket )
746+ }
699747
700748 var policyInBucket awshelper.Policy
701749
@@ -708,7 +756,7 @@ func (client *Client) EnableRootAccesstoS3Bucket(ctx context.Context, l log.Logg
708756 l .Debugf ("Policy not exists for bucket %s" , bucket )
709757 }
710758
711- if policyOutput .Policy != nil {
759+ if policyOutput != nil && policyOutput .Policy != nil {
712760 l .Debugf ("Policy already exists for bucket %s" , bucket )
713761
714762 policyInBucket , err = awshelper .UnmarshalPolicy (* policyOutput .Policy )
@@ -717,10 +765,13 @@ func (client *Client) EnableRootAccesstoS3Bucket(ctx context.Context, l log.Logg
717765 }
718766 }
719767
720- for _ , statement := range policyInBucket .Statement {
721- if statement .Sid == SidRootPolicy {
722- l .Debugf ("Policy for RootAccess already exists for bucket %s" , bucket )
723- return nil
768+ // Safely iterate over statements only if they exist
769+ if policyInBucket .Statement != nil {
770+ for _ , statement := range policyInBucket .Statement {
771+ if statement .Sid == SidRootPolicy {
772+ l .Debugf ("Policy for RootAccess already exists for bucket %s" , bucket )
773+ return nil
774+ }
724775 }
725776 }
726777
@@ -854,6 +905,10 @@ func (client *Client) EnablePublicAccessBlockingForS3Bucket(ctx context.Context,
854905}
855906
856907func (client * Client ) EnableAccessLoggingForS3BucketWide (ctx context.Context , l log.Logger ) error {
908+ if client .ExtendedRemoteStateConfigS3 == nil {
909+ return errors .Errorf ("client configuration is nil - cannot enable access logging for S3 bucket" )
910+ }
911+
857912 cfg := client .ExtendedRemoteStateConfigS3
858913 bucket := cfg .RemoteStateConfigS3 .Bucket
859914 logsBucket := cfg .AccessLoggingBucketName
@@ -1091,7 +1146,7 @@ func (client *Client) DeleteS3BucketObjects(ctx context.Context, l log.Logger, b
10911146// DeleteS3Bucket deletes the S3 bucket specified in the given config.
10921147func (client * Client ) DeleteS3Bucket (ctx context.Context , l log.Logger , bucketName string ) error {
10931148 var (
1094- cfg = & client .RemoteStateConfigS3
1149+ cfg = & client .ExtendedRemoteStateConfigS3 . RemoteStateConfigS3
10951150 key = cfg .Key
10961151 bucketInput = & s3.DeleteBucketInput {Bucket : aws .String (bucketName )}
10971152 )
@@ -1183,6 +1238,12 @@ func (client *Client) DoesS3ObjectExist(ctx context.Context, bucketName, key str
11831238}
11841239
11851240func (client * Client ) DoesS3ObjectExistWithLogging (ctx context.Context , l log.Logger , bucketName , key string ) (bool , error ) {
1241+ if client .s3Client == nil {
1242+ return false , errors .Errorf ("S3 client is nil - cannot check if S3 bucket %s exists" , bucketName )
1243+ }
1244+
1245+ l .Debugf ("Checking if bucket %s exists" , bucketName )
1246+
11861247 if exists , err := client .DoesS3ObjectExist (ctx , bucketName , key ); err != nil || exists {
11871248 return exists , err
11881249 }
@@ -1711,6 +1772,12 @@ func (client *Client) DoesS3BucketExist(ctx context.Context, bucketName string)
17111772
17121773// DoesS3BucketExistWithLogging checks if the S3 bucket exists and logs if not.
17131774func (client * Client ) DoesS3BucketExistWithLogging (ctx context.Context , l log.Logger , bucketName string ) (bool , error ) {
1775+ if client .s3Client == nil {
1776+ return false , errors .Errorf ("S3 client is nil - cannot check if S3 bucket %s exists" , bucketName )
1777+ }
1778+
1779+ l .Debugf ("Checking if bucket %s exists" , bucketName )
1780+
17141781 exists , err := client .DoesS3BucketExist (ctx , bucketName )
17151782 if err != nil || ! exists {
17161783 l .Debugf ("Remote state S3 bucket %s does not exist or you don't have permissions to access it." , bucketName )
0 commit comments