Skip to content

Commit

Permalink
Merge pull request #30067 from hashicorp/alisdair/redact-sensitive-va…
Browse files Browse the repository at this point in the history
…lues-from-function-errors

lang/funcs: Redact sensitive values from function errors
  • Loading branch information
alisdair authored Jan 4, 2022
2 parents 74761b2 + 5d7cb81 commit ef01d5d
Show file tree
Hide file tree
Showing 11 changed files with 394 additions and 123 deletions.
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

0 comments on commit ef01d5d

Please sign in to comment.