From 1fa1f00a3b16d87150e8a31be3578021c8c0c9b3 Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Wed, 20 Nov 2024 12:18:21 +0100 Subject: [PATCH] ephemeral: add write only attribute paths --- internal/plans/changes.go | 2 ++ internal/plans/changes_src.go | 4 ++++ internal/states/instance_object_src.go | 4 ++++ internal/states/state_deepcopy.go | 15 +++++++++++---- internal/states/statefile/version4.go | 11 +++++++++++ .../terraform/context_apply_ephemeral_test.go | 19 ++++++++++--------- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/internal/plans/changes.go b/internal/plans/changes.go index 1ed49724b0..9d069aa907 100644 --- a/internal/plans/changes.go +++ b/internal/plans/changes.go @@ -645,6 +645,8 @@ func (c *Change) Encode(ty cty.Type) (*ChangeSrc, error) { After: afterDV, BeforeSensitivePaths: sensitiveAttrsBefore, AfterSensitivePaths: sensitiveAttrsAfter, + BeforeWriteOnlyPaths: nil, // TODO: Add write-only paths + AfterWriteOnlyPaths: nil, // TODO: Add write-only paths Importing: c.Importing.Encode(), GeneratedConfig: c.GeneratedConfig, }, nil diff --git a/internal/plans/changes_src.go b/internal/plans/changes_src.go index ff851ea83e..d82ed45369 100644 --- a/internal/plans/changes_src.go +++ b/internal/plans/changes_src.go @@ -388,6 +388,10 @@ type ChangeSrc struct { // the serialized change. BeforeSensitivePaths, AfterSensitivePaths []cty.Path + // BeforeWriteOnlyPaths and AfterWriteOnlyPaths are paths for any values + // in Before or After (respectively) that are considered to be write-only. + BeforeWriteOnlyPaths, AfterWriteOnlyPaths []cty.Path + // Importing is present if the resource is being imported as part of this // change. // diff --git a/internal/states/instance_object_src.go b/internal/states/instance_object_src.go index 7960524b66..617e2eaf75 100644 --- a/internal/states/instance_object_src.go +++ b/internal/states/instance_object_src.go @@ -57,6 +57,10 @@ type ResourceInstanceObjectSrc struct { // state, or to save as sensitive paths when saving state AttrSensitivePaths []cty.Path + // AttrWriteOnlyPaths is an array of paths to mark as ephemeral coming out of + // state, or to save as write_only paths when saving state + AttrWriteOnlyPaths []cty.Path + // These fields all correspond to the fields of the same name on // ResourceInstanceObject. Private []byte diff --git a/internal/states/state_deepcopy.go b/internal/states/state_deepcopy.go index 8486e95485..cf830512b2 100644 --- a/internal/states/state_deepcopy.go +++ b/internal/states/state_deepcopy.go @@ -142,10 +142,16 @@ func (os *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc { copy(attrsJSON, os.AttrsJSON) } - var attrPaths []cty.Path + var sensitiveAttrPaths []cty.Path if os.AttrSensitivePaths != nil { - attrPaths = make([]cty.Path, len(os.AttrSensitivePaths)) - copy(attrPaths, os.AttrSensitivePaths) + sensitiveAttrPaths = make([]cty.Path, len(os.AttrSensitivePaths)) + copy(sensitiveAttrPaths, os.AttrSensitivePaths) + } + + var writeOnlyAttrPaths []cty.Path + if os.AttrWriteOnlyPaths != nil { + writeOnlyAttrPaths = make([]cty.Path, len(os.AttrWriteOnlyPaths)) + copy(writeOnlyAttrPaths, os.AttrWriteOnlyPaths) } var private []byte @@ -168,7 +174,8 @@ func (os *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc { Private: private, AttrsFlat: attrsFlat, AttrsJSON: attrsJSON, - AttrSensitivePaths: attrPaths, + AttrSensitivePaths: sensitiveAttrPaths, + AttrWriteOnlyPaths: writeOnlyAttrPaths, Dependencies: dependencies, CreateBeforeDestroy: os.CreateBeforeDestroy, decodeValueCache: os.decodeValueCache, diff --git a/internal/states/statefile/version4.go b/internal/states/statefile/version4.go index 6477e66cf2..d38e0b0b28 100644 --- a/internal/states/statefile/version4.go +++ b/internal/states/statefile/version4.go @@ -166,6 +166,16 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) { obj.AttrSensitivePaths = paths } + // write-only paths + if isV4.AttributeWriteOnlyPaths != nil { + paths, pathsDiags := unmarshalPaths([]byte(isV4.AttributeWriteOnlyPaths)) + diags = diags.Append(pathsDiags) + if pathsDiags.HasErrors() { + continue + } + obj.AttrWriteOnlyPaths = paths + } + { // Status raw := isV4.Status @@ -701,6 +711,7 @@ type instanceObjectStateV4 struct { AttributesRaw json.RawMessage `json:"attributes,omitempty"` AttributesFlat map[string]string `json:"attributes_flat,omitempty"` AttributeSensitivePaths json.RawMessage `json:"sensitive_attributes,omitempty"` + AttributeWriteOnlyPaths json.RawMessage `json:"write_only_attributes,omitempty"` PrivateRaw []byte `json:"private,omitempty"` diff --git a/internal/terraform/context_apply_ephemeral_test.go b/internal/terraform/context_apply_ephemeral_test.go index 1ead400508..1910946640 100644 --- a/internal/terraform/context_apply_ephemeral_test.go +++ b/internal/terraform/context_apply_ephemeral_test.go @@ -419,9 +419,10 @@ resource "ephem_write_only" "wo" { t.Fatalf("Expected 1 resource change, got %d", len(plan.Changes.Resources)) } - // if len(plan.Changes.Resources[0].AfterWriteOnlyPaths) != 1 { - // t.Fatalf("Expected 1 write-only attribute, got %d", len(plan.Changes.Resources[0].AfterWriteOnlyPaths)) - // } + if len(plan.Changes.Resources[0].AfterWriteOnlyPaths) != 1 { + t.Fatalf("Expected 1 write-only attribute, got %d", len(plan.Changes.Resources[0].AfterWriteOnlyPaths)) + } + schemas, schemaDiags := ctx.Schemas(m, plan.PriorState) assertNoDiagnostics(t, schemaDiags) planChanges, err := plan.Changes.Decode(schemas) @@ -468,11 +469,11 @@ resource "ephem_write_only" "wo" { t.Fatalf("normal attribute not as expected") } - // if len(resourceInstance.Current.AttrWriteOnlyPaths) != 1 { - // t.Fatalf("Expected 1 write only attribute") - // } + if len(resourceInstance.Current.AttrWriteOnlyPaths) != 1 { + t.Fatalf("Expected 1 write only attribute") + } - // if !resourceInstance.Current.AttrWriteOnlyPaths[0].Equals(cty.GetAttrPath("write_only")) { - // t.Fatalf("Expected write_only to be a write only attribute") - // } + if !resourceInstance.Current.AttrWriteOnlyPaths[0].Equals(cty.GetAttrPath("write_only")) { + t.Fatalf("Expected write_only to be a write only attribute") + } }