mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-20 22:33:53 -08:00
fix(misconf): populate context correctly for module instances (#8656)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
@@ -137,6 +137,8 @@ func (e *evaluator) EvaluateAll(ctx context.Context) (terraform.Modules, map[str
|
||||
|
||||
// expand out resources and modules via count, for-each and dynamic
|
||||
// (not a typo, we do this twice so every order is processed)
|
||||
// TODO: using a module in for_each or count does not work,
|
||||
// because the child module is evaluated later
|
||||
e.blocks = e.expandBlocks(e.blocks)
|
||||
e.blocks = e.expandBlocks(e.blocks)
|
||||
|
||||
@@ -239,10 +241,17 @@ func (e *evaluator) evaluateSubmodule(ctx context.Context, sm *submodule) bool {
|
||||
sm.modules, sm.fsMap = sm.eval.EvaluateAll(ctx)
|
||||
outputs := sm.eval.exportOutputs()
|
||||
|
||||
valueMap := e.ctx.Get("module").AsValueMap()
|
||||
if valueMap == nil {
|
||||
valueMap = make(map[string]cty.Value)
|
||||
}
|
||||
|
||||
// lastState needs to be captured after applying outputs – so that they
|
||||
// don't get treated as changes – but before running post-submodule
|
||||
// evaluation, so that changes from that can trigger re-evaluations of
|
||||
// the submodule if/when they feed back into inputs.
|
||||
ref := sm.definition.Definition.Reference()
|
||||
e.ctx.Set(blockInstanceValues(sm.definition.Definition, valueMap, outputs), "module", ref.NameLabel())
|
||||
e.ctx.Set(outputs, "module", sm.definition.Name)
|
||||
sm.lastState = sm.definition.inputVars()
|
||||
e.evaluateSteps()
|
||||
@@ -564,7 +573,7 @@ func (e *evaluator) getValuesByBlockType(blockType string) cty.Value {
|
||||
if valueMap == nil {
|
||||
valueMap = make(map[string]cty.Value)
|
||||
}
|
||||
valueMap[ref.NameLabel()] = blockInstanceValues(b, valueMap)
|
||||
valueMap[ref.NameLabel()] = blockInstanceValues(b, valueMap, b.Values())
|
||||
|
||||
// Update the map of all blocks with the same type.
|
||||
values[ref.TypeLabel()] = cty.ObjectVal(valueMap)
|
||||
@@ -588,7 +597,7 @@ func (e *evaluator) getResources() map[string]cty.Value {
|
||||
typeValues = make(map[string]cty.Value)
|
||||
values[ref.TypeLabel()] = typeValues
|
||||
}
|
||||
typeValues[ref.NameLabel()] = blockInstanceValues(b, typeValues)
|
||||
typeValues[ref.NameLabel()] = blockInstanceValues(b, typeValues, b.Values())
|
||||
}
|
||||
|
||||
return lo.MapValues(values, func(v map[string]cty.Value, _ string) cty.Value {
|
||||
@@ -600,14 +609,14 @@ func (e *evaluator) getResources() map[string]cty.Value {
|
||||
// If the count argument is used, a tuple is returned where the index corresponds to the argument index.
|
||||
// If the for_each argument is used, an object is returned where the key corresponds to the argument key.
|
||||
// In other cases, the values of the block itself are returned.
|
||||
func blockInstanceValues(b *terraform.Block, typeValues map[string]cty.Value) cty.Value {
|
||||
func blockInstanceValues(b *terraform.Block, typeValues map[string]cty.Value, values cty.Value) cty.Value {
|
||||
ref := b.Reference()
|
||||
key := ref.RawKey()
|
||||
|
||||
switch {
|
||||
case key.Type().Equals(cty.Number) && b.GetAttribute("count") != nil:
|
||||
idx, _ := key.AsBigFloat().Int64()
|
||||
return insertTupleElement(typeValues[ref.NameLabel()], int(idx), b.Values())
|
||||
return insertTupleElement(typeValues[ref.NameLabel()], int(idx), values)
|
||||
case isForEachKey(key) && b.GetAttribute("for_each") != nil:
|
||||
keyStr := ref.Key()
|
||||
|
||||
@@ -621,11 +630,10 @@ func blockInstanceValues(b *terraform.Block, typeValues map[string]cty.Value) ct
|
||||
instances = make(map[string]cty.Value)
|
||||
}
|
||||
|
||||
instances[keyStr] = b.Values()
|
||||
instances[keyStr] = values
|
||||
return cty.ObjectVal(instances)
|
||||
|
||||
default:
|
||||
return b.Values()
|
||||
return values
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1708,10 +1708,12 @@ func TestPopulateContextWithBlockInstances(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blockType string
|
||||
files map[string]string
|
||||
}{
|
||||
{
|
||||
name: "data blocks with count",
|
||||
blockType: "data",
|
||||
files: map[string]string{
|
||||
"main.tf": `data "d" "foo" {
|
||||
count = 1
|
||||
@@ -1731,6 +1733,7 @@ data "c" "foo" {
|
||||
},
|
||||
{
|
||||
name: "resource blocks with count",
|
||||
blockType: "resource",
|
||||
files: map[string]string{
|
||||
"main.tf": `resource "d" "foo" {
|
||||
count = 1
|
||||
@@ -1745,11 +1748,37 @@ resource "b" "foo" {
|
||||
resource "c" "foo" {
|
||||
count = 1
|
||||
value = b.foo[0].value
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "module block with count",
|
||||
blockType: "data",
|
||||
files: map[string]string{
|
||||
"main.tf": `module "a" {
|
||||
source = "./modules/a"
|
||||
count = 2
|
||||
inp = "Index ${count.index}"
|
||||
}
|
||||
|
||||
data "b" "foo" {
|
||||
count = 1
|
||||
value = module.a[0].value
|
||||
}
|
||||
|
||||
data "c" "foo" {
|
||||
count = 1
|
||||
value = data.b.foo[0].value
|
||||
}`,
|
||||
"modules/a/main.tf": `variable "inp" {}
|
||||
output "value" {
|
||||
value = var.inp
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "data blocks with for_each",
|
||||
blockType: "data",
|
||||
files: map[string]string{
|
||||
"main.tf": `data "d" "foo" {
|
||||
for_each = toset([0])
|
||||
@@ -1769,6 +1798,7 @@ data "c" "foo" {
|
||||
},
|
||||
{
|
||||
name: "resource blocks with for_each",
|
||||
blockType: "resource",
|
||||
files: map[string]string{
|
||||
"main.tf": `resource "d" "foo" {
|
||||
for_each = toset([0])
|
||||
@@ -1783,6 +1813,25 @@ resource "b" "foo" {
|
||||
resource "c" "foo" {
|
||||
for_each = b.foo
|
||||
value = each.value.value
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "module block with for_each",
|
||||
blockType: "data",
|
||||
files: map[string]string{
|
||||
"main.tf": `module "a" {
|
||||
for_each = toset([0])
|
||||
source = "./modules/a"
|
||||
inp = "Index ${each.key}"
|
||||
}
|
||||
|
||||
data "b" "foo" {
|
||||
value = module.a["0"].value
|
||||
}`,
|
||||
"modules/a/main.tf": `variable "inp" {}
|
||||
output "value" {
|
||||
value = var.inp
|
||||
}`,
|
||||
},
|
||||
},
|
||||
@@ -1791,8 +1840,8 @@ resource "c" "foo" {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
modules := parse(t, tt.files)
|
||||
require.Len(t, modules, 1)
|
||||
for _, b := range modules.GetBlocks() {
|
||||
require.GreaterOrEqual(t, len(modules), 1)
|
||||
for _, b := range modules.GetBlocks().OfType(tt.blockType) {
|
||||
attr := b.GetAttribute("value")
|
||||
assert.Equal(t, "Index 0", attr.Value().AsString())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user