Repository: pulumi/pulumi-terraform-bridge
Pull request #1327 (2023-08-04 16:39:25)

Remove panic on imports for TF Plugin Framework
This PR removes the panics on getDefaultValue on the Type, Attr, and Block schemas in the TF Plugin Framework schemashim, as they are causing issues when importing resources using the Plugin Framework.

Instead, we emit nil and an error, which we log using our standard logger, allowing the code to run without panic. 
I have built and run this against the [user reported panic](pulumi/pulumi-cloudflare#460) and verified that this resolves the issue.

We will file a followup issue to implement properly handling default values directly inside the pf package.

Fixes pulumi/pulumi-cloudflare#460.

- Return nil instead of panic from block schema
- resolve merge conflict
- fix linting
- Remove panic from Type schema
- Return a custom error message and log it during getDefaultValue
- Create global err and fix logic. Return explicit error if error is not nil or ErrSchemaDefaultValue


github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/84b90af..b8c93d0) with merge commit f726fa4cd00a53ff25db90e8c50f14a1d3879d2f
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/0552d68..33970cb) with merge commit f726fa4cd00a53ff25db90e8c50f14a1d3879d2f
t0yv0: Let's use this one https://github.com/pulumi/pulumi-terraform-bridge/issues/1329
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/3288de0..3545de5) with merge commit 1355b8d97dfea0f37406ebc3a6f95b28c2fb69ba
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/617044f..db3b803) with merge commit 1355b8d97dfea0f37406ebc3a6f95b28c2fb69ba

