github.com/opentofu/opentofu@v1.7.1/internal/command/jsonformat/structured/sensitive.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package structured 7 8 import ( 9 "github.com/opentofu/opentofu/internal/command/jsonformat/computed" 10 "github.com/opentofu/opentofu/internal/plans" 11 ) 12 13 type ProcessSensitiveInner func(change Change) computed.Diff 14 type CreateSensitiveDiff func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff 15 16 func (change Change) IsBeforeSensitive() bool { 17 if sensitive, ok := change.BeforeSensitive.(bool); ok { 18 return sensitive 19 } 20 return false 21 } 22 23 func (change Change) IsAfterSensitive() bool { 24 if sensitive, ok := change.AfterSensitive.(bool); ok { 25 return sensitive 26 } 27 return false 28 } 29 30 // CheckForSensitive is a helper function that handles all common functionality 31 // for processing a sensitive value. 32 // 33 // It returns the computed sensitive diff and true if this value was sensitive 34 // and needs to be rendered as such, otherwise it returns the second return 35 // value as false and the first value can be discarded. 36 // 37 // The actual processing of sensitive values happens within the 38 // ProcessSensitiveInner and CreateSensitiveDiff functions. Callers should 39 // implement these functions as appropriate when using this function. 40 // 41 // The ProcessSensitiveInner function should simply return a computed.Diff for 42 // the provided Change. The provided Change will be the same as the original 43 // change but with the sensitive metadata removed. The new inner diff is then 44 // passed into the actual CreateSensitiveDiff function which should return the 45 // actual sensitive diff. 46 // 47 // We include the inner change into the sensitive diff as a way to let the 48 // sensitive renderer have as much information as possible, while still letting 49 // it do the actual rendering. 50 func (change Change) CheckForSensitive(processInner ProcessSensitiveInner, createDiff CreateSensitiveDiff) (computed.Diff, bool) { 51 beforeSensitive := change.IsBeforeSensitive() 52 afterSensitive := change.IsAfterSensitive() 53 54 if !beforeSensitive && !afterSensitive { 55 return computed.Diff{}, false 56 } 57 58 // We are still going to give the change the contents of the actual change. 59 // So we create a new Change with everything matching the current value, 60 // except for the sensitivity. 61 // 62 // The change can choose what to do with this information, in most cases 63 // it will just be ignored in favour of printing `(sensitive value)`. 64 65 value := Change{ 66 BeforeExplicit: change.BeforeExplicit, 67 AfterExplicit: change.AfterExplicit, 68 Before: change.Before, 69 After: change.After, 70 Unknown: change.Unknown, 71 BeforeSensitive: false, 72 AfterSensitive: false, 73 ReplacePaths: change.ReplacePaths, 74 RelevantAttributes: change.RelevantAttributes, 75 } 76 77 inner := processInner(value) 78 79 action := inner.Action 80 sensitiveStatusChanged := beforeSensitive != afterSensitive 81 82 // nullNoOp is a stronger NoOp, where not only is there no change happening 83 // but the before and after values are not explicitly set and are both 84 // null. This will override even the sensitive state changing. 85 nullNoOp := change.Before == nil && !change.BeforeExplicit && change.After == nil && !change.AfterExplicit 86 87 if action == plans.NoOp && sensitiveStatusChanged && !nullNoOp { 88 // Let's override this, since it means the sensitive status has changed 89 // rather than the actual content of the value. 90 action = plans.Update 91 } 92 93 return createDiff(inner, beforeSensitive, afterSensitive, action), true 94 }