From fc9e8e4a1adeda938eaf4c28a44347142fd8d53a Mon Sep 17 00:00:00 2001 From: nikpivkin Date: Fri, 15 Nov 2024 17:22:59 +0600 Subject: [PATCH 1/3] fix(misconf): load full Terraform module Signed-off-by: nikpivkin --- .../resolvers/cache_integration_test.go | 24 ++++++++++++++++--- .../terraform/parser/resolvers/registry.go | 2 +- .../resolvers/registry_integration_test.go | 16 ++++++++----- .../terraform/parser/resolvers/remote.go | 10 +++++--- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go index 43ad7f06b15b..6419d867ebaa 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go @@ -1,14 +1,17 @@ package resolvers_test import ( + "bufio" "context" "io/fs" + "path" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser/resolvers" + "github.com/aquasecurity/trivy/pkg/log" ) type moduleResolver interface { @@ -25,6 +28,7 @@ func TestResolveModuleFromCache(t *testing.T) { opts resolvers.Options firstResolver moduleResolver expectedSubdir string + expectedString string }{ { name: "registry", @@ -35,6 +39,7 @@ func TestResolveModuleFromCache(t *testing.T) { }, firstResolver: resolvers.Registry, expectedSubdir: ".", + expectedString: "# AWS S3 bucket Terraform module", }, { name: "registry with subdir", @@ -45,6 +50,7 @@ func TestResolveModuleFromCache(t *testing.T) { }, firstResolver: resolvers.Registry, expectedSubdir: "modules/object", + expectedString: "# S3 bucket object", }, { name: "remote", @@ -54,6 +60,7 @@ func TestResolveModuleFromCache(t *testing.T) { }, firstResolver: resolvers.Remote, expectedSubdir: ".", + expectedString: "# AWS S3 bucket Terraform module", }, { name: "remote with subdir", @@ -63,6 +70,7 @@ func TestResolveModuleFromCache(t *testing.T) { }, firstResolver: resolvers.Remote, expectedSubdir: "modules/object", + expectedString: "# S3 bucket object", }, } @@ -73,17 +81,25 @@ func TestResolveModuleFromCache(t *testing.T) { tt.opts.OriginalSource = tt.opts.Source tt.opts.OriginalVersion = tt.opts.Version tt.opts.CacheDir = t.TempDir() + tt.opts.Logger = log.WithPrefix("test") - fsys, _, _, applies, err := tt.firstResolver.Resolve(context.Background(), nil, tt.opts) + fsys, _, subdir, applies, err := tt.firstResolver.Resolve(context.Background(), nil, tt.opts) require.NoError(t, err) assert.True(t, applies) + assert.Equal(t, tt.expectedSubdir, subdir) - _, err = fs.Stat(fsys, "main.tf") + f, err := fsys.Open(path.Join(tt.expectedSubdir, "README.md")) require.NoError(t, err) - _, _, _, applies, err = resolvers.Cache.Resolve(context.Background(), fsys, tt.opts) + r := bufio.NewReader(f) + line, _, err := r.ReadLine() + require.NoError(t, err) + assert.Equal(t, tt.expectedString, string(line)) + + _, _, subdir, applies, err = resolvers.Cache.Resolve(context.Background(), fsys, tt.opts) require.NoError(t, err) assert.True(t, applies) + assert.Equal(t, tt.expectedSubdir, subdir) }) } } @@ -101,6 +117,7 @@ func TestResolveModuleFromCacheWithDifferentSubdir(t *testing.T) { OriginalSource: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/object?ref=v4.1.2", AllowDownloads: true, CacheDir: cacheDir, + Logger: log.WithPrefix("test"), }) require.NoError(t, err) assert.True(t, applies) @@ -113,6 +130,7 @@ func TestResolveModuleFromCacheWithDifferentSubdir(t *testing.T) { Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/notification?ref=v4.1.2", OriginalSource: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/notification?ref=v4.1.2", CacheDir: cacheDir, + Logger: log.WithPrefix("test"), }) require.NoError(t, err) assert.True(t, applies) diff --git a/pkg/iac/scanners/terraform/parser/resolvers/registry.go b/pkg/iac/scanners/terraform/parser/resolvers/registry.go index 471416463cad..00084f2eaf0c 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/registry.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/registry.go @@ -46,7 +46,7 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option } inputVersion := opt.Version - source, _ := splitPackageSubdirRaw(opt.Source) + source, _ := splitPackageSubdirRaw(opt.OriginalSource) parts := strings.Split(source, "/") if len(parts) < 3 || len(parts) > 4 { return diff --git a/pkg/iac/scanners/terraform/parser/resolvers/registry_integration_test.go b/pkg/iac/scanners/terraform/parser/resolvers/registry_integration_test.go index e2d87104da2d..b8be4b10e0f2 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/registry_integration_test.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/registry_integration_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser/resolvers" + "github.com/aquasecurity/trivy/pkg/log" ) func TestResolveModuleFromOpenTofuRegistry(t *testing.T) { @@ -17,12 +18,15 @@ func TestResolveModuleFromOpenTofuRegistry(t *testing.T) { } fsys, _, path, _, err := resolvers.Registry.Resolve(context.Background(), nil, resolvers.Options{ - Source: "registry.opentofu.org/terraform-aws-modules/s3-bucket/aws", - RelativePath: "test", - Name: "bucket", - Version: "4.1.2", - AllowDownloads: true, - SkipCache: true, + Source: "registry.opentofu.org/terraform-aws-modules/s3-bucket/aws", + OriginalSource: "registry.opentofu.org/terraform-aws-modules/s3-bucket/aws", + RelativePath: "test", + Name: "bucket", + Version: "4.1.2", + OriginalVersion: "4.1.2", + AllowDownloads: true, + SkipCache: true, + Logger: log.WithPrefix("test"), }) require.NoError(t, err) diff --git a/pkg/iac/scanners/terraform/parser/resolvers/remote.go b/pkg/iac/scanners/terraform/parser/resolvers/remote.go index 467f2cee6970..797264adc814 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/remote.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/remote.go @@ -40,14 +40,18 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil return nil, "", "", false, nil } - src, subdir := splitPackageSubdirRaw(opt.OriginalSource) + src, subdir := splitPackageSubdirRaw(opt.Source) key := cacheKey(src, opt.OriginalVersion) opt.Logger.Debug("Caching module", log.String("key", key)) + opt.OriginalSource = opt.Source + opt.Source = src + baseCacheDir, err := locateCacheDir(opt.CacheDir) if err != nil { return nil, "", "", true, fmt.Errorf("failed to locate cache directory: %w", err) } + cacheDir := filepath.Join(baseCacheDir, key) if err := r.download(ctx, opt, cacheDir); err != nil { return nil, "", "", true, err @@ -56,9 +60,9 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil r.incrementCount(opt) opt.Logger.Debug("Successfully resolve module via remote download", log.String("name", opt.Name), - log.String("source", opt.Source), + log.String("source", opt.OriginalSource), ) - return os.DirFS(cacheDir), opt.Source, subdir, true, nil + return os.DirFS(cacheDir), opt.OriginalSource, subdir, true, nil } func (r *remoteResolver) download(ctx context.Context, opt Options, dst string) error { From d28d1186f431a9818d05cc7f7c031fd8254777af Mon Sep 17 00:00:00 2001 From: nikpivkin Date: Fri, 15 Nov 2024 19:07:22 +0600 Subject: [PATCH 2/3] test: mock remote modules Signed-off-by: nikpivkin --- .../resolvers/cache_integration_test.go | 147 +++++++++--------- .../terraform-aws-s3-bucket/README.md | 1 + .../modules/notification/README.md | 1 + .../modules/object/README.md | 1 + 4 files changed, 76 insertions(+), 74 deletions(-) create mode 100644 pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/README.md create mode 100644 pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/notification/README.md create mode 100644 pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/object/README.md diff --git a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go index 6419d867ebaa..1323242d3284 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go @@ -1,7 +1,8 @@ +//go:build unix + package resolvers_test import ( - "bufio" "context" "io/fs" "path" @@ -10,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/internal/gittest" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser/resolvers" "github.com/aquasecurity/trivy/pkg/log" ) @@ -18,10 +20,25 @@ type moduleResolver interface { Resolve(context.Context, fs.FS, resolvers.Options) (fs.FS, string, string, bool, error) } -func TestResolveModuleFromCache(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test in short mode") +func testOptions(t *testing.T, source string) resolvers.Options { + return resolvers.Options{ + Source: source, + OriginalSource: source, + Version: "", + OriginalVersion: "", + AllowDownloads: true, + CacheDir: t.TempDir(), + Logger: log.WithPrefix("test"), } +} + +func TestResolveModuleFromCache(t *testing.T) { + + repo := "terraform-aws-s3-bucket" + gs := gittest.NewServer(t, repo, "testdata/terraform-aws-s3-bucket") + defer gs.Close() + + repoURL := gs.URL + "/" + repo + ".git" tests := []struct { name string @@ -30,44 +47,38 @@ func TestResolveModuleFromCache(t *testing.T) { expectedSubdir string expectedString string }{ + // { + // name: "registry", + // opts: resolvers.Options{ + // Name: "bucket", + // Source: "terraform-aws-modules/s3-bucket/aws", + // Version: "4.1.2", + // }, + // firstResolver: resolvers.Registry, + // expectedSubdir: ".", + // expectedString: "# AWS S3 bucket Terraform module", + // }, + // { + // name: "registry with subdir", + // opts: resolvers.Options{ + // Name: "object", + // Source: "terraform-aws-modules/s3-bucket/aws//modules/object", + // Version: "4.1.2", + // }, + // firstResolver: resolvers.Registry, + // expectedSubdir: "modules/object", + // expectedString: "# S3 bucket object", + // }, { - name: "registry", - opts: resolvers.Options{ - Name: "bucket", - Source: "terraform-aws-modules/s3-bucket/aws", - Version: "4.1.2", - }, - firstResolver: resolvers.Registry, - expectedSubdir: ".", - expectedString: "# AWS S3 bucket Terraform module", - }, - { - name: "registry with subdir", - opts: resolvers.Options{ - Name: "object", - Source: "terraform-aws-modules/s3-bucket/aws//modules/object", - Version: "4.1.2", - }, - firstResolver: resolvers.Registry, - expectedSubdir: "modules/object", - expectedString: "# S3 bucket object", - }, - { - name: "remote", - opts: resolvers.Options{ - Name: "bucket", - Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git?ref=v4.1.2", - }, + name: "remote", + opts: testOptions(t, "git::"+repoURL), firstResolver: resolvers.Remote, expectedSubdir: ".", expectedString: "# AWS S3 bucket Terraform module", }, { - name: "remote with subdir", - opts: resolvers.Options{ - Name: "object", - Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/object?ref=v4.1.2", - }, + name: "remote with subdir", + opts: testOptions(t, "git::"+repoURL+"//modules/object"), firstResolver: resolvers.Remote, expectedSubdir: "modules/object", expectedString: "# S3 bucket object", @@ -77,61 +88,49 @@ func TestResolveModuleFromCache(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.opts.AllowDownloads = true - tt.opts.OriginalSource = tt.opts.Source - tt.opts.OriginalVersion = tt.opts.Version - tt.opts.CacheDir = t.TempDir() - tt.opts.Logger = log.WithPrefix("test") - - fsys, _, subdir, applies, err := tt.firstResolver.Resolve(context.Background(), nil, tt.opts) + fsys, _, dir, _, err := tt.firstResolver.Resolve(context.Background(), nil, tt.opts) require.NoError(t, err) - assert.True(t, applies) - assert.Equal(t, tt.expectedSubdir, subdir) + assert.Equal(t, tt.expectedSubdir, dir) - f, err := fsys.Open(path.Join(tt.expectedSubdir, "README.md")) + b, err := fs.ReadFile(fsys, path.Join(dir, "README.md")) require.NoError(t, err) + assert.Equal(t, tt.expectedString, string(b)) - r := bufio.NewReader(f) - line, _, err := r.ReadLine() + _, _, dir, _, err = resolvers.Cache.Resolve(context.Background(), fsys, tt.opts) require.NoError(t, err) - assert.Equal(t, tt.expectedString, string(line)) + assert.Equal(t, tt.expectedSubdir, dir) - _, _, subdir, applies, err = resolvers.Cache.Resolve(context.Background(), fsys, tt.opts) + b, err = fs.ReadFile(fsys, path.Join(dir, "README.md")) require.NoError(t, err) - assert.True(t, applies) - assert.Equal(t, tt.expectedSubdir, subdir) + assert.Equal(t, tt.expectedString, string(b)) }) } } func TestResolveModuleFromCacheWithDifferentSubdir(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test in short mode") - } + repo := "terraform-aws-s3-bucket" + gs := gittest.NewServer(t, repo, "testdata/terraform-aws-s3-bucket") + defer gs.Close() - cacheDir := t.TempDir() + repoURL := gs.URL + "/" + repo + ".git" + + fsys, _, dir, _, err := resolvers.Remote.Resolve( + context.Background(), nil, + testOptions(t, "git::"+repoURL+"//modules/object"), + ) + require.NoError(t, err) - fsys, _, _, applies, err := resolvers.Remote.Resolve(context.Background(), nil, resolvers.Options{ - Name: "object", - Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/object?ref=v4.1.2", - OriginalSource: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/object?ref=v4.1.2", - AllowDownloads: true, - CacheDir: cacheDir, - Logger: log.WithPrefix("test"), - }) + b, err := fs.ReadFile(fsys, path.Join(dir, "README.md")) require.NoError(t, err) - assert.True(t, applies) + assert.Equal(t, "# S3 bucket object", string(b)) - _, err = fs.Stat(fsys, "main.tf") + fsys, _, dir, _, err = resolvers.Remote.Resolve( + context.Background(), nil, + testOptions(t, "git::"+repoURL+"//modules/notification"), + ) require.NoError(t, err) - _, _, _, applies, err = resolvers.Cache.Resolve(context.Background(), nil, resolvers.Options{ - Name: "notification", - Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/notification?ref=v4.1.2", - OriginalSource: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/notification?ref=v4.1.2", - CacheDir: cacheDir, - Logger: log.WithPrefix("test"), - }) + b, err = fs.ReadFile(fsys, path.Join(dir, "README.md")) require.NoError(t, err) - assert.True(t, applies) + assert.Equal(t, "# S3 bucket notification", string(b)) } diff --git a/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/README.md b/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/README.md new file mode 100644 index 000000000000..26e6186c9cbe --- /dev/null +++ b/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/README.md @@ -0,0 +1 @@ +# AWS S3 bucket Terraform module \ No newline at end of file diff --git a/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/notification/README.md b/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/notification/README.md new file mode 100644 index 000000000000..9f2f884a9586 --- /dev/null +++ b/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/notification/README.md @@ -0,0 +1 @@ +# S3 bucket notification \ No newline at end of file diff --git a/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/object/README.md b/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/object/README.md new file mode 100644 index 000000000000..a016e2bb23cb --- /dev/null +++ b/pkg/iac/scanners/terraform/parser/resolvers/testdata/terraform-aws-s3-bucket/modules/object/README.md @@ -0,0 +1 @@ +# S3 bucket object \ No newline at end of file From 7a960e00f0fca7e8dc7f227fb2597a8161ca3719 Mon Sep 17 00:00:00 2001 From: nikpivkin Date: Mon, 18 Nov 2024 17:59:07 +0600 Subject: [PATCH 3/3] mock registry and fix resolution of remote modules Signed-off-by: nikpivkin --- .../resolvers/cache_integration_test.go | 88 +++++++++++++------ .../terraform/parser/resolvers/options.go | 2 + .../terraform/parser/resolvers/registry.go | 9 +- .../terraform/parser/resolvers/remote.go | 11 +-- 4 files changed, 77 insertions(+), 33 deletions(-) diff --git a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go index 1323242d3284..6bfe812519bd 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go @@ -4,8 +4,12 @@ package resolvers_test import ( "context" + "crypto/tls" "io/fs" + "net/http" + "net/http/httptest" "path" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -32,6 +36,18 @@ func testOptions(t *testing.T, source string) resolvers.Options { } } +func newRegistry(repoURL string) *httptest.Server { + mux := http.NewServeMux() + mux.HandleFunc("/v1/modules/terraform-aws-modules/s3-bucket/aws/download", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Terraform-Get", repoURL) + w.WriteHeader(http.StatusNoContent) + }) + + return httptest.NewTLSServer(mux) +} + +func buildGitSource(repoURL string) string { return "git::" + repoURL } + func TestResolveModuleFromCache(t *testing.T) { repo := "terraform-aws-s3-bucket" @@ -40,6 +56,11 @@ func TestResolveModuleFromCache(t *testing.T) { repoURL := gs.URL + "/" + repo + ".git" + registry := newRegistry(buildGitSource(repoURL)) + defer registry.Close() + + registryAddress := strings.TrimPrefix(registry.URL, "https://") + tests := []struct { name string opts resolvers.Options @@ -47,38 +68,48 @@ func TestResolveModuleFromCache(t *testing.T) { expectedSubdir string expectedString string }{ - // { - // name: "registry", - // opts: resolvers.Options{ - // Name: "bucket", - // Source: "terraform-aws-modules/s3-bucket/aws", - // Version: "4.1.2", - // }, - // firstResolver: resolvers.Registry, - // expectedSubdir: ".", - // expectedString: "# AWS S3 bucket Terraform module", - // }, - // { - // name: "registry with subdir", - // opts: resolvers.Options{ - // Name: "object", - // Source: "terraform-aws-modules/s3-bucket/aws//modules/object", - // Version: "4.1.2", - // }, - // firstResolver: resolvers.Registry, - // expectedSubdir: "modules/object", - // expectedString: "# S3 bucket object", - // }, { - name: "remote", - opts: testOptions(t, "git::"+repoURL), + name: "registry", + opts: resolvers.Options{ + Source: registryAddress + "/terraform-aws-modules/s3-bucket/aws", + Client: &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + }, + }, + firstResolver: resolvers.Registry, + expectedSubdir: ".", + expectedString: "# AWS S3 bucket Terraform module", + }, + { + name: "registry with subdir", + opts: resolvers.Options{ + Source: registryAddress + "/terraform-aws-modules/s3-bucket/aws//modules/object", + Client: &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + }, + }, + firstResolver: resolvers.Registry, + expectedSubdir: "modules/object", + expectedString: "# S3 bucket object", + }, + { + name: "remote", + opts: resolvers.Options{ + Source: buildGitSource(repoURL), + }, firstResolver: resolvers.Remote, expectedSubdir: ".", expectedString: "# AWS S3 bucket Terraform module", }, { - name: "remote with subdir", - opts: testOptions(t, "git::"+repoURL+"//modules/object"), + name: "remote with subdir", + opts: resolvers.Options{ + Source: buildGitSource(repoURL) + "//modules/object", + }, firstResolver: resolvers.Remote, expectedSubdir: "modules/object", expectedString: "# S3 bucket object", @@ -88,6 +119,11 @@ func TestResolveModuleFromCache(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + tt.opts.OriginalSource = tt.opts.Source + tt.opts.AllowDownloads = true + tt.opts.CacheDir = t.TempDir() + tt.opts.Logger = log.WithPrefix("test") + fsys, _, dir, _, err := tt.firstResolver.Resolve(context.Background(), nil, tt.opts) require.NoError(t, err) assert.Equal(t, tt.expectedSubdir, dir) diff --git a/pkg/iac/scanners/terraform/parser/resolvers/options.go b/pkg/iac/scanners/terraform/parser/resolvers/options.go index 73fd39689e84..937f89709dc3 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/options.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/options.go @@ -1,6 +1,7 @@ package resolvers import ( + "net/http" "strings" "github.com/aquasecurity/trivy/pkg/log" @@ -13,6 +14,7 @@ type Options struct { SkipCache bool RelativePath string CacheDir string + Client *http.Client } func (o *Options) hasPrefix(prefixes ...string) bool { diff --git a/pkg/iac/scanners/terraform/parser/resolvers/registry.go b/pkg/iac/scanners/terraform/parser/resolvers/registry.go index 00084f2eaf0c..1af19f753209 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/registry.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/registry.go @@ -41,6 +41,11 @@ const registryHostname = "registry.terraform.io" // nolint func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Options) (filesystem fs.FS, prefix string, downloadPath string, applies bool, err error) { + client := r.client + if opt.Client != nil { + client = opt.Client + } + if !opt.AllowDownloads { return } @@ -81,7 +86,7 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option if token != "" { req.Header.Set("Authorization", "Bearer "+token) } - resp, err := r.client.Do(req) + resp, err := client.Do(req) if err != nil { return nil, "", "", true, err } @@ -122,7 +127,7 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option req.Header.Set("X-Terraform-Version", opt.Version) } - resp, err := r.client.Do(req) + resp, err := client.Do(req) if err != nil { return nil, "", "", true, err } diff --git a/pkg/iac/scanners/terraform/parser/resolvers/remote.go b/pkg/iac/scanners/terraform/parser/resolvers/remote.go index 797264adc814..d70edde8c3b7 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/remote.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/remote.go @@ -40,19 +40,20 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil return nil, "", "", false, nil } - src, subdir := splitPackageSubdirRaw(opt.Source) - key := cacheKey(src, opt.OriginalVersion) + origSrc, subdir := splitPackageSubdirRaw(opt.OriginalSource) + key := cacheKey(origSrc, opt.OriginalVersion) opt.Logger.Debug("Caching module", log.String("key", key)) - opt.OriginalSource = opt.Source - opt.Source = src - baseCacheDir, err := locateCacheDir(opt.CacheDir) if err != nil { return nil, "", "", true, fmt.Errorf("failed to locate cache directory: %w", err) } cacheDir := filepath.Join(baseCacheDir, key) + + src, _ := splitPackageSubdirRaw(opt.Source) + + opt.Source = src if err := r.download(ctx, opt, cacheDir); err != nil { return nil, "", "", true, err }