github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/lang/funcs/sensitive_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package funcs 5 6 import ( 7 "fmt" 8 "testing" 9 10 "github.com/terramate-io/tf/lang/marks" 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 func TestSensitive(t *testing.T) { 15 tests := []struct { 16 Input cty.Value 17 WantErr string 18 }{ 19 { 20 cty.NumberIntVal(1), 21 ``, 22 }, 23 { 24 // Unknown values stay unknown while becoming sensitive 25 cty.UnknownVal(cty.String), 26 ``, 27 }, 28 { 29 // Null values stay unknown while becoming sensitive 30 cty.NullVal(cty.String), 31 ``, 32 }, 33 { 34 // DynamicVal can be marked as sensitive 35 cty.DynamicVal, 36 ``, 37 }, 38 { 39 // The marking is shallow only 40 cty.ListVal([]cty.Value{cty.NumberIntVal(1)}), 41 ``, 42 }, 43 { 44 // A value already marked is allowed and stays marked 45 cty.NumberIntVal(1).Mark(marks.Sensitive), 46 ``, 47 }, 48 { 49 // A value with some non-standard mark gets "fixed" to be marked 50 // with the standard "sensitive" mark. (This situation occurring 51 // would imply an inconsistency/bug elsewhere, so we're just 52 // being robust about it here.) 53 cty.NumberIntVal(1).Mark("bloop"), 54 ``, 55 }, 56 { 57 // A value deep already marked is allowed and stays marked, 58 // _and_ we'll also mark the outer collection as sensitive. 59 cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}), 60 ``, 61 }, 62 } 63 64 for _, test := range tests { 65 t.Run(fmt.Sprintf("sensitive(%#v)", test.Input), func(t *testing.T) { 66 got, err := Sensitive(test.Input) 67 68 if test.WantErr != "" { 69 if err == nil { 70 t.Fatal("succeeded; want error") 71 } 72 if got, want := err.Error(), test.WantErr; got != want { 73 t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) 74 } 75 return 76 } else if err != nil { 77 t.Fatalf("unexpected error: %s", err) 78 } 79 80 if !got.HasMark(marks.Sensitive) { 81 t.Errorf("result is not marked sensitive") 82 } 83 84 gotRaw, gotMarks := got.Unmark() 85 if len(gotMarks) != 1 { 86 // We're only expecting to have the "sensitive" mark we checked 87 // above. Any others are an error, even if they happen to 88 // appear alongside "sensitive". (We might change this rule 89 // if someday we decide to use marks for some additional 90 // unrelated thing in Terraform, but currently we assume that 91 // _all_ marks imply sensitive, and so returning any other 92 // marks would be confusing.) 93 t.Errorf("extraneous marks %#v", gotMarks) 94 } 95 96 // Disregarding shallow marks, the result should have the same 97 // effective value as the input. 98 wantRaw, _ := test.Input.Unmark() 99 if !gotRaw.RawEquals(wantRaw) { 100 t.Errorf("wrong unmarked result\ngot: %#v\nwant: %#v", got, wantRaw) 101 } 102 }) 103 } 104 } 105 106 func TestNonsensitive(t *testing.T) { 107 tests := []struct { 108 Input cty.Value 109 WantErr string 110 }{ 111 { 112 cty.NumberIntVal(1).Mark(marks.Sensitive), 113 ``, 114 }, 115 { 116 cty.DynamicVal.Mark(marks.Sensitive), 117 ``, 118 }, 119 { 120 cty.UnknownVal(cty.String).Mark(marks.Sensitive), 121 ``, 122 }, 123 { 124 cty.NullVal(cty.EmptyObject).Mark(marks.Sensitive), 125 ``, 126 }, 127 { 128 // The inner sensitive remains afterwards 129 cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}).Mark(marks.Sensitive), 130 ``, 131 }, 132 133 // Passing a value that is already non-sensitive is an error, 134 // because this function should always be used with specific 135 // intention, not just as a "make everything visible" hammer. 136 { 137 cty.NumberIntVal(1), 138 `the given value is not sensitive, so this call is redundant`, 139 }, 140 { 141 cty.NullVal(cty.String), 142 `the given value is not sensitive, so this call is redundant`, 143 }, 144 145 // Unknown values may become sensitive once they are known, so we 146 // permit them to be marked nonsensitive. 147 { 148 cty.DynamicVal, 149 ``, 150 }, 151 { 152 cty.UnknownVal(cty.String), 153 ``, 154 }, 155 } 156 157 for _, test := range tests { 158 t.Run(fmt.Sprintf("nonsensitive(%#v)", test.Input), func(t *testing.T) { 159 got, err := Nonsensitive(test.Input) 160 161 if test.WantErr != "" { 162 if err == nil { 163 t.Fatal("succeeded; want error") 164 } 165 if got, want := err.Error(), test.WantErr; got != want { 166 t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) 167 } 168 return 169 } else if err != nil { 170 t.Fatalf("unexpected error: %s", err) 171 } 172 173 if got.HasMark(marks.Sensitive) { 174 t.Errorf("result is still marked sensitive") 175 } 176 wantRaw, _ := test.Input.Unmark() 177 if !got.RawEquals(wantRaw) { 178 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Input) 179 } 180 }) 181 } 182 }