Skip to content

Conversation

austinvalle
Copy link
Member

@austinvalle austinvalle commented Sep 22, 2025

Related Issue

Description

There are some scenarios where an identity may be stored with all null values (a scenario that #1193 will eventually prevent from occurring), which should not be validated, since an identity with all null values is invalid.

The only real possibility of this happening ATM is with:

  • A migrated resource from SDKv2 which was storing all null attributes inadvertently
  • A framework resource that was storing all null attributes explicitly
  • A migrated resource from terraform-plugin-go which was storing all null attributes (there is no validation in the lower-level SDK)

Rollback Plan

  • If a change needs to be reverted, we will roll out an update to the code within 7 days.

Changes to Security Controls

No

@austinvalle austinvalle added this to the v1.16.1 milestone Sep 22, 2025
@austinvalle austinvalle requested a review from a team as a code owner September 22, 2025 21:47
@austinvalle
Copy link
Member Author

Original test failures without the fix applied in 02a37e3:

--- FAIL: TestServerReadResource (0.00s)
    --- FAIL: TestServerReadResource/response-identity-valid-update-empty-currentidentity (0.00s)
        server_readresource_test.go:1001: unexpected difference:   &fwserver.ReadResourceResponse{
              	Deferred: nil,
            - 	Diagnostics: diag.Diagnostics{
            - 		diag.ErrorDiagnostic{
            - 			detail:  "During the read operation, the Terraform Provider unexpectedly r"...,
            - 			summary: "Unexpected Identity Change",
            - 		},
            - 	},
            + 	Diagnostics: nil,
              	NewState:    &{Raw: s`tftypes.Object["test_computed":tftypes.String, "test_required":t`..., Schema: schema.Schema{Attributes: {"test_computed": schema.StringAttribute{Computed: true}, "test_required": schema.StringAttribute{Required: true}}}},
              	NewIdentity: &{Raw: s`tftypes.Object["test_attr_a":tftypes.String, "test_attr_b":tftyp`..., Schema: identityschema.Schema{Attributes: {"test_attr_a": identityschema.StringAttribute{RequiredForImport: true}, "test_attr_b": identityschema.Int64Attribute{OptionalForImport: true}}}},
              	Private:     &{Provider: &{data: {}}},
              }
--- FAIL: TestServerPlanResourceChange (0.01s)
    --- FAIL: TestServerPlanResourceChange/update-resourcewithmodifyplan-empty-prioridentity-plannedidentity-changed (0.00s)
        server_planresourcechange_test.go:7124: unexpected difference:   &fwserver.PlanResourceChangeResponse{
              	Deferred: nil,
            - 	Diagnostics: diag.Diagnostics{
            - 		diag.ErrorDiagnostic{
            - 			detail:  "During the planning operation, the Terraform Provider unexpected"...,
            - 			summary: "Unexpected Identity Change",
            - 		},
            - 	},
            + 	Diagnostics:    nil,
              	PlannedPrivate: &{Provider: &{data: {}}},
              	PlannedState:   &{Raw: s`tftypes.Object["test_computed":tftypes.String, "test_required":t`..., Schema: schema.Schema{Attributes: {"test_computed": schema.StringAttribute{Computed: true}, "test_required": schema.StringAttribute{Required: true}}}},
              	... // 2 identical fields
              }
--- FAIL: TestServerApplyResourceChange (0.00s)
    --- FAIL: TestServerApplyResourceChange/update-response-newidentity-empty-plannedidentity (0.00s)
        server_applyresourcechange_test.go:2228: unexpected difference:   &fwserver.ApplyResourceChangeResponse{
            - 	Diagnostics: diag.Diagnostics{
            - 		diag.ErrorDiagnostic{
            - 			detail:  "During the update operation, the Terraform Provider unexpectedly"...,
            - 			summary: "Unexpected Identity Change",
            - 		},
            - 	},
            + 	Diagnostics: nil,
              	NewState:    &{Raw: s`tftypes.Object["test_computed":tftypes.String, "test_required":t`..., Schema: schema.Schema{Attributes: {"test_computed": schema.StringAttribute{Computed: true}, "test_required": schema.StringAttribute{Required: true}}}},
              	NewIdentity: &{Raw: s`tftypes.Object["test_attr_a":tftypes.String, "test_attr_b":tftyp`..., Schema: identityschema.Schema{Attributes: {"test_attr_a": identityschema.StringAttribute{RequiredForImport: true}, "test_attr_b": identityschema.Int64Attribute{OptionalForImport: true}}}},
              	Private:     &{Provider: &{data: {}}},
              }
FAIL


// If we're refreshing the resource state (excluding a recently imported resource), validate that the new identity isn't changing
if !req.ResourceBehavior.MutableIdentity && !readFollowingImport && !req.CurrentIdentity.Raw.IsNull() && !req.CurrentIdentity.Raw.Equal(resp.NewIdentity.Raw) {
if !req.ResourceBehavior.MutableIdentity && !readFollowingImport && !req.CurrentIdentity.Raw.IsFullyNull() && !req.CurrentIdentity.Raw.Equal(resp.NewIdentity.Raw) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FullyNull is an interesting way to say it

@rainkwan rainkwan merged commit bd26b78 into main Sep 22, 2025
40 checks passed
@rainkwan rainkwan deleted the av/allow-empty-identity-objects branch September 22, 2025 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

identity: Allow identities with all null attributes to change

2 participants