Repository: cycloidio/terracost
Pull request #134 (2025-04-01 10:39:31)

aws: fix assigning default region
Fixed unchecked conversion to string of a potentially nil value.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a990e20..200c313 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@
   ([Issue #126](https://github.com/cycloidio/terracost/issue/126))
 - Now Dynamic are converted correctly to specific type to be used
   ([Issue #126](https://github.com/cycloidio/terracost/issue/133))
+- Fixed the unchecked conversion of a potentially nil region value in the AWS Terraform provider
+  ([Pull #134](https://github.com/cycloidio/terracost/pull/134))
 
 ### Added
 
diff --git a/aws/terraform_provider.go b/aws/terraform_provider.go
index aa5795a..33fc8f3 100644
--- a/aws/terraform_provider.go
+++ b/aws/terraform_provider.go
@@ -1,8 +1,11 @@
 package aws
 
 import (
+	"fmt"
+
 	"github.com/cycloidio/terracost/aws/region"
 	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/log"
 	"github.com/cycloidio/terracost/terraform"
 )
 
@@ -11,21 +14,35 @@ const (
 	RegistryName = "registry.terraform.io/hashicorp/aws"
 
 	// DefaultRegion is the region used by default when none is defined on the provider
-	DefaultRegion = "us-east-1"
+	DefaultRegion = region.Code("us-east-1")
 )
 
 // TerraformProviderInitializer is a terraform.ProviderInitializer that initializes the default AWS provider.
 var TerraformProviderInitializer = terraform.ProviderInitializer{
 	MatchNames: []string{ProviderName, RegistryName},
 	Provider: func(values map[string]interface{}) (terraform.Provider, error) {
+		var regCode region.Code
+
 		r, ok := values["region"]
-		// If no region is defined it means it was passed via ENV variables
-		// and it's not tracked on the Plan or HCL so we'll assume the
-		// region to be the DefaultRegion
 		if !ok {
-			r = DefaultRegion
+			// If no region is defined it means it was passed via ENV variables
+			// and it's not tracked on the Plan or HCL so we'll assume the
+			// region to be the DefaultRegion
+			regCode = DefaultRegion
+			log.Logger.Info(fmt.Sprintf("AWS terraform provider region not set, defaulting to %s", DefaultRegion))
+			return awstf.NewProvider(ProviderName, regCode)
+		}
+
+		switch value := r.(type) {
+		case string:
+			if regCode == "" {
+				log.Logger.Info(fmt.Sprintf("AWS terraform provider region not set, defaulting to %s", DefaultRegion))
+				return awstf.NewProvider(ProviderName, DefaultRegion)
+			}
+
+			return awstf.NewProvider(ProviderName, region.Code(value))
+		default:
+			return nil, fmt.Errorf("invalid region type (expected string): %T", r)
 		}
-		regCode := region.Code(r.(string))
-		return awstf.NewProvider(ProviderName, regCode)
 	},
 }


Test patch:
diff --git a/aws/terraform_provider_test.go b/aws/terraform_provider_test.go
new file mode 100644
index 0000000..930f47e
--- /dev/null
+++ b/aws/terraform_provider_test.go
@@ -0,0 +1,40 @@
+package aws_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/cycloidio/terracost/aws"
+)
+
+func TestTerraformProviderInitializer(t *testing.T) {
+
+	initalizer := aws.TerraformProviderInitializer
+
+	t.Run("WithoutRegion", func(t *testing.T) {
+		p, err := initalizer.Provider(map[string]interface{}{})
+		require.NoError(t, err)
+		assert.Equal(t, "aws", p.Name())
+	})
+	t.Run("WithRegion", func(t *testing.T) {
+		p, err := initalizer.Provider(map[string]interface{}{"region": "eu-west-1"})
+		require.NoError(t, err)
+		assert.Equal(t, "aws", p.Name())
+	})
+	t.Run("WithEmptyRegion", func(t *testing.T) {
+		p, err := initalizer.Provider(map[string]interface{}{"region": ""})
+		// default region assigned -> no error
+		require.NoError(t, err)
+		assert.Equal(t, "aws", p.Name())
+	})
+	t.Run("WithNilRegion", func(t *testing.T) {
+		_, err := initalizer.Provider(map[string]interface{}{"region": nil})
+		require.Error(t, err)
+	})
+	t.Run("WithInvalidRegionType", func(t *testing.T) {
+		_, err := initalizer.Provider(map[string]interface{}{"region": map[string]string{"foo": "bar"}})
+		require.Error(t, err)
+	})
+}