Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4ba0b39

Browse files
authored
feat(provisioner/terraform/tfparse): add support for built-in Terraform functions (#16183)
Relates to#15977Adds support for some functions in `tfparse` (only functions that do notreference local files).NOTE: for now, I'm importing trivy-iac. If we prefer to avoid a littledependency, I can do a little copying instead.
1 parent7bef4df commit4ba0b39

File tree

6 files changed

+222
-5
lines changed

6 files changed

+222
-5
lines changed

‎coderd/templateversions_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
489489
"foo": "bar",
490490
"a": var.a,
491491
"b": data.coder_parameter.b.value,
492-
"test":try(null_resource.test.name, "whatever"),
492+
"test":pathexpand("~/file.txt"),
493493
}
494494
}`,
495495
},
496-
expectError:`Function calls not allowed; Functionsmay not becalled here.`,
496+
expectError:`function "pathexpand"may not beused here`,
497497
},
498498
// We will allow coder_workspace_tags to set the scope on a template version import job
499499
// BUT the user ID will be ultimately determined by the API key in the scope.

‎go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,11 @@ require (
437437
sigs.k8s.io/yamlv1.4.0// indirect
438438
)
439439

440+
require (
441+
github.com/aquasecurity/trivy-iacv0.8.0
442+
github.com/zclconf/go-cty-yamlv1.0.3
443+
)
444+
440445
require (
441446
github.com/DataDog/datadog-agent/pkg/protov0.58.0// indirect
442447
github.com/DataDog/datadog-agent/pkg/tracev0.58.0// indirect
@@ -445,6 +450,8 @@ require (
445450
github.com/DataDog/go-runtime-metrics-internalv0.0.0-20241106155157-194426bbbd59// indirect
446451
github.com/DataDog/go-sqllexerv0.0.14// indirect
447452
github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributesv0.20.0// indirect
453+
github.com/apparentlymart/go-cidrv1.1.0// indirect
454+
github.com/bmatcuk/doublestar/v4v4.6.1// indirect
448455
github.com/cihub/seelogv0.0.0-20170130134532-f561c5e57575// indirect
449456
github.com/json-iterator/gov1.1.12// indirect
450457
github.com/lufia/plan9statsv0.0.0-20220913051719-115f729f3c8c// indirect

‎go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,13 @@ github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7X
8888
github.com/andybalholm/brotliv1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
8989
github.com/anmitsu/go-shlexv0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
9090
github.com/anmitsu/go-shlexv0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
91+
github.com/apparentlymart/go-cidrv1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
92+
github.com/apparentlymart/go-cidrv1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
9193
github.com/apparentlymart/go-textseg/v12v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
9294
github.com/apparentlymart/go-textseg/v15v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
9395
github.com/apparentlymart/go-textseg/v15v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
96+
github.com/aquasecurity/trivy-iacv0.8.0 h1:NKFhk/BTwQ0jIh4t74V8+6UIGUvPlaxO9HPlSMQi3fo=
97+
github.com/aquasecurity/trivy-iacv0.8.0/go.mod h1:ARiMeNqcaVWOXJmp8hmtMnNm/Jd836IOmDBUW5r4KEk=
9498
github.com/arbovm/levenshteinv0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
9599
github.com/arbovm/levenshteinv0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
96100
github.com/armon/circbufv0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs=
@@ -167,6 +171,8 @@ github.com/bep/tmc v0.5.1/go.mod h1:tGYHN8fS85aJPhDLgXETVKp+PR382OvFi2+q2GkGsq0=
167171
github.com/bgentry/speakeasyv0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
168172
github.com/bgentry/speakeasyv0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E=
169173
github.com/bgentry/speakeasyv0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
174+
github.com/bmatcuk/doublestar/v4v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
175+
github.com/bmatcuk/doublestar/v4v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
170176
github.com/bool64/sharedv0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
171177
github.com/bool64/sharedv0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
172178
github.com/bramvdbogaerde/go-scpv1.5.0 h1:a9BinAjTfQh273eh7vd3qUgmBC+bx+3TRDtkZWmIpzM=
@@ -965,6 +971,8 @@ github.com/zclconf/go-cty v1.16.0 h1:xPKEhst+BW5D0wxebMZkxgapvOE/dw7bFTlgSc9nD6w
965971
github.com/zclconf/go-ctyv1.16.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
966972
github.com/zclconf/go-cty-debugv0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
967973
github.com/zclconf/go-cty-debugv0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
974+
github.com/zclconf/go-cty-yamlv1.0.3 h1:og/eOQ7lvA/WWhHGFETVWNduJM7Rjsv2RRpx1sdFMLc=
975+
github.com/zclconf/go-cty-yamlv1.0.3/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
968976
github.com/zeebo/assertv1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
969977
github.com/zeebo/assertv1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
970978
github.com/zeebo/errsv1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs=
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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+
}

‎provisioner/terraform/tfparse/tfparse.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ func BuildEvalContext(vars map[string]string, params map[string]string) *hcl.Eva
477477
// The default function map for Terraform is not exposed, so we would essentially
478478
// have to re-implement or copy the entire map or a subset thereof.
479479
// ref: https://github.com/hashicorp/terraform/blob/e044e569c5bc81f82e9a4d7891f37c6fbb0a8a10/internal/lang/functions.go#L54
480-
Functions:nil,
480+
Functions:Functions(),
481481
}
482482
iflen(varDefaultsM)!=0 {
483483
evalCtx.Variables["var"]=cty.MapVal(varDefaultsM)

‎provisioner/terraform/tfparse/tfparse_test.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,52 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) {
416416
expectError:`There is no variable named "foo_bar"`,
417417
},
418418
{
419-
name:"main.tf with functions in workspace tags",
419+
name:"main.tf withallowedfunctions in workspace tags",
420420
files:map[string]string{
421421
"main.tf":`
422422
provider "foo" {}
423423
resource "foo_bar" "baz" {
424424
name = "foobar"
425425
}
426+
locals {
427+
some_path = pathexpand("file.txt")
428+
}
429+
variable "region" {
430+
type = string
431+
default = "us"
432+
}
433+
data "coder_parameter" "unrelated" {
434+
name = "unrelated"
435+
type = "list(string)"
436+
default = jsonencode(["a", "b"])
437+
}
438+
data "coder_parameter" "az" {
439+
name = "az"
440+
type = "string"
441+
default = "a"
442+
}
443+
data "coder_workspace_tags" "tags" {
444+
tags = {
445+
"platform" = "kubernetes",
446+
"cluster" = "${"devel"}${"opers"}"
447+
"region" = try(split(".", var.region)[1], "placeholder")
448+
"az" = try(split(".", data.coder_parameter.az.value)[1], "placeholder")
449+
}
450+
}`,
451+
},
452+
expectTags:map[string]string{"platform":"kubernetes","cluster":"developers","region":"placeholder","az":"placeholder"},
453+
},
454+
{
455+
name:"main.tf with disallowed functions in workspace tags",
456+
files:map[string]string{
457+
"main.tf":`
458+
provider "foo" {}
459+
resource "foo_bar" "baz" {
460+
name = "foobar"
461+
}
462+
locals {
463+
some_path = pathexpand("file.txt")
464+
}
426465
variable "region" {
427466
type = string
428467
default = "region.us"
@@ -443,11 +482,12 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) {
443482
"cluster" = "${"devel"}${"opers"}"
444483
"region" = try(split(".", var.region)[1], "placeholder")
445484
"az" = try(split(".", data.coder_parameter.az.value)[1], "placeholder")
485+
"some_path" = pathexpand("~/file.txt")
446486
}
447487
}`,
448488
},
449489
expectTags:nil,
450-
expectError:`Function calls not allowed; Functionsmay not becalled here.`,
490+
expectError:`function "pathexpand"may not beused here`,
451491
},
452492
{
453493
name:"supported types",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp