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