Procházet zdrojové kódy

feat(v2): add full GetSecretMap gRPC RPC

Moritz Johner před 3 měsíci
rodič
revize
bafa331529

+ 5 - 0
providers/v2/adapter/server.go

@@ -62,6 +62,11 @@ func (s *Server) GetSecret(ctx context.Context, req *pb.GetSecretRequest) (*pb.G
 	return s.storeServer.GetSecret(ctx, req)
 }
 
+// GetSecretMap retrieves multiple key/value pairs from a single secret object.
+func (s *Server) GetSecretMap(ctx context.Context, req *pb.GetSecretMapRequest) (*pb.GetSecretMapResponse, error) {
+	return s.storeServer.GetSecretMap(ctx, req)
+}
+
 // PushSecret pushes a secret to the provider.
 func (s *Server) PushSecret(ctx context.Context, req *pb.PushSecretRequest) (*pb.PushSecretResponse, error) {
 	return s.storeServer.PushSecret(ctx, req)

+ 1 - 40
providers/v2/adapter/store/client.go

@@ -17,9 +17,6 @@ package store
 
 import (
 	"context"
-	"encoding/json"
-	"fmt"
-	"strconv"
 
 	corev1 "k8s.io/api/core/v1"
 
@@ -54,26 +51,7 @@ func (w *Client) GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemot
 }
 
 func (w *Client) GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
-	secretData, err := w.v2Provider.GetSecret(ctx, ref, w.providerRef, w.sourceNamespace)
-	if err != nil {
-		return nil, err
-	}
-
-	values := make(map[string]any)
-	if err := json.Unmarshal(secretData, &values); err != nil {
-		return nil, fmt.Errorf("failed to decode secret as JSON object for extract: %w", err)
-	}
-
-	secretMap := make(map[string][]byte, len(values))
-	for key, value := range values {
-		byteValue, err := toByteValue(value)
-		if err != nil {
-			return nil, fmt.Errorf("failed to convert extracted value for key %q: %w", key, err)
-		}
-		secretMap[key] = byteValue
-	}
-
-	return secretMap, nil
+	return w.v2Provider.GetSecretMap(ctx, ref, w.providerRef, w.sourceNamespace)
 }
 
 // GetAllSecrets retrieves multiple secrets based on find criteria.
