Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/unreleased/BUG FIXES-20250922-175341.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: BUG FIXES
body: 'all: Added an additional validation check to ensure the resource identity object is not null.'
time: 2025-09-22T17:53:41.039656-04:00
custom:
Issue: "1193"
11 changes: 11 additions & 0 deletions internal/fwserver/server_createresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ func (s *Server) CreateResource(ctx context.Context, req *CreateResourceRequest,
return
}

if req.IdentitySchema != nil {
if resp.NewIdentity.Raw.IsFullyNull() {
resp.Diagnostics.AddError(
"Missing Resource Identity After Create",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource create. "+
"This is always an issue in the Terraform Provider and should be reported to the provider developers.",
)
return
}
}

semanticEqualityReq := SchemaSemanticEqualityRequest{
PriorData: fwschemadata.Data{
Description: fwschemadata.DataDescriptionPlan,
Expand Down
100 changes: 100 additions & 0 deletions internal/fwserver/server_createresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,106 @@ func TestServerCreateResource(t *testing.T) {
Private: testEmptyPrivate,
},
},
"response-invalid-nil-identity": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
},
request: &fwserver.CreateResourceRequest{
PlannedState: &tfsdk.Plan{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
IdentitySchema: testIdentitySchema,
ResourceSchema: testSchema,
Resource: &testprovider.ResourceWithIdentity{
Resource: &testprovider.Resource{
CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
resp.Identity.Raw = tftypes.NewValue(testIdentitySchema.Type().TerraformType(ctx), nil)
// Prevent missing resource state error diagnostic
var data testSchemaData

resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
},
},
},
},
expectedResponse: &fwserver.CreateResourceResponse{
Diagnostics: []diag.Diagnostic{
diag.NewErrorDiagnostic(
"Missing Resource Identity After Create",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource create. "+
"This is always an issue in the Terraform Provider and should be reported to the provider developers.",
),
},
NewIdentity: &tfsdk.ResourceIdentity{
Raw: tftypes.NewValue(testIdentityType, nil),
Schema: testIdentitySchema,
},
NewState: &tfsdk.State{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
Private: testEmptyPrivate,
},
},
"response-invalid-null-identity": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
},
request: &fwserver.CreateResourceRequest{
PlannedState: &tfsdk.Plan{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
IdentitySchema: testIdentitySchema,
ResourceSchema: testSchema,
Resource: &testprovider.ResourceWithIdentity{
Resource: &testprovider.Resource{
CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
resp.Diagnostics.Append(resp.Identity.Set(ctx, testIdentitySchemaData{})...)
// Prevent missing resource state error diagnostic
var data testSchemaData

resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
},
},
},
},
expectedResponse: &fwserver.CreateResourceResponse{
Diagnostics: []diag.Diagnostic{
diag.NewErrorDiagnostic(
"Missing Resource Identity After Create",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource create. "+
"This is always an issue in the Terraform Provider and should be reported to the provider developers.",
),
},
NewIdentity: &tfsdk.ResourceIdentity{
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
"test_id": tftypes.NewValue(tftypes.String, nil),
}),
Schema: testIdentitySchema,
},
NewState: &tfsdk.State{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
Private: testEmptyPrivate,
},
},
"response-invalid-newidentity": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
Expand Down
11 changes: 11 additions & 0 deletions internal/fwserver/server_readresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@ func (s *Server) ReadResource(ctx context.Context, req *ReadResourceRequest, res
}
}

if req.IdentitySchema != nil {
if resp.NewIdentity.Raw.IsFullyNull() {
resp.Diagnostics.AddError(
"Missing Resource Identity After Read",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource read. "+
"This is always an issue in the Terraform Provider and should be reported to the provider developers.",
)
return
}
}

