Repository: gruntwork-io/terragrunt (language: go)

Issue:
Replacing a terraform source https://... with file:///...
## Describe the bug

From 0.55.19+ Terragrunt replaces https:// with file:/// when the URL host is unknown (not GitHub, GitLab, ...) to `getter.Detector`.

## Steps To Reproduce

Steps to reproduce the behavior, code snippets and examples which can be used to reproduce the issue.

```hcl
terraform {
  source = "https://self-hosting.net/path/to/repo"
}
```
## Versions

- Terragrunt version: v0.55.19+




Discussion / hints:

Fix patch:
diff --git a/terraform/source.go b/terraform/source.go
index 41cdab368c..0e495886e8 100644
--- a/terraform/source.go
+++ b/terraform/source.go
@@ -191,8 +191,10 @@ func NewSource(source string, downloadDir string, workingDir string, logger *log
 // Convert the given source into a URL struct. This method should be able to handle all source URLs that the terraform
 // init command can handle, parsing local file paths, Git paths, and HTTP URLs correctly.
 func ToSourceUrl(source string, workingDir string) (*url.URL, error) {
-	// we need to remove the http(s) scheme to allow `getter.Detect` to add the source type
-	source = httpSchemeRegexp.ReplaceAllString(source, "")
+	source, err := normalizeSourceURL(source, workingDir)
+	if err != nil {
+		return nil, err
+	}
 
 	// The go-getter library is what Terraform's init command uses to download source URLs. Use that library to
 	// parse the URL.
@@ -204,6 +206,32 @@ func ToSourceUrl(source string, workingDir string) (*url.URL, error) {
 	return parseSourceUrl(rawSourceUrlWithGetter)
 }
 
+// We have to remove the http(s) scheme from the source URL to allow `getter.Detect` to add the source type, but only if the `getter` has a detector for that host.
+func normalizeSourceURL(source string, workingDir string) (string, error) {
+	newSource := httpSchemeRegexp.ReplaceAllString(source, "")
+
+	// We can't use `the getter.Detectors` global variable because we need to exclude `getter.FileDetector` from checking since it is not a URL detector.
+	detectors := []getter.Detector{
+		new(getter.GitHubDetector),
+		new(getter.GitLabDetector),
+		new(getter.GitDetector),
+		new(getter.BitBucketDetector),
+		new(getter.S3Detector),
+		new(getter.GCSDetector),
+	}
+
+	for _, detector := range detectors {
+		_, ok, err := detector.Detect(newSource, workingDir)
+		if err != nil {
+			return source, errors.WithStackTrace(err)
+		}
+		if ok {
+			return newSource, nil
+		}
+	}
+	return source, nil
+}
+
 // Parse the given source URL into a URL struct. This method can handle source URLs that include go-getter's "forced
 // getter" prefixes, such as git::.
 func parseSourceUrl(source string) (*url.URL, error) {


Test patch:
diff --git a/terraform/source_test.go b/terraform/source_test.go
index 663e3283a2..809472d0b3 100644
--- a/terraform/source_test.go
+++ b/terraform/source_test.go
@@ -3,6 +3,7 @@ package terraform
 import (
 	"fmt"
 	"net/url"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -78,6 +79,7 @@ func TestToSourceUrl(t *testing.T) {
 		{"https://www.googleapis.com/storage/v1/modules/foomodule.zip", "gcs::https://www.googleapis.com/storage/v1/modules/foomodule.zip"},
 		{"https://www.googleapis.com/storage/v1/modules/foomodule.zip", "gcs::https://www.googleapis.com/storage/v1/modules/foomodule.zip"},
 		{"git::https://name@dev.azure.com/name/project-name/_git/repo-name", "git::https://name@dev.azure.com/name/project-name/_git/repo-name"},
+		{"https://repositry.rnd.net/artifactory/generic-production-iac/tf-auto-azr-iam.2.6.0.zip", "https://repositry.rnd.net/artifactory/generic-production-iac/tf-auto-azr-iam.2.6.0.zip"},
 	}
 
 	for i, testCase := range testCases {
@@ -86,7 +88,7 @@ func TestToSourceUrl(t *testing.T) {
 		t.Run(fmt.Sprintf("testCase-%d", i), func(t *testing.T) {
 			t.Parallel()
 
-			actualSourceURL, err := ToSourceUrl(testCase.sourceURL, "")
+			actualSourceURL, err := ToSourceUrl(testCase.sourceURL, os.TempDir())
 			require.NoError(t, err)
 			assert.Equal(t, testCase.expectedSourceURL, actualSourceURL.String())
 		})