Skip to content

Commit 398620b

Browse files
authored
fix(terraform): apply parser options to submodule parsing (#8377)
1 parent 02ebb4c commit 398620b

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

pkg/iac/scanners/terraform/parser/parser.go

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ func (p *Parser) newModuleParser(moduleFS fs.FS, moduleSource, modulePath, modul
8383
mp.logger = log.WithPrefix("terraform parser").With("module", moduleName)
8484
mp.projectRoot = p.projectRoot
8585
mp.skipPaths = p.skipPaths
86+
mp.options = p.options
8687
p.children = append(p.children, mp)
8788
for _, option := range p.options {
8889
option(mp)

pkg/iac/scanners/terraform/parser/parser_test.go

+71-2
Original file line numberDiff line numberDiff line change
@@ -1648,9 +1648,10 @@ func TestNestedDynamicBlock(t *testing.T) {
16481648
assert.Len(t, nested, 4)
16491649
}
16501650

1651-
func parse(t *testing.T, files map[string]string) terraform.Modules {
1651+
func parse(t *testing.T, files map[string]string, opts ...Option) terraform.Modules {
16521652
fs := testutil.CreateFS(t, files)
1653-
parser := New(fs, "", OptionStopOnHCLError(true))
1653+
opts = append(opts, OptionStopOnHCLError(true))
1654+
parser := New(fs, "", opts...)
16541655
require.NoError(t, parser.ParseFS(context.TODO(), "."))
16551656

16561657
modules, _, err := parser.EvaluateAll(context.TODO())
@@ -1702,6 +1703,74 @@ resource "test_resource" "this" {
17021703
assert.Equal(t, "test_value", attr.GetRawValue())
17031704
}
17041705

1706+
// TestNestedModulesOptions ensures parser options are carried to the nested
1707+
// submodule evaluators.
1708+
// The test will include an invalid module that will fail to download
1709+
// if it is attempted.
1710+
func TestNestedModulesOptions(t *testing.T) {
1711+
// reset the previous default logger
1712+
prevLog := slog.Default()
1713+
defer slog.SetDefault(prevLog)
1714+
var buf bytes.Buffer
1715+
slog.SetDefault(slog.New(log.NewHandler(&buf, nil)))
1716+
1717+
files := map[string]string{
1718+
"main.tf": `
1719+
module "city" {
1720+
source = "./modules/city"
1721+
}
1722+
1723+
resource "city" "neighborhoods" {
1724+
names = module.city.neighborhoods
1725+
}
1726+
`,
1727+
"modules/city/main.tf": `
1728+
module "brooklyn" {
1729+
source = "./brooklyn"
1730+
}
1731+
1732+
module "queens" {
1733+
source = "./queens"
1734+
}
1735+
1736+
output "neighborhoods" {
1737+
value = [module.brooklyn.name, module.queens.name]
1738+
}
1739+
`,
1740+
"modules/city/brooklyn/main.tf": `
1741+
output "name" {
1742+
value = "Brooklyn"
1743+
}
1744+
`,
1745+
"modules/city/queens/main.tf": `
1746+
output "name" {
1747+
value = "Queens"
1748+
}
1749+
1750+
module "invalid" {
1751+
source = "https://example.invaliddomain"
1752+
}
1753+
`,
1754+
}
1755+
1756+
// Using the OptionWithDownloads(false) option will prevent the invalid
1757+
// module from being downloaded. If the log exists "failed to download"
1758+
// then the submodule evaluator attempted to download, which was disallowed.
1759+
modules := parse(t, files, OptionWithDownloads(false))
1760+
require.Len(t, modules, 4)
1761+
1762+
resources := modules.GetResourcesByType("city")
1763+
require.Len(t, resources, 1)
1764+
1765+
for _, res := range resources {
1766+
attr, _ := res.GetNestedAttribute("names")
1767+
require.NotNil(t, attr, res.FullName())
1768+
assert.Equal(t, []string{"Brooklyn", "Queens"}, attr.GetRawValue())
1769+
}
1770+
1771+
require.NotContains(t, buf.String(), "failed to download")
1772+
}
1773+
17051774
func TestCyclicModules(t *testing.T) {
17061775
files := map[string]string{
17071776
"main.tf": `

0 commit comments

Comments
 (0)