Patch:
diff --git a/pf/internal/schemashim/attr_schema.go b/pf/internal/schemashim/attr_schema.go
index f816f9fd..708be965 100644
--- a/pf/internal/schemashim/attr_schema.go
+++ b/pf/internal/schemashim/attr_schema.go
@@ -16,6 +16,7 @@ package schemashim
 
 import (
 	"fmt"
+	bridge "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
 
 	pfattr "github.com/hashicorp/terraform-plugin-framework/attr"
 	"github.com/hashicorp/terraform-plugin-framework/types"
@@ -58,7 +59,7 @@ func (*attrSchema) DefaultFunc() shim.SchemaDefaultFunc {
 func (*attrSchema) DefaultValue() (interface{}, error) {
 	// DefaultValue() should not be called by tfgen, but it currently may be called by ExtractInputsFromOutputs, so
 	// returning nil is better than a panic.
-	return nil, nil
+	return nil, bridge.ErrSchemaDefaultValue
 }
 
 func (s *attrSchema) Description() string {
diff --git a/pf/internal/schemashim/block_schema.go b/pf/internal/schemashim/block_schema.go
index 9208589f..bf01f554 100644
--- a/pf/internal/schemashim/block_schema.go
+++ b/pf/internal/schemashim/block_schema.go
@@ -16,6 +16,7 @@ package schemashim
 
 import (
 	"fmt"
+	bridge "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
 
 	"github.com/hashicorp/terraform-plugin-framework/types"
 	"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
@@ -120,7 +121,9 @@ func (*blockSchema) DefaultFunc() shim.SchemaDefaultFunc {
 }
 
 func (*blockSchema) DefaultValue() (interface{}, error) {
-	panic("DefaultValue() should not be called during schema generation")
+	// DefaultValue() should not be called by tfgen, but it currently may be called by ExtractInputsFromOutputs, so
+	// returning nil is better than a panic.
+	return nil, bridge.ErrSchemaDefaultValue
 }
 
 func (*blockSchema) ExactlyOneOf() []string {
diff --git a/pf/internal/schemashim/type_schema.go b/pf/internal/schemashim/type_schema.go
index 51d1d633..9d5b2161 100644
--- a/pf/internal/schemashim/type_schema.go
+++ b/pf/internal/schemashim/type_schema.go
@@ -17,8 +17,8 @@ package schemashim
 import (
 	pfattr "github.com/hashicorp/terraform-plugin-framework/attr"
 	"github.com/hashicorp/terraform-plugin-framework/types"
-
 	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/pfutils"
+	bridge "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
 	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
 	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
 )
@@ -93,7 +93,9 @@ func (*typeSchema) DefaultFunc() shim.SchemaDefaultFunc {
 }
 
 func (*typeSchema) DefaultValue() (interface{}, error) {
-	panic("DefaultValue() should not be called during schema generation")
+	// DefaultValue() should not be called by tfgen, but it currently may be called by ExtractInputsFromOutputs, so
+	// returning nil is better than a panic.
+	return nil, bridge.ErrSchemaDefaultValue
 }
 
 func (*typeSchema) Description() string {
diff --git a/pkg/tfbridge/schema.go b/pkg/tfbridge/schema.go
index f1b87d2b..b1ff4b37 100644
--- a/pkg/tfbridge/schema.go
+++ b/pkg/tfbridge/schema.go
@@ -27,12 +27,11 @@ import (
 	"github.com/golang/glog"
 	pbstruct "github.com/golang/protobuf/ptypes/struct"
 	"github.com/pkg/errors"
+	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
+	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
 	"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"
-
-	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
-	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
 )
 
 // This file deals with translating between the Pulumi representations of a resource's configuration and state and the
@@ -190,6 +189,10 @@ const defaultsKey = "__defaults"
 // marshaled back to assets by MakeTerraformOutputs.
 type AssetTable map[*SchemaInfo]resource.PropertyValue
 
+// ErrSchemaDefaultValue is used internally to avoid a panic in pf/schemashim.DefaultValue().
+// See https://github.com/pulumi/pulumi-terraform-bridge/issues/1329
+var ErrSchemaDefaultValue = fmt.Errorf("default values not supported")
+
 // nameRequiresDeleteBeforeReplace returns true if the given set of resource inputs includes an autonameable
 // property with a value that was not populated by the autonamer.
 func nameRequiresDeleteBeforeReplace(news resource.PropertyMap, olds resource.PropertyMap,
@@ -1426,9 +1429,20 @@ func extractInputs(oldInput, newState resource.PropertyValue, tfs shim.Schema, p
 }
 
 func getDefaultValue(tfs shim.Schema, ps *SchemaInfo) interface{} {
-	if dv, _ := tfs.DefaultValue(); dv != nil {
+	dv, err := tfs.DefaultValue()
+	if err != nil {
+		if errors.Is(err, ErrSchemaDefaultValue) {
+			// Log error output but continue otherwise.
+			// This avoids a panic on preview. See https://github.com/pulumi/pulumi-terraform-bridge/issues/1329.
+			glog.V(9).Infof(err.Error())
+		} else {
+			return err
+		}
+	}
+	if dv != nil {
 		return dv
 	}
+
 	// TODO: We should inspect SchemaInfo.Default for the default value as well
 	// if ps != nil {
 	// 	return ps.Default


Test patch:
diff --git a/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/bridge-metadata.json b/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/bridge-metadata.json
index fa6c8f78..0663fec6 100644
--- a/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/bridge-metadata.json
+++ b/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/bridge-metadata.json
@@ -3,6 +3,7 @@
         "resources": {
             "testbridge:index/testnest:Testnest": "testbridge_testnest",
             "testbridge:index/testres:AutoNameRes": "testbridge_autoname_res",
+            "testbridge:index/testnestattr:Testnestattr": "testbridge_testnestattr",
             "testbridge:index/testres:Privst": "testbridge_privst",
             "testbridge:index/testres:TestConfigRes": "testbridge_testconfigres",
             "testbridge:index/testres:TestDefaultInfoRes": "testbridge_test_default_info_res",
@@ -65,4 +66,4 @@
             "stringDefaultinfoConfigProp": "string_defaultinfo_config_prop"
         }
     }
-}
\ No newline at end of file
+}
diff --git a/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json b/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json
index 6672efb6..cc0d3294 100644
--- a/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json
+++ b/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json
@@ -75,6 +75,84 @@
             },
             "type": "object"
         },
+        "testbridge:index/TestnestService:TestnestService": {
+            "properties": {
+                "intport": {
+                    "type": "integer"
+                },
+                "ports": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/types/testbridge:index/TestnestServicePort:TestnestServicePort"
+                    }
+                },
+                "protocol": {
+                    "type": "string"
+                }
+            },
+            "type": "object",
+            "required": [
+                "intport",
+                "ports",
+                "protocol"
+            ]
+        },
+        "testbridge:index/TestnestServicePort:TestnestServicePort": {
+            "properties": {
+                "handlers": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "port": {
+                    "type": "integer"
+                }
+            },
+            "type": "object",
+            "required": [
+                "port"
+            ]
+        },
+        "testbridge:index/TestnestattrService:TestnestattrService": {
+            "properties": {
+                "intport": {
+                    "type": "integer"
+                },
+                "ports": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/types/testbridge:index/TestnestattrServicePort:TestnestattrServicePort"
+                    }
+                },
+                "protocol": {
+                    "type": "string"
+                }
+            },
+            "type": "object",
+            "required": [
+                "intport",
+                "ports",
+                "protocol"
+            ]
+        },
+        "testbridge:index/TestnestattrServicePort:TestnestattrServicePort": {
+            "properties": {
+                "handlers": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "port": {
+                    "type": "integer"
+                }
+            },
+            "type": "object",
+            "required": [
+                "port"
+            ]
+        },
         "testbridge:index/TestresService:TestresService": {
             "properties": {
                 "intport": {
@@ -187,6 +265,13 @@
                         "$ref": "#/types/testbridge:index/TestnestRule:TestnestRule"
                     },
                     "description": "List of rules to apply to the ruleset.\n"
+                },
+                "services": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/types/testbridge:index/TestnestService:TestnestService"
+                    },
+                    "description": "services: tests ListNestedAttributes support\n"
                 }
             },
             "inputProperties": {
@@ -196,6 +281,13 @@
                         "$ref": "#/types/testbridge:index/TestnestRule:TestnestRule"
                     },
                     "description": "List of rules to apply to the ruleset.\n"
