opentofu/helper/plugin/grpc_provisioner_test.go
James Bardin 49439d02d1 sanitize provisioner output strings
The grpc protocol requires strings to be valid utf8, but because
provisioners often don't have control over the command output, invalid
utf8 sequences can make it into the response causing grpc transport
errors.

Replace all invalid utf sequences with the standard utf replacement
character in the provisioner output. The code is a direct copy from the
go1.13 std library, and can be replaced with strings.ToValidUTF8 once
it's available.
2019-11-06 14:57:52 -05:00

83 lines
1.9 KiB
Go

package plugin
import (
"testing"
"unicode/utf8"
"github.com/golang/mock/gomock"
"github.com/hashicorp/terraform/helper/schema"
proto "github.com/hashicorp/terraform/internal/tfplugin5"
mockproto "github.com/hashicorp/terraform/plugin/mock_proto"
"github.com/hashicorp/terraform/terraform"
context "golang.org/x/net/context"
)
var _ proto.ProvisionerServer = (*GRPCProvisionerServer)(nil)
type validUTF8Matcher string
func (m validUTF8Matcher) Matches(x interface{}) bool {
resp := x.(*proto.ProvisionResource_Response)
return utf8.Valid([]byte(resp.Output))
}
func (m validUTF8Matcher) String() string {
return string(m)
}
func mockProvisionerServer(t *testing.T, c *gomock.Controller) *mockproto.MockProvisioner_ProvisionResourceServer {
server := mockproto.NewMockProvisioner_ProvisionResourceServer(c)
server.EXPECT().Send(
validUTF8Matcher("check for valid utf8"),
).Return(nil)
return server
}
// ensure that a provsioner cannot return invalid utf8 which isn't allowed in
// the grpc protocol.
func TestProvisionerInvalidUTF8(t *testing.T) {
p := &schema.Provisioner{
ConnSchema: map[string]*schema.Schema{
"foo": {
Type: schema.TypeString,
Optional: true,
},
},
Schema: map[string]*schema.Schema{
"foo": {
Type: schema.TypeInt,
Optional: true,
},
},
ApplyFunc: func(ctx context.Context) error {
out := ctx.Value(schema.ProvOutputKey).(terraform.UIOutput)
out.Output("invalid \xc3\x28\n")
return nil
},
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
srv := mockProvisionerServer(t, ctrl)
cfg := &proto.DynamicValue{
Msgpack: []byte("\x81\xa3foo\x01"),
}
conn := &proto.DynamicValue{
Msgpack: []byte("\x81\xa3foo\xa4host"),
}
provisionerServer := NewGRPCProvisionerServerShim(p)
req := &proto.ProvisionResource_Request{
Config: cfg,
Connection: conn,
}
if err := provisionerServer.ProvisionResource(req, srv); err != nil {
t.Fatal(err)
}
}