github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/terraform/attribute.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"io/fs"
     6  	"reflect"
     7  	"regexp"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/khulnasoft-lab/defsec/pkg/scanners/terraform/context"
    12  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
    13  
    14  	"github.com/hashicorp/hcl/v2"
    15  	"github.com/hashicorp/hcl/v2/hclsyntax"
    16  	"github.com/zclconf/go-cty/cty"
    17  	"github.com/zclconf/go-cty/cty/gocty"
    18  )
    19  
    20  type Attribute struct {
    21  	hclAttribute *hcl.Attribute
    22  	module       string
    23  	ctx          *context.Context
    24  	metadata     defsecTypes.Metadata
    25  	reference    Reference
    26  }
    27  
    28  func NewAttribute(attr *hcl.Attribute, ctx *context.Context, module string, parent defsecTypes.Metadata, parentRef Reference, moduleSource string, moduleFS fs.FS) *Attribute {
    29  	rng := defsecTypes.NewRange(
    30  		attr.Range.Filename,
    31  		attr.Range.Start.Line,
    32  		attr.Range.End.Line,
    33  		moduleSource,
    34  		moduleFS,
    35  	)
    36  	reference := extendReference(parentRef, attr.Name)
    37  	metadata := defsecTypes.NewMetadata(rng, reference.String())
    38  	return &Attribute{
    39  		hclAttribute: attr,
    40  		ctx:          ctx,
    41  		module:       module,
    42  		metadata:     metadata.WithParent(parent),
    43  		reference:    reference,
    44  	}
    45  }
    46  
    47  func (a *Attribute) GetMetadata() defsecTypes.Metadata {
    48  	return a.metadata
    49  }
    50  
    51  func (a *Attribute) GetRawValue() interface{} {
    52  	switch typ := a.Type(); typ {
    53  	case cty.String:
    54  		return a.Value().AsString()
    55  	case cty.Bool:
    56  		return a.Value().True()
    57  	case cty.Number:
    58  		float, _ := a.Value().AsBigFloat().Float64()
    59  		return float
    60  	default:
    61  		switch {
    62  		case typ.IsTupleType(), typ.IsListType():
    63  			values := a.Value().AsValueSlice()
    64  			if len(values) == 0 {
    65  				return []string{}
    66  			}
    67  			switch values[0].Type() {
    68  			case cty.String:
    69  				var output []string
    70  				for _, value := range values {
    71  					output = append(output, value.AsString())
    72  				}
    73  				return output
    74  			case cty.Number:
    75  				var output []float64
    76  				for _, value := range values {
    77  					bf := value.AsBigFloat()
    78  					f, _ := bf.Float64()
    79  					output = append(output, f)
    80  				}
    81  				return output
    82  			case cty.Bool:
    83  				var output []bool
    84  				for _, value := range values {
    85  					output = append(output, value.True())
    86  				}
    87  				return output
    88  			}
    89  		}
    90  	}
    91  	return nil
    92  }
    93  
    94  func (a *Attribute) AsBytesValueOrDefault(defaultValue []byte, parent *Block) defsecTypes.BytesValue {
    95  	if a.IsNil() {
    96  		return defsecTypes.BytesDefault(defaultValue, parent.GetMetadata())
    97  	}
    98  	if a.IsNotResolvable() || !a.IsString() {
    99  		return defsecTypes.BytesUnresolvable(a.GetMetadata())
   100  	}
   101  	return defsecTypes.BytesExplicit(
   102  		[]byte(a.Value().AsString()),
   103  		a.GetMetadata(),
   104  	)
   105  }
   106  
   107  func (a *Attribute) AsStringValueOrDefault(defaultValue string, parent *Block) defsecTypes.StringValue {
   108  	if a.IsNil() {
   109  		return defsecTypes.StringDefault(defaultValue, parent.GetMetadata())
   110  	}
   111  	if a.IsNotResolvable() || !a.IsString() {
   112  		return defsecTypes.StringUnresolvable(a.GetMetadata())
   113  	}
   114  	return defsecTypes.StringExplicit(
   115  		a.Value().AsString(),
   116  		a.GetMetadata(),
   117  	)
   118  }
   119  
   120  func (a *Attribute) AsStringValueSliceOrEmpty(parent *Block) (stringValues []defsecTypes.StringValue) {
   121  	if a.IsNil() {
   122  		return stringValues
   123  	}
   124  	return a.AsStringValues()
   125  }
   126  
   127  func (a *Attribute) AsBoolValueOrDefault(defaultValue bool, parent *Block) defsecTypes.BoolValue {
   128  	if a.IsNil() {
   129  		return defsecTypes.BoolDefault(defaultValue, parent.GetMetadata())
   130  	}
   131  	if a.IsNotResolvable() || !a.IsBool() {
   132  		return defsecTypes.BoolUnresolvable(a.GetMetadata())
   133  	}
   134  	return defsecTypes.BoolExplicit(
   135  		a.IsTrue(),
   136  		a.GetMetadata(),
   137  	)
   138  }
   139  
   140  func (a *Attribute) AsIntValueOrDefault(defaultValue int, parent *Block) defsecTypes.IntValue {
   141  	if a.IsNil() {
   142  		return defsecTypes.IntDefault(defaultValue, parent.GetMetadata())
   143  	}
   144  	if a.IsNotResolvable() || !a.IsNumber() {
   145  		return defsecTypes.IntUnresolvable(a.GetMetadata())
   146  	}
   147  	flt := a.AsNumber()
   148  	return defsecTypes.IntExplicit(
   149  		int(flt),
   150  		a.GetMetadata(),
   151  	)
   152  }
   153  
   154  func (a *Attribute) IsLiteral() bool {
   155  	if a == nil {
   156  		return false
   157  	}
   158  	return len(a.hclAttribute.Expr.Variables()) == 0
   159  }
   160  
   161  func (a *Attribute) IsResolvable() bool {
   162  	if a == nil {
   163  		return false
   164  	}
   165  	return a.Value() != cty.NilVal && a.Value().IsKnown()
   166  }
   167  
   168  func (a *Attribute) IsNotResolvable() bool {
   169  	return !a.IsResolvable()
   170  }
   171  
   172  func (a *Attribute) Type() cty.Type {
   173  	if a == nil {
   174  		return cty.NilType
   175  	}
   176  	return a.Value().Type()
   177  }
   178  
   179  func (a *Attribute) IsIterable() bool {
   180  	if a == nil {
   181  		return false
   182  	}
   183  	return a.Value().Type().IsListType() || a.Value().Type().IsCollectionType() || a.Value().Type().IsObjectType() || a.Value().Type().IsMapType() || a.Value().Type().IsListType() || a.Value().Type().IsSetType() || a.Value().Type().IsTupleType()
   184  }
   185  
   186  func (a *Attribute) Each(f func(key cty.Value, val cty.Value)) error {
   187  	if a == nil {
   188  		return nil
   189  	}
   190  	var outerErr error
   191  	defer func() {
   192  		if err := recover(); err != nil {
   193  			outerErr = fmt.Errorf("go-cty bug detected - cannot call ForEachElement: %s", err)
   194  		}
   195  	}()
   196  	val := a.Value()
   197  	val.ForEachElement(func(key cty.Value, val cty.Value) (stop bool) {
   198  		f(key, val)
   199  		return false
   200  	})
   201  	return outerErr
   202  }
   203  
   204  func (a *Attribute) IsString() bool {
   205  	if a == nil {
   206  		return false
   207  	}
   208  	return !a.Value().IsNull() && a.Value().IsKnown() && a.Value().Type() == cty.String
   209  }
   210  
   211  func (a *Attribute) IsNumber() bool {
   212  	if a != nil && !a.Value().IsNull() && a.Value().IsKnown() {
   213  		if a.Value().Type() == cty.Number {
   214  			return true
   215  		}
   216  		if a.Value().Type() == cty.String {
   217  			_, err := strconv.ParseFloat(a.Value().AsString(), 64)
   218  			return err == nil
   219  		}
   220  	}
   221  
   222  	return false
   223  }
   224  
   225  func (a *Attribute) IsBool() bool {
   226  	if a == nil {
   227  		return false
   228  	}
   229  	switch a.Value().Type() {
   230  	case cty.Bool, cty.Number:
   231  		return true
   232  	case cty.String:
   233  		val := a.Value().AsString()
   234  		val = strings.Trim(val, "\"")
   235  		return strings.EqualFold(val, "false") || strings.EqualFold(val, "true")
   236  	}
   237  	return false
   238  }
   239  
   240  func (a *Attribute) Value() (ctyVal cty.Value) {
   241  	if a == nil {
   242  		return cty.NilVal
   243  	}
   244  	defer func() {
   245  		if err := recover(); err != nil {
   246  			ctyVal = cty.NilVal
   247  		}
   248  	}()
   249  	ctyVal, _ = a.hclAttribute.Expr.Value(a.ctx.Inner())
   250  	if !ctyVal.IsKnown() || ctyVal.IsNull() {
   251  		return cty.NilVal
   252  	}
   253  	return ctyVal
   254  }
   255  
   256  // Allows a null value for a variable https://developer.hashicorp.com/terraform/language/expressions/types#null
   257  func (a *Attribute) NullableValue() (ctyVal cty.Value) {
   258  	if a == nil {
   259  		return cty.NilVal
   260  	}
   261  	defer func() {
   262  		if err := recover(); err != nil {
   263  			ctyVal = cty.NilVal
   264  		}
   265  	}()
   266  	ctyVal, _ = a.hclAttribute.Expr.Value(a.ctx.Inner())
   267  	if !ctyVal.IsKnown() {
   268  		return cty.NilVal
   269  	}
   270  	return ctyVal
   271  }
   272  
   273  func (a *Attribute) Name() string {
   274  	if a == nil {
   275  		return ""
   276  	}
   277  	return a.hclAttribute.Name
   278  }
   279  
   280  func (a *Attribute) AsStringValues() defsecTypes.StringValueList {
   281  	if a == nil {
   282  		return nil
   283  	}
   284  	return a.getStringValues(a.hclAttribute.Expr, a.ctx.Inner())
   285  }
   286  
   287  // nolint
   288  func (a *Attribute) getStringValues(expr hcl.Expression, ctx *hcl.EvalContext) (results []defsecTypes.StringValue) {
   289  
   290  	defer func() {
   291  		if err := recover(); err != nil {
   292  			results = []defsecTypes.StringValue{defsecTypes.StringUnresolvable(a.metadata)}
   293  		}
   294  	}()
   295  
   296  	switch t := expr.(type) {
   297  	case *hclsyntax.TupleConsExpr:
   298  		for _, expr := range t.Exprs {
   299  			val, err := expr.Value(a.ctx.Inner())
   300  			if err != nil {
   301  				results = append(results, defsecTypes.StringUnresolvable(a.metadata))
   302  				continue
   303  			}
   304  			results = append(results, a.valueToString(val))
   305  		}
   306  	case *hclsyntax.FunctionCallExpr, *hclsyntax.ConditionalExpr:
   307  		subVal, err := t.Value(ctx)
   308  		if err != nil {
   309  			return append(results, defsecTypes.StringUnresolvable(a.metadata))
   310  		}
   311  		return a.valueToStrings(subVal)
   312  	case *hclsyntax.LiteralValueExpr:
   313  		return a.valueToStrings(t.Val)
   314  	case *hclsyntax.TemplateExpr:
   315  		// walk the parts of the expression to ensure that it has a literal value
   316  		for _, p := range t.Parts {
   317  			val, err := p.Value(a.ctx.Inner())
   318  			if err != nil {
   319  				results = append(results, defsecTypes.StringUnresolvable(a.metadata))
   320  				continue
   321  			}
   322  			value := a.valueToString(val)
   323  			results = append(results, value)
   324  		}
   325  	case *hclsyntax.ScopeTraversalExpr:
   326  		// handle the case for referencing a data
   327  		if len(t.Variables()) > 0 {
   328  			if t.Variables()[0].RootName() == "data" {
   329  				// we can't resolve data lookups at this time, so make unresolvable
   330  				return append(results, defsecTypes.StringUnresolvable(a.metadata))
   331  			}
   332  		}
   333  		subVal, err := t.Value(ctx)
   334  		if err != nil {
   335  			return append(results, defsecTypes.StringUnresolvable(a.metadata))
   336  		}
   337  		return a.valueToStrings(subVal)
   338  	default:
   339  		val, err := t.Value(a.ctx.Inner())
   340  		if err != nil {
   341  			return append(results, defsecTypes.StringUnresolvable(a.metadata))
   342  		}
   343  		results = a.valueToStrings(val)
   344  	}
   345  	return results
   346  }
   347  
   348  func (a *Attribute) valueToStrings(value cty.Value) (results []defsecTypes.StringValue) {
   349  	defer func() {
   350  		if err := recover(); err != nil {
   351  			results = []defsecTypes.StringValue{defsecTypes.StringUnresolvable(a.metadata)}
   352  		}
   353  	}()
   354  	if value.IsNull() {
   355  		return []defsecTypes.StringValue{defsecTypes.StringUnresolvable(a.metadata)}
   356  	}
   357  	if !value.IsKnown() {
   358  		return []defsecTypes.StringValue{defsecTypes.StringUnresolvable(a.metadata)}
   359  	}
   360  	if value.Type().IsListType() || value.Type().IsTupleType() || value.Type().IsSetType() {
   361  		for _, val := range value.AsValueSlice() {
   362  			results = append(results, a.valueToString(val))
   363  		}
   364  	}
   365  	return results
   366  }
   367  
   368  func (a *Attribute) valueToString(value cty.Value) (result defsecTypes.StringValue) {
   369  	defer func() {
   370  		if err := recover(); err != nil {
   371  			result = defsecTypes.StringUnresolvable(a.metadata)
   372  		}
   373  	}()
   374  
   375  	result = defsecTypes.StringUnresolvable(a.metadata)
   376  
   377  	if value.IsNull() || !value.IsKnown() {
   378  		return result
   379  	}
   380  
   381  	switch value.Type() {
   382  	case cty.String:
   383  		return defsecTypes.String(value.AsString(), a.metadata)
   384  	default:
   385  		return result
   386  	}
   387  }
   388  
   389  func (a *Attribute) listContains(val cty.Value, stringToLookFor string, ignoreCase bool) bool {
   390  	if a == nil {
   391  		return false
   392  	}
   393  
   394  	valueSlice := val.AsValueSlice()
   395  	for _, value := range valueSlice {
   396  		if value.IsNull() || !value.IsKnown() {
   397  			// there is nothing we can do with this value
   398  			continue
   399  		}
   400  		stringToTest := value
   401  		if value.Type().IsObjectType() || value.Type().IsMapType() {
   402  			valueMap := value.AsValueMap()
   403  			stringToTest = valueMap["key"]
   404  		}
   405  		if value.Type().HasDynamicTypes() {
   406  			for _, extracted := range a.extractListValues() {
   407  				if extracted == stringToLookFor {
   408  					return true
   409  				}
   410  			}
   411  			return false
   412  		}
   413  		if !value.IsKnown() {
   414  			continue
   415  		}
   416  		if ignoreCase && strings.EqualFold(stringToTest.AsString(), stringToLookFor) {
   417  			return true
   418  		}
   419  		if stringToTest.AsString() == stringToLookFor {
   420  			return true
   421  		}
   422  	}
   423  	return false
   424  }
   425  
   426  func (a *Attribute) extractListValues() []string {
   427  	var values []string
   428  	if a.hclAttribute == nil || a.hclAttribute.Expr == nil || a.hclAttribute.Expr.Variables() == nil {
   429  		return values
   430  	}
   431  	for _, v := range a.hclAttribute.Expr.Variables() {
   432  		values = append(values, v.RootName())
   433  	}
   434  	return values
   435  }
   436  
   437  func (a *Attribute) mapContains(checkValue interface{}, val cty.Value) bool {
   438  	if a == nil {
   439  		return false
   440  	}
   441  	valueMap := val.AsValueMap()
   442  	switch t := checkValue.(type) {
   443  	case map[interface{}]interface{}:
   444  		for k, v := range t {
   445  			for key, value := range valueMap {
   446  				rawValue := getRawValue(value)
   447  				if key == k && evaluate(v, rawValue) {
   448  					return true
   449  				}
   450  			}
   451  		}
   452  		return false
   453  	case map[string]interface{}:
   454  		for k, v := range t {
   455  			for key, value := range valueMap {
   456  				rawValue := getRawValue(value)
   457  				if key == k && evaluate(v, rawValue) {
   458  					return true
   459  				}
   460  			}
   461  		}
   462  		return false
   463  	default:
   464  		for key := range valueMap {
   465  			if key == checkValue {
   466  				return true
   467  			}
   468  		}
   469  		return false
   470  	}
   471  }
   472  
   473  func (a *Attribute) NotContains(checkValue interface{}, equalityOptions ...EqualityOption) bool {
   474  	return !a.Contains(checkValue, equalityOptions...)
   475  }
   476  
   477  func (a *Attribute) Contains(checkValue interface{}, equalityOptions ...EqualityOption) bool {
   478  	if a == nil {
   479  		return false
   480  	}
   481  	ignoreCase := false
   482  	for _, option := range equalityOptions {
   483  		if option == IgnoreCase {
   484  			ignoreCase = true
   485  		}
   486  	}
   487  	val := a.Value()
   488  	if val.IsNull() {
   489  		return false
   490  	}
   491  
   492  	if val.Type().IsObjectType() || val.Type().IsMapType() {
   493  		return a.mapContains(checkValue, val)
   494  	}
   495  
   496  	stringToLookFor := fmt.Sprintf("%v", checkValue)
   497  
   498  	if val.Type().IsListType() || val.Type().IsTupleType() {
   499  		return a.listContains(val, stringToLookFor, ignoreCase)
   500  	}
   501  
   502  	if ignoreCase && containsIgnoreCase(val.AsString(), stringToLookFor) {
   503  		return true
   504  	}
   505  
   506  	return strings.Contains(val.AsString(), stringToLookFor)
   507  }
   508  
   509  func (a *Attribute) OnlyContains(checkValue interface{}) bool {
   510  	if a == nil {
   511  		return false
   512  	}
   513  	val := a.Value()
   514  	if val.IsNull() {
   515  		return false
   516  	}
   517  
   518  	checkSlice, ok := checkValue.([]interface{})
   519  	if !ok {
   520  		return false
   521  	}
   522  
   523  	if val.Type().IsListType() || val.Type().IsTupleType() {
   524  		for _, value := range val.AsValueSlice() {
   525  			found := false
   526  			for _, cVal := range checkSlice {
   527  				switch t := cVal.(type) {
   528  				case string:
   529  					if t == value.AsString() {
   530  						found = true
   531  						break
   532  					}
   533  				case bool:
   534  					if t == value.True() {
   535  						found = true
   536  						break
   537  					}
   538  				case int, int8, int16, int32, int64:
   539  					i, _ := value.AsBigFloat().Int64()
   540  					if t == i {
   541  						found = true
   542  						break
   543  					}
   544  				case float32, float64:
   545  					f, _ := value.AsBigFloat().Float64()
   546  					if t == f {
   547  						found = true
   548  						break
   549  					}
   550  				}
   551  
   552  			}
   553  			if !found {
   554  				return false
   555  			}
   556  		}
   557  		return true
   558  	}
   559  
   560  	return false
   561  }
   562  
   563  func containsIgnoreCase(left, substring string) bool {
   564  	return strings.Contains(strings.ToLower(left), strings.ToLower(substring))
   565  }
   566  
   567  func (a *Attribute) StartsWith(prefix interface{}) bool {
   568  	if a == nil {
   569  		return false
   570  	}
   571  	if a.Value().Type() == cty.String {
   572  		return strings.HasPrefix(a.Value().AsString(), fmt.Sprintf("%v", prefix))
   573  	}
   574  	return false
   575  }
   576  
   577  func (a *Attribute) EndsWith(suffix interface{}) bool {
   578  	if a == nil {
   579  		return false
   580  	}
   581  	if a.Value().Type() == cty.String {
   582  		return strings.HasSuffix(a.Value().AsString(), fmt.Sprintf("%v", suffix))
   583  	}
   584  	return false
   585  }
   586  
   587  type EqualityOption int
   588  
   589  const (
   590  	IgnoreCase EqualityOption = iota
   591  )
   592  
   593  func (a *Attribute) Equals(checkValue interface{}, equalityOptions ...EqualityOption) bool {
   594  	if a == nil {
   595  		return false
   596  	}
   597  	if a.Value().Type() == cty.String {
   598  		for _, option := range equalityOptions {
   599  			if option == IgnoreCase {
   600  				return strings.EqualFold(strings.ToLower(a.Value().AsString()), strings.ToLower(fmt.Sprintf("%v", checkValue)))
   601  			}
   602  		}
   603  		result := strings.EqualFold(a.Value().AsString(), fmt.Sprintf("%v", checkValue))
   604  		return result
   605  	}
   606  	if a.Value().Type() == cty.Bool {
   607  		return a.Value().True() == checkValue
   608  	}
   609  	if a.Value().Type() == cty.Number {
   610  		checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number)
   611  		if err != nil {
   612  			return false
   613  		}
   614  		return a.Value().RawEquals(checkNumber)
   615  	}
   616  
   617  	return false
   618  }
   619  
   620  func (a *Attribute) NotEqual(checkValue interface{}, equalityOptions ...EqualityOption) bool {
   621  	return !a.Equals(checkValue, equalityOptions...)
   622  }
   623  
   624  func (a *Attribute) RegexMatches(re regexp.Regexp) bool {
   625  	if a == nil {
   626  		return false
   627  	}
   628  	if a.Value().Type() == cty.String {
   629  		match := re.MatchString(a.Value().AsString())
   630  		return match
   631  	}
   632  	return false
   633  }
   634  
   635  func (a *Attribute) IsNotAny(options ...interface{}) bool {
   636  	return !a.IsAny(options...)
   637  }
   638  
   639  func (a *Attribute) IsAny(options ...interface{}) bool {
   640  	if a == nil {
   641  		return false
   642  	}
   643  	if a.Value().Type() == cty.String {
   644  		value := a.Value().AsString()
   645  		for _, option := range options {
   646  			if option == value {
   647  				return true
   648  			}
   649  		}
   650  	}
   651  	if a.Value().Type() == cty.Number {
   652  		for _, option := range options {
   653  			checkValue, err := gocty.ToCtyValue(option, cty.Number)
   654  			if err != nil {
   655  				return false
   656  			}
   657  			if a.Value().RawEquals(checkValue) {
   658  				return true
   659  			}
   660  		}
   661  	}
   662  	return false
   663  }
   664  
   665  func (a *Attribute) IsNone(options ...interface{}) bool {
   666  	if a == nil {
   667  		return false
   668  	}
   669  	if a.Value().Type() == cty.String {
   670  		for _, option := range options {
   671  			if option == a.Value().AsString() {
   672  				return false
   673  			}
   674  		}
   675  	}
   676  	if a.Value().Type() == cty.Number {
   677  		for _, option := range options {
   678  			checkValue, err := gocty.ToCtyValue(option, cty.Number)
   679  			if err != nil {
   680  				return false
   681  			}
   682  			if a.Value().RawEquals(checkValue) {
   683  				return false
   684  			}
   685  
   686  		}
   687  	}
   688  
   689  	return true
   690  }
   691  
   692  func (a *Attribute) IsTrue() bool {
   693  	if a == nil {
   694  		return false
   695  	}
   696  	switch a.Value().Type() {
   697  	case cty.Bool:
   698  		return a.Value().True()
   699  	case cty.String:
   700  		val := a.Value().AsString()
   701  		val = strings.Trim(val, "\"")
   702  		return strings.ToLower(val) == "true"
   703  	case cty.Number:
   704  		val := a.Value().AsBigFloat()
   705  		f, _ := val.Float64()
   706  		return f > 0
   707  	}
   708  	return false
   709  }
   710  
   711  func (a *Attribute) IsFalse() bool {
   712  	if a == nil {
   713  		return false
   714  	}
   715  	switch a.Value().Type() {
   716  	case cty.Bool:
   717  		return a.Value().False()
   718  	case cty.String:
   719  		val := a.Value().AsString()
   720  		val = strings.Trim(val, "\"")
   721  		return strings.ToLower(val) == "false"
   722  	case cty.Number:
   723  		val := a.Value().AsBigFloat()
   724  		f, _ := val.Float64()
   725  		return f == 0
   726  	}
   727  	return false
   728  }
   729  
   730  func (a *Attribute) IsEmpty() bool {
   731  	if a == nil {
   732  		return false
   733  	}
   734  	if a.Value().Type() == cty.String {
   735  		return len(a.Value().AsString()) == 0
   736  	}
   737  	if a.Type().IsListType() || a.Type().IsTupleType() {
   738  		return len(a.Value().AsValueSlice()) == 0
   739  	}
   740  	if a.Type().IsMapType() || a.Type().IsObjectType() {
   741  		return len(a.Value().AsValueMap()) == 0
   742  	}
   743  	if a.Value().Type() == cty.Number {
   744  		// a number can't ever be empty
   745  		return false
   746  	}
   747  	if a.Value().IsNull() {
   748  		return a.isNullAttributeEmpty()
   749  	}
   750  	return true
   751  }
   752  
   753  func (a *Attribute) IsNotEmpty() bool {
   754  	return !a.IsEmpty()
   755  }
   756  
   757  func (a *Attribute) isNullAttributeEmpty() bool {
   758  	if a == nil {
   759  		return false
   760  	}
   761  	switch t := a.hclAttribute.Expr.(type) {
   762  	case *hclsyntax.FunctionCallExpr, *hclsyntax.ScopeTraversalExpr,
   763  		*hclsyntax.ConditionalExpr, *hclsyntax.LiteralValueExpr:
   764  		return false
   765  	case *hclsyntax.TemplateExpr:
   766  		// walk the parts of the expression to ensure that it has a literal value
   767  		for _, p := range t.Parts {
   768  			switch pt := p.(type) {
   769  			case *hclsyntax.LiteralValueExpr:
   770  				if pt != nil && !pt.Val.IsNull() {
   771  					return false
   772  				}
   773  			case *hclsyntax.ScopeTraversalExpr:
   774  				return false
   775  			}
   776  		}
   777  	}
   778  	return true
   779  }
   780  
   781  func (a *Attribute) MapValue(mapKey string) cty.Value {
   782  	if a == nil {
   783  		return cty.NilVal
   784  	}
   785  	if a.Type().IsObjectType() || a.Type().IsMapType() {
   786  		attrMap := a.Value().AsValueMap()
   787  		for key, value := range attrMap {
   788  			if key == mapKey {
   789  				return value
   790  			}
   791  		}
   792  	}
   793  	return cty.NilVal
   794  }
   795  
   796  func (a *Attribute) LessThan(checkValue interface{}) bool {
   797  	if a == nil {
   798  		return false
   799  	}
   800  	if a.Value().Type() == cty.Number {
   801  		checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number)
   802  		if err != nil {
   803  			return false
   804  		}
   805  
   806  		return a.Value().LessThan(checkNumber).True()
   807  	}
   808  	return false
   809  }
   810  
   811  func (a *Attribute) LessThanOrEqualTo(checkValue interface{}) bool {
   812  	if a == nil {
   813  		return false
   814  	}
   815  	if a.Value().Type() == cty.Number {
   816  		checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number)
   817  		if err != nil {
   818  			return false
   819  		}
   820  
   821  		return a.Value().LessThanOrEqualTo(checkNumber).True()
   822  	}
   823  	return false
   824  }
   825  
   826  func (a *Attribute) GreaterThan(checkValue interface{}) bool {
   827  	if a == nil {
   828  		return false
   829  	}
   830  	if a.Value().Type() == cty.Number {
   831  		checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number)
   832  		if err != nil {
   833  			return false
   834  		}
   835  
   836  		return a.Value().GreaterThan(checkNumber).True()
   837  	}
   838  	return false
   839  }
   840  
   841  func (a *Attribute) GreaterThanOrEqualTo(checkValue interface{}) bool {
   842  	if a == nil {
   843  		return false
   844  	}
   845  	if a.Value().Type() == cty.Number {
   846  		checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number)
   847  		if err != nil {
   848  			return false
   849  		}
   850  
   851  		return a.Value().GreaterThanOrEqualTo(checkNumber).True()
   852  	}
   853  	return false
   854  }
   855  
   856  func (a *Attribute) IsDataBlockReference() bool {
   857  	if a == nil {
   858  		return false
   859  	}
   860  	switch t := a.hclAttribute.Expr.(type) {
   861  	case *hclsyntax.ScopeTraversalExpr:
   862  		split := t.Traversal.SimpleSplit()
   863  		return split.Abs.RootName() == "data"
   864  	}
   865  	return false
   866  }
   867  
   868  func createDotReferenceFromTraversal(parentRef string, traversals ...hcl.Traversal) (*Reference, error) {
   869  	var refParts []string
   870  	var key cty.Value
   871  	for _, x := range traversals {
   872  		for _, p := range x {
   873  			switch part := p.(type) {
   874  			case hcl.TraverseRoot:
   875  				refParts = append(refParts, part.Name)
   876  			case hcl.TraverseAttr:
   877  				refParts = append(refParts, part.Name)
   878  			case hcl.TraverseIndex:
   879  				key = part.Key
   880  			}
   881  		}
   882  	}
   883  	ref, err := newReference(refParts, parentRef)
   884  	if err != nil {
   885  		return nil, err
   886  	}
   887  	if !key.IsNull() {
   888  		ref.SetKey(key)
   889  	}
   890  	return ref, nil
   891  }
   892  
   893  func (a *Attribute) ReferencesBlock(b *Block) bool {
   894  	if a == nil {
   895  		return false
   896  	}
   897  	for _, ref := range a.AllReferences() {
   898  		if ref.RefersTo(b.reference) {
   899  			return true
   900  		}
   901  	}
   902  	return false
   903  }
   904  
   905  func (a *Attribute) AllReferences(blocks ...*Block) []*Reference {
   906  	if a == nil {
   907  		return nil
   908  	}
   909  	refs := a.extractReferences()
   910  	for _, block := range blocks {
   911  		for _, ref := range refs {
   912  			if ref.TypeLabel() == "each" && block.HasChild("for_each") {
   913  				refs = append(refs, block.GetAttribute("for_each").AllReferences()...)
   914  			}
   915  		}
   916  	}
   917  	return refs
   918  }
   919  
   920  // nolint
   921  func (a *Attribute) referencesFromExpression(expression hcl.Expression) []*Reference {
   922  	var refs []*Reference
   923  	switch t := expression.(type) {
   924  	case *hclsyntax.ConditionalExpr:
   925  		if ref, err := createDotReferenceFromTraversal(a.module, t.TrueResult.Variables()...); err == nil {
   926  			refs = append(refs, ref)
   927  		}
   928  		if ref, err := createDotReferenceFromTraversal(a.module, t.FalseResult.Variables()...); err == nil {
   929  			refs = append(refs, ref)
   930  		}
   931  		if ref, err := createDotReferenceFromTraversal(a.module, t.Condition.Variables()...); err == nil {
   932  			refs = append(refs, ref)
   933  		}
   934  	case *hclsyntax.ScopeTraversalExpr:
   935  		if ref, err := createDotReferenceFromTraversal(a.module, t.Variables()...); err == nil {
   936  			refs = append(refs, ref)
   937  		}
   938  	case *hclsyntax.TemplateWrapExpr:
   939  		refs = a.referencesFromExpression(t.Wrapped)
   940  	case *hclsyntax.TemplateExpr:
   941  		for _, part := range t.Parts {
   942  			ref, err := createDotReferenceFromTraversal(a.module, part.Variables()...)
   943  			if err != nil {
   944  				continue
   945  			}
   946  			refs = append(refs, ref)
   947  		}
   948  	case *hclsyntax.TupleConsExpr:
   949  		if ref, err := createDotReferenceFromTraversal(a.module, t.Variables()...); err == nil {
   950  			refs = append(refs, ref)
   951  		}
   952  	case *hclsyntax.RelativeTraversalExpr:
   953  		switch s := t.Source.(type) {
   954  		case *hclsyntax.IndexExpr:
   955  			if collectionRef, err := createDotReferenceFromTraversal(a.module, s.Collection.Variables()...); err == nil {
   956  				key, _ := s.Key.Value(a.ctx.Inner())
   957  				collectionRef.SetKey(key)
   958  				refs = append(refs, collectionRef)
   959  			}
   960  		default:
   961  			if ref, err := createDotReferenceFromTraversal(a.module, t.Source.Variables()...); err == nil {
   962  				refs = append(refs, ref)
   963  			}
   964  		}
   965  	default:
   966  		if reflect.TypeOf(expression).String() == "*json.expression" {
   967  			if ref, err := createDotReferenceFromTraversal(a.module, expression.Variables()...); err == nil {
   968  				refs = append(refs, ref)
   969  			}
   970  		}
   971  	}
   972  	return refs
   973  }
   974  
   975  func (a *Attribute) extractReferences() []*Reference {
   976  	if a == nil {
   977  		return nil
   978  	}
   979  	return a.referencesFromExpression(a.hclAttribute.Expr)
   980  }
   981  
   982  func (a *Attribute) IsResourceBlockReference(resourceType string) bool {
   983  	if a == nil {
   984  		return false
   985  	}
   986  	switch t := a.hclAttribute.Expr.(type) {
   987  	case *hclsyntax.ScopeTraversalExpr:
   988  		split := t.Traversal.SimpleSplit()
   989  		return split.Abs.RootName() == resourceType
   990  	}
   991  	return false
   992  }
   993  
   994  func (a *Attribute) References(r Reference) bool {
   995  	if a == nil {
   996  		return false
   997  	}
   998  	for _, ref := range a.AllReferences() {
   999  		if ref.RefersTo(r) {
  1000  			return true
  1001  		}
  1002  	}
  1003  	return false
  1004  }
  1005  
  1006  func getRawValue(value cty.Value) interface{} {
  1007  	if value.IsNull() || !value.IsKnown() {
  1008  		return value
  1009  	}
  1010  
  1011  	typeName := value.Type().FriendlyName()
  1012  
  1013  	switch typeName {
  1014  	case "string":
  1015  		return value.AsString()
  1016  	case "number":
  1017  		return value.AsBigFloat()
  1018  	case "bool":
  1019  		return value.True()
  1020  	}
  1021  
  1022  	return value
  1023  }
  1024  
  1025  func (a *Attribute) IsNil() bool {
  1026  	return a == nil
  1027  }
  1028  
  1029  func (a *Attribute) IsNotNil() bool {
  1030  	return !a.IsNil()
  1031  }
  1032  
  1033  func (a *Attribute) HasIntersect(checkValues ...interface{}) bool {
  1034  	if !a.Type().IsListType() && !a.Type().IsTupleType() {
  1035  		return false
  1036  	}
  1037  
  1038  	for _, item := range checkValues {
  1039  		if a.Contains(item) {
  1040  			return true
  1041  		}
  1042  	}
  1043  	return false
  1044  
  1045  }
  1046  
  1047  func (a *Attribute) AsNumber() float64 {
  1048  	if a.Value().Type() == cty.Number {
  1049  		v, _ := a.Value().AsBigFloat().Float64()
  1050  		return v
  1051  	}
  1052  	if a.Value().Type() == cty.String {
  1053  		v, _ := strconv.ParseFloat(a.Value().AsString(), 64)
  1054  		return v
  1055  	}
  1056  	panic("Attribute is not a number")
  1057  }