terraform-plugin-framework
terraform-plugin-framework copied to clipboard
Computed sensitive attribute alongside computed boolean in SetNestedAttribute causes entire set to be deleted and recreated in subsequent plans
Module version
github.com/hashicorp/terraform-plugin-framework v1.11.0
Relevant provider source code
func (r *sensitiveResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Sensitive resource.",
Attributes: map[string]schema.Attribute{
"tables": schema.SetNestedAttribute{
Description: "List of configuration tables.",
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"rows": schema.ListNestedAttribute{
Description: "List of table rows.",
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"sensitive_fields": schema.SetNestedAttribute{
Description: "The sensitive configuration fields in the row.",
Optional: true,
Computed: true,
Default: setdefault.StaticValue(types.SetValueMust(types.ObjectType{AttrTypes: map[string]attr.Type{
"name": types.StringType,
"value": types.StringType,
}}, nil)),
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "The name of the configuration field.",
Required: true,
},
"value": schema.StringAttribute{
Description: "The sensitive value for the configuration field.",
Required: true,
Sensitive: true,
},
},
},
},
"default_row": schema.BoolAttribute{
Description: "Whether this row is the default.",
Computed: true,
Optional: true,
Default: booldefault.StaticBool(false),
},
},
},
},
},
},
},
},
}
}
func (r *sensitiveResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
resp.State.Raw = req.Plan.Raw
}
func (r *sensitiveResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
resp.State.Raw = req.State.Raw
}
func (r *sensitiveResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
resp.State.Raw = req.Plan.Raw
}
func (r *sensitiveResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
}
Terraform Configuration Files
resource "example_sensitive" "sensitive" {
# If tables is a list instead of a set, the unexpected plans do not occur
tables = [
{
rows = [
{
fields = [
{
name = "Key ID"
value = "jwtSymmetricKey1"
},
{
name = "Encoding"
value = "b64u"
}
]
sensitive_fields = [
{
name = "Key"
value = "Asdf"
},
]
# If this attribute is uncommented, the unexpected plans do not occur
# default_row = false
}
]
},
]
}
Debug Output
https://gist.github.com/henryrecker-pingidentity/9cb39885e2d338fc7189543d501b413c
Expected Behavior
Plans after initial create should indicate no changes needed, infrastructure matches configuration.
Actual Behavior
After a Create runs successfully, a subsequent apply will generate a plan that completely deletes the "tables" attribute. Another subsequent apply after that will recreate the "tables" attribute, as it is written in the HCL. And it will continue to flip-flop from there.
If the "tables" attribute is changed to ListNestedAttribute rather than SetNestedAttribute, the bug stops occurring.
Steps to Reproduce
Apply provided HCL repeatedly. Uncommenting the "default_row" boolean prevents the flip-flopping, as does changing tables to a list in the schema.
This provider can be found on the "SensitivePlanBug" branch here - https://github.com/henryrecker-pingidentity/terraform-provider-example/tree/SensitivePlanBug
References
Seems very similar to #867