github.com/google/osv-scalibr@v0.4.1/enricher/secrets/secrets_test.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package secrets_test 16 17 import ( 18 "context" 19 "errors" 20 "testing" 21 "time" 22 23 "github.com/google/go-cmp/cmp" 24 "github.com/google/go-cmp/cmp/cmpopts" 25 "github.com/google/osv-scalibr/enricher/secrets" 26 "github.com/google/osv-scalibr/inventory" 27 "github.com/google/osv-scalibr/veles" 28 "github.com/google/osv-scalibr/veles/velestest" 29 ) 30 31 type testEnricherSubCase struct { 32 name string 33 input inventory.Inventory 34 want inventory.Inventory 35 } 36 37 func TestEnricher(t *testing.T) { 38 errTest := errors.New("some validation error") 39 path := "/foo/bar/key.json" 40 cases := []struct { 41 name string 42 engine *veles.ValidationEngine 43 subs []testEnricherSubCase 44 }{ 45 { 46 name: "only strings supported", 47 engine: veles.NewValidationEngine(veles.WithValidator(velestest.NewFakeStringSecretValidator(veles.ValidationValid, nil))), 48 subs: []testEnricherSubCase{ 49 { 50 name: "supported", 51 input: inventory.Inventory{ 52 Secrets: []*inventory.Secret{ 53 { 54 Secret: velestest.NewFakeStringSecret("FOO"), 55 Location: path, 56 }, 57 }, 58 }, 59 want: inventory.Inventory{ 60 Secrets: []*inventory.Secret{ 61 { 62 Secret: velestest.NewFakeStringSecret("FOO"), 63 Location: path, 64 Validation: inventory.SecretValidationResult{ 65 Status: veles.ValidationValid, 66 }, 67 }, 68 }, 69 }, 70 }, 71 { 72 name: "unsupported", 73 input: inventory.Inventory{ 74 Secrets: []*inventory.Secret{ 75 { 76 Secret: velestest.NewFakeIntSecret(123), 77 Location: path, 78 }, 79 }, 80 }, 81 want: inventory.Inventory{ 82 Secrets: []*inventory.Secret{ 83 { 84 Secret: velestest.NewFakeIntSecret(123), 85 Location: path, 86 Validation: inventory.SecretValidationResult{ 87 Status: veles.ValidationUnsupported, 88 }, 89 }, 90 }, 91 }, 92 }, 93 }, 94 }, 95 { 96 name: "per_secret_errors", 97 engine: veles.NewValidationEngine( 98 veles.WithValidator(velestest.NewFakeStringSecretValidator(veles.ValidationValid, nil)), 99 veles.WithValidator(velestest.NewFakeIntSecretValidator(veles.ValidationFailed, errTest)), 100 ), 101 subs: []testEnricherSubCase{ 102 { 103 name: "single_error", 104 input: inventory.Inventory{ 105 Secrets: []*inventory.Secret{ 106 { 107 Secret: velestest.NewFakeIntSecret(123), 108 Location: path, 109 }, 110 }, 111 }, 112 want: inventory.Inventory{ 113 Secrets: []*inventory.Secret{ 114 { 115 Secret: velestest.NewFakeIntSecret(123), 116 Location: path, 117 Validation: inventory.SecretValidationResult{ 118 Status: veles.ValidationFailed, 119 Err: errTest, 120 }, 121 }, 122 }, 123 }, 124 }, 125 { 126 name: "multiple_errors", 127 input: inventory.Inventory{ 128 Secrets: []*inventory.Secret{ 129 { 130 Secret: velestest.NewFakeIntSecret(123), 131 Location: path, 132 }, 133 { 134 Secret: velestest.NewFakeIntSecret(456), 135 Location: path, 136 }, 137 }, 138 }, 139 want: inventory.Inventory{ 140 Secrets: []*inventory.Secret{ 141 { 142 Secret: velestest.NewFakeIntSecret(123), 143 Location: path, 144 Validation: inventory.SecretValidationResult{ 145 Status: veles.ValidationFailed, 146 Err: errTest, 147 }, 148 }, 149 { 150 Secret: velestest.NewFakeIntSecret(456), 151 Location: path, 152 Validation: inventory.SecretValidationResult{ 153 Status: veles.ValidationFailed, 154 Err: errTest, 155 }, 156 }, 157 }, 158 }, 159 }, 160 { 161 name: "mixed", 162 input: inventory.Inventory{ 163 Secrets: []*inventory.Secret{ 164 { 165 Secret: velestest.NewFakeIntSecret(123), 166 Location: path, 167 }, 168 { 169 Secret: velestest.NewFakeStringSecret("foo"), 170 Location: path, 171 }, 172 }, 173 }, 174 want: inventory.Inventory{ 175 Secrets: []*inventory.Secret{ 176 { 177 Secret: velestest.NewFakeIntSecret(123), 178 Location: path, 179 Validation: inventory.SecretValidationResult{ 180 Status: veles.ValidationFailed, 181 Err: errTest, 182 }, 183 }, 184 { 185 Secret: velestest.NewFakeStringSecret("foo"), 186 Location: path, 187 Validation: inventory.SecretValidationResult{ 188 Status: veles.ValidationValid, 189 }, 190 }, 191 }, 192 }, 193 }, 194 }, 195 }, 196 } 197 for _, tc := range cases { 198 t.Run(tc.name, func(t *testing.T) { 199 enricher := secrets.NewWithEngine(tc.engine) 200 for _, sc := range tc.subs { 201 t.Run(sc.name, func(t *testing.T) { 202 if err := enricher.Enrich(t.Context(), nil, &sc.input); err != nil { 203 t.Errorf("Enrich() error: %v, want nil", err) 204 } 205 got := &sc.input 206 want := &sc.want 207 // We can rely on the order of Secrets in the inventory here, since the enricher is not supposed to change it. 208 if diff := cmp.Diff(want, got, cmpopts.EquateErrors(), cmpopts.IgnoreTypes(time.Time{})); diff != "" { 209 t.Errorf("Enrich() got diff (-want +got):\n%s", diff) 210 } 211 }) 212 } 213 }) 214 } 215 } 216 217 func TestEnricher_respectsContext(t *testing.T) { 218 enricher := secrets.NewWithEngine(veles.NewValidationEngine( 219 veles.WithValidator(velestest.NewFakeStringSecretValidator(veles.ValidationValid, nil)), 220 )) 221 inv := &inventory.Inventory{ 222 Secrets: []*inventory.Secret{ 223 { 224 Secret: velestest.NewFakeStringSecret("foo"), 225 Location: "/foo/bar/baz.json", 226 }, 227 }, 228 } 229 ctx, cancel := context.WithCancel(t.Context()) 230 cancel() 231 if err := enricher.Enrich(ctx, nil, inv); !errors.Is(err, context.Canceled) { 232 t.Errorf("enricher.Enrich() error = nil, want context cancelled") 233 } 234 } 235 236 func TestAddValidator(t *testing.T) { 237 secret := inventory.Secret{ 238 Secret: velestest.NewFakeStringSecret("foo"), 239 Location: "/foo/bar/baz.json", 240 } 241 inv := inventory.Inventory{Secrets: []*inventory.Secret{&secret}} 242 enricher := secrets.NewWithEngine(veles.NewValidationEngine()).(*secrets.Enricher) 243 244 // Ensure that it's unsupported. 245 if err := enricher.Enrich(t.Context(), nil, &inv); err != nil { 246 t.Errorf("Enrich() error: %v, want nil", err) 247 } 248 if got, want := secret.Validation.Status, veles.ValidationUnsupported; got != want { 249 t.Errorf("Enrich() validation status = %q, want %q", got, want) 250 } 251 252 // Add new validator and ensure that we now get the correct result. 253 if present := secrets.AddValidator(enricher, velestest.NewFakeStringSecretValidator(veles.ValidationValid, nil)); present { 254 t.Errorf("AddValidator() = %t, want false", present) 255 } 256 if err := enricher.Enrich(t.Context(), nil, &inv); err != nil { 257 t.Errorf("Enrich() error: %v, want nil", err) 258 } 259 if got, want := secret.Validation.Status, veles.ValidationValid; got != want { 260 t.Errorf("Enrich() validation status = %q, want %q", got, want) 261 } 262 }