Skip to content

Commit

Permalink
Strip secret values from Configure
Browse files Browse the repository at this point in the history
  • Loading branch information
iwahbe committed Sep 24, 2024
1 parent 22452e6 commit 2b3f3c7
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 8 deletions.
1 change: 1 addition & 0 deletions pf/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/pulumi/pulumi-terraform-bridge/v3 v3.91.0
github.com/pulumi/pulumi-terraform-bridge/x/muxer v0.0.8
github.com/stretchr/testify v1.9.0
pgregory.net/rapid v0.6.1
)

require (
Expand Down
37 changes: 37 additions & 0 deletions pf/internal/plugin/provider_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package plugin
import (
"context"

"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
Expand Down Expand Up @@ -80,5 +81,41 @@ func (p providerThunk) Configure(
if ctx.Value(setupConfigureKey) != nil {
return plugin.ConfigureResponse{}, nil
}
req.Inputs = removeSecrets(req.Inputs)
contract.Assertf(!req.Inputs.ContainsSecrets(),
"Inputs to configure should not contain secrets")
return p.GrpcProvider.Configure(ctx, req)
}

func removeSecrets(v resource.PropertyMap) resource.PropertyMap {
var remove func(resource.PropertyValue) resource.PropertyValue
remove = func(v resource.PropertyValue) resource.PropertyValue {
switch {
case v.IsArray():
arr := make([]resource.PropertyValue, 0, len(v.ArrayValue()))
for _, v := range v.ArrayValue() {
arr = append(arr, remove(v))
}
return resource.NewProperty(arr)
case v.IsObject():
obj := make(resource.PropertyMap, len(v.ObjectValue()))
for k, v := range v.ObjectValue() {
obj[k] = remove(v)
}
return resource.NewProperty(obj)
case v.IsComputed():
return resource.MakeComputed(remove(v.Input().Element))
case v.IsOutput():
o := v.OutputValue()
o.Secret = false
o.Element = remove(o.Element)
return resource.NewProperty(o)
case v.IsSecret():
return remove(v.SecretValue().Element)
default:
return v
}
}

return remove(resource.NewProperty(v)).ObjectValue()
}
87 changes: 87 additions & 0 deletions pf/tests/provider_configure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,90 @@ func TestJSONNestedConfigure(t *testing.T) {
}
}`)
}

func TestJSONNestedConfigureWithSecrets(t *testing.T) {
server, err := newProviderServer(t, testprovider.SyntheticTestBridgeProvider())
require.NoError(t, err)
replay.ReplaySequence(t, server, `
[
{
"method": "/pulumirpc.ResourceProvider/Configure",
"request": {
"args": {
"stringConfigProp": "{\"4dabf18193072939515e22adb298388d\":\"1b47061264138c4ac30d75fd1eb44270\",\"value\":\"secret-example\"}",
"mapNestedProp": "{\"k1\":{\"4dabf18193072939515e22adb298388d\":\"1b47061264138c4ac30d75fd1eb44270\",\"value\":1},\"k2\":2}",
"listNestedProps": "[{\"4dabf18193072939515e22adb298388d\":\"1b47061264138c4ac30d75fd1eb44270\",\"value\":true},false]"
}
},
"response": {
"supportsPreview": true,
"acceptResources": true
}
},
{
"method": "/pulumirpc.ResourceProvider/Create",
"request": {
"urn": "urn:pulumi:test-stack::basicprogram::testbridge:index/testres:TestConfigRes::r1",
"preview": false
},
"response": {
"id": "id-1",
"properties": {
"configCopy": "secret-example",
"id": "id-1"
}
}
}
]`)
}

func TestConfigureWithSecrets(t *testing.T) {
server, err := newProviderServer(t, testprovider.SyntheticTestBridgeProvider())
require.NoError(t, err)
replay.ReplaySequence(t, server, `
[
{
"method": "/pulumirpc.ResourceProvider/Configure",
"request": {
"args": {
"stringConfigProp": {
"4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
"value": "secret-example"
},
"mapNestedProp": {
"k1": {
"4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
"value": 1
},
"k2": 2
},
"listNestedProps": [
{
"4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
"value": true
},
false
]
}
},
"response": {
"supportsPreview": true,
"acceptResources": true
}
},
{
"method": "/pulumirpc.ResourceProvider/Create",
"request": {
"urn": "urn:pulumi:test-stack::basicprogram::testbridge:index/testres:TestConfigRes::r1",
"preview": false
},
"response": {
"id": "id-1",
"properties": {
"configCopy": "secret-example",
"id": "id-1"
}
}
}
]`)
}
16 changes: 8 additions & 8 deletions pkg/tfbridge/config_encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,11 @@ func (*ConfigEncoding) tryUnwrapSecret(encoded any) (any, bool) {
}

func (enc *ConfigEncoding) convertStringToPropertyValue(s string, typ shim.ValueType) (resource.PropertyValue, error) {
// If the schema expects a string, we can just return this as-is.
if typ == shim.TypeString {
return resource.NewStringProperty(s), nil
}

// Otherwise, we will attempt to deserialize the input string as JSON and convert the result into a Pulumi
// We attempt to deserialize the input string as JSON and convert the result into a Pulumi
// property. If the input string is empty, we will return an appropriate zero value.
//
// We need to do this for all incoming strings, even if the target type is also a string. This is how
// we account for secret or computed string values.
if s == "" {
return enc.zeroValue(typ), nil
}
Expand Down Expand Up @@ -102,10 +100,12 @@ func (enc *ConfigEncoding) convertStringToPropertyValue(s string, typ shim.Value

func (*ConfigEncoding) zeroValue(typ shim.ValueType) resource.PropertyValue {
switch typ {
case shim.TypeString:
return resource.NewProperty("")
case shim.TypeBool:
return resource.NewPropertyValue(false)
return resource.NewProperty(false)
case shim.TypeInt, shim.TypeFloat:
return resource.NewPropertyValue(0)
return resource.NewProperty[float64](0)
case shim.TypeList, shim.TypeSet:
return resource.NewPropertyValue([]interface{}{})
default:
Expand Down

0 comments on commit 2b3f3c7

Please sign in to comment.