Skip to content
Draft
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
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/hashicorp/terraform-provider-corner

go 1.23.7

replace github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0-beta.1 => github.com/BBBmau/terraform-plugin-sdk/v2 v2.24.1-0.20250421144349-aa2d9d850504
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Todo: Remove this line and update SDKv2 dependency once v2.25.0 releases.

Copy link
Member

Choose a reason for hiding this comment

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

@SBGoods This PR should be good to open / resolve the conflicts after #349 was merged 👍🏻


require (
github.com/hashicorp/go-cty v1.5.0
github.com/hashicorp/go-memdb v1.3.5
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/BBBmau/terraform-plugin-sdk/v2 v2.24.1-0.20250421144349-aa2d9d850504 h1:zPdCQeMRS+5zNm1f21Yq8HSkuppKcjY7YzQGmCER9GI=
github.com/BBBmau/terraform-plugin-sdk/v2 v2.24.1-0.20250421144349-aa2d9d850504/go.mod h1:fVJWDD6/eNOK0aG55CK5g8vTv3Ph9UD/dZztPPvFDgw=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
Expand Down Expand Up @@ -105,8 +107,6 @@ github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9T
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-mux v0.19.0-alpha.1 h1:WCzSBsp719WKEV/+j+4/o742paM0twYm7B84y7x8pOM=
github.com/hashicorp/terraform-plugin-mux v0.19.0-alpha.1/go.mod h1:iKph9LFBiD4a33AJLgqg7IKSVg2kdlYvx0IRd+ys3Ig=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0-beta.1 h1:Ia0jU/ZLzyfReSg4TMHq6ffYGCNCREzpSMBqswM71a0=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0-beta.1/go.mod h1:fVJWDD6/eNOK0aG55CK5g8vTv3Ph9UD/dZztPPvFDgw=
github.com/hashicorp/terraform-plugin-testing v1.13.0-beta.1 h1:YpdITO9pgpSVSBoxL9DqiOG/2/rUQtcnP6encYAtKd0=
github.com/hashicorp/terraform-plugin-testing v1.13.0-beta.1/go.mod h1:2fJBV6Eim03FqxyaPbPW2qZadDbfD1+yj/tRnDHBjjI=
github.com/hashicorp/terraform-registry-address v0.2.4 h1:JXu/zHB2Ymg/TGVCRu10XqNa4Sh2bWcqCNyKWjnCPJA=
Expand Down
46 changes: 40 additions & 6 deletions internal/sdkv2provider/resource_write_once.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ func resourceWriteOnce() *schema.Resource {
EnableLegacyTypeSystemPlanErrors: true,
EnableLegacyTypeSystemApplyErrors: true,

// This resource intentionally omits the update function
// to test that write-only attributes bypass the SDKv2's internal
// validation for non-ForceNew configured attributes
// Ref: https://github.com/hashicorp/terraform-plugin-sdk/issues/1471
CreateContext: resourceWriteOnceCreate,
ReadContext: resourceWriteOnceRead,
UpdateContext: resourceWriteOnceUpdate,
DeleteContext: resourceWriteOnceDelete,

Schema: map[string]*schema.Schema{
Expand All @@ -38,6 +41,42 @@ func resourceWriteOnce() *schema.Resource {
Optional: true,
WriteOnly: true,
},
"nested_list_block": {
Type: schema.TypeList,
Optional: true,
// Block must be set to force new since there is no update method
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"string_attr": {
Type: schema.TypeString,
Required: true,
},
"writeonly_string": {
Type: schema.TypeString,
Optional: true,
WriteOnly: true,
},
"double_nested_list_block": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"string_attr": {
Type: schema.TypeString,
Required: true,
},
"writeonly_string": {
Type: schema.TypeString,
Optional: true,
WriteOnly: true,
},
},
},
},
},
},
},
},
CustomizeDiff: func(ctx context.Context, rd *schema.ResourceDiff, _ interface{}) error {
valPath := cty.GetAttrPath("writeonce_string")
Expand Down Expand Up @@ -92,11 +131,6 @@ func resourceWriteOnceRead(ctx context.Context, d *schema.ResourceData, meta int
return nil
}

func resourceWriteOnceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Once created, the only operation that can occur is replacement (delete/create)
return nil
}

func resourceWriteOnceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// Config isn't set for Delete, so can't verify write-only data
return nil
Expand Down
104 changes: 104 additions & 0 deletions internal/sdkv2provider/resource_write_once_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,77 @@ func TestWriteOnceResource(t *testing.T) {
Config: `resource "corner_writeonce" "test" {
trigger_attr = "1"
writeonce_string = "fakepassword"
nested_list_block {
string_attr = "world!"
writeonly_string = "fakepassword"
double_nested_list_block {
string_attr = "world!"
writeonly_string = "fakepassword"
}
}
}`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("writeonce_string"), knownvalue.Null()),
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("nested_list_block"), knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
"double_nested_list_block": knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
}),
}),
}),
})),
plancheck.ExpectResourceAction("corner_writeonce.test", plancheck.ResourceActionCreate),
},
},
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("writeonce_string"), knownvalue.Null()),
statecheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("nested_list_block"), knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
"double_nested_list_block": knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
}),
}),
}),
})),
},
},
{
// Now that the resource is created, we can remove the attribute with no planned changes
Config: `resource "corner_writeonce" "test" {
trigger_attr = "1"
nested_list_block {
string_attr = "world!"
writeonly_string = "fakepassword"
double_nested_list_block {
string_attr = "world!"
writeonly_string = "fakepassword"
}
}
}`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("writeonce_string"), knownvalue.Null()),
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("nested_list_block"), knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
"double_nested_list_block": knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
}),
}),
}),
})),
plancheck.ExpectResourceAction("corner_writeonce.test", plancheck.ResourceActionNoop),
},
},
Expand All @@ -59,10 +111,30 @@ func TestWriteOnceResource(t *testing.T) {
Config: `resource "corner_writeonce" "test" {
trigger_attr = "1"
writeonce_string = "this value cannot prompt a change on it's own"
nested_list_block {
string_attr = "world!"
writeonly_string = "this value cannot prompt a change on it's own"
double_nested_list_block {
string_attr = "world!"
writeonly_string = "this value cannot prompt a change on it's own"
}
}
}`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("writeonce_string"), knownvalue.Null()),
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("nested_list_block"), knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
"double_nested_list_block": knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
}),
}),
}),
})),
plancheck.ExpectResourceAction("corner_writeonce.test", plancheck.ResourceActionNoop),
},
},
Expand All @@ -72,15 +144,47 @@ func TestWriteOnceResource(t *testing.T) {
Config: `resource "corner_writeonce" "test" {
trigger_attr = "2"
writeonce_string = "fakepassword"
nested_list_block {
string_attr = "world!"
writeonly_string = "fakepassword"
double_nested_list_block {
string_attr = "world!"
writeonly_string = "fakepassword"
}
}
}`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("writeonce_string"), knownvalue.Null()),
plancheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("nested_list_block"), knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
"double_nested_list_block": knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
}),
}),
}),
})),
plancheck.ExpectResourceAction("corner_writeonce.test", plancheck.ResourceActionReplace),
},
},
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("writeonce_string"), knownvalue.Null()),
statecheck.ExpectKnownValue("corner_writeonce.test", tfjsonpath.New("nested_list_block"), knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
"double_nested_list_block": knownvalue.ListExact([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"string_attr": knownvalue.StringExact("world!"),
"writeonly_string": knownvalue.Null(),
}),
}),
}),
})),
},
},
},
Expand Down
Loading