|
| 1 | +package tfparse |
| 2 | + |
| 3 | +import ( |
| 4 | +"github.com/aquasecurity/trivy-iac/pkg/scanners/terraform/parser/funcs" |
| 5 | +"github.com/hashicorp/hcl/v2/ext/tryfunc" |
| 6 | +ctyyaml"github.com/zclconf/go-cty-yaml" |
| 7 | +"github.com/zclconf/go-cty/cty" |
| 8 | +"github.com/zclconf/go-cty/cty/function" |
| 9 | +"github.com/zclconf/go-cty/cty/function/stdlib" |
| 10 | +"golang.org/x/xerrors" |
| 11 | +) |
| 12 | + |
| 13 | +// Functions returns a set of functions that are safe to use in the context of |
| 14 | +// evaluating Terraform expressions without any ability to reference local files. |
| 15 | +// Functions that refer to file operations are replaced with stubs that return a |
| 16 | +// descriptive error to the user. |
| 17 | +funcFunctions()map[string]function.Function { |
| 18 | +returnallFunctions |
| 19 | +} |
| 20 | + |
| 21 | +var ( |
| 22 | +// Adapted from github.com/aquasecurity/trivy-iac@v0.8.0/pkg/scanners/terraform/parser/functions.go |
| 23 | +// We cannot support all available functions here, as the result of reading a file will be different |
| 24 | +// depending on the execution environment. |
| 25 | +safeFunctions=map[string]function.Function{ |
| 26 | +"abs":stdlib.AbsoluteFunc, |
| 27 | +"basename":funcs.BasenameFunc, |
| 28 | +"base64decode":funcs.Base64DecodeFunc, |
| 29 | +"base64encode":funcs.Base64EncodeFunc, |
| 30 | +"base64gzip":funcs.Base64GzipFunc, |
| 31 | +"base64sha256":funcs.Base64Sha256Func, |
| 32 | +"base64sha512":funcs.Base64Sha512Func, |
| 33 | +"bcrypt":funcs.BcryptFunc, |
| 34 | +"can":tryfunc.CanFunc, |
| 35 | +"ceil":stdlib.CeilFunc, |
| 36 | +"chomp":stdlib.ChompFunc, |
| 37 | +"cidrhost":funcs.CidrHostFunc, |
| 38 | +"cidrnetmask":funcs.CidrNetmaskFunc, |
| 39 | +"cidrsubnet":funcs.CidrSubnetFunc, |
| 40 | +"cidrsubnets":funcs.CidrSubnetsFunc, |
| 41 | +"coalesce":funcs.CoalesceFunc, |
| 42 | +"coalescelist":stdlib.CoalesceListFunc, |
| 43 | +"compact":stdlib.CompactFunc, |
| 44 | +"concat":stdlib.ConcatFunc, |
| 45 | +"contains":stdlib.ContainsFunc, |
| 46 | +"csvdecode":stdlib.CSVDecodeFunc, |
| 47 | +"dirname":funcs.DirnameFunc, |
| 48 | +"distinct":stdlib.DistinctFunc, |
| 49 | +"element":stdlib.ElementFunc, |
| 50 | +"chunklist":stdlib.ChunklistFunc, |
| 51 | +"flatten":stdlib.FlattenFunc, |
| 52 | +"floor":stdlib.FloorFunc, |
| 53 | +"format":stdlib.FormatFunc, |
| 54 | +"formatdate":stdlib.FormatDateFunc, |
| 55 | +"formatlist":stdlib.FormatListFunc, |
| 56 | +"indent":stdlib.IndentFunc, |
| 57 | +"index":funcs.IndexFunc,// stdlib.IndexFunc is not compatible |
| 58 | +"join":stdlib.JoinFunc, |
| 59 | +"jsondecode":stdlib.JSONDecodeFunc, |
| 60 | +"jsonencode":stdlib.JSONEncodeFunc, |
| 61 | +"keys":stdlib.KeysFunc, |
| 62 | +"length":funcs.LengthFunc, |
| 63 | +"list":funcs.ListFunc, |
| 64 | +"log":stdlib.LogFunc, |
| 65 | +"lookup":funcs.LookupFunc, |
| 66 | +"lower":stdlib.LowerFunc, |
| 67 | +"map":funcs.MapFunc, |
| 68 | +"matchkeys":funcs.MatchkeysFunc, |
| 69 | +"max":stdlib.MaxFunc, |
| 70 | +"md5":funcs.Md5Func, |
| 71 | +"merge":stdlib.MergeFunc, |
| 72 | +"min":stdlib.MinFunc, |
| 73 | +"parseint":stdlib.ParseIntFunc, |
| 74 | +"pow":stdlib.PowFunc, |
| 75 | +"range":stdlib.RangeFunc, |
| 76 | +"regex":stdlib.RegexFunc, |
| 77 | +"regexall":stdlib.RegexAllFunc, |
| 78 | +"replace":funcs.ReplaceFunc, |
| 79 | +"reverse":stdlib.ReverseListFunc, |
| 80 | +"rsadecrypt":funcs.RsaDecryptFunc, |
| 81 | +"setintersection":stdlib.SetIntersectionFunc, |
| 82 | +"setproduct":stdlib.SetProductFunc, |
| 83 | +"setsubtract":stdlib.SetSubtractFunc, |
| 84 | +"setunion":stdlib.SetUnionFunc, |
| 85 | +"sha1":funcs.Sha1Func, |
| 86 | +"sha256":funcs.Sha256Func, |
| 87 | +"sha512":funcs.Sha512Func, |
| 88 | +"signum":stdlib.SignumFunc, |
| 89 | +"slice":stdlib.SliceFunc, |
| 90 | +"sort":stdlib.SortFunc, |
| 91 | +"split":stdlib.SplitFunc, |
| 92 | +"strrev":stdlib.ReverseFunc, |
| 93 | +"substr":stdlib.SubstrFunc, |
| 94 | +"timestamp":funcs.TimestampFunc, |
| 95 | +"timeadd":stdlib.TimeAddFunc, |
| 96 | +"title":stdlib.TitleFunc, |
| 97 | +"tostring":funcs.MakeToFunc(cty.String), |
| 98 | +"tonumber":funcs.MakeToFunc(cty.Number), |
| 99 | +"tobool":funcs.MakeToFunc(cty.Bool), |
| 100 | +"toset":funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)), |
| 101 | +"tolist":funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)), |
| 102 | +"tomap":funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)), |
| 103 | +"transpose":funcs.TransposeFunc, |
| 104 | +"trim":stdlib.TrimFunc, |
| 105 | +"trimprefix":stdlib.TrimPrefixFunc, |
| 106 | +"trimspace":stdlib.TrimSpaceFunc, |
| 107 | +"trimsuffix":stdlib.TrimSuffixFunc, |
| 108 | +"try":tryfunc.TryFunc, |
| 109 | +"upper":stdlib.UpperFunc, |
| 110 | +"urlencode":funcs.URLEncodeFunc, |
| 111 | +"uuid":funcs.UUIDFunc, |
| 112 | +"uuidv5":funcs.UUIDV5Func, |
| 113 | +"values":stdlib.ValuesFunc, |
| 114 | +"yamldecode":ctyyaml.YAMLDecodeFunc, |
| 115 | +"yamlencode":ctyyaml.YAMLEncodeFunc, |
| 116 | +"zipmap":stdlib.ZipmapFunc, |
| 117 | +} |
| 118 | + |
| 119 | +// the below functions are not safe for usage in the context of tfparse, as their return |
| 120 | +// values may change depending on the underlying filesystem. |
| 121 | +stubFileFunctions=map[string]function.Function{ |
| 122 | +"abspath":makeStubFunction("abspath",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 123 | +"file":makeStubFunction("file",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 124 | +"fileexists":makeStubFunction("fileexists",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 125 | +"fileset":makeStubFunction("fileset",cty.String, function.Parameter{Name:"path",Type:cty.String}, function.Parameter{Name:"pattern",Type:cty.String}), |
| 126 | +"filebase64":makeStubFunction("filebase64",cty.String, function.Parameter{Name:"path",Type:cty.String}, function.Parameter{Name:"pattern",Type:cty.String}), |
| 127 | +"filebase64sha256":makeStubFunction("filebase64sha256",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 128 | +"filebase64sha512":makeStubFunction("filebase64sha512",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 129 | +"filemd5":makeStubFunction("filemd5",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 130 | +"filesha1":makeStubFunction("filesha1",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 131 | +"filesha256":makeStubFunction("filesha256",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 132 | +"filesha512":makeStubFunction("filesha512",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 133 | +"pathexpand":makeStubFunction("pathexpand",cty.String, function.Parameter{Name:"path",Type:cty.String}), |
| 134 | +} |
| 135 | + |
| 136 | +allFunctions=mergeMaps(safeFunctions,stubFileFunctions) |
| 137 | +) |
| 138 | + |
| 139 | +// mergeMaps returns a new map which is the result of merging each key and value |
| 140 | +// of all maps in ms, in order. Successive maps may override values of previous |
| 141 | +// maps. |
| 142 | +funcmergeMaps[K,Vcomparable](ms...map[K]V)map[K]V { |
| 143 | +merged:=make(map[K]V) |
| 144 | +for_,m:=rangems { |
| 145 | +fork,v:=rangem { |
| 146 | +merged[k]=v |
| 147 | +} |
| 148 | +} |
| 149 | +returnmerged |
| 150 | +} |
| 151 | + |
| 152 | +// makeStubFunction returns a function.Function with the required return type and parameters |
| 153 | +// that will always return an unknown type and an error. |
| 154 | +funcmakeStubFunction(namestring,returnType cty.Type,params...function.Parameter) function.Function { |
| 155 | +varspec function.Spec |
| 156 | +spec.Params=params |
| 157 | +spec.Type=function.StaticReturnType(returnType) |
| 158 | +spec.Impl=func(_ []cty.Value,_ cty.Type) (cty.Value,error) { |
| 159 | +returncty.UnknownVal(returnType),xerrors.Errorf("function %q may not be used here",name) |
| 160 | +} |
| 161 | +returnfunction.New(&spec) |
| 162 | +} |