github.com/terraform-linters/tflint@v0.51.2-0.20240520175844-3750771571b6/terraform/lang/funcs/sensitive_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package funcs 5 6 import ( 7 "fmt" 8 "testing" 9 10 "github.com/terraform-linters/tflint-plugin-sdk/terraform/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 not an error, 134 // as this function may be used with specific to ensure that all 135 // values are indeed non-sensitive 136 { 137 cty.NumberIntVal(1), 138 ``, 139 }, 140 { 141 cty.NullVal(cty.String), 142 ``, 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 } 183 184 func TestIssensitive(t *testing.T) { 185 tests := []struct { 186 Input cty.Value 187 Sensitive bool 188 WantErr string 189 }{ 190 { 191 cty.NumberIntVal(1).Mark(marks.Sensitive), 192 true, 193 ``, 194 }, 195 { 196 cty.NumberIntVal(1), 197 false, 198 ``, 199 }, 200 { 201 cty.DynamicVal.Mark(marks.Sensitive), 202 true, 203 ``, 204 }, 205 { 206 cty.UnknownVal(cty.String).Mark(marks.Sensitive), 207 true, 208 ``, 209 }, 210 { 211 cty.NullVal(cty.EmptyObject).Mark(marks.Sensitive), 212 true, 213 ``, 214 }, 215 { 216 cty.NullVal(cty.String), 217 false, 218 ``, 219 }, 220 { 221 cty.DynamicVal, 222 false, 223 ``, 224 }, 225 { 226 cty.UnknownVal(cty.String), 227 false, 228 ``, 229 }, 230 } 231 232 for _, test := range tests { 233 t.Run(fmt.Sprintf("issensitive(%#v)", test.Input), func(t *testing.T) { 234 got, err := Issensitive(test.Input) 235 236 if test.WantErr != "" { 237 if err == nil { 238 t.Fatal("succeeded; want error") 239 } 240 if got, want := err.Error(), test.WantErr; got != want { 241 t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) 242 } 243 return 244 } else if err != nil { 245 t.Fatalf("unexpected error: %s", err) 246 } 247 248 if (got.True() && !test.Sensitive) || (got.False() && test.Sensitive) { 249 t.Errorf("wrong result \ngot: %#v\nwant: %#v", got, test.Sensitive) 250 } 251 }) 252 } 253 254 }