github.com/google/osv-scalibr@v0.4.1/veles/secrets/azurestorageaccountaccesskey/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 azurestorageaccountaccesskey_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/azurestorageaccountaccesskey" 26 ) 27 28 // Azure Storage account access key is composed by 86 base64 characters followed by '==' 29 // Reference: 30 // https://learn.microsoft.com/en-us/purview/sit-defn-azure-storage-account-key-generic 31 const testKey = `YutGV0Vlauqsobd6tPWz2AKwHhBXMEWsAH+rSbz0UZUfaMVj1CFrcNQK47ygmrC4vHmc7eOp1LdM+AStk5mMYA==` 32 33 // TestDetector_truePositives tests for cases where we know the Detector 34 // will find a valid key/s. 35 func TestDetector_truePositives(t *testing.T) { 36 engine, err := veles.NewDetectionEngine([]veles.Detector{azurestorageaccountaccesskey.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: "AzureStoragekey : " + testKey, 47 want: []veles.Secret{ 48 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 49 }, 50 }, { 51 // According to Microsoft documentation the key can start with 52 // zero to one of the greater than symbol (>), apostrophe ('), 53 // equal sign (=), quotation mark (?), or number sign (#) 54 // Therefore the equal sign after the api key should be present in the result 55 name: "match at end of string", 56 input: `AZURE_ACCOUNT_STORAGE_ACCESS_KEY=` + testKey, 57 want: []veles.Secret{ 58 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: `=` + testKey}, 59 }, 60 }, { 61 name: "match in middle of string", 62 input: `AZURE_KEY="` + testKey + `"`, 63 want: []veles.Secret{ 64 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 65 }, 66 }, { 67 name: "multiple matches", 68 input: "AZURE_KEY:" + testKey + "AZURE_ACCOUNT_STORAGE_ACCESS_KEY:" + testKey + "AZURE_KEY:" + testKey, 69 want: []veles.Secret{ 70 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 71 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 72 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 73 }, 74 }, { 75 name: "larger_input_containing_key", 76 input: fmt.Sprintf(` 77 CONFIG_FILE=config.txt 78 storage_access_KEY="%s" 79 CLOUD_PROJECT=my-project 80 `, testKey), 81 want: []veles.Secret{ 82 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 83 }, 84 }, { 85 name: "potential match longer than max key length", 86 input: "azure_account_key:" + testKey + `test`, 87 want: []veles.Secret{ 88 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 89 }, 90 }, { 91 name: "match_with_command_line", 92 input: fmt.Sprintf(`az storage container create 93 --account-name sample_username 94 --name sample-container 95 --account-key %s 96 --auth-mode key`, testKey), 97 want: []veles.Secret{ 98 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: testKey}, 99 }, 100 }, { 101 // the equal sign in the result is present according to Ms Documentation 102 // See comment at row 51 103 name: "match_with_connection_string", 104 input: fmt.Sprintf(` 105 DefaultEndpointsProtocol=http;AccountName=devstoreaccount1; 106 AccountKey=%s; 107 BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1; 108 QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1; 109 TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;`, testKey), 110 want: []veles.Secret{ 111 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: "=" + testKey}, 112 }, 113 }, { 114 // the equal sign is present as per Microsoft documentation 115 // See comment at row 51 116 name: "match with env vars", 117 input: "AZURE_STORAGE_KEY=" + testKey, 118 want: []veles.Secret{ 119 azurestorageaccountaccesskey.AzureStorageAccountAccessKey{Key: "=" + testKey}, 120 }, 121 }} 122 for _, tc := range cases { 123 t.Run(tc.name, func(t *testing.T) { 124 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 125 if err != nil { 126 t.Errorf("Detect() error: %v, want nil", err) 127 } 128 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 129 t.Errorf("Detect() diff (-want +got):\n%s", diff) 130 } 131 }) 132 } 133 } 134 135 // TestDetector_trueNegatives tests for cases where we know the Detector 136 // will not find a valid key. 137 func TestDetector_trueNegatives(t *testing.T) { 138 engine, err := veles.NewDetectionEngine([]veles.Detector{azurestorageaccountaccesskey.NewDetector()}) 139 if err != nil { 140 t.Fatal(err) 141 } 142 cases := []struct { 143 name string 144 input string 145 want []veles.Secret 146 }{{ 147 name: "empty input", 148 input: "", 149 }, { 150 name: "short key should not match", 151 input: "Azure_storage_key:" + testKey[:len(testKey)-1], 152 }, { 153 name: "special character ($) in key should not match", 154 input: `Azure.storage.key : Yut$V0Vlauqsobd6tPWz2AKwHhBXMEWsAH+rSbz0UZUfaMVj1CFrcNQK47ygmrC4vHmc7eOp1LdM+AStk5mMYA==`, 155 }, 156 } 157 for _, tc := range cases { 158 t.Run(tc.name, func(t *testing.T) { 159 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 160 if err != nil { 161 t.Errorf("Detect() error: %v, want nil", err) 162 } 163 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 164 t.Errorf("Detect() diff (-want +got):\n%s", diff) 165 } 166 }) 167 } 168 }