semanticEqualityReq := SchemaSemanticEqualityRequest{
PriorData: fwschemadata.Data{
Description: fwschemadata.DataDescriptionState,
Expand Down
34 changes: 34 additions & 0 deletions internal/fwserver/server_readresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ func TestServerReadResource(t *testing.T) {
Schema: testIdentitySchema,
}

testEmptyIdentity := &tfsdk.ResourceIdentity{
Schema: testIdentitySchema,
Raw: tftypes.NewValue(testIdentitySchema.Type().TerraformType(context.Background()), nil),
}

testNewStateRemoved := &tfsdk.State{
Raw: tftypes.NewValue(testType, nil),
Schema: testSchema,
Expand Down Expand Up @@ -649,6 +654,35 @@ func TestServerReadResource(t *testing.T) {
Private: testEmptyPrivate,
},
},
"response-invalid-nil-identity": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
},
request: &fwserver.ReadResourceRequest{
CurrentState: testCurrentState,
CurrentIdentity: nil,
IdentitySchema: testIdentitySchema,
Resource: &testprovider.ResourceWithIdentity{
Resource: &testprovider.Resource{
ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
resp.Identity = req.Identity
},
},
},
},
expectedResponse: &fwserver.ReadResourceResponse{
Diagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Missing Resource Identity After Read",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource read. "+
"This is always an issue in the Terraform Provider and should be reported to the provider developers.",
),
},
NewState: testCurrentState,
NewIdentity: testEmptyIdentity,
Private: testEmptyPrivate,
},
},
"response-identity-valid-update-null-currentidentity": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
Expand Down
11 changes: 11 additions & 0 deletions internal/fwserver/server_updateresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,17 @@ func (s *Server) UpdateResource(ctx context.Context, req *UpdateResourceRequest,
}
}

if req.IdentitySchema != nil {
if resp.NewIdentity.Raw.IsFullyNull() {
resp.Diagnostics.AddError(
"Missing Resource Identity After Update",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource update. "+
"This is always an issue in the Terraform Provider and should be reported to the provider developers.",
)
return
}
}

semanticEqualityReq := SchemaSemanticEqualityRequest{
PriorData: fwschemadata.Data{
Description: fwschemadata.DataDescriptionPlan,
Expand Down
110 changes: 110 additions & 0 deletions internal/fwserver/server_updateresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,116 @@ func TestServerUpdateResource(t *testing.T) {
Private: testEmptyPrivate,
},
},
"response-new-identity-nil": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
},
request: &fwserver.UpdateResourceRequest{
PlannedState: &tfsdk.Plan{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
PlannedIdentity: &tfsdk.ResourceIdentity{
Raw: tftypes.NewValue(testIdentityType, nil),
Schema: testIdentitySchema,
},
IdentitySchema: testIdentitySchema,
ResourceSchema: testSchema,
Resource: &testprovider.ResourceWithIdentity{
Resource: &testprovider.Resource{
UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data testSchemaData
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)

resp.Identity.Raw = tftypes.NewValue(testIdentityType, nil)

},
},
},
},
expectedResponse: &fwserver.UpdateResourceResponse{
Diagnostics: []diag.Diagnostic{
diag.NewErrorDiagnostic(
"Missing Resource Identity After Update",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource update. This is always an issue in the Terraform Provider and should be reported to the provider developers.",
),
},
NewIdentity: &tfsdk.ResourceIdentity{
Raw: tftypes.NewValue(testIdentityType, nil),
Schema: testIdentitySchema,
},
NewState: &tfsdk.State{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
Private: testEmptyPrivate,
},
},
"response-new-identity-null": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
},
request: &fwserver.UpdateResourceRequest{
PlannedState: &tfsdk.Plan{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
PlannedIdentity: &tfsdk.ResourceIdentity{
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
"test_id": tftypes.NewValue(tftypes.String, nil),
}),
Schema: testIdentitySchema,
},
IdentitySchema: testIdentitySchema,
ResourceSchema: testSchema,
Resource: &testprovider.ResourceWithIdentity{
Resource: &testprovider.Resource{
UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data testSchemaData
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)

var identityData testIdentitySchemaData
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
resp.Diagnostics.Append(resp.Identity.Set(ctx, &identityData)...)

},
},
},
},
expectedResponse: &fwserver.UpdateResourceResponse{
Diagnostics: []diag.Diagnostic{
diag.NewErrorDiagnostic(
"Missing Resource Identity After Update",
"The Terraform Provider unexpectedly returned no resource identity data after having no errors in the resource update. This is always an issue in the Terraform Provider and should be reported to the provider developers.",
),
},
NewIdentity: &tfsdk.ResourceIdentity{
Raw: tftypes.NewValue(testIdentityType, map[string]tftypes.Value{
"test_id": tftypes.NewValue(tftypes.String, nil),
}),
Schema: testIdentitySchema,
},
NewState: &tfsdk.State{
Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{
"test_computed": tftypes.NewValue(tftypes.String, nil),
"test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"),
}),
Schema: testSchema,
},
Private: testEmptyPrivate,
},
},
"response-newstate-semantic-equality": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
Expand Down