From 98b8abe4dd20c3956175c45554f9b382a49c90c1 Mon Sep 17 00:00:00 2001 From: Aaron Friel Date: Fri, 16 Dec 2022 15:39:54 -0800 Subject: [PATCH] fix(sdkgen/go): Convert before secret wrapping of inputs to prevent invalid cast Codegen for wrapping input properties as secrets performed an incorrect cast, as seen in Pulumi's AWS classic SDK. Using the sample program and the resource constructor described in #11664 as our test case, from `pulumi-aws/sdk/v5/go/aws/secretmanager/secretVersion.go`: ```go func NewSecretVersion(ctx *pulumi.Context, name string, args *SecretVersionArgs, opts ...pulumi.ResourceOption) (*SecretVersion, error) { if args == nil { return nil, errors.New("missing one or more required arguments") } if args.SecretId == nil { return nil, errors.New("invalid value for required argument 'SecretId'") } if args.SecretBinary != nil { 82: args.SecretBinary = pulumi.ToSecret(args.SecretBinary).(pulumi.StringPtrOutput) } if args.SecretString != nil { 85: args.SecretString = pulumi.ToSecret(args.SecretString).(pulumi.StringPtrOutput) } ``` `args.SecretBinary` is of type `pulumi.StringPtrInput` and `pulumi.ToSecret` returns `pulumi.Output` returns its input as an Output-wrapped value marked secret. As `StringPtrInput` is an interface accepting multiple input types, the return value would be either `pulumi.StringOutput` `pulumi.StringPtrOutput`. These are both concrete types, and casting to the incorrect one would panic. Fortunately we can cast back to the input type, as verified by building the new codegen and testing the Pulumi program in #11664. The new codegen below converts an input type `T` to `pulumi.Output`, then casts back to `T`. ```go func NewSecretVersion(ctx *pulumi.Context, // ... if args.SecretBinary != nil { 82: args.SecretBinary = pulumi.ToSecret(args.SecretBinary).(pulumi.StringPtrInput) } if args.SecretString != nil { 85: args.SecretString = pulumi.ToSecret(args.SecretString).(pulumi.StringPtrInput) } ``` --- ...ructors-when-secret-wrapping-input-arguments.yaml | 4 ++++ pkg/codegen/go/gen.go | 3 ++- .../go/foo/deeply/nested/module/resource.go | 2 +- .../nested-module/go/foo/nested/module/resource.go | 2 +- .../go/configstation/provider.go | 2 +- .../test/testdata/secrets/go/mypkg/resource.go | 12 ++++++------ .../simple-resource-schema/go/example/resource.go | 2 +- .../simple-yaml-schema/go/example/resource.go | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 changelog/pending/20221217--sdkgen-go--illegal-cast-in-resource-constructors-when-secret-wrapping-input-arguments.yaml diff --git a/changelog/pending/20221217--sdkgen-go--illegal-cast-in-resource-constructors-when-secret-wrapping-input-arguments.yaml b/changelog/pending/20221217--sdkgen-go--illegal-cast-in-resource-constructors-when-secret-wrapping-input-arguments.yaml new file mode 100644 index 000000000000..081414b1069a --- /dev/null +++ b/changelog/pending/20221217--sdkgen-go--illegal-cast-in-resource-constructors-when-secret-wrapping-input-arguments.yaml @@ -0,0 +1,4 @@ +changes: +- type: fix + scope: sdkgen/go + description: Illegal cast in resource constructors when secret-wrapping input arguments. diff --git a/pkg/codegen/go/gen.go b/pkg/codegen/go/gen.go index 135fff3d9f20..b54d470f1fa5 100644 --- a/pkg/codegen/go/gen.go +++ b/pkg/codegen/go/gen.go @@ -1763,7 +1763,8 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso // Setup secrets for _, p := range secretInputProps { fmt.Fprintf(w, "\tif args.%s != nil {\n", pkg.fieldName(r, p)) - fmt.Fprintf(w, "\t\targs.%[1]s = pulumi.ToSecret(args.%[1]s).(%[2]s)\n", pkg.fieldName(r, p), pkg.outputType(p.Type)) + + fmt.Fprintf(w, "\t\targs.%[1]s = pulumi.ToSecret(args.%[1]s).(%[2]s)\n", pkg.fieldName(r, p), pkg.inputType(p.Type)) fmt.Fprintf(w, "\t}\n") } if len(secretProps) > 0 { diff --git a/pkg/codegen/testing/test/testdata/nested-module-thirdparty/go/foo/deeply/nested/module/resource.go b/pkg/codegen/testing/test/testdata/nested-module-thirdparty/go/foo/deeply/nested/module/resource.go index 3aa183987c2a..260fcb5e7832 100644 --- a/pkg/codegen/testing/test/testdata/nested-module-thirdparty/go/foo/deeply/nested/module/resource.go +++ b/pkg/codegen/testing/test/testdata/nested-module-thirdparty/go/foo/deeply/nested/module/resource.go @@ -24,7 +24,7 @@ func NewResource(ctx *pulumi.Context, } if args.Baz != nil { - args.Baz = pulumi.ToSecret(args.Baz).(pulumi.StringPtrOutput) + args.Baz = pulumi.ToSecret(args.Baz).(pulumi.StringPtrInput) } secrets := pulumi.AdditionalSecretOutputs([]string{ "baz", diff --git a/pkg/codegen/testing/test/testdata/nested-module/go/foo/nested/module/resource.go b/pkg/codegen/testing/test/testdata/nested-module/go/foo/nested/module/resource.go index c001edaaae7f..bc9e7181905a 100644 --- a/pkg/codegen/testing/test/testdata/nested-module/go/foo/nested/module/resource.go +++ b/pkg/codegen/testing/test/testdata/nested-module/go/foo/nested/module/resource.go @@ -24,7 +24,7 @@ func NewResource(ctx *pulumi.Context, } if args.Bar != nil { - args.Bar = pulumi.ToSecret(args.Bar).(pulumi.StringPtrOutput) + args.Bar = pulumi.ToSecret(args.Bar).(pulumi.StringPtrInput) } secrets := pulumi.AdditionalSecretOutputs([]string{ "bar", diff --git a/pkg/codegen/testing/test/testdata/provider-config-schema/go/configstation/provider.go b/pkg/codegen/testing/test/testdata/provider-config-schema/go/configstation/provider.go index 31aaa998f1d6..40d7045b7199 100644 --- a/pkg/codegen/testing/test/testdata/provider-config-schema/go/configstation/provider.go +++ b/pkg/codegen/testing/test/testdata/provider-config-schema/go/configstation/provider.go @@ -26,7 +26,7 @@ func NewProvider(ctx *pulumi.Context, args.FavoriteColor = pulumi.StringPtr(getEnvOrDefault("", nil, "FAVE_COLOR").(string)) } if args.SecretSandwiches != nil { - args.SecretSandwiches = pulumi.ToSecret(args.SecretSandwiches).(config.SandwichArrayOutput) + args.SecretSandwiches = pulumi.ToSecret(args.SecretSandwiches).(config.SandwichArrayInput) } var resource Provider err := ctx.RegisterResource("pulumi:providers:configstation", name, args, &resource, opts...) diff --git a/pkg/codegen/testing/test/testdata/secrets/go/mypkg/resource.go b/pkg/codegen/testing/test/testdata/secrets/go/mypkg/resource.go index 3573b7a92695..3a28a855ab8d 100644 --- a/pkg/codegen/testing/test/testdata/secrets/go/mypkg/resource.go +++ b/pkg/codegen/testing/test/testdata/secrets/go/mypkg/resource.go @@ -48,22 +48,22 @@ func NewResource(ctx *pulumi.Context, return nil, errors.New("invalid value for required argument 'FooMap'") } if args.Config != nil { - args.Config = pulumi.ToSecret(args.Config).(ConfigOutput) + args.Config = pulumi.ToSecret(args.Config).(ConfigInput) } if args.ConfigArray != nil { - args.ConfigArray = pulumi.ToSecret(args.ConfigArray).(ConfigArrayOutput) + args.ConfigArray = pulumi.ToSecret(args.ConfigArray).(ConfigArrayInput) } if args.ConfigMap != nil { - args.ConfigMap = pulumi.ToSecret(args.ConfigMap).(ConfigMapOutput) + args.ConfigMap = pulumi.ToSecret(args.ConfigMap).(ConfigMapInput) } if args.Foo != nil { - args.Foo = pulumi.ToSecret(args.Foo).(pulumi.StringOutput) + args.Foo = pulumi.ToSecret(args.Foo).(pulumi.StringInput) } if args.FooArray != nil { - args.FooArray = pulumi.ToSecret(args.FooArray).(pulumi.StringArrayOutput) + args.FooArray = pulumi.ToSecret(args.FooArray).(pulumi.StringArrayInput) } if args.FooMap != nil { - args.FooMap = pulumi.ToSecret(args.FooMap).(pulumi.StringMapOutput) + args.FooMap = pulumi.ToSecret(args.FooMap).(pulumi.StringMapInput) } secrets := pulumi.AdditionalSecretOutputs([]string{ "config", diff --git a/pkg/codegen/testing/test/testdata/simple-resource-schema/go/example/resource.go b/pkg/codegen/testing/test/testdata/simple-resource-schema/go/example/resource.go index 67ae1dd2db01..68aeac4e1bce 100644 --- a/pkg/codegen/testing/test/testdata/simple-resource-schema/go/example/resource.go +++ b/pkg/codegen/testing/test/testdata/simple-resource-schema/go/example/resource.go @@ -25,7 +25,7 @@ func NewResource(ctx *pulumi.Context, } if args.Bar != nil { - args.Bar = pulumi.ToSecret(args.Bar).(pulumi.StringPtrOutput) + args.Bar = pulumi.ToSecret(args.Bar).(pulumi.StringPtrInput) } secrets := pulumi.AdditionalSecretOutputs([]string{ "bar", diff --git a/pkg/codegen/testing/test/testdata/simple-yaml-schema/go/example/resource.go b/pkg/codegen/testing/test/testdata/simple-yaml-schema/go/example/resource.go index 061dadab2cbc..3df52ff9e4fe 100644 --- a/pkg/codegen/testing/test/testdata/simple-yaml-schema/go/example/resource.go +++ b/pkg/codegen/testing/test/testdata/simple-yaml-schema/go/example/resource.go @@ -24,7 +24,7 @@ func NewResource(ctx *pulumi.Context, } if args.Bar != nil { - args.Bar = pulumi.ToSecret(args.Bar).(pulumi.StringPtrOutput) + args.Bar = pulumi.ToSecret(args.Bar).(pulumi.StringPtrInput) } secrets := pulumi.AdditionalSecretOutputs([]string{ "bar",