@@ -16,6 +16,7 @@ import (
16
16
17
17
"github.com/aquasecurity/trivy/pkg/iac/terraform/context"
18
18
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
19
+ "github.com/aquasecurity/trivy/pkg/log"
19
20
)
20
21
21
22
type Attribute struct {
@@ -828,3 +829,108 @@ func safeOp[T any](a *Attribute, fn func(cty.Value) T) T {
828
829
829
830
return fn (val )
830
831
}
832
+
833
+ // RewriteExpr applies the given function `transform` to the expression of the attribute,
834
+ // recursively traversing and transforming it.
835
+ func (a * Attribute ) RewriteExpr (transform func (hclsyntax.Expression ) hclsyntax.Expression ) {
836
+ a .hclAttribute .Expr = RewriteExpr (a .hclAttribute .Expr .(hclsyntax.Expression ), transform )
837
+ }
838
+
839
+ // nolint: gocyclo
840
+ // RewriteExpr recursively rewrites an HCL expression tree in-place,
841
+ // applying the provided transformation function `transform` to each node.
842
+ func RewriteExpr (
843
+ expr hclsyntax.Expression ,
844
+ transform func (hclsyntax.Expression ) hclsyntax.Expression ,
845
+ ) hclsyntax.Expression {
846
+ if expr == nil {
847
+ return nil
848
+ }
849
+ switch e := expr .(type ) {
850
+ case * hclsyntax.LiteralValueExpr :
851
+ case * hclsyntax.TemplateExpr :
852
+ for i , p := range e .Parts {
853
+ e .Parts [i ] = RewriteExpr (p , transform )
854
+ }
855
+ case * hclsyntax.TemplateWrapExpr :
856
+ e .Wrapped = RewriteExpr (e .Wrapped , transform )
857
+ case * hclsyntax.BinaryOpExpr :
858
+ e .LHS = RewriteExpr (e .LHS , transform )
859
+ e .RHS = RewriteExpr (e .RHS , transform )
860
+ case * hclsyntax.UnaryOpExpr :
861
+ e .Val = RewriteExpr (e .Val , transform )
862
+ case * hclsyntax.TupleConsExpr :
863
+ for i , elem := range e .Exprs {
864
+ e .Exprs [i ] = RewriteExpr (elem , transform )
865
+ }
866
+ case * hclsyntax.ParenthesesExpr :
867
+ e .Expression = RewriteExpr (e .Expression , transform )
868
+ case * hclsyntax.ObjectConsExpr :
869
+ for i , item := range e .Items {
870
+ e .Items [i ].KeyExpr = RewriteExpr (item .KeyExpr , transform )
871
+ e .Items [i ].ValueExpr = RewriteExpr (item .ValueExpr , transform )
872
+ }
873
+ case * hclsyntax.ObjectConsKeyExpr :
874
+ e .Wrapped = RewriteExpr (e .Wrapped , transform )
875
+ case * hclsyntax.ScopeTraversalExpr :
876
+ case * hclsyntax.RelativeTraversalExpr :
877
+ e .Source = RewriteExpr (e .Source , transform )
878
+ case * hclsyntax.ConditionalExpr :
879
+ e .Condition = RewriteExpr (e .Condition , transform )
880
+ e .TrueResult = RewriteExpr (e .TrueResult , transform )
881
+ e .FalseResult = RewriteExpr (e .FalseResult , transform )
882
+ case * hclsyntax.FunctionCallExpr :
883
+ for i , arg := range e .Args {
884
+ e .Args [i ] = RewriteExpr (arg , transform )
885
+ }
886
+ case * hclsyntax.IndexExpr :
887
+ e .Collection = RewriteExpr (e .Collection , transform )
888
+ e .Key = RewriteExpr (e .Key , transform )
889
+ case * hclsyntax.ForExpr :
890
+ e .CollExpr = RewriteExpr (e .CollExpr , transform )
891
+ e .KeyExpr = RewriteExpr (e .KeyExpr , transform )
892
+ e .ValExpr = RewriteExpr (e .ValExpr , transform )
893
+ e .CondExpr = RewriteExpr (e .CondExpr , transform )
894
+ case * hclsyntax.SplatExpr :
895
+ e .Source = RewriteExpr (e .Source , transform )
896
+ case * hclsyntax.AnonSymbolExpr :
897
+ default :
898
+ log .Debug (
899
+ "RewriteExpr encountered an unhandled expression type" ,
900
+ log .Prefix (log .PrefixMisconfiguration ),
901
+ log .String ("expr_type" , fmt .Sprintf ("%T" , expr )),
902
+ )
903
+ }
904
+ return transform (expr )
905
+ }
906
+
907
+ // UnknownValuePrefix is a placeholder string used to represent parts of a
908
+ // template expression that cannot be fully evaluated due to unknown values.
909
+ const UnknownValuePrefix = "__UNRESOLVED__"
910
+
911
+ // PartialTemplateExpr is a wrapper around hclsyntax.TemplateExpr that
912
+ // replaces unknown or unevaluated parts with placeholder strings during evaluation.
913
+ type PartialTemplateExpr struct {
914
+ * hclsyntax.TemplateExpr
915
+ }
916
+
917
+ func (e * PartialTemplateExpr ) Value (ctx * hcl.EvalContext ) (cty.Value , hcl.Diagnostics ) {
918
+ parts := make ([]hclsyntax.Expression , len (e .Parts ))
919
+ for i , part := range e .Parts {
920
+ partVal , diags := part .Value (ctx )
921
+ if diags .HasErrors () || ! partVal .IsKnown () {
922
+ parts [i ] = & hclsyntax.LiteralValueExpr {
923
+ Val : cty .StringVal (UnknownValuePrefix ),
924
+ SrcRange : part .Range (),
925
+ }
926
+ } else {
927
+ parts [i ] = part
928
+ }
929
+ }
930
+ newTemplate := & hclsyntax.TemplateExpr {
931
+ Parts : parts ,
932
+ SrcRange : e .SrcRange ,
933
+ }
934
+
935
+ return newTemplate .Value (ctx )
936
+ }
0 commit comments