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  }