github.com/google/osv-scalibr@v0.4.1/veles/secrets/rubygemsapikey/detector_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 rubygemsapikey_test
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  	"github.com/google/go-cmp/cmp/cmpopts"
    24  	"github.com/google/osv-scalibr/veles"
    25  	"github.com/google/osv-scalibr/veles/secrets/rubygemsapikey"
    26  )
    27  
    28  const testKey = `rubygems_cec9db9373ea171daaaa0bf2337edce187f09558cb19c1b2`
    29  
    30  // TestDetector_truePositives tests for cases where we know the Detector
    31  // will find a RubyGems API key/s.
    32  func TestDetector_truePositives(t *testing.T) {
    33  	engine, err := veles.NewDetectionEngine([]veles.Detector{rubygemsapikey.NewDetector()})
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	cases := []struct {
    38  		name  string
    39  		input string
    40  		want  []veles.Secret
    41  	}{{
    42  		name:  "simple matching string",
    43  		input: testKey,
    44  		want: []veles.Secret{
    45  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    46  		},
    47  	}, {
    48  		name:  "match at end of string",
    49  		input: `RUBYGEMS_API_KEY=` + testKey,
    50  		want: []veles.Secret{
    51  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    52  		},
    53  	}, {
    54  		name:  "match in middle of string",
    55  		input: `RUBYGEMS_API_KEY="` + testKey + `"`,
    56  		want: []veles.Secret{
    57  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    58  		},
    59  	}, {
    60  		name:  "multiple matches",
    61  		input: testKey + testKey + testKey,
    62  		want: []veles.Secret{
    63  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    64  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    65  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    66  		},
    67  	}, {
    68  		name:  "multiple distinct matches",
    69  		input: testKey + "\n" + testKey[:len(testKey)-1] + "1\n",
    70  		want: []veles.Secret{
    71  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    72  			rubygemsapikey.RubyGemsAPIKey{Key: testKey[:len(testKey)-1] + "1"},
    73  		},
    74  	}, {
    75  		name: "larger_input_containing_key",
    76  		input: fmt.Sprintf(`
    77  :test_api_key: rubygems_abc
    78  :rubygems_api_key: %s 
    79  		`, testKey),
    80  		want: []veles.Secret{
    81  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    82  		},
    83  	}, {
    84  		name:  "potential match longer than max key length",
    85  		input: testKey + `test`,
    86  		want: []veles.Secret{
    87  			rubygemsapikey.RubyGemsAPIKey{Key: testKey},
    88  		},
    89  	}}
    90  	for _, tc := range cases {
    91  		t.Run(tc.name, func(t *testing.T) {
    92  			got, err := engine.Detect(t.Context(), strings.NewReader(tc.input))
    93  			if err != nil {
    94  				t.Errorf("Detect() error: %v, want nil", err)
    95  			}
    96  			fmt.Printf("got = %+v\n", got)
    97  			if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" {
    98  				t.Errorf("Detect() diff (-want +got):\n%s", diff)
    99  			}
   100  		})
   101  	}
   102  }
   103  
   104  // TestDetector_trueNegatives tests for cases where we know the Detector
   105  // will not find a RubyGems API key.
   106  func TestDetector_trueNegatives(t *testing.T) {
   107  	engine, err := veles.NewDetectionEngine([]veles.Detector{rubygemsapikey.NewDetector()})
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	cases := []struct {
   112  		name  string
   113  		input string
   114  		want  []veles.Secret
   115  	}{{
   116  		name:  "empty input",
   117  		input: "",
   118  	}, {
   119  		name:  "short key should not match",
   120  		input: testKey[:len(testKey)-1],
   121  	}, {
   122  		name:  "special character in key should not match",
   123  		input: `rubygems_cec9db9373ea171daaaa0bf2337edce187f09558cb19c1b.`,
   124  	}, {
   125  		name:  "special character in prefix should not match",
   126  		input: `ruby.gems_cec9db9373ea171daaaa0bf2337edce187f09558cb19c1b2`,
   127  	}, {
   128  		name:  "special character after prefix should not match",
   129  		input: `rubygems_.cec9db9373ea171daaaa0bf2337edce187f09558cb19c1b2`,
   130  	}, {
   131  		name:  "incorrect casing of prefix should not match",
   132  		input: `rubyGEMS_cec9db9373ea171daaaa0bf2337edce187f09558cb19c1b2`,
   133  	}, {
   134  		name:  "invalid casing in key should not match",
   135  		input: `rubygems_cec9db9373ea171daaaa0bf2337EDCE187f09558cb19c1b2`,
   136  	}}
   137  	for _, tc := range cases {
   138  		t.Run(tc.name, func(t *testing.T) {
   139  			got, err := engine.Detect(t.Context(), strings.NewReader(tc.input))
   140  			if err != nil {
   141  				t.Errorf("Detect() error: %v, want nil", err)
   142  			}
   143  			if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" {
   144  				t.Errorf("Detect() diff (-want +got):\n%s", diff)
   145  			}
   146  		})
   147  	}
   148  }