| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*
- Copyright © The ESO Authors
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- https://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package barbican
- import (
- "context"
- "encoding/json"
- "fmt"
- "net/http"
- "testing"
- "github.com/gophercloud/gophercloud/v2"
- th "github.com/gophercloud/gophercloud/v2/testhelper"
- thclient "github.com/gophercloud/gophercloud/v2/testhelper/client"
- "github.com/stretchr/testify/assert"
- esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
- )
- func TestExtractUUIDFromRef(t *testing.T) {
- testCases := []struct {
- name string
- secretRef string
- expectedUUID string
- }{
- {
- name: "valid barbican secret ref",
- secretRef: "https://barbican.example.com/v1/secrets/12345678-1234-1234-1234-123456789abc",
- expectedUUID: "12345678-1234-1234-1234-123456789abc",
- },
- {
- name: "secret ref without protocol",
- secretRef: "barbican.example.com/v1/secrets/87654321-4321-4321-4321-cba987654321",
- expectedUUID: "87654321-4321-4321-4321-cba987654321",
- },
- {
- name: "empty string",
- secretRef: "",
- expectedUUID: "",
- },
- {
- name: "trailing slash",
- secretRef: "https://barbican.example.com/v1/secrets/12345678-1234-1234-1234-123456789abc/",
- expectedUUID: "",
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- uuid := extractUUIDFromRef(tc.secretRef)
- assert.Equal(t, tc.expectedUUID, uuid)
- })
- }
- }
- func TestGetSecretPayloadProperty(t *testing.T) {
- testPayload := []byte(`{"username":"admin","password":"secret123","nested":{"key":"value"}}`)
- testCases := []struct {
- name string
- payload []byte
- property string
- expectError bool
- errorMessage string
- expectedData []byte
- }{
- {
- name: "empty property returns full payload",
- payload: testPayload,
- property: "",
- expectError: false,
- expectedData: testPayload,
- },
- {
- name: "valid property extraction",
- payload: testPayload,
- property: "username",
- expectError: false,
- expectedData: []byte(`"admin"`),
- },
- {
- name: "nested property extraction",
- payload: testPayload,
- property: "nested",
- expectError: false,
- expectedData: []byte(`{"key":"value"}`),
- },
- {
- name: "property not found",
- payload: testPayload,
- property: "nonexistent",
- expectError: true,
- errorMessage: "property nonexistent not found in secret payload",
- },
- {
- name: "invalid JSON",
- payload: []byte("invalid-json"),
- property: "username",
- expectError: true,
- errorMessage: "barbican client",
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- data, err := getSecretPayloadProperty(tc.payload, tc.property)
- if tc.expectError {
- assert.Error(t, err)
- assert.Contains(t, err.Error(), tc.errorMessage)
- assert.Nil(t, data)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tc.expectedData, data)
- }
- })
- }
- }
- func TestUnsupportedOperations(t *testing.T) {
- client := &Client{
- keyManager: &gophercloud.ServiceClient{},
- }
- // Test PushSecret
- err := client.PushSecret(context.Background(), nil, nil)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "does not support pushing secrets")
- // Test SecretExists
- exists, err := client.SecretExists(context.Background(), nil)
- assert.Error(t, err)
- assert.False(t, exists)
- assert.Contains(t, err.Error(), "does not support checking secret existence")
- // Test DeleteSecret
- err = client.DeleteSecret(context.Background(), nil)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "does not support deleting secrets")
- }
- func TestValidateAndClose(t *testing.T) {
- client := &Client{
- keyManager: &gophercloud.ServiceClient{},
- }
- // Test Validate
- result, err := client.Validate()
- assert.NoError(t, err)
- assert.Equal(t, esv1.ValidationResultUnknown, result)
- // Test Close
- err = client.Close(context.Background())
- assert.NoError(t, err)
- }
- func TestGetAllSecretsValidation(t *testing.T) {
- client := &Client{
- keyManager: &gophercloud.ServiceClient{},
- }
- testCases := []struct {
- name string
- findRef esv1.ExternalSecretFind
- expectError bool
- errorMessage string
- }{
- {
- name: "no name specified should return error",
- findRef: esv1.ExternalSecretFind{
- Name: nil,
- },
- expectError: true,
- errorMessage: "missing field",
- },
- {
- name: "empty name regex should return error",
- findRef: esv1.ExternalSecretFind{
- Name: &esv1.FindName{
- RegExp: "",
- },
- },
- expectError: true,
- errorMessage: "missing field",
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- _, err := client.GetAllSecrets(context.Background(), tc.findRef)
- if tc.expectError {
- assert.Error(t, err)
- assert.Contains(t, err.Error(), tc.errorMessage)
- } else if err != nil {
- assert.Contains(t, err.Error(), "barbican client")
- }
- })
- }
- }
- func TestGetAllSecretsRegexpMatch(t *testing.T) {
- type fakeSecret struct {
- name string
- uuid string
- payload string
- }
- all := []fakeSecret{
- {name: "db-a", uuid: "11111111-1111-1111-1111-111111111111", payload: "payload-db-a"},
- {name: "db-b", uuid: "22222222-2222-2222-2222-222222222222", payload: "payload-db-b"},
- {name: "web-a", uuid: "33333333-3333-3333-3333-333333333333", payload: "payload-web-a"},
- }
- fakeServer := th.SetupHTTP()
- defer fakeServer.Teardown()
- // Barbican's list endpoint only does exact-name matching, so mirror that
- // here: honor the ?name= query with a literal comparison, like the real
- // service does. A regexp value therefore matches nothing server-side, which
- // is exactly the reported bug.
- fakeServer.Mux.HandleFunc("/secrets", func(w http.ResponseWriter, r *http.Request) {
- nameFilter := r.URL.Query().Get("name")
- type listed struct {
- Name string `json:"name"`
- SecretRef string `json:"secret_ref"`
- }
- var out []listed
- for _, s := range all {
- if nameFilter != "" && s.name != nameFilter {
- continue
- }
- out = append(out, listed{
- Name: s.name,
- SecretRef: fmt.Sprintf("http://barbican.example.com/v1/secrets/%s", s.uuid),
- })
- }
- body, _ := json.Marshal(map[string]any{"secrets": out, "total": len(out)})
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- _, _ = w.Write(body)
- })
- for _, s := range all {
- payload := s.payload
- fakeServer.Mux.HandleFunc("/secrets/"+s.uuid+"/payload", func(w http.ResponseWriter, _ *http.Request) {
- w.Header().Set("Content-Type", "text/plain")
- w.WriteHeader(http.StatusOK)
- _, _ = w.Write([]byte(payload))
- })
- }
- client := &Client{keyManager: thclient.ServiceClient(fakeServer)}
- result, err := client.GetAllSecrets(context.Background(), esv1.ExternalSecretFind{
- Name: &esv1.FindName{RegExp: "^db-"},
- })
- assert.NoError(t, err)
- // Only the db-* secrets should match the pattern, not web-a and not just a
- // literal secret named "^db-".
- assert.Len(t, result, 2)
- assert.Equal(t, []byte("payload-db-a"), result["11111111-1111-1111-1111-111111111111"])
- assert.Equal(t, []byte("payload-db-b"), result["22222222-2222-2222-2222-222222222222"])
- assert.NotContains(t, result, "33333333-3333-3333-3333-333333333333")
- }
|