From dc6be312cf592a294bfe370762856d98de29a64d Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Sat, 23 Nov 2024 07:31:53 +0100 Subject: [PATCH] feat: add yaml based encoding for get secrets as map (#4001) --- pkg/provider/bitwarden/client.go | 36 ++++++++++- pkg/provider/bitwarden/client_test.go | 86 +++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/pkg/provider/bitwarden/client.go b/pkg/provider/bitwarden/client.go index 5b76f1cc4..94215d4a9 100644 --- a/pkg/provider/bitwarden/client.go +++ b/pkg/provider/bitwarden/client.go @@ -15,11 +15,13 @@ limitations under the License. package bitwarden import ( + "bytes" "context" "encoding/json" "errors" "fmt" + "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" "k8s.io/kube-openapi/pkg/validation/strfmt" @@ -238,9 +240,12 @@ func (p *Provider) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecre return nil, err } + if err := yaml.Unmarshal(data, map[string]any{}); err == nil { + return p.parseYamlSecretData(data) + } + kv := make(map[string]json.RawMessage) - err = json.Unmarshal(data, &kv) - if err != nil { + if err := json.Unmarshal(data, &kv); err != nil { return nil, fmt.Errorf("error unmarshalling secret: %w", err) } @@ -258,6 +263,33 @@ func (p *Provider) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecre return secretData, nil } +func (p *Provider) parseYamlSecretData(data []byte) (map[string][]byte, error) { + kv := make(map[string]any) + if err := yaml.Unmarshal(data, &kv); err != nil { + return nil, fmt.Errorf("error unmarshalling secret: %w", err) + } + + secretData := make(map[string][]byte) + for k, v := range kv { + switch t := v.(type) { + case string: + secretData[k] = []byte(t) + case []byte: + secretData[k] = t + case map[string]any: + d, err := yaml.Marshal(t) + if err != nil { + return nil, fmt.Errorf("error marshaling secret: %w", err) + } + secretData[k] = bytes.TrimSpace(d) + default: + secretData[k] = []byte(fmt.Sprintf("%v", t)) // Convert to string and then []byte + } + } + + return secretData, nil +} + // GetAllSecrets gets multiple secrets from the provider and loads into a kubernetes secret. // First load all secrets from secretStore path configuration // Then, gets secrets from a matching name or matching custom_metadata. diff --git a/pkg/provider/bitwarden/client_test.go b/pkg/provider/bitwarden/client_test.go index 4010801ff..3672600a0 100644 --- a/pkg/provider/bitwarden/client_test.go +++ b/pkg/provider/bitwarden/client_test.go @@ -934,6 +934,92 @@ func TestProviderGetSecretMap(t *testing.T) { }, want: []byte("value"), }, + { + name: "get secret map with yaml", + fields: fields{ + kube: func() client.Client { + return fake.NewFakeClient() + }, + namespace: "default", + store: &v1beta1.SecretStore{}, + mock: func(c *FakeClient) { + c.GetSecretReturnsOnCallN(0, &SecretResponse{ + ID: "d8f29773-3019-4973-9bbc-66327d077fe2", + Key: "key", + Note: "note", + OrganizationID: "org", + Value: `key: value`, + }) + }, + }, + args: args{ + ctx: context.Background(), + ref: v1beta1.ExternalSecretDataRemoteRef{ + Key: "d8f29773-3019-4973-9bbc-66327d077fe2", + Property: "key", + }, + key: "key", + }, + want: []byte("value"), + }, + { + name: "get secret map with nested yaml", + fields: fields{ + kube: func() client.Client { + return fake.NewFakeClient() + }, + namespace: "default", + store: &v1beta1.SecretStore{}, + mock: func(c *FakeClient) { + c.GetSecretReturnsOnCallN(0, &SecretResponse{ + ID: "d8f29773-3019-4973-9bbc-66327d077fe2", + Key: "key", + Note: "note", + OrganizationID: "org", + Value: `key: + key2: value`, + }) + }, + }, + args: args{ + ctx: context.Background(), + ref: v1beta1.ExternalSecretDataRemoteRef{ + Key: "d8f29773-3019-4973-9bbc-66327d077fe2", + Property: "key", + }, + key: "key", + }, + want: []byte("key2: value"), + }, + { + name: "get secret map with binary yaml data", + fields: fields{ + kube: func() client.Client { + return fake.NewFakeClient() + }, + namespace: "default", + store: &v1beta1.SecretStore{}, + mock: func(c *FakeClient) { + c.GetSecretReturnsOnCallN(0, &SecretResponse{ + ID: "d8f29773-3019-4973-9bbc-66327d077fe2", + Key: "key", + Note: "note", + OrganizationID: "org", + Value: `key: value +key2: !!binary VGhpcyBpcyBhIHRlc3Q=`, + }) + }, + }, + args: args{ + ctx: context.Background(), + ref: v1beta1.ExternalSecretDataRemoteRef{ + Key: "d8f29773-3019-4973-9bbc-66327d077fe2", + Property: "key2", + }, + key: "key2", + }, + want: []byte(`This is a test`), + }, { name: "get secret map - missing key", fields: fields{