github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/terraform/context/context.go (about) 1 package context 2 3 import ( 4 "strings" 5 6 "github.com/hashicorp/hcl/v2" 7 "github.com/zclconf/go-cty/cty" 8 ) 9 10 type Context struct { 11 ctx *hcl.EvalContext 12 parent *Context 13 } 14 15 func NewContext(ctx *hcl.EvalContext, parent *Context) *Context { 16 if ctx.Variables == nil { 17 ctx.Variables = make(map[string]cty.Value) 18 } 19 return &Context{ 20 ctx: ctx, 21 parent: parent, 22 } 23 } 24 25 func (c *Context) NewChild() *Context { 26 return NewContext(c.ctx.NewChild(), c) 27 } 28 29 func (c *Context) Parent() *Context { 30 return c.parent 31 } 32 33 func (c *Context) Inner() *hcl.EvalContext { 34 return c.ctx 35 } 36 37 func (c *Context) Root() *Context { 38 root := c 39 for root.Parent() != nil { 40 root = root.Parent() 41 } 42 return root 43 } 44 45 func (c *Context) Get(parts ...string) cty.Value { 46 if len(parts) == 0 { 47 return cty.NilVal 48 } 49 src := c.ctx.Variables 50 for i, part := range parts { 51 if i == len(parts)-1 { 52 return src[part] 53 } 54 nextPart := src[part] 55 if nextPart == cty.NilVal { 56 return cty.NilVal 57 } 58 src = nextPart.AsValueMap() 59 } 60 return cty.NilVal 61 } 62 63 func (c *Context) GetByDot(path string) cty.Value { 64 return c.Get(strings.Split(path, ".")...) 65 } 66 67 func (c *Context) SetByDot(val cty.Value, path string) { 68 c.Set(val, strings.Split(path, ".")...) 69 } 70 71 func (c *Context) Set(val cty.Value, parts ...string) { 72 if len(parts) == 0 { 73 return 74 } 75 76 v := mergeVars(c.ctx.Variables[parts[0]], parts[1:], val) 77 c.ctx.Variables[parts[0]] = v 78 } 79 80 func mergeVars(src cty.Value, parts []string, value cty.Value) cty.Value { 81 82 if len(parts) == 0 { 83 if value.IsKnown() && value.Type().IsObjectType() && !value.IsNull() && value.LengthInt() > 0 && src.IsKnown() && src.Type().IsObjectType() && !src.IsNull() && src.LengthInt() > 0 { 84 return mergeObjects(src, value) 85 } 86 return value 87 } 88 89 data := make(map[string]cty.Value) 90 if src.Type().IsObjectType() && !src.IsNull() && src.LengthInt() > 0 { 91 data = src.AsValueMap() 92 tmp, ok := src.AsValueMap()[parts[0]] 93 if !ok { 94 src = cty.ObjectVal(make(map[string]cty.Value)) 95 } else { 96 src = tmp 97 } 98 } 99 100 data[parts[0]] = mergeVars(src, parts[1:], value) 101 102 return cty.ObjectVal(data) 103 } 104 105 func mergeObjects(a cty.Value, b cty.Value) cty.Value { 106 output := make(map[string]cty.Value) 107 108 for key, val := range a.AsValueMap() { 109 output[key] = val 110 } 111 for key, val := range b.AsValueMap() { 112 old, exists := output[key] 113 if exists && val.IsKnown() && val.Type().IsObjectType() && !val.IsNull() && val.LengthInt() > 0 && old.IsKnown() && old.Type().IsObjectType() && !old.IsNull() && old.LengthInt() > 0 { 114 output[key] = mergeObjects(val, old) 115 } else { 116 output[key] = val 117 } 118 } 119 return cty.ObjectVal(output) 120 }