8000 test(terraform): test to demonstrate 'count' meta argument incorrectl… by Emyrk · Pull Request #8479 · aquasecurity/trivy · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

Emyrk
Copy link
Contributor
@Emyrk Emyrk commented Mar 3, 2025

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 inc 8000 onsistent 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
Copy link
Contributor Author
Emyrk commented Mar 5, 2025

@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
Contributor

Hi @Emyrk !

Thanks. I'll look into it.

@Emyrk
Copy link
Contributor Author
Emyrk commented Mar 13, 2025

@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
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 😢

Copy link
Contributor Author
@Emyrk Emyrk left a comment

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
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 simar7 and nikpivkin as code owners March 19, 2025 18:04
@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
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
Copy link
Contributor Author
Emyrk commented May 2, 2025

@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
Copy link
Contributor Author
Emyrk commented May 7, 2025

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

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
0