@@ -17,6 +17,7 @@ import (
1717
1818 "github.com/aquasecurity/trivy/internal/testutil"
1919 "github.com/aquasecurity/trivy/pkg/iac/terraform"
20+ tfcontext "github.com/aquasecurity/trivy/pkg/iac/terraform/context"
2021 "github.com/aquasecurity/trivy/pkg/log"
2122 "github.com/aquasecurity/trivy/pkg/set"
2223)
@@ -2291,6 +2292,80 @@ func TestTFVarsFileDoesNotExist(t *testing.T) {
22912292 assert .ErrorContains (t , err , "file does not exist" )
22922293}
22932294
2295+ func Test_OptionsWithEvalHook (t * testing.T ) {
2296+ fs := testutil .CreateFS (map [string ]string {
2297+ "main.tf" : `
2298+ data "your_custom_data" "this" {
2299+ default = ["foo", "foh", "fum"]
2300+ unaffected = "bar"
2301+ }
2302+
2303+ // Testing the hook affects some value, which is used in another evaluateStep
2304+ // action (expanding blocks)
2305+ data "random_thing" "that" {
2306+ dynamic "repeated" {
2307+ for_each = data.your_custom_data.this.value
2308+ content {
2309+ value = repeated.value
2310+ }
2311+ }
2312+ }
2313+
2314+ locals {
2315+ referenced = data.your_custom_data.this.value
2316+ static_ref = data.your_custom_data.this.unaffected
2317+ }
2318+ ` })
2319+
2320+ parser := New (fs , "" , OptionWithEvalHook (
2321+ // A basic example of how to have a 'default' value for a data block.
2322+ // To see a more practical example, see how 'evaluateVariable' handles
2323+ // the 'default' value of a variable.
2324+ func (ctx * tfcontext.Context , blocks terraform.Blocks , inputVars map [string ]cty.Value ) {
2325+ dataBlocks := blocks .OfType ("data" )
2326+ for _ , block := range dataBlocks {
2327+ if len (block .Labels ()) >= 1 && block .Labels ()[0 ] == "your_custom_data" {
2328+ def := block .GetAttribute ("default" )
2329+ ctx .Set (cty .ObjectVal (map [string ]cty.Value {
2330+ "value" : def .Value (),
2331+ }), "data" , "your_custom_data" , "this" )
2332+ }
2333+ }
2334+
2335+ },
2336+ ))
2337+
2338+ require .NoError (t , parser .ParseFS (t .Context (), "." ))
2339+
2340+ modules , err := parser .EvaluateAll (t .Context ())
2341+ require .NoError (t , err )
2342+ assert .Len (t , modules , 1 )
2343+
2344+ rootModule := modules [0 ]
2345+
2346+ // Check the default value of the data block
2347+ blocks := rootModule .GetDatasByType ("your_custom_data" )
2348+ assert .Len (t , blocks , 1 )
2349+ expList := cty .TupleVal ([]cty.Value {cty .StringVal ("foo" ), cty .StringVal ("foh" ), cty .StringVal ("fum" )})
2350+ assert .True (t , expList .Equals (blocks [0 ].GetAttribute ("default" ).Value ()).True (), "default value matched list" )
2351+ assert .Equal (t , "bar" , blocks [0 ].GetAttribute ("unaffected" ).Value ().AsString ())
2352+
2353+ // Check the referenced 'data.your_custom_data.this.value' exists in the eval
2354+ // context, and it is the default value of the data block.
2355+ locals := rootModule .GetBlocks ().OfType ("locals" )
2356+ assert .Len (t , locals , 1 )
2357+ assert .True (t , expList .Equals (locals [0 ].GetAttribute ("referenced" ).Value ()).True (), "referenced value matched list" )
2358+ assert .Equal (t , "bar" , locals [0 ].GetAttribute ("static_ref" ).Value ().AsString ())
2359+
2360+ // Check the dynamic block is expanded correctly
2361+ dynamicBlocks := rootModule .GetDatasByType ("random_thing" )
2362+ assert .Len (t , dynamicBlocks , 1 )
2363+ assert .Len (t , dynamicBlocks [0 ].GetBlocks ("repeated" ), 3 )
2364+ for i , repeat := range dynamicBlocks [0 ].GetBlocks ("repeated" ) {
2365+ assert .Equal (t , expList .Index (cty .NumberIntVal (int64 (i ))), repeat .GetAttribute ("value" ).Value ())
2366+ }
2367+ }
2368+
22942369func Test_OptionsWithTfVars (t * testing.T ) {
22952370 fs := testutil .CreateFS (map [string ]string {
22962371 "main.tf" : `resource "test" "this" {
0 commit comments