+                },
+                "services": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/types/testbridge:index/TestnestService:TestnestService"
+                    },
+                    "description": "services: tests ListNestedAttributes support\n"
                 }
             },
             "stateInputs": {
@@ -207,6 +299,46 @@
                             "$ref": "#/types/testbridge:index/TestnestRule:TestnestRule"
                         },
                         "description": "List of rules to apply to the ruleset.\n"
+                    },
+                    "services": {
+                        "type": "array",
+                        "items": {
+                            "$ref": "#/types/testbridge:index/TestnestService:TestnestService"
+                        },
+                        "description": "services: tests ListNestedAttributes support\n"
+                    }
+                },
+                "type": "object"
+            }
+        },
+        "testbridge:index/testnestattr:Testnestattr": {
+            "properties": {
+                "services": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/types/testbridge:index/TestnestattrService:TestnestattrService"
+                    },
+                    "description": "services: tests ListNestedAttributes support\n"
+                }
+            },
+            "inputProperties": {
+                "services": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/types/testbridge:index/TestnestattrService:TestnestattrService"
+                    },
+                    "description": "services: tests ListNestedAttributes support\n"
+                }
+            },
+            "stateInputs": {
+                "description": "Input properties used for looking up and filtering Testnestattr resources.\n",
+                "properties": {
+                    "services": {
+                        "type": "array",
+                        "items": {
+                            "$ref": "#/types/testbridge:index/TestnestattrService:TestnestattrService"
+                        },
+                        "description": "services: tests ListNestedAttributes support\n"
                     }
                 },
                 "type": "object"
diff --git a/pf/tests/internal/testprovider/testbridge.go b/pf/tests/internal/testprovider/testbridge.go
index 23e76699..73b3583f 100644
--- a/pf/tests/internal/testprovider/testbridge.go
+++ b/pf/tests/internal/testprovider/testbridge.go
@@ -79,6 +79,9 @@ func SyntheticTestBridgeProvider() tfbridge.ProviderInfo {
 					},
 				},
 			},
+			"testbridge_testnestattr": {
+				Tok: "testbridge:index/testnestattr:Testnestattr",
+			},
 			"testbridge_testcompres":   {Tok: "testbridge:index/testres:Testcompres"},
 			"testbridge_testconfigres": {Tok: "testbridge:index/testres:TestConfigRes"},
 
