Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lang/funcs: Redact sensitive values from function errors #30067

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/lang/funcs/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ var LookupFunc = function.New(&function.Spec{
return defaultVal.WithMarks(markses...), nil
}

return cty.UnknownVal(cty.DynamicPseudoType).WithMarks(markses...), fmt.Errorf(
"lookup failed to find '%s'", lookupKey)
return cty.UnknownVal(cty.DynamicPseudoType), fmt.Errorf(
"lookup failed to find key %s", redactIfSensitive(lookupKey, keyMarks))
},
})

Expand Down
41 changes: 41 additions & 0 deletions internal/lang/funcs/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"math"
"testing"

"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/zclconf/go-cty/cty"
)

Expand Down Expand Up @@ -899,6 +900,46 @@ func TestLookup(t *testing.T) {
}
}

func TestLookup_error(t *testing.T) {
simpleMap := cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
})

tests := map[string]struct {
Values []cty.Value
WantErr string
}{
"failed to find non-sensitive key": {
[]cty.Value{
simpleMap,
cty.StringVal("boop"),
},
`lookup failed to find key "boop"`,
},
"failed to find sensitive key": {
[]cty.Value{
simpleMap,
cty.StringVal("boop").Mark(marks.Sensitive),
},
"lookup failed to find key (sensitive value)",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
_, err := Lookup(test.Values...)

if err == nil {
t.Fatal("succeeded; want error")
}

if err.Error() != test.WantErr {
t.Errorf("wrong error\ngot: %#v\nwant: %#v", err, test.WantErr)
}
})
}
}

func TestMatchkeys(t *testing.T) {
tests := []struct {
Keys cty.Value
Expand Down
22 changes: 12 additions & 10 deletions internal/lang/funcs/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,24 @@ import (
var Base64DecodeFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "str",
Type: cty.String,
Name: "str",
Type: cty.String,
AllowMarked: true,
},
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
s := args[0].AsString()
str, strMarks := args[0].Unmark()
s := str.AsString()
sDec, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode base64 data '%s'", s)
return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode base64 data %s", redactIfSensitive(s, strMarks))
}
if !utf8.Valid([]byte(sDec)) {
log.Printf("[DEBUG] the result of decoding the provided string is not valid UTF-8: %s", sDec)
log.Printf("[DEBUG] the result of decoding the provided string is not valid UTF-8: %s", redactIfSensitive(sDec, strMarks))
return cty.UnknownVal(cty.String), fmt.Errorf("the result of decoding the provided string is not valid UTF-8")
}
return cty.StringVal(string(sDec)), nil
return cty.StringVal(string(sDec)).WithMarks(strMarks), nil
},
})

Expand Down Expand Up @@ -125,7 +127,7 @@ var TextDecodeBase64Func = function.New(&function.Spec{
case base64.CorruptInputError:
return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given value is has an invalid base64 symbol at offset %d", int(err))
default:
return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid source string: %T", err)
return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid source string: %w", err)
}

}
Expand Down Expand Up @@ -156,13 +158,13 @@ var Base64GzipFunc = function.New(&function.Spec{
var b bytes.Buffer
gz := gzip.NewWriter(&b)
if _, err := gz.Write([]byte(s)); err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to write gzip raw data: '%s'", s)
return cty.UnknownVal(cty.String), fmt.Errorf("failed to write gzip raw data: %w", err)
}
if err := gz.Flush(); err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to flush gzip writer: '%s'", s)
return cty.UnknownVal(cty.String), fmt.Errorf("failed to flush gzip writer: %w", err)
}
if err := gz.Close(); err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to close gzip writer: '%s'", s)
return cty.UnknownVal(cty.String), fmt.Errorf("failed to close gzip writer: %w", err)
}
return cty.StringVal(base64.StdEncoding.EncodeToString(b.Bytes())), nil
},
Expand Down
40 changes: 40 additions & 0 deletions internal/lang/funcs/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"testing"

"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/zclconf/go-cty/cty"
)

Expand All @@ -18,6 +19,11 @@ func TestBase64Decode(t *testing.T) {
cty.StringVal("abc123!?$*&()'-=@~"),
false,
},
{
cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+").Mark(marks.Sensitive),
cty.StringVal("abc123!?$*&()'-=@~").Mark(marks.Sensitive),
false,
},
{ // Invalid base64 data decoding
cty.StringVal("this-is-an-invalid-base64-data"),
cty.UnknownVal(cty.String),
Expand Down Expand Up @@ -50,6 +56,40 @@ func TestBase64Decode(t *testing.T) {
}
}

func TestBase64Decode_error(t *testing.T) {
tests := map[string]struct {
String cty.Value
WantErr string
}{
"invalid base64": {
cty.StringVal("dfg"),
`failed to decode base64 data "dfg"`,
},
"sensitive invalid base64": {
cty.StringVal("dfg").Mark(marks.Sensitive),
`failed to decode base64 data (sensitive value)`,
},
"invalid utf-8": {
cty.StringVal("whee"),
"the result of decoding the provided string is not valid UTF-8",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
_, err := Base64Decode(test.String)

if err == nil {
t.Fatal("succeeded; want error")
}

if err.Error() != test.WantErr {
t.Errorf("wrong error result\ngot: %#v\nwant: %#v", err.Error(), test.WantErr)
}
})
}
}

func TestBase64Encode(t *testing.T) {
tests := []struct {
String cty.Value
Expand Down
Loading