Thanks to visit codestin.com
Credit goes to github.com

Skip to content

test(terraform): test to demonstrate 'count' meta argument incorrectl… - #8479

Closed
Emyrk wants to merge 11 commits into
aquasecurity:mainfrom
Emyrk:stevenmasley/module_output_count
Closed

test(terraform): test to demonstrate 'count' meta argument incorrectl…#8479
Emyrk wants to merge 11 commits into
aquasecurity:mainfrom
Emyrk:stevenmasley/module_output_count

Conversation

@Emyrk

@Emyrk Emyrk commented Mar 3, 2025

Copy link
Copy Markdown
Contributor

Description

count & for_each meta argument is incorrectly handled when referencing a submodule's output. The expansion arguments only work when referencing within the same scope.

This is being caused because expandBlockCounts defaults to a count = 1 for unknown values.

ExpandingBlocks happens before submodule evaluation:
https://github.com/aquasecurity/trivy/blob/main/pkg/iac/scanners/terraform/parser/evaluator.go#L139-L142

So expanded blocks cannot reference submodule exports. This is inconsistent with terraform plan/apply which renders 0 data blocks in this unit test.

The solution presented allows expandBlocks to be called during evaluateSteps, which occurs again after submodules are expanded.

There is still an issue if the count/for_each argument is used in a module block, meaning a submodule depends on another module output. Since submodule evaluation will not happen again. See the test TestBlockCountModules. It is skipped for now.

Checklist

  • I've read the guidelines for contributing to this repository.
  • I've followed the conventions in the PR title.
  • I've added tests that prove my fix is effective or that my feature works.
  • I've updated the documentation with the relevant information (if needed).
  • I've added usage information (if the PR introduces new options)
  • I've included a "before" and "after" example to the description (if the PR is a user interface change).

@Emyrk

Emyrk commented Mar 5, 2025

Copy link
Copy Markdown
Contributor Author

@nikpivkin and @simar7, what are your thoughts on this bug? The unit test is a good example and self description. It fails on the latest main.

The test only passes because I added in e.blocks = e.expandBlocks(e.blocks), but that solution is incomplete. It was added just to demonstrate the problem.

I don't have a good solution for a more robust fix.

@nikpivkin

Copy link
Copy Markdown
Contributor

Hi @Emyrk !

Thanks. I'll look into it.

@Emyrk

Emyrk commented Mar 13, 2025

Copy link
Copy Markdown
Contributor Author

@nikpivkin any updates on your thoughts?

@Emyrk
Emyrk force-pushed the stevenmasley/module_output_count branch from 29a795b to 6b58370 Compare March 19, 2025 17:48
Comment on lines +143 to +156
// A pointer for this module is needed up front to correctly set the module parent hierarchy.
// The actual instance is created at the end, when all terraform blocks
// are evaluated.
rootModule := new(terraform.Module)

submodules := e.evaluateSubmodules(ctx, rootModule, fsMap)

e.logger.Debug("Starting post-submodules evaluation...")
e.evaluateSteps()

e.logger.Debug("Module evaluation complete.")
// terraform.NewModule must be called at the end, as `e.blocks` can be
// changed up until the last moment.
*rootModule = *terraform.NewModule(e.projectRootPath, e.modulePath, e.blocks, e.ignores)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels really unfortunate 😢

Comment thread pkg/iac/scanners/terraform/parser/evaluator.go Outdated

@Emyrk Emyrk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR currently only solves this for count, but the same problem exists for other expansion block types. If this solution is satisfactory, I can write some tests for the other meta arguments.

Updated to solve for_each as well

Comment on lines +263 to +265
// Always attempt to expand any blocks that might now be expandable
// due to new context being set.
e.blocks = e.expandBlocks(e.blocks)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the biggest change. It allows expandBlocks to occur in evaluateSteps.

From my understanding of expandBlocks this should be a safe operation. Is there a reason it is currently called outside this context? @nikpivkin ?

@Emyrk
Emyrk marked this pull request as ready for review March 19, 2025 18:04
@Emyrk
Emyrk requested review from nikpivkin and simar7 as code owners March 19, 2025 18:04
Comment thread pkg/iac/scanners/terraform/parser/parser_test.go
@Emyrk Emyrk mentioned this pull request Apr 8, 2025
Emyrk added 6 commits April 9, 2025 10:00
Do not expand unknown `count` blocks. Run `expandBlocks` in eval to
allow submodule returns to affect the `count` when using module
outputs.
The depth of submodule evalutation is still limited
Module counts are incorrectly being handled
@Emyrk
Emyrk force-pushed the stevenmasley/module_output_count branch from 80e01d1 to 6eb6063 Compare April 9, 2025 15:07
This was referenced Apr 9, 2025
Comment on lines +1970 to +1998
func TestBlockCountModules(t *testing.T) {
t.Skip(
"This test is currently failing. " +
"The count passed to `module bar` is not being set correctly. " +
"The count value is sourced from the output of `module foo`. " +
"Submodules cannot be dependent on the output of other submodules right now. ",
)
// `count` meta attributes are incorrectly handled when referencing
// a module output.
files := map[string]string{
"main.tf": `
module "foo" {
source = "./modules/foo"
}
module "bar" {
source = "./modules/foo"
count = module.foo.staticZero
}
`,
"modules/foo/main.tf": `
output "staticZero" {
value = 0
}
`,
}

modules := parse(t, files)
require.Len(t, modules, 2)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does evaluating sub-modules also need to occur in the inner loop? Defering them if their count/for_each is unknown?

@Emyrk

Emyrk commented May 2, 2025

Copy link
Copy Markdown
Contributor Author

@nikpivkin I updated this PR against the latest main. It solves an issue using module outputs for count & for_each arguments.

It does not solve submodules dependent on each other 😢.

@Emyrk

Emyrk commented May 7, 2025

Copy link
Copy Markdown
Contributor Author

@nikpivkin and @simar7 sorry to keep pinging you on this. Just want to make sure it does not slip through the cracks

@Emyrk Emyrk closed this May 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants