Skip to content

Commit 1c71bb5

Browse files
authored
v1.10 backport: Functions that allow marks must also deal with unknown values (#35985)
* backport of commit 1e01124 * backport of commit c4741dc * backport of commit a51be5e * backport of commit 651a80f * backport of commit 2ae0174 * backport of commit ac54255 * backport of commit 04aee4e * backport of commit 297972e
1 parent 4efabfc commit 1c71bb5

15 files changed

Lines changed: 203 additions & 90 deletions

internal/lang/funcs/collection.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var LengthFunc = function.New(&function.Spec{
4040
coll := args[0]
4141
collTy := args[0].Type()
4242
marks := coll.Marks()
43+
4344
switch {
4445
case collTy == cty.DynamicPseudoType:
4546
return cty.UnknownVal(cty.Number).WithMarks(marks), nil
@@ -222,14 +223,16 @@ var IndexFunc = function.New(&function.Spec{
222223
var LookupFunc = function.New(&function.Spec{
223224
Params: []function.Parameter{
224225
{
225-
Name: "inputMap",
226-
Type: cty.DynamicPseudoType,
227-
AllowMarked: true,
226+
Name: "inputMap",
227+
Type: cty.DynamicPseudoType,
228+
AllowMarked: true,
229+
AllowUnknown: true,
228230
},
229231
{
230-
Name: "key",
231-
Type: cty.String,
232-
AllowMarked: true,
232+
Name: "key",
233+
Type: cty.String,
234+
AllowMarked: true,
235+
AllowUnknown: true,
233236
},
234237
},
235238
VarParam: &function.Parameter{
@@ -276,7 +279,7 @@ var LookupFunc = function.New(&function.Spec{
276279
}
277280
},
278281
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
279-
var defaultVal cty.Value
282+
defaultVal := cty.NullVal(retType)
280283
defaultValueSet := false
281284

282285
if len(args) == 3 {
@@ -297,12 +300,13 @@ var LookupFunc = function.New(&function.Spec{
297300
if len(keyMarks) > 0 {
298301
markses = append(markses, keyMarks)
299302
}
300-
lookupKey := keyVal.AsString()
301303

302-
if !mapVar.IsKnown() {
304+
if !(mapVar.IsKnown() && keyVal.IsKnown()) {
303305
return cty.UnknownVal(retType).WithMarks(markses...), nil
304306
}
305307

308+
lookupKey := keyVal.AsString()
309+
306310
if mapVar.Type().IsObjectType() {
307311
if mapVar.Type().HasAttribute(lookupKey) {
308312
return mapVar.GetAttr(lookupKey).WithMarks(markses...), nil

internal/lang/funcs/collection_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ func TestLength(t *testing.T) {
169169
}).Mark("secret"),
170170
cty.NumberIntVal(3).Mark("secret"),
171171
},
172+
{ // Marked objects return a marked length
173+
cty.UnknownVal(cty.String).Mark("secret"),
174+
cty.UnknownVal(cty.Number).Refine().NotNull().NumberRangeLowerBound(cty.NumberIntVal(0), true).NewValue().Mark("secret"),
175+
},
172176
{ // Marks on object attribute values do not propagate
173177
cty.ObjectVal(map[string]cty.Value{
174178
"a": cty.StringVal("hello").Mark("a"),
@@ -884,6 +888,15 @@ func TestLookup(t *testing.T) {
884888
cty.StringVal("beep").Mark("a"),
885889
false,
886890
},
891+
{ // propagate marks from unknown map
892+
[]cty.Value{
893+
cty.UnknownVal(cty.Map(cty.String)).Mark("a"),
894+
cty.StringVal("boop").Mark("b"),
895+
cty.StringVal("nope"),
896+
},
897+
cty.UnknownVal(cty.String).Mark("a").Mark("b"),
898+
false,
899+
},
887900
}
888901

889902
for _, test := range tests {

internal/lang/funcs/conversion.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func MakeToFunc(wantTy cty.Type) function.Function {
3737
AllowNull: true,
3838
AllowMarked: true,
3939
AllowDynamicType: true,
40+
AllowUnknown: true,
4041
},
4142
},
4243
Type: func(args []cty.Value) (cty.Type, error) {
@@ -61,8 +62,10 @@ func MakeToFunc(wantTy cty.Type) function.Function {
6162
return wantTy, nil
6263
},
6364
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
64-
// We didn't set "AllowUnknown" on our argument, so it is guaranteed
65-
// to be known here but may still be null.
65+
if !args[0].IsKnown() {
66+
return cty.UnknownVal(retType).WithSameMarks(args[0]), nil
67+
}
68+
6669
ret, err := convert.Convert(args[0], retType)
6770
if err != nil {
6871
val, _ := args[0].UnmarkDeep()

internal/lang/funcs/conversion_test.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,24 @@ func TestTo(t *testing.T) {
181181
cty.DynamicVal,
182182
`incompatible object type for conversion: attribute "foo" is required`,
183183
},
184+
{
185+
cty.UnknownVal(cty.Object(map[string]cty.Type{"foo": cty.String})).Mark(marks.Ephemeral).Mark("boop"),
186+
cty.Map(cty.String),
187+
cty.UnknownVal(cty.Map(cty.String)).Mark(marks.Ephemeral).Mark("boop"),
188+
``,
189+
},
190+
{
191+
cty.ObjectVal(map[string]cty.Value{
192+
"foo": cty.StringVal("hello"),
193+
"bar": cty.StringVal("world").Mark("beep"),
194+
}).Mark("boop"),
195+
cty.Map(cty.String),
196+
cty.MapVal(map[string]cty.Value{
197+
"foo": cty.StringVal("hello"),
198+
"bar": cty.StringVal("world").Mark("beep"),
199+
}).Mark("boop"),
200+
``,
201+
},
184202
}
185203

186204
for _, test := range tests {
@@ -322,13 +340,15 @@ func TestEphemeralAsNull(t *testing.T) {
322340
{
323341
cty.ObjectVal(map[string]cty.Value{
324342
"addr": cty.StringVal("127.0.0.1:12654").Mark(marks.Ephemeral),
325-
"greet": cty.StringVal("hello"),
343+
"greet": cty.StringVal("hello").Mark(marks.Sensitive),
326344
"happy": cty.True,
345+
"both": cty.NumberIntVal(2).WithMarks(cty.NewValueMarks(marks.Sensitive, marks.Ephemeral)),
327346
}),
328347
cty.ObjectVal(map[string]cty.Value{
329348
"addr": cty.NullVal(cty.String),
330-
"greet": cty.StringVal("hello"),
349+
"greet": cty.StringVal("hello").Mark(marks.Sensitive),
331350
"happy": cty.True,
351+
"both": cty.NullVal(cty.Number).Mark(marks.Sensitive),
332352
}),
333353
},
334354
}

internal/lang/funcs/encoding.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ import (
2121
var Base64DecodeFunc = function.New(&function.Spec{
2222
Params: []function.Parameter{
2323
{
24-
Name: "str",
25-
Type: cty.String,
26-
AllowMarked: true,
24+
Name: "str",
25+
Type: cty.String,
26+
AllowMarked: true,
27+
AllowUnknown: true,
2728
},
2829
},
2930
Type: function.StaticReturnType(cty.String),
3031
RefineResult: refineNotNull,
3132
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
3233
str, strMarks := args[0].Unmark()
34+
if !str.IsKnown() {
35+
return cty.UnknownVal(cty.String).WithMarks(strMarks), nil
36+
}
37+
3338
s := str.AsString()
3439
sDec, err := base64.StdEncoding.DecodeString(s)
3540
if err != nil {

internal/lang/funcs/encoding_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ func TestBase64Decode(t *testing.T) {
3737
cty.UnknownVal(cty.String),
3838
true,
3939
},
40+
// unknown marked
41+
{
42+
cty.UnknownVal(cty.String).Mark("a").Mark("b"),
43+
cty.UnknownVal(cty.String).RefineNotNull().Mark("a").Mark("b"),
44+
false,
45+
},
4046
}
4147

4248
for _, test := range tests {

internal/lang/funcs/filesystem.go

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,21 @@ func MakeFileFunc(baseDir string, encBase64 bool) function.Function {
2828
return function.New(&function.Spec{
2929
Params: []function.Parameter{
3030
{
31-
Name: "path",
32-
Type: cty.String,
33-
AllowMarked: true,
31+
Name: "path",
32+
Type: cty.String,
33+
AllowMarked: true,
34+
AllowUnknown: true,
3435
},
3536
},
3637
Type: function.StaticReturnType(cty.String),
3738
RefineResult: refineNotNull,
3839
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
3940
pathArg, pathMarks := args[0].Unmark()
41+
42+
if !pathArg.IsKnown() {
43+
return cty.UnknownVal(cty.String).WithMarks(pathMarks), nil
44+
}
45+
4046
path := pathArg.AsString()
4147
src, err := readFileBytes(baseDir, path, pathMarks)
4248
if err != nil {
@@ -94,13 +100,16 @@ func MakeTemplateFileFunc(baseDir string, funcsCb func() (funcs map[string]funct
94100
return function.New(&function.Spec{
95101
Params: []function.Parameter{
96102
{
97-
Name: "path",
98-
Type: cty.String,
99-
AllowMarked: true,
103+
Name: "path",
104+
Type: cty.String,
105+
AllowMarked: true,
106+
AllowUnknown: true,
100107
},
101108
{
102-
Name: "vars",
103-
Type: cty.DynamicPseudoType,
109+
Name: "vars",
110+
Type: cty.DynamicPseudoType,
111+
AllowMarked: true,
112+
AllowUnknown: true,
104113
},
105114
},
106115
Type: func(args []cty.Value) (cty.Type, error) {
@@ -125,12 +134,19 @@ func MakeTemplateFileFunc(baseDir string, funcsCb func() (funcs map[string]funct
125134
},
126135
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
127136
pathArg, pathMarks := args[0].Unmark()
137+
138+
vars, varsMarks := args[1].UnmarkDeep()
139+
140+
if !pathArg.IsKnown() {
141+
return cty.UnknownVal(retType).WithMarks(pathMarks, varsMarks), nil
142+
}
143+
128144
expr, tmplMarks, err := loadTmpl(pathArg.AsString(), pathMarks)
129145
if err != nil {
130146
return cty.DynamicVal, err
131147
}
132-
result, err := renderTmpl(expr, args[1])
133-
return result.WithMarks(tmplMarks), err
148+
result, err := renderTmpl(expr, vars)
149+
return result.WithMarks(tmplMarks, varsMarks), err
134150
},
135151
})
136152

@@ -142,15 +158,21 @@ func MakeFileExistsFunc(baseDir string) function.Function {
142158
return function.New(&function.Spec{
143159
Params: []function.Parameter{
144160
{
145-
Name: "path",
146-
Type: cty.String,
147-
AllowMarked: true,
161+
Name: "path",
162+
Type: cty.String,
163+
AllowMarked: true,
164+
AllowUnknown: true,
148165
},
149166
},
150167
Type: function.StaticReturnType(cty.Bool),
151168
RefineResult: refineNotNull,
152169
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
153170
pathArg, pathMarks := args[0].Unmark()
171+
172+
if !pathArg.IsKnown() {
173+
return cty.UnknownVal(cty.Bool).WithMarks(pathMarks), nil
174+
}
175+
154176
path := pathArg.AsString()
155177
path, err := homedir.Expand(path)
156178
if err != nil {
@@ -210,24 +232,30 @@ func MakeFileSetFunc(baseDir string) function.Function {
210232
return function.New(&function.Spec{
211233
Params: []function.Parameter{
212234
{
213-
Name: "path",
214-
Type: cty.String,
215-
AllowMarked: true,
235+
Name: "path",
236+
Type: cty.String,
237+
AllowMarked: true,
238+
AllowUnknown: true,
216239
},
217240
{
218-
Name: "pattern",
219-
Type: cty.String,
220-
AllowMarked: true,
241+
Name: "pattern",
242+
Type: cty.String,
243+
AllowMarked: true,
244+
AllowUnknown: true,
221245
},
222246
},
223247
Type: function.StaticReturnType(cty.Set(cty.String)),
224248
RefineResult: refineNotNull,
225249
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
226250
pathArg, pathMarks := args[0].Unmark()
227-
path := pathArg.AsString()
228251
patternArg, patternMarks := args[1].Unmark()
229-
pattern := patternArg.AsString()
230252

253+
if !pathArg.IsKnown() || !patternArg.IsKnown() {
254+
return cty.UnknownVal(retType).WithMarks(pathMarks, patternMarks), nil
255+
}
256+
257+
path := pathArg.AsString()
258+
pattern := patternArg.AsString()
231259
marks := []cty.ValueMarks{pathMarks, patternMarks}
232260

233261
if !filepath.IsAbs(path) {

internal/lang/funcs/filesystem_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ func TestFile(t *testing.T) {
2929
cty.StringVal("Hello World"),
3030
``,
3131
},
32+
{
33+
cty.UnknownVal(cty.String).Mark(marks.Sensitive),
34+
cty.UnknownVal(cty.String).RefineNotNull().Mark(marks.Sensitive),
35+
``,
36+
},
3237
{
3338
cty.StringVal("testdata/icon.png"),
3439
cty.NilVal,
@@ -199,6 +204,38 @@ func TestTemplateFile(t *testing.T) {
199204
cty.StringVal("Hello World").Mark(marks.Sensitive),
200205
``,
201206
},
207+
{
208+
cty.StringVal("testdata/list.tmpl").Mark("path"),
209+
cty.ObjectVal(map[string]cty.Value{
210+
"list": cty.ListVal([]cty.Value{
211+
cty.StringVal("a"),
212+
cty.StringVal("b").Mark("var"),
213+
cty.StringVal("c"),
214+
}),
215+
}),
216+
cty.StringVal("- a\n- b\n- c\n").Mark("path").Mark("var"),
217+
``,
218+
},
219+
{
220+
cty.StringVal("testdata/list.tmpl").Mark("path"),
221+
cty.ObjectVal(map[string]cty.Value{
222+
"list": cty.ListVal([]cty.Value{
223+
cty.StringVal("a"),
224+
cty.UnknownVal(cty.String).Mark("var"),
225+
cty.StringVal("c"),
226+
}),
227+
}),
228+
cty.UnknownVal(cty.String).RefineNotNull().Mark("path").Mark("var"),
229+
``,
230+
},
231+
{
232+
cty.UnknownVal(cty.String).Mark("path"),
233+
cty.ObjectVal(map[string]cty.Value{
234+
"key": cty.StringVal("value").Mark("var"),
235+
}),
236+
cty.DynamicVal.Mark("path").Mark("var"),
237+
``,
238+
},
202239
}
203240

204241
funcs := map[string]function.Function{
@@ -277,6 +314,11 @@ func TestFileExists(t *testing.T) {
277314
cty.BoolVal(false),
278315
`failed to stat (sensitive value)`,
279316
},
317+
{
318+
cty.UnknownVal(cty.String).Mark(marks.Sensitive),
319+
cty.UnknownVal(cty.Bool).RefineNotNull().Mark(marks.Sensitive),
320+
``,
321+
},
280322
}
281323

282324
// Ensure "unreadable" directory cannot be listed during the test run
@@ -509,6 +551,18 @@ func TestFileSet(t *testing.T) {
509551
}),
510552
``,
511553
},
554+
{
555+
cty.StringVal("testdata"),
556+
cty.UnknownVal(cty.String),
557+
cty.UnknownVal(cty.Set(cty.String)).RefineNotNull(),
558+
``,
559+
},
560+
{
561+
cty.StringVal("testdata"),
562+
cty.UnknownVal(cty.String).Mark(marks.Sensitive),
563+
cty.UnknownVal(cty.Set(cty.String)).RefineNotNull().Mark(marks.Sensitive),
564+
``,
565+
},
512566
}
513567

514568
for _, test := range tests {

0 commit comments

Comments
 (0)