github.com/google/osv-scalibr@v0.4.1/veles/secrets/hcp/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 hcp_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/hcp" 25 ) 26 27 func TestPairDetector(t *testing.T) { 28 engine, err := veles.NewDetectionEngine([]veles.Detector{hcp.NewPairDetector()}) 29 if err != nil { 30 t.Fatal(err) 31 } 32 33 id := "53au9oDSqR8SBzIy6QJASHnyC1SMQxE2" // 32 chars 34 sec := "GGoNkaj1uVBWLO5Lk0-G3duEBK2Mi-w8kUpIJfX7u93fgWqnbMiaKYJgKrO2F6Vc" // 64 chars 35 36 cases := []struct { 37 name string 38 input string 39 want []veles.Secret 40 }{ 41 {"param_pair", "hcp_client_id=" + id + "\nhcp_client_secret=" + sec, []veles.Secret{hcp.ClientCredentials{ClientID: id, ClientSecret: sec}}}, 42 {"env_pair", "HCP_CLIENT_ID=" + id + "\nHCP_CLIENT_SECRET=" + sec, []veles.Secret{hcp.ClientCredentials{ClientID: id, ClientSecret: sec}}}, 43 {"kv_colon_pair", "hcp_client_id: '" + id + "'\nhcp_client_secret: \"" + sec + "\"", []veles.Secret{hcp.ClientCredentials{ClientID: id, ClientSecret: sec}}}, 44 {"id_only", "hcp_client_id=" + id, []veles.Secret{hcp.ClientCredentials{ClientID: id}}}, 45 {"secret_only", "hcp_client_secret=" + sec, []veles.Secret{hcp.ClientCredentials{ClientSecret: sec}}}, 46 {"wrong_secret", "client_secret=" + id, []veles.Secret{}}, 47 {"secret_before_id_within_window", "hcp_client_secret=" + sec + "\n...\nHCP_CLIENT_ID=" + id, []veles.Secret{hcp.ClientCredentials{ClientID: id, ClientSecret: sec}}}, 48 {"too_far_apart", func() string { 49 filler := strings.Repeat("a", 10*10*1<<10) // 100 KiB 50 return "HCP_CLIENT_ID=" + id + "\n" + filler + "\nHCP_CLIENT_SECRET=" + sec 51 }(), []veles.Secret{hcp.ClientCredentials{ClientID: id}, hcp.ClientCredentials{ClientSecret: sec}}}, 52 {"secret_before_id_too_far", func() string { 53 filler := strings.Repeat("b", 10*10*1<<10) // 100 KiB 54 return "HCP_CLIENT_SECRET=" + sec + "\n" + filler + "\nHCP_CLIENT_ID=" + id 55 }(), []veles.Secret{hcp.ClientCredentials{ClientSecret: sec}, hcp.ClientCredentials{ClientID: id}}}, 56 } 57 58 for _, tc := range cases { 59 t.Run(tc.name, func(t *testing.T) { 60 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 61 if err != nil { 62 t.Fatalf("Detect() error: %v", err) 63 } 64 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 65 t.Errorf("Detect() diff (-want +got):\n%s", diff) 66 } 67 }) 68 } 69 } 70 71 func TestAccessTokenDetector(t *testing.T) { 72 engine, err := veles.NewDetectionEngine([]veles.Detector{hcp.NewAccessTokenDetector()}) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 // JWT with strict HCP-like fields in payload: header.payload.signature (base64url) 78 payload := "eyJpc3MiOiJodHRwczovL2F1dGguaWRwLmhhc2hpY29ycC5jb20vIiwiYXVkIjpbImh0dHBzOi8vYXBpLmhhc2hpY29ycC5jbG91ZCJdLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ" 79 header := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" 80 sig := "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" 81 jwt := header + "." + payload + "." + sig 82 83 // Same structure but different issuer (should be rejected) 84 payloadWrongIss := "eyJpc3MiOiJodHRwczovL3NvbWUtcmFuZG9tLWlkcC5pbnRlcm5hbC8iLCJhdWQiOlsiaHR0cHM6Ly9hcGkuaGFzaGljb3JwLmNsb3VkIl0sImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9" 85 jtwWrong := header + "." + payloadWrongIss + "." + sig 86 87 cases := []struct { 88 name string 89 input string 90 want []veles.Secret 91 }{ 92 {"bare_jwt_hcp", jwt, []veles.Secret{hcp.AccessToken{Token: jwt}}}, 93 {"wrong_issuer", jtwWrong, nil}, 94 } 95 96 for _, tc := range cases { 97 t.Run(tc.name, func(t *testing.T) { 98 got, err := engine.Detect(t.Context(), strings.NewReader(tc.input)) 99 if err != nil { 100 t.Fatalf("Detect() error: %v", err) 101 } 102 if diff := cmp.Diff(tc.want, got, cmpopts.EquateEmpty()); diff != "" { 103 t.Errorf("Detect() diff (-want +got):\n%s", diff) 104 } 105 }) 106 } 107 }