github.com/google/osv-scalibr@v0.4.1/veles/secrets/pyxkeyv2/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 pyxkeyv2_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/pyxkeyv2" 26 ) 27 28 const ( 29 testKey = `sk-pyx-2testestestestestestestestestestestestestestes` 30 testKeyMixedCase = `sk-pyx-2testesTESTesTESTestestestestestestestestestes` 31 ) 32 33 // TestDetector_truePositives tests for cases where we know the Detector 34 // will find a pyx v2 user key. 35 func TestDetector_truePositives(t *testing.T) { 36 engine, err := veles.NewDetectionEngine([]veles.Detector{pyxkeyv2.NewDetector()}) 37 if err != nil { 38 t.Fatal(err) 39 } 40 cases := []struct { 41 name string 42 input string 43 want []veles.Secret 44 }{{ 45 name: "simple matching string", 46 input: testKey, 47 want: []veles.Secret{ 48 pyxkeyv2.PyxKeyV2{Key: testKey}, 49 }, 50 }, { 51 name: "match at end of string", 52 input: `PYX_KEY=` + testKey, 53 want: []veles.Secret{ 54 pyxkeyv2.PyxKeyV2{Key: testKey}, 55 }, 56 }, { 57 name: "match in middle of string", 58 input: `PYX_KEY="` + testKey + `"`, 59 want: []veles.Secret{ 60 pyxkeyv2.PyxKeyV2{Key: testKey}, 61 }, 62 }, { 63 name: "matching string with mixed case", 64 input: testKeyMixedCase, 65 want: []veles.Secret{ 66 pyxkeyv2.PyxKeyV2{Key: testKeyMixedCase}, 67 }, 68 }, { 69 name: "multiple matches", 70 input: testKey + testKey + testKey, 71 want: []veles.Secret{ 72 pyxkeyv2.PyxKeyV2{Key: testKey}, 73 pyxkeyv2.PyxKeyV2{Key: testKey}, 74 pyxkeyv2.PyxKeyV2{Key: testKey}, 75 }, 76 }, { 77 name: "multiple distinct matches", 78 input: testKey + "\n" + testKey[:len(testKey)-1] + "A\n", 79 want: []veles.Secret{ 80 pyxkeyv2.PyxKeyV2{Key: testKey}, 81 pyxkeyv2.PyxKeyV2{Key: testKey[:len(testKey)-1] + "A"}, 82 }, 83 }, { 84 name: "larger_input_containing_key", 85 input: fmt.Sprintf(` 86 CONFIG_FILE=config.txt 87 PYX_KEY=%s 88 CLOUD_PROJECT=my-project 89 `, testKey), 90 want: []veles.Secret{ 91 pyxkeyv2.PyxKeyV2{Key: testKey}, 92 }, 93 }, { 94 name: "potential match longer than max key length", 95 input: testKey + `test`, 96 want: []veles.Secret{ 97 pyxkeyv2.PyxKeyV2{Key: testKey}, 98 }, 99 }} 100 for _, tc := range cases { 101 t.Run(tc.name, func(t *testing.T) { 102 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 103 if err != nil { 104 t.Errorf("Detect() error: %v, want nil", err) 105 } 106 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 107 t.Errorf("Detect() diff (-want +got):\n%s", diff) 108 } 109 }) 110 } 111 } 112 113 // TestDetector_trueNegatives tests for cases where we know the Detector 114 // will not find a pyx v2 user key. 115 func TestDetector_trueNegatives(t *testing.T) { 116 engine, err := veles.NewDetectionEngine([]veles.Detector{pyxkeyv2.NewDetector()}) 117 if err != nil { 118 t.Fatal(err) 119 } 120 cases := []struct { 121 name string 122 input string 123 want []veles.Secret 124 }{{ 125 name: "empty input", 126 input: "", 127 }, { 128 name: "short key should not match", 129 input: testKey[:len(testKey)-1], 130 }, { 131 name: "incorrect casing of prefix should not match", 132 input: `SK-pyx-2testestestestestestestestestestestestestestes`, 133 }, { 134 name: "number in key should not match", 135 input: `sk-pyx-21estestestestestestestestestestestestesteste.`, 136 }, { 137 name: "special character in key should not match", 138 input: `sk-pyx-2testestestestestestestestestestestestesteste.`, 139 }, { 140 name: "unexpected special character in prefix should not match", 141 input: `sk.pyx-2testestestestestestestestestestestestestestes`, 142 }, { 143 name: "special character after prefix should not match", 144 input: `sk-pyx-2.estestestestestestestestestestestestestestes`, 145 }} 146 for _, tc := range cases { 147 t.Run(tc.name, func(t *testing.T) { 148 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 149 if err != nil { 150 t.Errorf("Detect() error: %v, want nil", err) 151 } 152 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 153 t.Errorf("Detect() diff (-want +got):\n%s", diff) 154 } 155 }) 156 } 157 }