Browse Source

Support PushSecret metadata (#2600)

* Support PushSecret metadata

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>

* Refactor GCP PushSecret

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>

---------

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>
Shuhei Kitagawa 2 years ago
parent
commit
da85f80d97
40 changed files with 367 additions and 127 deletions
  1. 5 0
      apis/externalsecrets/v1alpha1/pushsecret_types.go
  2. 11 3
      apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go
  3. 2 1
      apis/externalsecrets/v1beta1/provider.go
  4. 2 1
      apis/externalsecrets/v1beta1/provider_schema_test.go
  5. 10 0
      config/crds/bases/external-secrets.io_pushsecrets.yaml
  6. 6 0
      deploy/crds/bundle.yaml
  7. 7 6
      pkg/controllers/pushsecret/pushsecret_controller.go
  8. 1 1
      pkg/controllers/secretstore/client_manager_test.go
  9. 2 1
      pkg/provider/akeyless/akeyless.go
  10. 2 1
      pkg/provider/alibaba/kms.go
  11. 2 1
      pkg/provider/aws/parameterstore/parameterstore.go
  12. 1 1
      pkg/provider/aws/parameterstore/parameterstore_test.go
  13. 2 1
      pkg/provider/aws/secretsmanager/secretsmanager.go
  14. 1 1
      pkg/provider/aws/secretsmanager/secretsmanager_test.go
  15. 2 1
      pkg/provider/azure/keyvault/keyvault.go
  16. 1 1
      pkg/provider/azure/keyvault/keyvault_test.go
  17. 2 1
      pkg/provider/conjur/provider.go
  18. 2 1
      pkg/provider/delinea/client.go
  19. 2 1
      pkg/provider/doppler/client.go
  20. 2 1
      pkg/provider/fake/fake.go
  21. 1 1
      pkg/provider/fake/fake_test.go
  22. 43 41
      pkg/provider/gcp/secretmanager/client.go
  23. 82 34
      pkg/provider/gcp/secretmanager/client_test.go
  24. 135 0
      pkg/provider/gcp/secretmanager/push_secret.go
  25. 2 1
      pkg/provider/gitlab/gitlab.go
  26. 6 5
      pkg/provider/ibm/provider.go
  27. 2 1
      pkg/provider/keepersecurity/client.go
  28. 1 1
      pkg/provider/keepersecurity/client_test.go
  29. 2 1
      pkg/provider/kubernetes/client.go
  30. 1 1
      pkg/provider/kubernetes/client_test.go
  31. 2 1
      pkg/provider/onepassword/onepassword.go
  32. 2 1
      pkg/provider/oracle/oracle.go
  33. 2 1
      pkg/provider/scaleway/client.go
  34. 8 8
      pkg/provider/scaleway/client_test.go
  35. 3 1
      pkg/provider/senhasegura/dsm/dsm.go
  36. 2 1
      pkg/provider/testing/fake/fake.go
  37. 2 1
      pkg/provider/vault/vault.go
  38. 1 1
      pkg/provider/vault/vault_test.go
  39. 2 1
      pkg/provider/webhook/webhook.go
  40. 3 1
      pkg/provider/yandex/common/secretsclient.go

+ 5 - 0
apis/externalsecrets/v1alpha1/pushsecret_types.go

@@ -16,6 +16,7 @@ package v1alpha1
 
 import (
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
@@ -97,6 +98,10 @@ type PushSecretMatch struct {
 type PushSecretData struct {
 	// Match a given Secret Key to be pushed to the provider.
 	Match PushSecretMatch `json:"match"`
+	// Metadata is metadata attached to the secret.
+	// The structure of metadata is provider specific, please look it up in the provider documentation.
+	// +optional
+	Metadata *apiextensionsv1.JSON `json:"metadata,omitempty"`
 }
 
 // PushSecretConditionType indicates the condition of the PushSecret.

+ 11 - 3
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -20,6 +20,7 @@ package v1alpha1
 
 import (
 	metav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 )
@@ -1055,6 +1056,11 @@ func (in *PushSecret) DeepCopyObject() runtime.Object {
 func (in *PushSecretData) DeepCopyInto(out *PushSecretData) {
 	*out = *in
 	out.Match = in.Match
+	if in.Metadata != nil {
+		in, out := &in.Metadata, &out.Metadata
+		*out = new(apiextensionsv1.JSON)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretData.
@@ -1180,7 +1186,9 @@ func (in *PushSecretSpec) DeepCopyInto(out *PushSecretSpec) {
 	if in.Data != nil {
 		in, out := &in.Data, &out.Data
 		*out = make([]PushSecretData, len(*in))
-		copy(*out, *in)
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
 	}
 }
 
@@ -1210,7 +1218,7 @@ func (in *PushSecretStatus) DeepCopyInto(out *PushSecretStatus) {
 				in, out := &inVal, &outVal
 				*out = make(map[string]PushSecretData, len(*in))
 				for key, val := range *in {
-					(*out)[key] = val
+					(*out)[key] = *val.DeepCopy()
 				}
 			}
 			(*out)[key] = outVal
@@ -1543,7 +1551,7 @@ func (in SyncedPushSecretsMap) DeepCopyInto(out *SyncedPushSecretsMap) {
 				in, out := &inVal, &outVal
 				*out = make(map[string]PushSecretData, len(*in))
 				for key, val := range *in {
-					(*out)[key] = val
+					(*out)[key] = *val.DeepCopy()
 				}
 			}
 			(*out)[key] = outVal

+ 2 - 1
apis/externalsecrets/v1beta1/provider.go

@@ -17,6 +17,7 @@ package v1beta1
 import (
 	"context"
 
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -68,7 +69,7 @@ type SecretsClient interface {
 	GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error)
 
 	// PushSecret will write a single secret into the provider
-	PushSecret(ctx context.Context, value []byte, remoteRef PushRemoteRef) error
+	PushSecret(ctx context.Context, value []byte, metadata *apiextensionsv1.JSON, remoteRef PushRemoteRef) error
 
 	// DeleteSecret will delete the secret from a provider
 	DeleteSecret(ctx context.Context, remoteRef PushRemoteRef) error

+ 2 - 1
apis/externalsecrets/v1beta1/provider_schema_test.go

@@ -18,6 +18,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -35,7 +36,7 @@ func (p *PP) NewClient(_ context.Context, _ GenericStore, _ client.Client, _ str
 }
 
 // PushSecret writes a single secret into a provider.
-func (p *PP) PushSecret(_ context.Context, _ []byte, _ PushRemoteRef) error {
+func (p *PP) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ PushRemoteRef) error {
 	return nil
 }
 

+ 10 - 0
config/crds/bases/external-secrets.io_pushsecrets.yaml

@@ -67,6 +67,11 @@ spec:
                       - remoteRef
                       - secretKey
                       type: object
+                    metadata:
+                      description: Metadata is metadata attached to the secret. The
+                        structure of metadata is provider specific, please look it
+                        up in the provider documentation.
+                      x-kubernetes-preserve-unknown-fields: true
                   required:
                   - match
                   type: object
@@ -219,6 +224,11 @@ spec:
                         - remoteRef
                         - secretKey
                         type: object
+                      metadata:
+                        description: Metadata is metadata attached to the secret.
+                          The structure of metadata is provider specific, please look
+                          it up in the provider documentation.
+                        x-kubernetes-preserve-unknown-fields: true
                     required:
                     - match
                     type: object

+ 6 - 0
deploy/crds/bundle.yaml

@@ -4042,6 +4042,9 @@ spec:
                           - remoteRef
                           - secretKey
                         type: object
+                      metadata:
+                        description: Metadata is metadata attached to the secret. The structure of metadata is provider specific, please look it up in the provider documentation.
+                        x-kubernetes-preserve-unknown-fields: true
                     required:
                       - match
                     type: object
@@ -4170,6 +4173,9 @@ spec:
                             - remoteRef
                             - secretKey
                           type: object
+                        metadata:
+                          description: Metadata is metadata attached to the secret. The structure of metadata is provider specific, please look it up in the provider documentation.
+                          x-kubernetes-preserve-unknown-fields: true
                       required:
                         - match
                       type: object

+ 7 - 6
pkg/controllers/pushsecret/pushsecret_controller.go

@@ -254,16 +254,17 @@ func (r *Reconciler) PushSecretToProviders(ctx context.Context, stores map[esapi
 		if err != nil {
 			return out, fmt.Errorf("could not get secrets client for store %v: %w", store.GetName(), err)
 		}
-		for _, ref := range ps.Spec.Data {
-			secretValue, ok := secret.Data[ref.Match.SecretKey]
+		for _, data := range ps.Spec.Data {
+			secretValue, ok := secret.Data[data.Match.SecretKey]
 			if !ok {
-				return out, fmt.Errorf("secret key %v does not exist", ref.Match.SecretKey)
+				return out, fmt.Errorf("secret key %v does not exist", data.Match.SecretKey)
 			}
-			err := client.PushSecret(ctx, secretValue, ref.Match.RemoteRef)
+
+			err := client.PushSecret(ctx, secretValue, data.Metadata, data.Match.RemoteRef)
 			if err != nil {
-				return out, fmt.Errorf(errSetSecretFailed, ref.Match.SecretKey, store.GetName(), err)
+				return out, fmt.Errorf(errSetSecretFailed, data.Match.SecretKey, store.GetName(), err)
 			}
-			out[storeKey][statusRef(ref.Match.RemoteRef)] = ref
+			out[storeKey][statusRef(data.Match.RemoteRef)] = data
 		}
 	}
 	return out, nil

+ 1 - 1
pkg/controllers/secretstore/client_manager_test.go

@@ -340,7 +340,7 @@ type MockFakeClient struct {
 	closeCalled bool
 }
 
-func (c *MockFakeClient) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (c *MockFakeClient) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return nil
 }
 

+ 2 - 1
pkg/provider/akeyless/akeyless.go

@@ -30,6 +30,7 @@ import (
 	"github.com/akeylesslabs/akeyless-go/v3"
 	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/client-go/kubernetes"
 	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -227,7 +228,7 @@ func (a *Akeyless) Validate() (esv1beta1.ValidationResult, error) {
 	return esv1beta1.ValidationResultReady, nil
 }
 
-func (a *Akeyless) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (a *Akeyless) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/alibaba/kms.go

@@ -26,6 +26,7 @@ import (
 	"github.com/avast/retry-go/v4"
 	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -58,7 +59,7 @@ type SMInterface interface {
 	Endpoint() string
 }
 
-func (kms *KeyManagementService) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (kms *KeyManagementService) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/aws/parameterstore/parameterstore.go

@@ -26,6 +26,7 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/ssm"
 	"github.com/tidwall/gjson"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	utilpointer "k8s.io/utils/ptr"
 	ctrl "sigs.k8s.io/controller-runtime"
 
@@ -130,7 +131,7 @@ func (pm *ParameterStore) DeleteSecret(ctx context.Context, remoteRef esv1beta1.
 	return nil
 }
 
-func (pm *ParameterStore) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (pm *ParameterStore) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	parameterType := "String"
 	overwrite := true
 

+ 1 - 1
pkg/provider/aws/parameterstore/parameterstore_test.go

@@ -435,7 +435,7 @@ func TestPushSecret(t *testing.T) {
 			ps := ParameterStore{
 				client: &tc.args.client,
 			}
-			err := ps.PushSecret(context.TODO(), []byte(fakeValue), ref)
+			err := ps.PushSecret(context.TODO(), []byte(fakeValue), nil, ref)
 
 			// Error nil XOR tc.want.err nil
 			if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {

+ 2 - 1
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -28,6 +28,7 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
 	"github.com/tidwall/gjson"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	utilpointer "k8s.io/utils/ptr"
 	ctrl "sigs.k8s.io/controller-runtime"
 
@@ -187,7 +188,7 @@ func (sm *SecretsManager) DeleteSecret(ctx context.Context, remoteRef esv1beta1.
 	return err
 }
 
-func (sm *SecretsManager) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (sm *SecretsManager) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	secretName := remoteRef.GetRemoteKey()
 	managedBy := managedBy
 	externalSecrets := externalSecrets

+ 1 - 1
pkg/provider/aws/secretsmanager/secretsmanager_test.go

@@ -570,7 +570,7 @@ func TestSetSecret(t *testing.T) {
 			sm := SecretsManager{
 				client: &tc.args.client,
 			}
-			err := sm.PushSecret(context.Background(), []byte("fake-value"), ref)
+			err := sm.PushSecret(context.Background(), []byte("fake-value"), nil, ref)
 
 			// Error nil XOR tc.want.err nil
 			if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {

+ 2 - 1
pkg/provider/azure/keyvault/keyvault.go

@@ -39,6 +39,7 @@ import (
 	"golang.org/x/crypto/sha3"
 	authv1 "k8s.io/api/authentication/v1"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/kubernetes"
@@ -496,7 +497,7 @@ func (a *Azure) setKeyVaultKey(ctx context.Context, secretName string, value []b
 }
 
 // PushSecret stores secrets into a Key vault instance.
-func (a *Azure) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (a *Azure) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	objectType, secretName := getObjType(esv1beta1.ExternalSecretDataRemoteRef{Key: remoteRef.GetRemoteKey()})
 	switch objectType {
 	case defaultObjType:

+ 1 - 1
pkg/provider/azure/keyvault/keyvault_test.go

@@ -757,7 +757,7 @@ func TestAzureKeyVaultPushSecret(t *testing.T) {
 	}
 	for k, v := range successCases {
 		sm.baseClient = v.mockClient
-		err := sm.PushSecret(context.Background(), v.setValue, v.pushRef)
+		err := sm.PushSecret(context.Background(), v.setValue, nil, v.pushRef)
 		if !utils.ErrorContains(err, v.expectError) {
 			if err == nil {
 				t.Errorf("[%d] unexpected error: <nil>, expected: '%s'", k, v.expectError)

+ 2 - 1
pkg/provider/conjur/provider.go

@@ -23,6 +23,7 @@ import (
 	"github.com/cyberark/conjur-api-go/conjurapi"
 	"github.com/cyberark/conjur-api-go/conjurapi/authn"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -114,7 +115,7 @@ func (p *Provider) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretData
 }
 
 // PushSecret will write a single secret into the provider.
-func (p *Provider) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (p *Provider) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	// NOT IMPLEMENTED
 	return nil
 }

+ 2 - 1
pkg/provider/delinea/client.go

@@ -24,6 +24,7 @@ import (
 
 	"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
 	"github.com/tidwall/gjson"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 )
@@ -70,7 +71,7 @@ func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretData
 	return []byte(val.String()), nil
 }
 
-func (c *client) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (c *client) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return errors.New("pushing secrets is not supported by Delinea DevOps Secrets Vault")
 }
 

+ 2 - 1
pkg/provider/doppler/client.go

@@ -23,6 +23,7 @@ import (
 	"time"
 
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -119,7 +120,7 @@ func (c *Client) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) erro
 	return fmt.Errorf("not implemented")
 }
 
-func (c *Client) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (c *Client) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/fake/fake.go

@@ -19,6 +19,7 @@ import (
 	"fmt"
 
 	"github.com/tidwall/gjson"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -106,7 +107,7 @@ func (p *Provider) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) er
 	return nil
 }
 
-func (p *Provider) PushSecret(_ context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (p *Provider) PushSecret(_ context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	currentData, ok := p.config[remoteRef.GetRemoteKey()]
 	if !ok {
 		p.config[remoteRef.GetRemoteKey()] = &Data{

+ 1 - 1
pkg/provider/fake/fake_test.go

@@ -216,7 +216,7 @@ func TestSetSecret(t *testing.T) {
 				},
 			}, nil, "")
 			gomega.Expect(err).ToNot(gomega.HaveOccurred())
-			err = cl.PushSecret(context.TODO(), []byte(row.expValue), esv1alpha1.PushSecretRemoteRef{
+			err = cl.PushSecret(context.TODO(), []byte(row.expValue), nil, esv1alpha1.PushSecretRemoteRef{
 				RemoteKey: row.requestKey,
 			})
 			if row.expErr != "" {

+ 43 - 41
pkg/provider/gcp/secretmanager/client.go

@@ -14,7 +14,6 @@ limitations under the License.
 package secretmanager
 
 import (
-	"bytes"
 	"context"
 	"encoding/json"
 	"errors"
@@ -27,11 +26,11 @@ import (
 	"github.com/googleapis/gax-go/v2"
 	"github.com/googleapis/gax-go/v2/apierror"
 	"github.com/tidwall/gjson"
-	"github.com/tidwall/sjson"
 	"google.golang.org/api/iterator"
 	"google.golang.org/genproto/protobuf/field_mask"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	ctrl "sigs.k8s.io/controller-runtime"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -127,7 +126,7 @@ func parseError(err error) error {
 }
 
 // PushSecret pushes a kubernetes secret key into gcp provider Secret.
-func (c *Client) PushSecret(ctx context.Context, payload []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (c *Client) PushSecret(ctx context.Context, payload []byte, metadata *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	gcpSecret, err := c.smClient.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{
 		Name: fmt.Sprintf("projects/%s/secrets/%s", c.store.ProjectID, remoteRef.GetRemoteKey()),
 	})
@@ -158,24 +157,25 @@ func (c *Client) PushSecret(ctx context.Context, payload []byte, remoteRef esv1b
 		}
 	}
 
-	manager, ok := gcpSecret.Labels[managedByKey]
-	if !ok || manager != managedByValue {
-		if remoteRef.GetProperty() == "" {
-			return fmt.Errorf("secret %v is not managed by external secrets", remoteRef.GetRemoteKey())
-		}
+	builder, err := newPushSecretBuilder(payload, metadata, remoteRef)
+	if err != nil {
+		return err
+	}
 
-		labels := map[string]string{}
-		for k, v := range gcpSecret.Labels {
-			labels[k] = v
-		}
-		labels[managedByKey] = managedByValue
+	annotations, labels, err := builder.buildMetadata(gcpSecret.Annotations, gcpSecret.Labels)
+	if err != nil {
+		return err
+	}
+
+	if !mapEqual(gcpSecret.Annotations, annotations) || !mapEqual(gcpSecret.Labels, labels) {
 		_, err = c.smClient.UpdateSecret(ctx, &secretmanagerpb.UpdateSecretRequest{
 			Secret: &secretmanagerpb.Secret{
-				Name:   gcpSecret.Name,
-				Labels: labels,
+				Name:        gcpSecret.Name,
+				Labels:      labels,
+				Annotations: annotations,
 			},
 			UpdateMask: &field_mask.FieldMask{
-				Paths: []string{"labels"},
+				Paths: []string{"labels", "annotations"},
 			},
 		})
 		metrics.ObserveAPICall(constants.ProviderGCPSM, constants.CallGCPSMUpdateSecret, err)
@@ -193,30 +193,18 @@ func (c *Client) PushSecret(ctx context.Context, payload []byte, remoteRef esv1b
 		return err
 	}
 
-	if gcpVersion != nil && gcpVersion.Payload != nil {
-		if remoteRef.GetProperty() == "" && bytes.Equal(payload, gcpVersion.Payload.Data) {
-			return nil
-		}
-
-		if remoteRef.GetProperty() != "" {
-			val := getDataByProperty(gcpVersion, remoteRef.GetProperty())
-			if val.Exists() && val.String() == string(payload) {
-				return nil
-			}
-		}
+	if gcpVersion != nil && gcpVersion.Payload != nil && !builder.needUpdate(gcpVersion.Payload.Data) {
+		return nil
 	}
 
-	data := payload
-	if remoteRef.GetProperty() != "" {
-		var base []byte
-		if gcpVersion != nil && gcpVersion.Payload != nil {
-			base = gcpVersion.Payload.Data
-		}
+	var original []byte
+	if gcpVersion != nil && gcpVersion.Payload != nil {
+		original = gcpVersion.Payload.Data
+	}
 
-		data, err = sjson.SetBytes(base, remoteRef.GetProperty(), payload)
-		if err != nil {
-			return err
-		}
+	data, err := builder.buildData(original)
+	if err != nil {
+		return err
 	}
 
 	addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{
@@ -389,7 +377,7 @@ func (c *Client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretData
 		return nil, fmt.Errorf("invalid secret received. no secret string for key: %s", ref.Key)
 	}
 
-	val := getDataByProperty(result, ref.Property)
+	val := getDataByProperty(result.Payload.Data, ref.Property)
 	if !val.Exists() {
 		return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
 	}
@@ -523,10 +511,10 @@ func (c *Client) Validate() (esv1beta1.ValidationResult, error) {
 	return esv1beta1.ValidationResultReady, nil
 }
 
-func getDataByProperty(resp *secretmanagerpb.AccessSecretVersionResponse, property string) gjson.Result {
+func getDataByProperty(data []byte, property string) gjson.Result {
 	var payload string
-	if resp.Payload.Data != nil {
-		payload = string(resp.Payload.Data)
+	if data != nil {
+		payload = string(data)
 	}
 	idx := strings.Index(property, ".")
 	refProperty := property
@@ -539,3 +527,17 @@ func getDataByProperty(resp *secretmanagerpb.AccessSecretVersionResponse, proper
 	}
 	return gjson.Get(payload, property)
 }
+
+func mapEqual(m1, m2 map[string]string) bool {
+	if len(m1) != len(m2) {
+		return false
+	}
+
+	for k1, v1 := range m1 {
+		if v2, ok := m2[k1]; !ok || v1 != v2 {
+			return false
+		}
+	}
+
+	return true
+}

+ 82 - 34
pkg/provider/gcp/secretmanager/client_test.go

@@ -26,6 +26,7 @@ import (
 	"github.com/googleapis/gax-go/v2/apierror"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	pointer "k8s.io/utils/ptr"
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
@@ -586,7 +587,9 @@ func TestPushSecret(t *testing.T) {
 
 	type args struct {
 		mock                          *fakesm.MockSMClient
+		Metadata                      *apiextensionsv1.JSON
 		GetSecretMockReturn           fakesm.SecretMockReturn
+		UpdateSecretReturn            fakesm.SecretMockReturn
 		AccessSecretVersionMockReturn fakesm.AccessSecretVersionMockReturn
 		AddSecretVersionMockReturn    fakesm.AddSecretVersionMockReturn
 		CreateSecretMockReturn        fakesm.SecretMockReturn
@@ -595,13 +598,13 @@ func TestPushSecret(t *testing.T) {
 	type want struct {
 		err error
 	}
-	tests := map[string]struct {
-		reason string
-		args   args
-		want   want
+	tests := []struct {
+		desc string
+		args args
+		want want
 	}{
-		"SetSecret": {
-			reason: "SetSecret successfully pushes a secret",
+		{
+			desc: "SetSecret successfully pushes a secret",
 			args: args{
 				mock:                          smtc.mockClient,
 				GetSecretMockReturn:           fakesm.SecretMockReturn{Secret: &secret, Err: nil},
@@ -611,8 +614,49 @@ func TestPushSecret(t *testing.T) {
 				err: nil,
 			},
 		},
-		"AddSecretVersion": {
-			reason: "secret not pushed if AddSecretVersion errors",
+		{
+			desc: "successfully pushes a secret with metadata",
+			args: args{
+				mock: smtc.mockClient,
+				Metadata: &apiextensionsv1.JSON{
+					Raw: []byte(`{"annotations":{"annotation-key1":"annotation-value1"},"labels":{"label-key1":"label-value1"}}`),
+				},
+				GetSecretMockReturn: fakesm.SecretMockReturn{Secret: &secret, Err: nil},
+				UpdateSecretReturn: fakesm.SecretMockReturn{Secret: &secretmanagerpb.Secret{
+					Name: "projects/default/secrets/baz",
+					Replication: &secretmanagerpb.Replication{
+						Replication: &secretmanagerpb.Replication_Automatic_{
+							Automatic: &secretmanagerpb.Replication_Automatic{},
+						},
+					},
+					Labels: map[string]string{
+						"managed-by": "external-secrets",
+						"label-key1": "label-value1",
+					},
+					Annotations: map[string]string{
+						"annotation-key1": "annotation-value1",
+					},
+				}, Err: nil},
+				AccessSecretVersionMockReturn: fakesm.AccessSecretVersionMockReturn{Res: &res, Err: nil},
+				AddSecretVersionMockReturn:    fakesm.AddSecretVersionMockReturn{SecretVersion: &secretVersion, Err: nil}},
+			want: want{
+				err: nil,
+			},
+		},
+		{
+			desc: "failed to push a secret with invalid metadata type",
+			args: args{
+				mock: smtc.mockClient,
+				Metadata: &apiextensionsv1.JSON{
+					Raw: []byte(`{"tags":{"tag-key1":"tag-value1"}}`),
+				},
+				GetSecretMockReturn: fakesm.SecretMockReturn{Secret: &secret, Err: nil}},
+			want: want{
+				err: fmt.Errorf("failed to decode PushSecret metadata"),
+			},
+		},
+		{
+			desc: "secret not pushed if AddSecretVersion errors",
 			args: args{
 				mock:                          smtc.mockClient,
 				GetSecretMockReturn:           fakesm.SecretMockReturn{Secret: &secret, Err: nil},
@@ -623,8 +667,8 @@ func TestPushSecret(t *testing.T) {
 				err: APIerror,
 			},
 		},
-		"AccessSecretVersion": {
-			reason: "secret not pushed if AccessSecretVersion errors",
+		{
+			desc: "secret not pushed if AccessSecretVersion errors",
 			args: args{
 				mock:                          smtc.mockClient,
 				GetSecretMockReturn:           fakesm.SecretMockReturn{Secret: &secret, Err: nil},
@@ -634,8 +678,8 @@ func TestPushSecret(t *testing.T) {
 				err: APIerror,
 			},
 		},
-		"NotManagedByESO": {
-			reason: "secret not pushed if not managed-by external-secrets",
+		{
+			desc: "secret not pushed if not managed-by external-secrets",
 			args: args{
 				mock:                smtc.mockClient,
 				GetSecretMockReturn: fakesm.SecretMockReturn{Secret: &wrongLabelSecret, Err: nil},
@@ -644,8 +688,8 @@ func TestPushSecret(t *testing.T) {
 				err: labelError,
 			},
 		},
-		"SecretAlreadyExists": {
-			reason: "don't push a secret with the same key and value",
+		{
+			desc: "don't push a secret with the same key and value",
 			args: args{
 				mock:                          smtc.mockClient,
 				AccessSecretVersionMockReturn: fakesm.AccessSecretVersionMockReturn{Res: &res2, Err: nil},
@@ -655,8 +699,8 @@ func TestPushSecret(t *testing.T) {
 				err: nil,
 			},
 		},
-		"GetSecretNotFound": {
-			reason: "secret is created if one doesn't already exist",
+		{
+			desc: "secret is created if one doesn't already exist",
 			args: args{
 				mock:                          smtc.mockClient,
 				GetSecretMockReturn:           fakesm.SecretMockReturn{Secret: nil, Err: notFoundError},
@@ -668,8 +712,8 @@ func TestPushSecret(t *testing.T) {
 				err: nil,
 			},
 		},
-		"CreateSecretReturnsNotFoundError": {
-			reason: "secret not created if CreateSecret returns not found error",
+		{
+			desc: "secret not created if CreateSecret returns not found error",
 			args: args{
 				mock:                   smtc.mockClient,
 				GetSecretMockReturn:    fakesm.SecretMockReturn{Secret: nil, Err: notFoundError},
@@ -679,8 +723,8 @@ func TestPushSecret(t *testing.T) {
 				err: notFoundError,
 			},
 		},
-		"CreateSecretReturnsError": {
-			reason: "secret not created if CreateSecret returns error",
+		{
+			desc: "secret not created if CreateSecret returns error",
 			args: args{
 				mock:                smtc.mockClient,
 				GetSecretMockReturn: fakesm.SecretMockReturn{Secret: nil, Err: canceledError},
@@ -689,8 +733,8 @@ func TestPushSecret(t *testing.T) {
 				err: canceledError,
 			},
 		},
-		"AccessSecretVersionReturnsError": {
-			reason: "access secret version for an existing secret returns error",
+		{
+			desc: "access secret version for an existing secret returns error",
 			args: args{
 				mock:                          smtc.mockClient,
 				GetSecretMockReturn:           fakesm.SecretMockReturn{Secret: &secret, Err: nil},
@@ -701,9 +745,10 @@ func TestPushSecret(t *testing.T) {
 			},
 		},
 	}
-	for name, tc := range tests {
-		t.Run(name, func(t *testing.T) {
+	for _, tc := range tests {
+		t.Run(tc.desc, func(t *testing.T) {
 			tc.args.mock.NewGetSecretFn(tc.args.GetSecretMockReturn)
+			tc.args.mock.NewUpdateSecretFn(tc.args.UpdateSecretReturn)
 			tc.args.mock.NewCreateSecretFn(tc.args.CreateSecretMockReturn)
 			tc.args.mock.NewAccessSecretVersionFn(tc.args.AccessSecretVersionMockReturn)
 			tc.args.mock.NewAddSecretVersionFn(tc.args.AddSecretVersionMockReturn)
@@ -714,17 +759,20 @@ func TestPushSecret(t *testing.T) {
 					ProjectID: smtc.projectID,
 				},
 			}
-			err := c.PushSecret(context.Background(), []byte("fake-value"), ref)
-			// Error nil XOR tc.want.err nil
-			if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {
-				t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error: %v", name, tc.reason, tc.want.err, err)
-			}
+			err := c.PushSecret(context.Background(), []byte("fake-value"), tc.args.Metadata, ref)
+			if err != nil {
+				if tc.want.err == nil {
+					t.Errorf("received an unexpected error: %v", err)
+				}
 
-			// if errors are the same type but their contents do not match
-			if err != nil && tc.want.err != nil {
-				if !strings.Contains(err.Error(), tc.want.err.Error()) {
-					t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error got nil", name, tc.reason, tc.want.err)
+				if got, expected := err.Error(), tc.want.err.Error(); !strings.Contains(got, expected) {
+					t.Errorf("received an unexpected error: %q should have contained %s", got, expected)
 				}
+				return
+			}
+
+			if tc.want.err != nil {
+				t.Errorf("expected to receive an error but got nil")
 			}
 		})
 	}
@@ -906,7 +954,7 @@ func TestPushSecret_Property(t *testing.T) {
 				store:    &esv1beta1.GCPSMProvider{},
 			}
 
-			err := client.PushSecret(context.Background(), []byte(tc.payload), tc.ref)
+			err := client.PushSecret(context.Background(), []byte(tc.payload), nil, tc.ref)
 			if err != nil {
 				if tc.expectedErr == "" {
 					t.Fatalf("PushSecret returns unexpected error: %v", err)

+ 135 - 0
pkg/provider/gcp/secretmanager/push_secret.go

@@ -0,0 +1,135 @@
+/*
+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
+
+	http://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 secretmanager
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+
+	"github.com/tidwall/sjson"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+
+	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+)
+
+type Metadata struct {
+	Annotations map[string]string `json:"annotations"`
+	Labels      map[string]string `json:"labels"`
+}
+
+func newPushSecretBuilder(payload []byte, metadata *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) (pushSecretBuilder, error) {
+	if remoteRef.GetProperty() == "" {
+		return &psBuilder{
+			payload:   payload,
+			metadata:  metadata,
+			remoteRef: remoteRef,
+		}, nil
+	}
+
+	if metadata != nil {
+		return nil, errors.New("cannot specify metadata and property at the same time")
+	}
+
+	return &propertyPSBuilder{
+		payload:   payload,
+		remoteRef: remoteRef,
+	}, nil
+}
+
+type pushSecretBuilder interface {
+	buildMetadata(annotations, labels map[string]string) (map[string]string, map[string]string, error)
+	needUpdate(original []byte) bool
+	buildData(original []byte) ([]byte, error)
+}
+
+type psBuilder struct {
+	payload   []byte
+	metadata  *apiextensionsv1.JSON
+	remoteRef esv1beta1.PushRemoteRef
+}
+
+func (b *psBuilder) buildMetadata(_, labels map[string]string) (map[string]string, map[string]string, error) {
+	if manager, ok := labels[managedByKey]; !ok || manager != managedByValue {
+		return nil, nil, fmt.Errorf("secret %v is not managed by external secrets", b.remoteRef.GetRemoteKey())
+	}
+
+	var metadata Metadata
+	if b.metadata != nil {
+		decoder := json.NewDecoder(bytes.NewReader(b.metadata.Raw))
+		// Want to return an error if unknown fields exist
+		decoder.DisallowUnknownFields()
+
+		if err := decoder.Decode(&metadata); err != nil {
+			return nil, nil, fmt.Errorf("failed to decode PushSecret metadata: %w", err)
+		}
+	}
+
+	newLabels := map[string]string{}
+	if metadata.Labels != nil {
+		newLabels = metadata.Labels
+	}
+	newLabels[managedByKey] = managedByValue
+
+	return metadata.Annotations, newLabels, nil
+}
+
+func (b *psBuilder) needUpdate(original []byte) bool {
+	if original == nil {
+		return true
+	}
+
+	return !bytes.Equal(b.payload, original)
+}
+
+func (b *psBuilder) buildData(_ []byte) ([]byte, error) {
+	return b.payload, nil
+}
+
+type propertyPSBuilder struct {
+	payload   []byte
+	remoteRef esv1beta1.PushRemoteRef
+}
+
+func (b *propertyPSBuilder) buildMetadata(annotations, labels map[string]string) (map[string]string, map[string]string, error) {
+	newAnnotations := map[string]string{}
+	newLabels := map[string]string{}
+	if annotations != nil {
+		newAnnotations = annotations
+	}
+	if labels != nil {
+		newLabels = labels
+	}
+
+	newLabels[managedByKey] = managedByValue
+	return newAnnotations, newLabels, nil
+}
+
+func (b *propertyPSBuilder) needUpdate(original []byte) bool {
+	if original == nil {
+		return true
+	}
+
+	val := getDataByProperty(original, b.remoteRef.GetProperty())
+	return !val.Exists() || val.String() != string(b.payload)
+}
+
+func (b *propertyPSBuilder) buildData(original []byte) ([]byte, error) {
+	var base []byte
+	if original != nil {
+		base = original
+	}
+	return sjson.SetBytes(base, b.remoteRef.GetProperty(), b.payload)
+}

+ 2 - 1
pkg/provider/gitlab/gitlab.go

@@ -25,6 +25,7 @@ import (
 	"github.com/tidwall/gjson"
 	"github.com/xanzy/go-gitlab"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/types"
 	ctrl "sigs.k8s.io/controller-runtime"
 
@@ -112,7 +113,7 @@ func (g *gitlabBase) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef)
 	return fmt.Errorf("not implemented")
 }
 
-func (g *gitlabBase) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (g *gitlabBase) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 6 - 5
pkg/provider/ibm/provider.go

@@ -22,18 +22,19 @@ import (
 	"strings"
 	"time"
 
-	core "github.com/IBM/go-sdk-core/v5/core"
+	"github.com/IBM/go-sdk-core/v5/core"
 	sm "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2"
 	"github.com/google/uuid"
-	gjson "github.com/tidwall/gjson"
+	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
-	types "k8s.io/apimachinery/pkg/types"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/constants"
 	"github.com/external-secrets/external-secrets/pkg/metrics"
-	utils "github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils"
 )
 
 const (
@@ -125,7 +126,7 @@ func (ibm *providerIBM) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRe
 }
 
 // Not Implemented PushSecret.
-func (ibm *providerIBM) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (ibm *providerIBM) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/keepersecurity/client.go

@@ -23,6 +23,7 @@ import (
 
 	ksm "github.com/keeper-security/secrets-manager-go/core"
 	"golang.org/x/exp/maps"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 )
@@ -160,7 +161,7 @@ func (c *Client) Close(_ context.Context) error {
 	return nil
 }
 
-func (c *Client) PushSecret(_ context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (c *Client) PushSecret(_ context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	parts, err := c.buildSecretNameAndKey(remoteRef)
 	if err != nil {
 		return err

+ 1 - 1
pkg/provider/keepersecurity/client_test.go

@@ -619,7 +619,7 @@ func TestClientPushSecret(t *testing.T) {
 				ksmClient: tt.fields.ksmClient,
 				folderID:  tt.fields.folderID,
 			}
-			if err := c.PushSecret(tt.args.ctx, tt.args.value, tt.args.remoteRef); (err != nil) != tt.wantErr {
+			if err := c.PushSecret(tt.args.ctx, tt.args.value, nil, tt.args.remoteRef); (err != nil) != tt.wantErr {
 				t.Errorf("PushSecret() error = %v, wantErr %v", err, tt.wantErr)
 			}
 		})

+ 2 - 1
pkg/provider/kubernetes/client.go

@@ -23,6 +23,7 @@ import (
 
 	"github.com/tidwall/gjson"
 	v1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	labels "k8s.io/apimachinery/pkg/labels"
@@ -129,7 +130,7 @@ func (c *Client) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushRemot
 	return c.fullDelete(ctx, remoteRef.GetRemoteKey())
 }
 
-func (c *Client) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (c *Client) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	if remoteRef.GetProperty() == "" {
 		return fmt.Errorf("requires property in RemoteRef to push secret value")
 	}

+ 1 - 1
pkg/provider/kubernetes/client_test.go

@@ -850,7 +850,7 @@ func TestPushSecret(t *testing.T) {
 				userSecretClient: tt.fields.Client,
 				store:            &esv1beta1.KubernetesProvider{},
 			}
-			err := p.PushSecret(context.Background(), []byte(tt.fields.PushValue), tt.ref)
+			err := p.PushSecret(context.Background(), []byte(tt.fields.PushValue), nil, tt.ref)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("ProviderKubernetes.DeleteSecret() error = %v, wantErr %v", err, tt.wantErr)
 				return

+ 2 - 1
pkg/provider/onepassword/onepassword.go

@@ -22,6 +22,7 @@ import (
 	"github.com/1Password/connect-sdk-go/connect"
 	"github.com/1Password/connect-sdk-go/onepassword"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -157,7 +158,7 @@ func (provider *ProviderOnePassword) DeleteSecret(_ context.Context, _ esv1beta1
 }
 
 // Not Implemented PushSecret.
-func (provider *ProviderOnePassword) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (provider *ProviderOnePassword) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/oracle/oracle.go

@@ -25,6 +25,7 @@ import (
 	"github.com/oracle/oci-go-sdk/v56/secrets"
 	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -74,7 +75,7 @@ type KmsVCInterface interface {
 }
 
 // Not Implemented PushSecret.
-func (vms *VaultManagementService) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (vms *VaultManagementService) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/scaleway/client.go

@@ -26,6 +26,7 @@ import (
 	smapi "github.com/scaleway/scaleway-sdk-go/api/secret/v1alpha1"
 	"github.com/scaleway/scaleway-sdk-go/scw"
 	"github.com/tidwall/gjson"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/find"
@@ -114,7 +115,7 @@ func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretData
 	return value, nil
 }
 
-func (c *client) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (c *client) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	scwRef, err := decodeScwSecretRef(remoteRef.GetRemoteKey())
 	if err != nil {
 		return err

+ 8 - 8
pkg/provider/scaleway/client_test.go

@@ -204,7 +204,7 @@ func TestPushSecret(t *testing.T) {
 		data := []byte("some secret data 6a8ff33b-c69a-4e42-b162-b7b595ee7f5f")
 		secretName := "secret-creation-test"
 
-		pushErr := c.PushSecret(ctx, data, pushRemoteRef("name:"+secretName))
+		pushErr := c.PushSecret(ctx, data, nil, pushRemoteRef("name:"+secretName))
 
 		assert.NoError(t, pushErr)
 		assert.Len(t, db.secret(secretName).versions, 1)
@@ -216,9 +216,9 @@ func TestPushSecret(t *testing.T) {
 		c := newTestClient()
 		data := []byte("some secret data a11d416b-9169-4f4a-8c27-d2959b22e189")
 		secretName := "secret-update-test"
-		assert.NoError(t, c.PushSecret(ctx, []byte("original data"), pushRemoteRef("name:"+secretName)))
+		assert.NoError(t, c.PushSecret(ctx, []byte("original data"), nil, pushRemoteRef("name:"+secretName)))
 
-		pushErr := c.PushSecret(ctx, data, pushRemoteRef("name:"+secretName))
+		pushErr := c.PushSecret(ctx, data, nil, pushRemoteRef("name:"+secretName))
 
 		assert.NoError(t, pushErr)
 		assert.Len(t, db.secret(secretName).versions, 2)
@@ -231,7 +231,7 @@ func TestPushSecret(t *testing.T) {
 		data := []byte("some secret data a11d416b-9169-4f4a-8c27-d2959b22e189")
 		secretName := "push-me"
 
-		pushErr := c.PushSecret(ctx, data, pushRemoteRef("name:"+secretName))
+		pushErr := c.PushSecret(ctx, data, nil, pushRemoteRef("name:"+secretName))
 
 		assert.NoError(t, pushErr)
 		assert.Len(t, db.secret(secretName).versions, 1)
@@ -242,7 +242,7 @@ func TestPushSecret(t *testing.T) {
 		ctx := context.Background()
 		c := newTestClient()
 
-		pushErr := c.PushSecret(ctx, []byte("some data"), pushRemoteRef("invalid:abcd"))
+		pushErr := c.PushSecret(ctx, []byte("some data"), nil, pushRemoteRef("invalid:abcd"))
 
 		assert.Error(t, pushErr)
 	})
@@ -251,7 +251,7 @@ func TestPushSecret(t *testing.T) {
 		ctx := context.Background()
 		c := newTestClient()
 
-		pushErr := c.PushSecret(ctx, []byte("some data"), pushRemoteRef("id:"+db.secret("cant-push").id))
+		pushErr := c.PushSecret(ctx, []byte("some data"), nil, pushRemoteRef("id:"+db.secret("cant-push").id))
 
 		assert.Error(t, pushErr)
 	})
@@ -261,7 +261,7 @@ func TestPushSecret(t *testing.T) {
 		c := newTestClient()
 		secret := db.secret("not-changed")
 
-		pushErr := c.PushSecret(ctx, secret.versions[0].data, pushRemoteRef("name:"+secret.name))
+		pushErr := c.PushSecret(ctx, secret.versions[0].data, nil, pushRemoteRef("name:"+secret.name))
 
 		assert.NoError(t, pushErr)
 		assert.Equal(t, 1, len(secret.versions))
@@ -272,7 +272,7 @@ func TestPushSecret(t *testing.T) {
 		c := newTestClient()
 		secret := db.secret("disabling-old-versions")
 
-		pushErr := c.PushSecret(ctx, []byte("some new data"), pushRemoteRef("name:"+secret.name))
+		pushErr := c.PushSecret(ctx, []byte("some new data"), nil, pushRemoteRef("name:"+secret.name))
 
 		assert.NoError(t, pushErr)
 		assert.Equal(t, 2, len(secret.versions))

+ 3 - 1
pkg/provider/senhasegura/dsm/dsm.go

@@ -24,6 +24,8 @@ import (
 	"net/http"
 	"net/url"
 
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	senhaseguraAuth "github.com/external-secrets/external-secrets/pkg/provider/senhasegura/auth"
 )
@@ -95,7 +97,7 @@ func (dsm *DSM) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) error
 }
 
 // Not Implemented PushSecret.
-func (dsm *DSM) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (dsm *DSM) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 2 - 1
pkg/provider/testing/fake/fake.go

@@ -17,6 +17,7 @@ package fake
 import (
 	"context"
 
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -79,7 +80,7 @@ func (v *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecret
 }
 
 // Not Implemented PushSecret.
-func (v *Client) PushSecret(_ context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (v *Client) PushSecret(_ context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	v.SetSecretArgs[remoteRef.GetRemoteKey()] = SetSecretCallArgs{
 		Value:     value,
 		RemoteRef: remoteRef,

+ 2 - 1
pkg/provider/vault/vault.go

@@ -44,6 +44,7 @@ import (
 	"github.com/tidwall/gjson"
 	authenticationv1 "k8s.io/api/authentication/v1"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/kubernetes"
@@ -482,7 +483,7 @@ func (v *client) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushRemot
 	return nil
 }
 
-func (v *client) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
+func (v *client) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv1.JSON, remoteRef esv1beta1.PushRemoteRef) error {
 	label := map[string]interface{}{
 		"custom_metadata": map[string]string{
 			"managed-by": "external-secrets",

+ 1 - 1
pkg/provider/vault/vault_test.go

@@ -2040,7 +2040,7 @@ func TestSetSecret(t *testing.T) {
 			if val == nil {
 				val = []byte(`{"fake-key":"fake-value"}`)
 			}
-			err := client.PushSecret(context.Background(), val, ref)
+			err := client.PushSecret(context.Background(), val, nil, ref)
 
 			// Error nil XOR tc.want.err nil
 			if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {

+ 2 - 1
pkg/provider/webhook/webhook.go

@@ -30,6 +30,7 @@ import (
 	"github.com/PaesslerAG/jsonpath"
 	"gopkg.in/yaml.v3"
 	corev1 "k8s.io/api/core/v1"
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -122,7 +123,7 @@ func (w *WebHook) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) err
 }
 
 // Not Implemented PushSecret.
-func (w *WebHook) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (w *WebHook) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }
 

+ 3 - 1
pkg/provider/yandex/common/secretsclient.go

@@ -17,6 +17,8 @@ import (
 	"context"
 	"fmt"
 
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 )
 
@@ -38,7 +40,7 @@ func (c *yandexCloudSecretsClient) DeleteSecret(_ context.Context, _ esv1beta1.P
 	return fmt.Errorf("not implemented")
 }
 
-func (c *yandexCloudSecretsClient) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
+func (c *yandexCloudSecretsClient) PushSecret(_ context.Context, _ []byte, _ *apiextensionsv1.JSON, _ esv1beta1.PushRemoteRef) error {
 	return fmt.Errorf("not implemented")
 }