lang/funcs: Conversion functions can handle sensitive values
In order to avoid updating every one of our existing functions with explicit support for sensitive values, there's a default rule in the functions system which makes the result of a function sensitive if any of its arguments contain sensitive values. We were applying that default to the various type conversion functions, like tomap and tolist, which meant that converting a complex-typed value with a sensitive value anywhere inside it would result in a wholly-sensitive result. That's unnecessarily conservative because the cty conversion layer (which these functions are wrapping) already knows how to handle sensitivity in a more precise way. Therefore we can opt in to handling marked values (which Terraform uses for sensitivity) here and the only special thing we need to do is handle errors related to sensitive values differently, so we won't print their values out literally in case of an error (and so that the attempt to print them out literally won't panic trying to extract the marked values).
This commit is contained in:
parent
8f233cde4c
commit
14336ae6f8
|
@ -28,8 +28,9 @@ func MakeToFunc(wantTy cty.Type) function.Function {
|
||||||
// messages to be more appropriate for an explicit type
|
// messages to be more appropriate for an explicit type
|
||||||
// conversion, whereas the cty function system produces
|
// conversion, whereas the cty function system produces
|
||||||
// messages aimed at _implicit_ type conversions.
|
// messages aimed at _implicit_ type conversions.
|
||||||
Type: cty.DynamicPseudoType,
|
Type: cty.DynamicPseudoType,
|
||||||
AllowNull: true,
|
AllowNull: true,
|
||||||
|
AllowMarked: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Type: func(args []cty.Value) (cty.Type, error) {
|
Type: func(args []cty.Value) (cty.Type, error) {
|
||||||
|
@ -65,6 +66,11 @@ func MakeToFunc(wantTy cty.Type) function.Function {
|
||||||
// once we note that the value isn't either "true" or "false".
|
// once we note that the value isn't either "true" or "false".
|
||||||
gotTy := args[0].Type()
|
gotTy := args[0].Type()
|
||||||
switch {
|
switch {
|
||||||
|
case args[0].ContainsMarked():
|
||||||
|
// Generic message so we won't inadvertently disclose
|
||||||
|
// information about sensitive values.
|
||||||
|
return cty.NilVal, function.NewArgErrorf(0, "cannot convert this sensitive %s to %s", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint())
|
||||||
|
|
||||||
case gotTy == cty.String && wantTy == cty.Bool:
|
case gotTy == cty.String && wantTy == cty.Bool:
|
||||||
what := "string"
|
what := "string"
|
||||||
if !args[0].IsNull() {
|
if !args[0].IsNull() {
|
||||||
|
|
|
@ -32,6 +32,18 @@ func TestTo(t *testing.T) {
|
||||||
cty.NullVal(cty.String),
|
cty.NullVal(cty.String),
|
||||||
``,
|
``,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("a").Mark("boop"),
|
||||||
|
cty.String,
|
||||||
|
cty.StringVal("a").Mark("boop"),
|
||||||
|
``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.NullVal(cty.String).Mark("boop"),
|
||||||
|
cty.String,
|
||||||
|
cty.NullVal(cty.String).Mark("boop"),
|
||||||
|
``,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
cty.True,
|
cty.True,
|
||||||
cty.String,
|
cty.String,
|
||||||
|
@ -44,12 +56,24 @@ func TestTo(t *testing.T) {
|
||||||
cty.DynamicVal,
|
cty.DynamicVal,
|
||||||
`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
|
`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("a").Mark("boop"),
|
||||||
|
cty.Bool,
|
||||||
|
cty.DynamicVal,
|
||||||
|
`cannot convert this sensitive string to bool`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
cty.StringVal("a"),
|
cty.StringVal("a"),
|
||||||
cty.Number,
|
cty.Number,
|
||||||
cty.DynamicVal,
|
cty.DynamicVal,
|
||||||
`cannot convert "a" to number; given string must be a decimal representation of a number`,
|
`cannot convert "a" to number; given string must be a decimal representation of a number`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("a").Mark("boop"),
|
||||||
|
cty.Number,
|
||||||
|
cty.DynamicVal,
|
||||||
|
`cannot convert this sensitive string to number`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
cty.NullVal(cty.String),
|
cty.NullVal(cty.String),
|
||||||
cty.Number,
|
cty.Number,
|
||||||
|
@ -86,6 +110,30 @@ func TestTo(t *testing.T) {
|
||||||
cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("true")}),
|
cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("true")}),
|
||||||
``,
|
``,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
|
||||||
|
cty.Map(cty.String),
|
||||||
|
cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
|
||||||
|
``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
|
||||||
|
cty.Map(cty.String),
|
||||||
|
cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
|
||||||
|
``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
|
||||||
|
cty.List(cty.String),
|
||||||
|
cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
|
||||||
|
``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
|
||||||
|
cty.List(cty.String),
|
||||||
|
cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
|
||||||
|
``,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
cty.EmptyTupleVal,
|
cty.EmptyTupleVal,
|
||||||
cty.String,
|
cty.String,
|
||||||
|
|
Loading…
Reference in New Issue