@@ -138,20 +116,3 @@ func (w *Client) Validate() (esv1.ValidationResult, error) {
 func (w *Client) Close(ctx context.Context) error {
 	return w.v2Provider.Close(ctx)
 }
-
-func toByteValue(value any) ([]byte, error) {
-	switch v := value.(type) {
-	case string:
-		return []byte(v), nil
-	case float64:
-		return []byte(strconv.FormatFloat(v, 'f', -1, 64)), nil
-	case bool:
-		return []byte(strconv.FormatBool(v)), nil
-	case nil:
-		return nil, nil
-	case map[string]any, []any:
-		return json.Marshal(v)
-	default:
-		return nil, fmt.Errorf("unsupported extracted value type: %T", v)
-	}
-}

+ 17 - 29
providers/v2/adapter/store/client_test.go

@@ -16,7 +16,6 @@ package store
 
 import (
 	"context"
-	"strings"
 	"testing"
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
@@ -24,12 +23,16 @@ import (
 )
 
 type fakeV2Provider struct {
-	getSecretResponse []byte
-	getSecretErr      error
+	getSecretMapResponse map[string][]byte
+	getSecretMapErr      error
 }
 
 func (f *fakeV2Provider) GetSecret(context.Context, esv1.ExternalSecretDataRemoteRef, *pb.ProviderReference, string) ([]byte, error) {
-	return f.getSecretResponse, f.getSecretErr
+	return nil, nil
+}
+
+func (f *fakeV2Provider) GetSecretMap(context.Context, esv1.ExternalSecretDataRemoteRef, *pb.ProviderReference, string) (map[string][]byte, error) {
+	return f.getSecretMapResponse, f.getSecretMapErr
 }
 
 func (f *fakeV2Provider) GetAllSecrets(context.Context, esv1.ExternalSecretFind, *pb.ProviderReference, string) (map[string][]byte, error) {
@@ -61,9 +64,13 @@ func (f *fakeV2Provider) Close(context.Context) error {
 }
 
 func TestGetSecretMap(t *testing.T) {
-	t.Run("converts JSON object to byte map", func(t *testing.T) {
+	t.Run("delegates to provider GetSecretMap", func(t *testing.T) {
+		expected := map[string][]byte{
+			"foo": []byte("bar"),
+			"baz": []byte("qux"),
+		}
 		provider := &fakeV2Provider{
-			getSecretResponse: []byte(`{"foo":"bar","num":42,"obj":{"nested":"value"}}`),
+			getSecretMapResponse: expected,
 		}
 		client := NewClient(provider, &pb.ProviderReference{Name: "provider"}, "default")
 
@@ -71,30 +78,11 @@ func TestGetSecretMap(t *testing.T) {
 		if err != nil {
 			t.Fatalf("GetSecretMap() error = %v", err)
 		}
-
-		if string(secretMap["foo"]) != "bar" {
-			t.Fatalf("expected foo=bar, got %q", string(secretMap["foo"]))
-		}
-		if string(secretMap["num"]) != "42" {
-			t.Fatalf("expected num=42, got %q", string(secretMap["num"]))
-		}
-		if string(secretMap["obj"]) != `{"nested":"value"}` {
-			t.Fatalf("expected obj JSON value, got %q", string(secretMap["obj"]))
-		}
-	})
-
-	t.Run("returns error for non JSON object payload", func(t *testing.T) {
-		provider := &fakeV2Provider{
-			getSecretResponse: []byte(`"plain-string"`),
-		}
-		client := NewClient(provider, &pb.ProviderReference{Name: "provider"}, "default")
-
-		_, err := client.GetSecretMap(context.Background(), esv1.ExternalSecretDataRemoteRef{Key: "sample"})
-		if err == nil {
-			t.Fatal("expected error, got nil")
+		if len(secretMap) != len(expected) {
+			t.Fatalf("expected %d keys, got %d", len(expected), len(secretMap))
 		}
-		if !strings.Contains(err.Error(), "failed to decode secret as JSON object for extract") {
-			t.Fatalf("expected JSON decode error, got %v", err)
+		if string(secretMap["foo"]) != "bar" || string(secretMap["baz"]) != "qux" {
+			t.Fatalf("unexpected secret map: %#v", secretMap)
 		}
 	})
 }

+ 37 - 0
providers/v2/adapter/store/server.go

@@ -138,6 +138,43 @@ func (s *Server) GetSecret(ctx context.Context, req *pb.GetSecretRequest) (*pb.G
 	}, nil
 }
 
+// GetSecretMap retrieves multiple key/value pairs from a single secret object.
+func (s *Server) GetSecretMap(ctx context.Context, req *pb.GetSecretMapRequest) (*pb.GetSecretMapResponse, error) {
+	if req == nil || req.RemoteRef == nil {
+		return nil, fmt.Errorf("request or remote ref is nil")
+	}
+	if err := validateSourceNamespace(req.SourceNamespace); err != nil {
+		return nil, err
+	}
+
+	client, err := s.getClient(ctx, req.ProviderRef, req.SourceNamespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get client: %w", err)
+	}
+	defer func() { _ = client.Close(ctx) }()
+
+	ref := esv1.ExternalSecretDataRemoteRef{
+		Key:      req.RemoteRef.Key,
+		Version:  req.RemoteRef.Version,
+		Property: req.RemoteRef.Property,
+	}
+	if req.RemoteRef.DecodingStrategy != "" {
+		ref.DecodingStrategy = esv1.ExternalSecretDecodingStrategy(req.RemoteRef.DecodingStrategy)
+	}
+	if req.RemoteRef.MetadataPolicy != "" {
+		ref.MetadataPolicy = esv1.ExternalSecretMetadataPolicy(req.RemoteRef.MetadataPolicy)
+	}
+
+	secrets, err := client.GetSecretMap(ctx, ref)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get secret map: %w", err)
+	}
+
+	return &pb.GetSecretMapResponse{
+		Secrets: secrets,
+	}, nil
+}
+
 // PushSecret writes a secret to the provider.
 func (s *Server) PushSecret(ctx context.Context, req *pb.PushSecretRequest) (*pb.PushSecretResponse, error) {
 	if req == nil || req.PushSecretData == nil {

+ 37 - 0
providers/v2/adapter/v1_to_v2.go

@@ -154,6 +154,43 @@ func (s *V1AdapterServer) GetSecret(ctx context.Context, req *pb.GetSecretReques
 	}, nil
 }
 
+// GetSecretMap retrieves multiple key/value pairs from a single secret object.
+func (s *V1AdapterServer) GetSecretMap(ctx context.Context, req *pb.GetSecretMapRequest) (*pb.GetSecretMapResponse, error) {
+	if req == nil || req.RemoteRef == nil {
+		return nil, fmt.Errorf("request or remote ref is nil")
+	}
+	if err := validateSourceNamespace(req.SourceNamespace); err != nil {
+		return nil, err
+	}
+
+	client, err := s.getClient(ctx, req.ProviderRef, req.SourceNamespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get client: %w", err)
+	}
+	defer func() { _ = client.Close(ctx) }()
+
+	ref := esv1.ExternalSecretDataRemoteRef{
+		Key:      req.RemoteRef.Key,
+		Version:  req.RemoteRef.Version,
+		Property: req.RemoteRef.Property,
+	}
+	if req.RemoteRef.DecodingStrategy != "" {
+		ref.DecodingStrategy = esv1.ExternalSecretDecodingStrategy(req.RemoteRef.DecodingStrategy)
+	}
+	if req.RemoteRef.MetadataPolicy != "" {
+		ref.MetadataPolicy = esv1.ExternalSecretMetadataPolicy(req.RemoteRef.MetadataPolicy)
+	}
+
+	secrets, err := client.GetSecretMap(ctx, ref)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get secret map: %w", err)
+	}
+
+	return &pb.GetSecretMapResponse{
+		Secrets: secrets,
+	}, nil
+}
+
 // PushSecret writes a secret to the provider.
 func (s *V1AdapterServer) PushSecret(ctx context.Context, req *pb.PushSecretRequest) (*pb.PushSecretResponse, error) {
 	if req == nil || req.PushSecretData == nil {

+ 51 - 0
providers/v2/common/grpc/client.go

@@ -108,6 +108,57 @@ func (c *grpcProviderClient) GetSecret(ctx context.Context, ref esv1.ExternalSec
 	return resp.Value, nil
 }
 
+// GetSecretMap retrieves multiple key/value pairs from a single provider object via gRPC.
+func (c *grpcProviderClient) GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef, providerRef *pb.ProviderReference, sourceNamespace string) (map[string][]byte, error) {
+	start := time.Now()
+	var err error
+	defer func() {
+		clientMetrics.ObserveRequest("GetSecretMap", c.conn.Target(), err, time.Since(start))
+	}()
+
+	c.log.V(1).Info("getting secret map via gRPC",
+		"key", ref.Key,
+		"version", ref.Version,
+		"property", ref.Property,
+		"connectionState", c.conn.GetState().String(),
+		"providerRef", providerRef,
+		"sourceNamespace", sourceNamespace)
+
+	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
+	defer cancel()
+
+	pbRef := &pb.ExternalSecretDataRemoteRef{
+		Key:              ref.Key,
+		Version:          ref.Version,
+		Property:         ref.Property,
+		DecodingStrategy: string(ref.DecodingStrategy),
+		MetadataPolicy:   string(ref.MetadataPolicy),
+	}
+
+	req := &pb.GetSecretMapRequest{
+		RemoteRef:       pbRef,
+		ProviderRef:     providerRef,
+		SourceNamespace: sourceNamespace,
+	}
+
+	c.log.V(1).Info("calling GetSecretMap RPC",
+		"target", c.conn.Target())
+
+	resp, err := c.client.GetSecretMap(ctx, req)
+	if err != nil {
+		c.log.Error(err, "GetSecretMap RPC failed",
+			"connectionState", c.conn.GetState().String(),
+			"target", c.conn.Target())
+		err = fmt.Errorf("failed to get secret map via gRPC: %w", err)
+		return nil, err
+	}
+
+	c.log.V(1).Info("GetSecretMap RPC succeeded",
+		"secretCount", len(resp.Secrets))
+
+	return resp.Secrets, nil
+}
+
 // Validate checks if the provider is properly configured via gRPC.
 func (c *grpcProviderClient) Validate(ctx context.Context, providerRef *pb.ProviderReference, sourceNamespace string) error {
 	start := time.Now()

+ 40 - 5
providers/v2/common/grpc/client_test.go

@@ -33,6 +33,7 @@ const bufSize = 1024 * 1024
 type mockServer struct {
 	pb.UnimplementedSecretStoreProviderServer
 	getSecretResponse *pb.GetSecretResponse
+	getSecretMap      map[string][]byte
 	validateResponse  *pb.ValidateResponse
 }
 
@@ -42,8 +43,16 @@ func (m *mockServer) GetSecret(ctx context.Context, req *pb.GetSecretRequest) (*
 	}
 	return &pb.GetSecretResponse{
 		Value: []byte("test-secret-value"),
-		Metadata: map[string]string{
-			"version": "1",
+	}, nil
+}
+
+func (m *mockServer) GetSecretMap(ctx context.Context, req *pb.GetSecretMapRequest) (*pb.GetSecretMapResponse, error) {
+	if m.getSecretMap != nil {
+		return &pb.GetSecretMapResponse{Secrets: m.getSecretMap}, nil
+	}
+	return &pb.GetSecretMapResponse{
+		Secrets: map[string][]byte{
+			"foo": []byte("bar"),
 		},
 	}, nil
 }
@@ -100,7 +109,7 @@ func TestClient_GetSecret(t *testing.T) {
 		Property: "password",
 	}
 
-	value, err := client.GetSecret(context.Background(), ref)
+	value, err := client.GetSecret(context.Background(), ref, &pb.ProviderReference{Name: "provider"}, "default")
 	if err != nil {
 		t.Fatalf("GetSecret failed: %v", err)
 	}
@@ -118,7 +127,7 @@ func TestClient_Validate(t *testing.T) {
 
 		client := NewClientWithConn(conn)
 
-		err := client.Validate(context.Background())
+		err := client.Validate(context.Background(), &pb.ProviderReference{Name: "provider"}, "default")
 		if err != nil {
 			t.Fatalf("Validate failed: %v", err)
 		}
@@ -136,7 +145,7 @@ func TestClient_Validate(t *testing.T) {
 
 		client := NewClientWithConn(conn)
 
-		err := client.Validate(context.Background())
+		err := client.Validate(context.Background(), &pb.ProviderReference{Name: "provider"}, "default")
 		if err == nil {
 			t.Fatal("Expected validation to fail, but it succeeded")
 		}
@@ -147,6 +156,32 @@ func TestClient_Validate(t *testing.T) {
 	})
 }
 
+func TestClient_GetSecretMap(t *testing.T) {
+	mock := &mockServer{
+		getSecretMap: map[string][]byte{
+			"a": []byte("b"),
+		},
+	}
+	conn, cleanup := setupTestServer(t, mock)
+	defer cleanup()
+
+	client := NewClientWithConn(conn)
+
+	value, err := client.GetSecretMap(
+		context.Background(),
+		esv1.ExternalSecretDataRemoteRef{Key: "test-key"},
+		&pb.ProviderReference{Name: "provider"},
+		"default",
+	)
+	if err != nil {
+		t.Fatalf("GetSecretMap failed: %v", err)
+	}
+
+	if string(value["a"]) != "b" {
+		t.Fatalf("Expected map[a]=b, got %#v", value)
+	}
+}
+
 func TestClient_Close(t *testing.T) {
 	mock := &mockServer{}
 	conn, cleanup := setupTestServer(t, mock)

+ 16 - 0
providers/v2/common/grpc/resilient.go

@@ -130,6 +130,22 @@ func (rc *ResilientClient) GetSecret(ctx context.Context, ref esv1.ExternalSecre
 	return result, err
 }
 
+// GetSecretMap retrieves multiple key/value pairs from a single provider object with retry logic and circuit breaking.
+func (rc *ResilientClient) GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef, providerRef *pb.ProviderReference, sourceNamespace string) (map[string][]byte, error) {
+	var result map[string][]byte
+
+	err := rc.executeWithResilience(ctx, func(client v2.Provider) error {
+		secretMap, err := client.GetSecretMap(ctx, ref, providerRef, sourceNamespace)
+		if err != nil {
+			return err
+		}
+		result = secretMap
+		return nil
+	})
+
+	return result, err
+}
+
 // GetAllSecrets retrieves multiple secrets with retry logic and circuit breaking.
 func (rc *ResilientClient) GetAllSecrets(ctx context.Context, find esv1.ExternalSecretFind, providerRef *pb.ProviderReference, sourceNamespace string) (map[string][]byte, error) {
 	var result map[string][]byte

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 393 - 253
providers/v2/common/proto/provider/secretstore.pb.go


+ 21 - 0
providers/v2/common/proto/provider/secretstore.proto

@@ -8,6 +8,9 @@ option go_package = "github.com/external-secrets/external-secrets/proto/provider
 service SecretStoreProvider {
   // GetSecret retrieves a single secret from the provider
   rpc GetSecret(GetSecretRequest) returns (GetSecretResponse);
+
+  // GetSecretMap retrieves multiple key/value pairs from a single provider object
+  rpc GetSecretMap(GetSecretMapRequest) returns (GetSecretMapResponse);
   
   // PushSecret writes a secret to the provider
   rpc PushSecret(PushSecretRequest) returns (PushSecretResponse);
@@ -64,6 +67,24 @@ message GetSecretResponse {
   bytes value = 1;
 }
 
+// GetSecretMapRequest contains the information needed to fetch a secret map
+message GetSecretMapRequest {
+  // The reference to the secret to retrieve
+  ExternalSecretDataRemoteRef remote_ref = 1;
+
+  // Reference to the provider configuration CRD
+  ProviderReference provider_ref = 2;
+
+  // Namespace of the ExternalSecret making the request (for validation)
+  string source_namespace = 3;
+}
+
+// GetSecretMapResponse contains the retrieved key/value pairs
+message GetSecretMapResponse {
+  // Map of secret keys to their values
+  map<string, bytes> secrets = 1;
+}
+
 // ExternalSecretDataRemoteRef defines how to find the secret in the provider
 message ExternalSecretDataRemoteRef {
   // Key is the identifier for the secret in the provider's system

+ 41 - 1
providers/v2/common/proto/provider/secretstore_grpc.pb.go

@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
 // - protoc-gen-go-grpc v1.5.1
-// - protoc             v6.32.1
+// - protoc             v6.33.1
 // source: providers/v2/common/proto/provider/secretstore.proto
 
 package provider
@@ -20,6 +20,7 @@ const _ = grpc.SupportPackageIsVersion9
 
 const (
 	SecretStoreProvider_GetSecret_FullMethodName     = "/provider.v1.SecretStoreProvider/GetSecret"
+	SecretStoreProvider_GetSecretMap_FullMethodName  = "/provider.v1.SecretStoreProvider/GetSecretMap"
 	SecretStoreProvider_PushSecret_FullMethodName    = "/provider.v1.SecretStoreProvider/PushSecret"
 	SecretStoreProvider_DeleteSecret_FullMethodName  = "/provider.v1.SecretStoreProvider/DeleteSecret"
 	SecretStoreProvider_SecretExists_FullMethodName  = "/provider.v1.SecretStoreProvider/SecretExists"
@@ -36,6 +37,8 @@ const (
 type SecretStoreProviderClient interface {
 	// GetSecret retrieves a single secret from the provider
 	GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error)
+	// GetSecretMap retrieves multiple key/value pairs from a single provider object
+	GetSecretMap(ctx context.Context, in *GetSecretMapRequest, opts ...grpc.CallOption) (*GetSecretMapResponse, error)
 	// PushSecret writes a secret to the provider
 	PushSecret(ctx context.Context, in *PushSecretRequest, opts ...grpc.CallOption) (*PushSecretResponse, error)
 	// DeleteSecret deletes a secret from the provider
@@ -68,6 +71,16 @@ func (c *secretStoreProviderClient) GetSecret(ctx context.Context, in *GetSecret
 	return out, nil
 }
 
+func (c *secretStoreProviderClient) GetSecretMap(ctx context.Context, in *GetSecretMapRequest, opts ...grpc.CallOption) (*GetSecretMapResponse, error) {
+	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+	out := new(GetSecretMapResponse)
+	err := c.cc.Invoke(ctx, SecretStoreProvider_GetSecretMap_FullMethodName, in, out, cOpts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *secretStoreProviderClient) PushSecret(ctx context.Context, in *PushSecretRequest, opts ...grpc.CallOption) (*PushSecretResponse, error) {
 	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
 	out := new(PushSecretResponse)
@@ -136,6 +149,8 @@ func (c *secretStoreProviderClient) Capabilities(ctx context.Context, in *Capabi
 type SecretStoreProviderServer interface {
 	// GetSecret retrieves a single secret from the provider
 	GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error)
+	// GetSecretMap retrieves multiple key/value pairs from a single provider object
+	GetSecretMap(context.Context, *GetSecretMapRequest) (*GetSecretMapResponse, error)
 	// PushSecret writes a secret to the provider
 	PushSecret(context.Context, *PushSecretRequest) (*PushSecretResponse, error)
 	// DeleteSecret deletes a secret from the provider
@@ -161,6 +176,9 @@ type UnimplementedSecretStoreProviderServer struct{}
 func (UnimplementedSecretStoreProviderServer) GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method GetSecret not implemented")
 }
+func (UnimplementedSecretStoreProviderServer) GetSecretMap(context.Context, *GetSecretMapRequest) (*GetSecretMapResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetSecretMap not implemented")
+}
 func (UnimplementedSecretStoreProviderServer) PushSecret(context.Context, *PushSecretRequest) (*PushSecretResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method PushSecret not implemented")
 }
@@ -218,6 +236,24 @@ func _SecretStoreProvider_GetSecret_Handler(srv interface{}, ctx context.Context
 	return interceptor(ctx, in, info, handler)
 }
 
+func _SecretStoreProvider_GetSecretMap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetSecretMapRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(SecretStoreProviderServer).GetSecretMap(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: SecretStoreProvider_GetSecretMap_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(SecretStoreProviderServer).GetSecretMap(ctx, req.(*GetSecretMapRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _SecretStoreProvider_PushSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(PushSecretRequest)
 	if err := dec(in); err != nil {
@@ -337,6 +373,10 @@ var SecretStoreProvider_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "GetSecret",
 			Handler:    _SecretStoreProvider_GetSecret_Handler,
 		},
+		{
+			MethodName: "GetSecretMap",
+			Handler:    _SecretStoreProvider_GetSecretMap_Handler,
+		},
 		{
 			MethodName: "PushSecret",
 			Handler:    _SecretStoreProvider_PushSecret_Handler,

+ 4 - 0
providers/v2/common/types.go

@@ -31,6 +31,10 @@ type Provider interface {
 	// The providerRef references the provider configuration CRD, and sourceNamespace is the namespace of the ExternalSecret.
 	GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef, providerRef *pb.ProviderReference, sourceNamespace string) ([]byte, error)
 
+	// GetSecretMap retrieves multiple key/value pairs from a single secret object.
+	// The providerRef references the provider configuration CRD, and sourceNamespace is the namespace of the ExternalSecret.
+	GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef, providerRef *pb.ProviderReference, sourceNamespace string) (map[string][]byte, error)
+
 	// GetAllSecrets retrieves multiple secrets based on find criteria.
 	// Returns a map of secret names to their byte values.
 	// The providerRef references the provider configuration CRD, and sourceNamespace is the namespace of the ExternalSecret.

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů