From 6be3ddf9e72ccabb4cacf62803e57d776ef7fd41 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 15 Apr 2024 13:46:53 -0700 Subject: [PATCH] planfile: Reject value marks that we cannot serialize The plan file format can only preserve the "sensitive" mark, but previously it was just silently treating any other mark as if it were the sensitive mark. Now we'll reject any other marks at serialization time. There are not currently any other marks used by the modules runtime and so in practice this cannot fail yet, but this is here to guard against misbehavior if we introduce new marks in future without considering whether and how they are to be serialized. (For any mark we choose not to serialize, it'll be the caller's responsibility to replace the values using unsupported marks with suitable unmarked placeholders.) --- internal/plans/planfile/tfplan.go | 9 +++++++++ internal/plans/planfile/tfplan_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/internal/plans/planfile/tfplan.go b/internal/plans/planfile/tfplan.go index ca792ab625..539b81d655 100644 --- a/internal/plans/planfile/tfplan.go +++ b/internal/plans/planfile/tfplan.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform/internal/plans/planproto" "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/internal/tfdiags" "github.com/hashicorp/terraform/version" ) @@ -860,6 +861,14 @@ func pathValueMarksFromTfplan(paths []*planproto.Path, marks cty.ValueMarks) ([] func pathValueMarksToTfplan(pvm []cty.PathValueMarks) ([]*planproto.Path, error) { ret := make([]*planproto.Path, 0, len(pvm)) for _, p := range pvm { + for mark := range p.Marks { + if mark != marks.Sensitive { + return nil, fmt.Errorf("%s: cannot serialize values marked as %#v (this is a bug in Terraform)", tfdiags.FormatCtyPath(p.Path), mark) + } + } + if _, ok := p.Marks[marks.Sensitive]; !ok { + continue + } path, err := pathToTfplan(p.Path) if err != nil { return nil, err diff --git a/internal/plans/planfile/tfplan_test.go b/internal/plans/planfile/tfplan_test.go index 2a6cd1256d..12bb8b3fad 100644 --- a/internal/plans/planfile/tfplan_test.go +++ b/internal/plans/planfile/tfplan_test.go @@ -447,3 +447,28 @@ func TestTFPlanRoundTripDestroy(t *testing.T) { } } } + +func TestTFPlanEncodeUnsupportedMarks(t *testing.T) { + v := cty.ObjectVal(map[string]cty.Value{ + "beep": cty.StringVal("boop").Mark("unsupported"), + }) + change := &plans.Change{ + Action: plans.Create, + Before: cty.NullVal(v.Type()), + After: v, + } + changeSrc, err := change.Encode(v.Type()) + if err != nil { + t.Fatalf("failed to encode change for testing: %s", err) + } + + _, err = changeToTfplan(changeSrc) + if err == nil { + t.Fatalf("unexpected success; want error") + } + got := err.Error() + want := `.beep: cannot serialize values marked as "unsupported" (this is a bug in Terraform)` + if got != want { + t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) + } +}