hashicorp / hashicorp/terraform-plugin-framework
Computed sensitive attribute alongside computed boolean in SetNestedAttribute causes entire set to be deleted and recreated in subsequent plans
- Dominant language
- Go
- Stars
- 384
- Forks
- 107
- Avg merge
- 3m
- Merged PRs (30d)
- 1
Description
### Module version
```
github.com/hashicorp/terraform-plugin-framework v1.11.0
```
### Relevant provider source code
```go
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
```hcl
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
Contributor guide
Assessment
This issue has not been assessed yet.