@@ -199,6 +202,7 @@ func (p *syntheticProvider) Resources(context.Context) []func() resource.Resourc
 	return []func() resource.Resource{
 		newTestres,
 		newTestnest,
+		newTestnestattr,
 		newTestCompRes,
 		newTestConfigRes,
 		newTestDefaultInfoRes,
diff --git a/pf/tests/internal/testprovider/testbridge_resource_testnest.go b/pf/tests/internal/testprovider/testbridge_resource_testnest.go
index d8e83e4e..ea712b11 100644
--- a/pf/tests/internal/testprovider/testbridge_resource_testnest.go
+++ b/pf/tests/internal/testprovider/testbridge_resource_testnest.go
@@ -20,11 +20,15 @@ import (
 	"github.com/hashicorp/terraform-plugin-framework/resource"
 	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
 	rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
 )
 
 type testnest struct{}
 
 var _ resource.Resource = &testnest{}
+var _ resource.ResourceWithImportState = &testnest{}
 
 func newTestnest() resource.Resource {
 	return &testnest{}
@@ -32,6 +36,50 @@ func newTestnest() resource.Resource {
 
 func (*testnest) schema() rschema.Schema {
 	return rschema.Schema{
+		Attributes: map[string]rschema.Attribute{
+			"id": schema.StringAttribute{
+				Computed: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			// Example borrowed from https://github.com/fly-apps/terraform-provider-fly/blob/28438713f2bdf08dbd0aa2fae9d74baaca9845f1/internal/provider/machine_resource.go#L176
+			"services": schema.ListNestedAttribute{
+				MarkdownDescription: "services: tests ListNestedAttributes support",
+				Optional:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"ports": schema.ListNestedAttribute{
+							MarkdownDescription: "External ports and handlers",
+							Required:            true,
+							NestedObject: schema.NestedAttributeObject{
+								Attributes: map[string]schema.Attribute{
+									"port": schema.Int64Attribute{
+										MarkdownDescription: "External port",
+										Required:            true,
+									},
+									"handlers": schema.ListAttribute{
+										ElementType:         types.StringType,
+										MarkdownDescription: "How the edge should process requests",
+										Optional:            true,
+									},
+								},
+							},
+						},
+						"protocol": schema.StringAttribute{
+							MarkdownDescription: "network protocol",
+							Required:            true,
+						},
+						// TODO internal_port gets mangled to internalPort by Pulumi renaming and does
+						// not work end-to-end yet.
+						"intport": schema.Int64Attribute{
+							MarkdownDescription: "Port application listens on internally",
+							Required:            true,
+						},
+					},
+				},
+			},
+		},
 		Blocks: map[string]schema.Block{
 			"rules": schema.ListNestedBlock{
 				MarkdownDescription: "List of rules to apply to the ruleset.",
@@ -98,3 +146,24 @@ func (e *testnest) Update(ctx context.Context, req resource.UpdateRequest, resp
 func (e *testnest) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
 	panic("unimplemented")
 }
+
+// ImportState is called when the provider must import the state of a resource instance. This method must return enough
+// state so the Read method can properly refresh the full resource.
+//
+// If setting an attribute with the import identifier, it is recommended to use the ImportStatePassthroughID() call in
+// this method.
+func (e *testnest) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	type ruleModel struct{}
+
+	type model struct {
+		ID       types.String   `tfsdk:"id"`
+		Rules    []ruleModel    `tfsdk:"rules"`
+		Services []ServiceModel `tfsdk:"services"`
+	}
+
+	resp.Diagnostics = resp.State.Set(ctx, &model{
+		ID:       types.StringValue(req.ID),
+		Rules:    []ruleModel{},
+		Services: []ServiceModel{},
+	})
+}
diff --git a/pf/tests/internal/testprovider/testbridge_resource_testnestattr.go b/pf/tests/internal/testprovider/testbridge_resource_testnestattr.go
new file mode 100644
index 00000000..9c313d47
--- /dev/null
+++ b/pf/tests/internal/testprovider/testbridge_resource_testnestattr.go
@@ -0,0 +1,130 @@
+// Copyright 2016-2023, Pulumi Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package testprovider
+
+import (
+	"context"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type testnestattr struct{}
+
+var _ resource.Resource = &testnestattr{}
+var _ resource.ResourceWithImportState = &testnestattr{}
+
+func newTestnestattr() resource.Resource {
+	return &testnestattr{}
+}
+
+func (*testnestattr) schema() rschema.Schema {
+	return rschema.Schema{
+		Attributes: map[string]rschema.Attribute{
+			"id": schema.StringAttribute{
+				Computed: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			// Example borrowed from https://github.com/fly-apps/terraform-provider-fly/blob/28438713f2bdf08dbd0aa2fae9d74baaca9845f1/internal/provider/machine_resource.go#L176
+			"services": schema.ListNestedAttribute{
+				MarkdownDescription: "services: tests ListNestedAttributes support",
+				Optional:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"ports": schema.ListNestedAttribute{
+							MarkdownDescription: "External ports and handlers",
+							Required:            true,
+							NestedObject: schema.NestedAttributeObject{
+								Attributes: map[string]schema.Attribute{
+									"port": schema.Int64Attribute{
+										MarkdownDescription: "External port",
+										Required:            true,
+									},
+									"handlers": schema.ListAttribute{
+										ElementType:         types.StringType,
+										MarkdownDescription: "How the edge should process requests",
+										Optional:            true,
+									},
+								},
+							},
+						},
+						"protocol": schema.StringAttribute{
+							MarkdownDescription: "network protocol",
+							Required:            true,
+						},
+						// TODO internal_port gets mangled to internalPort by Pulumi renaming and does
+						// not work end-to-end yet.
+						"intport": schema.Int64Attribute{
+							MarkdownDescription: "Port application listens on internally",
+							Required:            true,
+							PlanModifiers: []planmodifier.Int64{
+								int64planmodifier.UseStateForUnknown(),
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func (e *testnestattr) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_testnestattr"
+}
+
+func (e *testnestattr) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = e.schema()
+}
+
+func (e *testnestattr) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	panic("unimplemented")
+}
+
+func (e *testnestattr) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+	panic("unimplemented")
+}
+
+func (e *testnestattr) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	panic("unimplemented")
+}
+
+func (e *testnestattr) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+	panic("unimplemented")
+}
+
+// ImportState is called when the provider must import the state of a resource instance. This method must return enough
+// state so the Read method can properly refresh the full resource.
+//
+// If setting an attribute with the import identifier, it is recommended to use the ImportStatePassthroughID() call in
+// this method.
+func (e *testnestattr) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+
+	type model struct {
+		ID       types.String   `tfsdk:"id"`
+		Services []ServiceModel `tfsdk:"services"`
+	}
+
+	resp.Diagnostics = resp.State.Set(ctx, &model{
+		ID:       types.StringValue(req.ID),
+		Services: []ServiceModel{},
+	})
+}
diff --git a/pf/tests/provider_read_test.go b/pf/tests/provider_read_test.go
index 2cacb580..dc58378e 100644
--- a/pf/tests/provider_read_test.go
+++ b/pf/tests/provider_read_test.go
@@ -179,3 +179,52 @@ func TestImportRandomPassword(t *testing.T) {
 	}`
 	testutils.Replay(t, server, testCase)
 }
+
+func TestImportingResourcesWithBlocks(t *testing.T) {
+	// Importing a resource that has blocks such as Testnest resource used to panic. Ensure that it minimally
+	// succeeds.
+	server := newProviderServer(t, testprovider.SyntheticTestBridgeProvider())
+	testCase := `
+	{
+	  "method": "/pulumirpc.ResourceProvider/Read",
+	  "request": {
+	    "id": "zone/929e99f1a4152bfe415bbb3b29d1a227/my-ruleset-id",
+	    "urn": "urn:pulumi:testing::testing::testbridge:index/testnest:Testnest::myresource",
+	    "properties": {}
+	  },
+	  "response": {
+            "id": "*",
+            "inputs": "*",
+            "properties": {
+               	"id": "*",
+               	"rules": [],
+				"services": []
+            }
+          }
+	}`
+	testutils.Replay(t, server, testCase)
+}
+
+func TestImportingResourcesWithNestedAttributes(t *testing.T) {
+	// Importing a resource that has attribute blocks such as Testnest resource used to panic. Ensure that it minimally
+	// succeeds.
+	server := newProviderServer(t, testprovider.SyntheticTestBridgeProvider())
+	testCase := `
+	{
+	  "method": "/pulumirpc.ResourceProvider/Read",
+	  "request": {
+	    "id": "zone/929e99f1a4152bfe415bbb3b29d1a227/my-ruleset-id",
+	    "urn": "urn:pulumi:testing::testing::testbridge:index/testnestattr:Testnestattr::someresource",
+	    "properties": {}
+	  },
+	  "response": {
+		"id": "*",
+		"inputs": "*",
+		"properties": {
+			"id": "zone/929e99f1a4152bfe415bbb3b29d1a227/my-ruleset-id",
+			"services": []
+		}
+      }
+	}`
+	testutils.Replay(t, server, testCase)
+}