github.com/terraform-linters/tflint@v0.51.2-0.20240520175844-3750771571b6/terraform/lang/functions.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package lang
     5  
     6  import (
     7  	"github.com/hashicorp/hcl/v2/ext/tryfunc"
     8  	ctyyaml "github.com/zclconf/go-cty-yaml"
     9  	"github.com/zclconf/go-cty/cty"
    10  	"github.com/zclconf/go-cty/cty/function"
    11  	"github.com/zclconf/go-cty/cty/function/stdlib"
    12  
    13  	"github.com/terraform-linters/tflint/terraform/lang/funcs"
    14  	"github.com/terraform-linters/tflint/terraform/lang/funcs/terraform"
    15  )
    16  
    17  var impureFunctions = []string{
    18  	"bcrypt",
    19  	"timestamp",
    20  	"uuid",
    21  }
    22  
    23  // Functions returns the set of functions that should be used to when evaluating
    24  // expressions in the receiving scope.
    25  func (s *Scope) Functions() map[string]function.Function {
    26  	s.funcsLock.Lock()
    27  	if s.funcs == nil {
    28  		// Some of our functions are just directly the cty stdlib functions.
    29  		// Others are implemented in the subdirectory "funcs" here in this
    30  		// repository. New functions should generally start out their lives
    31  		// in the "funcs" directory and potentially graduate to cty stdlib
    32  		// later if the functionality seems to be something domain-agnostic
    33  		// that would be useful to all applications using cty functions.
    34  
    35  		coreFuncs := map[string]function.Function{
    36  			"abs":              stdlib.AbsoluteFunc,
    37  			"abspath":          funcs.AbsPathFunc,
    38  			"alltrue":          funcs.AllTrueFunc,
    39  			"anytrue":          funcs.AnyTrueFunc,
    40  			"basename":         funcs.BasenameFunc,
    41  			"base64decode":     funcs.Base64DecodeFunc,
    42  			"base64encode":     funcs.Base64EncodeFunc,
    43  			"base64gzip":       funcs.Base64GzipFunc,
    44  			"base64sha256":     funcs.Base64Sha256Func,
    45  			"base64sha512":     funcs.Base64Sha512Func,
    46  			"bcrypt":           funcs.BcryptFunc,
    47  			"can":              tryfunc.CanFunc,
    48  			"ceil":             stdlib.CeilFunc,
    49  			"chomp":            stdlib.ChompFunc,
    50  			"cidrhost":         funcs.CidrHostFunc,
    51  			"cidrnetmask":      funcs.CidrNetmaskFunc,
    52  			"cidrsubnet":       funcs.CidrSubnetFunc,
    53  			"cidrsubnets":      funcs.CidrSubnetsFunc,
    54  			"coalesce":         funcs.CoalesceFunc,
    55  			"coalescelist":     stdlib.CoalesceListFunc,
    56  			"compact":          stdlib.CompactFunc,
    57  			"concat":           stdlib.ConcatFunc,
    58  			"contains":         stdlib.ContainsFunc,
    59  			"csvdecode":        stdlib.CSVDecodeFunc,
    60  			"dirname":          funcs.DirnameFunc,
    61  			"distinct":         stdlib.DistinctFunc,
    62  			"element":          stdlib.ElementFunc,
    63  			"endswith":         funcs.EndsWithFunc,
    64  			"chunklist":        stdlib.ChunklistFunc,
    65  			"file":             funcs.MakeFileFunc(s.BaseDir, false),
    66  			"fileexists":       funcs.MakeFileExistsFunc(s.BaseDir),
    67  			"fileset":          funcs.MakeFileSetFunc(s.BaseDir),
    68  			"filebase64":       funcs.MakeFileFunc(s.BaseDir, true),
    69  			"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
    70  			"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
    71  			"filemd5":          funcs.MakeFileMd5Func(s.BaseDir),
    72  			"filesha1":         funcs.MakeFileSha1Func(s.BaseDir),
    73  			"filesha256":       funcs.MakeFileSha256Func(s.BaseDir),
    74  			"filesha512":       funcs.MakeFileSha512Func(s.BaseDir),
    75  			"flatten":          stdlib.FlattenFunc,
    76  			"floor":            stdlib.FloorFunc,
    77  			"format":           stdlib.FormatFunc,
    78  			"formatdate":       stdlib.FormatDateFunc,
    79  			"formatlist":       stdlib.FormatListFunc,
    80  			"indent":           stdlib.IndentFunc,
    81  			"index":            funcs.IndexFunc, // stdlib.IndexFunc is not compatible
    82  			"join":             stdlib.JoinFunc,
    83  			"jsondecode":       stdlib.JSONDecodeFunc,
    84  			"jsonencode":       stdlib.JSONEncodeFunc,
    85  			"keys":             stdlib.KeysFunc,
    86  			"length":           funcs.LengthFunc,
    87  			"list":             funcs.ListFunc,
    88  			"log":              stdlib.LogFunc,
    89  			"lookup":           funcs.LookupFunc,
    90  			"lower":            stdlib.LowerFunc,
    91  			"map":              funcs.MapFunc,
    92  			"matchkeys":        funcs.MatchkeysFunc,
    93  			"max":              stdlib.MaxFunc,
    94  			"md5":              funcs.Md5Func,
    95  			"merge":            stdlib.MergeFunc,
    96  			"min":              stdlib.MinFunc,
    97  			"one":              funcs.OneFunc,
    98  			"parseint":         stdlib.ParseIntFunc,
    99  			"pathexpand":       funcs.PathExpandFunc,
   100  			"plantimestamp":    funcs.PlantimestampFunc,
   101  			"pow":              stdlib.PowFunc,
   102  			"range":            stdlib.RangeFunc,
   103  			"regex":            stdlib.RegexFunc,
   104  			"regexall":         stdlib.RegexAllFunc,
   105  			"replace":          funcs.ReplaceFunc,
   106  			"reverse":          stdlib.ReverseListFunc,
   107  			"rsadecrypt":       funcs.RsaDecryptFunc,
   108  			"sensitive":        funcs.SensitiveFunc,
   109  			"nonsensitive":     funcs.NonsensitiveFunc,
   110  			"issensitive":      funcs.IssensitiveFunc,
   111  			"setintersection":  stdlib.SetIntersectionFunc,
   112  			"setproduct":       stdlib.SetProductFunc,
   113  			"setsubtract":      stdlib.SetSubtractFunc,
   114  			"setunion":         stdlib.SetUnionFunc,
   115  			"sha1":             funcs.Sha1Func,
   116  			"sha256":           funcs.Sha256Func,
   117  			"sha512":           funcs.Sha512Func,
   118  			"signum":           stdlib.SignumFunc,
   119  			"slice":            stdlib.SliceFunc,
   120  			"sort":             stdlib.SortFunc,
   121  			"split":            stdlib.SplitFunc,
   122  			"startswith":       funcs.StartsWithFunc,
   123  			"strcontains":      funcs.StrContainsFunc,
   124  			"strrev":           stdlib.ReverseFunc,
   125  			"substr":           stdlib.SubstrFunc,
   126  			"sum":              funcs.SumFunc,
   127  			"textdecodebase64": funcs.TextDecodeBase64Func,
   128  			"textencodebase64": funcs.TextEncodeBase64Func,
   129  			"timestamp":        funcs.TimestampFunc,
   130  			"timeadd":          stdlib.TimeAddFunc,
   131  			"timecmp":          funcs.TimeCmpFunc,
   132  			"title":            stdlib.TitleFunc,
   133  			"tostring":         funcs.MakeToFunc(cty.String),
   134  			"tonumber":         funcs.MakeToFunc(cty.Number),
   135  			"tobool":           funcs.MakeToFunc(cty.Bool),
   136  			"toset":            funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
   137  			"tolist":           funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
   138  			"tomap":            funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
   139  			"transpose":        funcs.TransposeFunc,
   140  			"trim":             stdlib.TrimFunc,
   141  			"trimprefix":       stdlib.TrimPrefixFunc,
   142  			"trimspace":        stdlib.TrimSpaceFunc,
   143  			"trimsuffix":       stdlib.TrimSuffixFunc,
   144  			"try":              tryfunc.TryFunc,
   145  			"upper":            stdlib.UpperFunc,
   146  			"urlencode":        funcs.URLEncodeFunc,
   147  			"uuid":             funcs.UUIDFunc,
   148  			"uuidv5":           funcs.UUIDV5Func,
   149  			"values":           stdlib.ValuesFunc,
   150  			"yamldecode":       ctyyaml.YAMLDecodeFunc,
   151  			"yamlencode":       ctyyaml.YAMLEncodeFunc,
   152  			"zipmap":           stdlib.ZipmapFunc,
   153  		}
   154  
   155  		coreFuncs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {
   156  			// The templatefile function prevents recursive calls to itself
   157  			// by copying this map and overwriting the "templatefile" and
   158  			// "core:templatefile" entries.
   159  			return s.funcs
   160  		})
   161  
   162  		if s.PureOnly {
   163  			// Force our few impure functions to return unknown so that we
   164  			// can defer evaluating them until a later pass.
   165  			for _, name := range impureFunctions {
   166  				coreFuncs[name] = function.Unpredictable(s.funcs[name])
   167  			}
   168  		}
   169  
   170  		// All of the built-in functions are also available under the "core::"
   171  		// namespace, to distinguish from the "provider::" and "module::"
   172  		// namespaces that can serve as external extension points.
   173  		s.funcs = make(map[string]function.Function, len(coreFuncs)*2)
   174  		for name, fn := range coreFuncs {
   175  			s.funcs[name] = fn
   176  			s.funcs["core::"+name] = fn
   177  		}
   178  
   179  		// Built-in Terraform provider-defined functions are typically obtained dynamically,
   180  		// but given that they are built-ins, they are provided just like regular functions.
   181  		s.funcs["provider::terraform::encode_tfvars"] = terraform.EncodeTfvarsFunc
   182  		s.funcs["provider::terraform::decode_tfvars"] = terraform.DecodeTfvarsFunc
   183  		s.funcs["provider::terraform::encode_expr"] = terraform.EncodeExprFunc
   184  	}
   185  	s.funcsLock.Unlock()
   186  
   187  	return s.funcs
   188  }
   189  
   190  // NewMockFunction creates a mock function that returns a dynamic value.
   191  // This is primarily used to replace provider-defined functions.
   192  func NewMockFunction(call *FunctionCall) function.Function {
   193  	params := make([]function.Parameter, call.ArgsCount)
   194  	for idx := 0; idx < call.ArgsCount; idx++ {
   195  		params[idx] = function.Parameter{
   196  			Type:             cty.DynamicPseudoType,
   197  			AllowNull:        true,
   198  			AllowUnknown:     true,
   199  			AllowDynamicType: true,
   200  			AllowMarked:      true,
   201  		}
   202  	}
   203  
   204  	return function.New(&function.Spec{
   205  		Params: params,
   206  		Type:   function.StaticReturnType(cty.DynamicPseudoType),
   207  		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
   208  			return cty.DynamicVal, nil
   209  		},
   210  	})
   211  }