github.com/google/osv-scalibr@v0.4.1/veles/secrets/gcpexpressmode/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 gcpexpressmode_test 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-cmp/cmp/cmpopts" 23 "github.com/google/osv-scalibr/veles" 24 "github.com/google/osv-scalibr/veles/secrets/gcpexpressmode" 25 ) 26 27 const ( 28 testKey = "AQ.Ab8Rthat-is-1-very-nice-KeyYouGotThere_ShameIfLost" 29 ) 30 31 func TestDetector_truePositives(t *testing.T) { 32 engine, err := veles.NewDetectionEngine([]veles.Detector{gcpexpressmode.NewDetector()}) 33 if err != nil { 34 t.Fatalf("veles.NewDetectionEngine() error: %v", err) 35 } 36 cases := []struct { 37 name string 38 input string 39 want []veles.Secret 40 }{ 41 { 42 name: "simple matching string", 43 input: testKey, 44 want: []veles.Secret{ 45 gcpexpressmode.APIKey{Key: testKey}, 46 }, 47 }, 48 { 49 name: "match at end of string", 50 input: "API_KEY=" + testKey, 51 want: []veles.Secret{ 52 gcpexpressmode.APIKey{Key: testKey}, 53 }, 54 }, 55 { 56 name: "match in middle of string", 57 input: `API_KEY="` + testKey + `"`, 58 want: []veles.Secret{ 59 gcpexpressmode.APIKey{Key: testKey}, 60 }, 61 }, 62 { 63 name: "multiple matches", 64 input: testKey + "\n" + testKey + testKey, 65 want: []veles.Secret{ 66 gcpexpressmode.APIKey{Key: testKey}, 67 gcpexpressmode.APIKey{Key: testKey}, 68 gcpexpressmode.APIKey{Key: testKey}, 69 }, 70 }, 71 { 72 name: "multiple distinct matches", 73 input: testKey + "\n" + testKey[:len(testKey)-1] + "1\n", 74 want: []veles.Secret{ 75 gcpexpressmode.APIKey{Key: testKey}, 76 gcpexpressmode.APIKey{Key: testKey[:len(testKey)-1] + "1"}, 77 }, 78 }, 79 } 80 for _, tc := range cases { 81 t.Run(tc.name, func(t *testing.T) { 82 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 83 if err != nil { 84 t.Errorf("Detect() error: %v, want nil", err) 85 } 86 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 87 t.Errorf("Detect() diff (-want +got):\n%s", diff) 88 } 89 }) 90 } 91 } 92 93 func TestDetector_trueNegatives(t *testing.T) { 94 engine, err := veles.NewDetectionEngine([]veles.Detector{gcpexpressmode.NewDetector()}) 95 if err != nil { 96 t.Fatal(err) 97 } 98 cases := []struct { 99 name string 100 input string 101 want []veles.Secret 102 }{ 103 { 104 name: "empty input", 105 input: "", 106 }, 107 { 108 name: "short key should not match", 109 input: testKey[:len(testKey)-1], 110 }, 111 { 112 name: "incorrect casing of prefix should not match", 113 input: strings.ToLower(testKey), 114 }, 115 { 116 name: "special character in key should not match", 117 input: "AQ.Ab8Rthat-is-1-very-n.ce-KeyYouGotThere_ShameIfLost", 118 }, 119 { 120 name: "wrong prefix should not match", 121 input: "AQ-Ab8Rthat-is-1-very-n.ce-KeyYouGotThere_ShameIfLost", 122 }, 123 } 124 for _, tc := range cases { 125 t.Run(tc.name, func(t *testing.T) { 126 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 127 if err != nil { 128 t.Errorf("Detect() error: %v, want nil", err) 129 } 130 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 131 t.Errorf("Detect() diff (-want +got):\n%s", diff) 132 } 133 }) 134 } 135 }