Bläddra i källkod

Merge branch 'beach-team' of https://github.com/external-secrets/external-secrets into HEAD

Conch Horse (EngineerBetterCI) 4 år sedan
förälder
incheckning
3d77b80013
42 ändrade filer med 3861 tillägg och 18 borttagningar
  1. 8 0
      apis/externalsecrets/v1alpha1/register.go
  2. 120 0
      apis/externalsecrets/v1alpha1/secretsink_types.go
  3. 229 0
      apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go
  4. 5 0
      apis/externalsecrets/v1beta1/provider.go
  5. 9 0
      apis/externalsecrets/v1beta1/provider_schema_test.go
  6. 14 0
      apis/externalsecrets/v1beta1/secretstore_types.go
  7. 11 0
      cmd/root.go
  8. 10 0
      config/crds/bases/external-secrets.io_clustersecretstores.yaml
  9. 142 0
      config/crds/bases/external-secrets.io_secretsinks.yaml
  10. 7 0
      config/crds/bases/external-secrets.io_secretstores.yaml
  11. 6 0
      deploy/charts/external-secrets/templates/rbac.yaml
  12. 159 0
      deploy/crds/bundle.yaml
  13. 784 0
      pkg/controllers/secretsink/internal/fakes/client.go
  14. 1288 0
      pkg/controllers/secretsink/internal/fakes/manager.go
  15. 196 0
      pkg/controllers/secretsink/internal/fakes/statuswriter.go
  16. 232 0
      pkg/controllers/secretsink/secretsink_controller.go
  17. 316 0
      pkg/controllers/secretsink/secretsink_controller_test.go
  18. 44 0
      pkg/controllers/secretsink/suite_test.go
  19. 9 0
      pkg/controllers/secretstore/common.go
  20. 33 0
      pkg/controllers/secretstore/common_test.go
  21. 9 0
      pkg/provider/akeyless/akeyless.go
  22. 9 0
      pkg/provider/alibaba/kms.go
  23. 6 1
      pkg/provider/aws/parameterstore/parameterstore.go
  24. 5 0
      pkg/provider/aws/provider.go
  25. 5 0
      pkg/provider/aws/secretsmanager/secretsmanager.go
  26. 10 0
      pkg/provider/azure/keyvault/keyvault.go
  27. 34 2
      pkg/provider/fake/fake.go
  28. 9 2
      pkg/provider/fake/fake_test.go
  29. 10 0
      pkg/provider/gcp/secretmanager/secretsmanager.go
  30. 10 0
      pkg/provider/gitlab/gitlab.go
  31. 10 0
      pkg/provider/ibm/provider.go
  32. 10 0
      pkg/provider/kubernetes/kubernetes.go
  33. 10 0
      pkg/provider/onepassword/onepassword.go
  34. 10 0
      pkg/provider/oracle/oracle.go
  35. 5 0
      pkg/provider/senhasegura/dsm/dsm.go
  36. 5 0
      pkg/provider/senhasegura/provider.go
  37. 22 0
      pkg/provider/testing/fake/fake.go
  38. 12 3
      pkg/provider/vault/vault.go
  39. 10 0
      pkg/provider/webhook/webhook.go
  40. 6 1
      pkg/provider/yandex/common/provider.go
  41. 14 9
      pkg/provider/yandex/common/secretsclient.go
  42. 18 0
      pkg/provider/yandex/common/secretsetter.go

+ 8 - 0
apis/externalsecrets/v1alpha1/register.go

@@ -60,8 +60,16 @@ var (
 	ClusterSecretStoreGroupVersionKind = SchemeGroupVersion.WithKind(ClusterSecretStoreKind)
 )
 
+var (
+	SecretSinkKind             = reflect.TypeOf(SecretSink{}).Name()
+	SecretSinkGroupKind        = schema.GroupKind{Group: Group, Kind: SecretSinkKind}.String()
+	SecretSinkKindAPIVersion   = SecretSinkKind + "." + SchemeGroupVersion.String()
+	SecretSinkGroupVersionKind = SchemeGroupVersion.WithKind(SecretSinkKind)
+)
+
 func init() {
 	SchemeBuilder.Register(&ExternalSecret{}, &ExternalSecretList{})
 	SchemeBuilder.Register(&SecretStore{}, &SecretStoreList{})
 	SchemeBuilder.Register(&ClusterSecretStore{}, &ClusterSecretStoreList{})
+	SchemeBuilder.Register(&SecretSink{}, &SecretSinkList{})
 }

+ 120 - 0
apis/externalsecrets/v1alpha1/secretsink_types.go

@@ -0,0 +1,120 @@
+/*
+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 v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type SecretSinkStoreRef struct {
+	// Name of the SecretStore resource
+	Name string `json:"name"`
+
+	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+	// Defaults to `SecretStore`
+	// +optional
+	Kind string `json:"kind,omitempty"`
+}
+
+// SecretSinkSpec configures the behavior of the SecretSink.
+type SecretSinkSpec struct {
+	SecretStoreRefs []SecretSinkStoreRef `json:"secretStoreRefs"`
+	Selector        SecretSinkSelector   `json:"selector"`
+	Data            []SecretSinkData     `json:"data,omitempty"`
+}
+
+type SecretSinkSecret struct {
+	Name string `json:"name"`
+}
+
+type SecretSinkSelector struct {
+	Secret SecretSinkSecret `json:"secret"`
+}
+
+type SecretSinkRemoteRefs struct {
+	RemoteKey string `json:"remoteKey"`
+}
+
+type SecretSinkMatch struct {
+	SecretKey  string                 `json:"secretKey"`
+	RemoteRefs []SecretSinkRemoteRefs `json:"remoteRefs"`
+}
+
+type SecretSinkData struct {
+	Match []SecretSinkMatch `json:"match"`
+}
+
+// SecretSinkConditionType indicates the condition of the SecretSink.
+type SecretSinkConditionType string
+
+const (
+	SecretSinkReady SecretSinkConditionType = "Ready"
+)
+
+// SecretSinkStatusCondition indicates the status of the SecretSink.
+type SecretSinkStatusCondition struct {
+	Type   SecretSinkConditionType `json:"type"`
+	Status corev1.ConditionStatus  `json:"status"`
+
+	// +optional
+	Reason string `json:"reason,omitempty"`
+
+	// +optional
+	Message string `json:"message,omitempty"`
+
+	// +optional
+	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
+}
+
+// SecretSinkStatus indicates the history of the status of SecretSink.
+type SecretSinkStatus struct {
+	// +nullable
+	// refreshTime is the time and date the external secret was fetched and
+	// the target secret updated
+	RefreshTime metav1.Time `json:"refreshTime,omitempty"`
+
+	// SyncedResourceVersion keeps track of the last synced version.
+	SyncedResourceVersion string `json:"syncedResourceVersion,omitempty"`
+
+	// +optional
+	Conditions []SecretSinkStatusCondition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
+// Secretsinks is the Schema for the secretsinks API.
+// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={secretsinks}
+
+type SecretSink struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   SecretSinkSpec   `json:"spec,omitempty"`
+	Status SecretSinkStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// SecretSinkList contains a list of SecretSink resources.
+type SecretSinkList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []SecretSink `json:"items"`
+}

+ 229 - 0
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -964,6 +964,235 @@ func (in *OracleSecretRef) DeepCopy() *OracleSecretRef {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSink) DeepCopyInto(out *SecretSink) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSink.
+func (in *SecretSink) DeepCopy() *SecretSink {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSink)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SecretSink) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkData) DeepCopyInto(out *SecretSinkData) {
+	*out = *in
+	if in.Match != nil {
+		in, out := &in.Match, &out.Match
+		*out = make([]SecretSinkMatch, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkData.
+func (in *SecretSinkData) DeepCopy() *SecretSinkData {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkData)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkList) DeepCopyInto(out *SecretSinkList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]SecretSink, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkList.
+func (in *SecretSinkList) DeepCopy() *SecretSinkList {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SecretSinkList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkMatch) DeepCopyInto(out *SecretSinkMatch) {
+	*out = *in
+	if in.RemoteRefs != nil {
+		in, out := &in.RemoteRefs, &out.RemoteRefs
+		*out = make([]SecretSinkRemoteRefs, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkMatch.
+func (in *SecretSinkMatch) DeepCopy() *SecretSinkMatch {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkMatch)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkRemoteRefs) DeepCopyInto(out *SecretSinkRemoteRefs) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkRemoteRefs.
+func (in *SecretSinkRemoteRefs) DeepCopy() *SecretSinkRemoteRefs {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkRemoteRefs)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkSecret) DeepCopyInto(out *SecretSinkSecret) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkSecret.
+func (in *SecretSinkSecret) DeepCopy() *SecretSinkSecret {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkSecret)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkSelector) DeepCopyInto(out *SecretSinkSelector) {
+	*out = *in
+	out.Secret = in.Secret
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkSelector.
+func (in *SecretSinkSelector) DeepCopy() *SecretSinkSelector {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkSelector)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkSpec) DeepCopyInto(out *SecretSinkSpec) {
+	*out = *in
+	if in.SecretStoreRefs != nil {
+		in, out := &in.SecretStoreRefs, &out.SecretStoreRefs
+		*out = make([]SecretSinkStoreRef, len(*in))
+		copy(*out, *in)
+	}
+	out.Selector = in.Selector
+	if in.Data != nil {
+		in, out := &in.Data, &out.Data
+		*out = make([]SecretSinkData, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkSpec.
+func (in *SecretSinkSpec) DeepCopy() *SecretSinkSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkStatus) DeepCopyInto(out *SecretSinkStatus) {
+	*out = *in
+	in.RefreshTime.DeepCopyInto(&out.RefreshTime)
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]SecretSinkStatusCondition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkStatus.
+func (in *SecretSinkStatus) DeepCopy() *SecretSinkStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkStatusCondition) DeepCopyInto(out *SecretSinkStatusCondition) {
+	*out = *in
+	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkStatusCondition.
+func (in *SecretSinkStatusCondition) DeepCopy() *SecretSinkStatusCondition {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkStatusCondition)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkStoreRef) DeepCopyInto(out *SecretSinkStoreRef) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkStoreRef.
+func (in *SecretSinkStoreRef) DeepCopy() *SecretSinkStoreRef {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkStoreRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SecretStore) DeepCopyInto(out *SecretStore) {
 	*out = *in

+ 5 - 0
apis/externalsecrets/v1beta1/provider.go

@@ -51,6 +51,8 @@ type Provider interface {
 
 	// ValidateStore checks if the provided store is valid
 	ValidateStore(store GenericStore) error
+	// Capabilities returns the provider Capabilities (Read, Write, ReadWrite)
+	Capabilities() SecretStoreCapabilities
 }
 
 // +kubebuilder:object:root=false
@@ -65,6 +67,9 @@ type SecretsClient interface {
 	// then the secret entry will be deleted depending on the deletionPolicy.
 	GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error)
 
+	// SetSecret will write a single secret into the provider
+	SetSecret(secretKey, remoteKey string) error
+
 	// Validate checks if the client is configured correctly
 	// and is able to retrieve secrets from the provider.
 	// If the validation result is unknown it will be ignored.

+ 9 - 0
apis/externalsecrets/v1beta1/provider_schema_test.go

@@ -25,11 +25,20 @@ type PP struct{}
 
 const shouldBeRegistered = "provider should be registered"
 
+func (p *PP) Capabilities() SecretStoreCapabilities {
+	return SecretStoreReadOnly
+}
+
 // New constructs a SecretsManager Provider.
 func (p *PP) NewClient(ctx context.Context, store GenericStore, kube client.Client, namespace string) (SecretsClient, error) {
 	return p, nil
 }
 
+// SetSecret writes a single secret into a provider.
+func (p *PP) SetSecret(secretKey, remoteKey string) error {
+	return nil
+}
+
 // GetSecret returns a single secret from the provider.
 func (p *PP) GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error) {
 	return []byte("NOOP"), nil

+ 14 - 0
apis/externalsecrets/v1beta1/secretstore_types.go

@@ -137,10 +137,21 @@ type SecretStoreStatusCondition struct {
 	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
 }
 
+// SecretStoreCapabilities defines the possible operations a SecretStore can do.
+type SecretStoreCapabilities string
+
+const (
+	SecretStoreReadOnly  SecretStoreCapabilities = "ReadOnly"
+	SecretStoreWriteOnly SecretStoreCapabilities = "WriteOnly"
+	SecretStoreReadWrite SecretStoreCapabilities = "ReadWrite"
+)
+
 // SecretStoreStatus defines the observed state of the SecretStore.
 type SecretStoreStatus struct {
 	// +optional
 	Conditions []SecretStoreStatusCondition `json:"conditions"`
+	// +optional
+	Capabilities SecretStoreCapabilities `json:"capabilities"`
 }
 
 // +kubebuilder:object:root=true
@@ -149,6 +160,7 @@ type SecretStoreStatus struct {
 // SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields.
 // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
 // +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// +kubebuilder:printcolumn:name="Capabilities",type=string,JSONPath=`.status.capabilities`
 // +kubebuilder:subresource:status
 // +kubebuilder:resource:scope=Namespaced,categories={externalsecrets},shortName=ss
 type SecretStore struct {
@@ -173,6 +185,8 @@ type SecretStoreList struct {
 
 // ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields.
 // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// +kubebuilder:printcolumn:name="Capabilities",type=string,JSONPath=`.status.capabilities`
 // +kubebuilder:subresource:status
 // +kubebuilder:resource:scope=Cluster,categories={externalsecrets},shortName=css
 type ClusterSecretStore struct {

+ 11 - 0
cmd/root.go

@@ -37,6 +37,7 @@ import (
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/controllers/clusterexternalsecret"
 	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret"
+	"github.com/external-secrets/external-secrets/pkg/controllers/secretsink"
 	"github.com/external-secrets/external-secrets/pkg/controllers/secretstore"
 )
 
@@ -146,6 +147,16 @@ var rootCmd = &cobra.Command{
 			setupLog.Error(err, errCreateController, "controller", "ExternalSecret")
 			os.Exit(1)
 		}
+		if err = (&secretsink.Reconciler{
+			Client:          mgr.GetClient(),
+			Log:             ctrl.Log.WithName("controllers").WithName("SecretSink"),
+			Scheme:          mgr.GetScheme(),
+			ControllerClass: controllerClass,
+			RequeueInterval: time.Hour,
+		}).SetupWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateController, "controller", "SecretSink")
+			os.Exit(1)
+		}
 		if enableClusterExternalSecretReconciler {
 			if err = (&clusterexternalsecret.Reconciler{
 				Client:          mgr.GetClient(),

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

@@ -1387,6 +1387,12 @@ spec:
     - jsonPath: .metadata.creationTimestamp
       name: AGE
       type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+      name: Status
+      type: string
+    - jsonPath: .status.capabilities
+      name: Capabilities
+      type: string
     name: v1beta1
     schema:
       openAPIV3Schema:
@@ -2885,6 +2891,10 @@ spec:
           status:
             description: SecretStoreStatus defines the observed state of the SecretStore.
             properties:
+              capabilities:
+                description: SecretStoreCapabilities defines the possible operations
+                  a SecretStore can do.
+                type: string
               conditions:
                 items:
                   properties:

+ 142 - 0
config/crds/bases/external-secrets.io_secretsinks.yaml

@@ -0,0 +1,142 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.0
+  creationTimestamp: null
+  name: secretsinks.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+    - secretsinks
+    kind: SecretSink
+    listKind: SecretSinkList
+    plural: secretsinks
+    singular: secretsink
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: AGE
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+      name: Status
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: SecretSinkSpec configures the behavior of the SecretSink.
+            properties:
+              data:
+                items:
+                  properties:
+                    match:
+                      items:
+                        properties:
+                          remoteRefs:
+                            items:
+                              properties:
+                                remoteKey:
+                                  type: string
+                              required:
+                              - remoteKey
+                              type: object
+                            type: array
+                          secretKey:
+                            type: string
+                        required:
+                        - remoteRefs
+                        - secretKey
+                        type: object
+                      type: array
+                  required:
+                  - match
+                  type: object
+                type: array
+              secretStoreRefs:
+                items:
+                  properties:
+                    kind:
+                      description: Kind of the SecretStore resource (SecretStore or
+                        ClusterSecretStore) Defaults to `SecretStore`
+                      type: string
+                    name:
+                      description: Name of the SecretStore resource
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              selector:
+                properties:
+                  secret:
+                    properties:
+                      name:
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - secret
+                type: object
+            required:
+            - secretStoreRefs
+            - selector
+            type: object
+          status:
+            description: SecretSinkStatus indicates the history of the status of SecretSink.
+            properties:
+              conditions:
+                items:
+                  description: SecretSinkStatusCondition indicates the status of the
+                    SecretSink.
+                  properties:
+                    lastTransitionTime:
+                      format: date-time
+                      type: string
+                    message:
+                      type: string
+                    reason:
+                      type: string
+                    status:
+                      type: string
+                    type:
+                      description: SecretSinkConditionType indicates the condition
+                        of the SecretSink.
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+              refreshTime:
+                description: refreshTime is the time and date the external secret
+                  was fetched and the target secret updated
+                format: date-time
+                nullable: true
+                type: string
+              syncedResourceVersion:
+                description: SyncedResourceVersion keeps track of the last synced
+                  version.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 7 - 0
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -1390,6 +1390,9 @@ spec:
     - jsonPath: .status.conditions[?(@.type=="Ready")].reason
       name: Status
       type: string
+    - jsonPath: .status.capabilities
+      name: Capabilities
+      type: string
     name: v1beta1
     schema:
       openAPIV3Schema:
@@ -2888,6 +2891,10 @@ spec:
           status:
             description: SecretStoreStatus defines the observed state of the SecretStore.
             properties:
+              capabilities:
+                description: SecretStoreCapabilities defines the possible operations
+                  a SecretStore can do.
+                type: string
               conditions:
                 items:
                   properties:

+ 6 - 0
deploy/charts/external-secrets/templates/rbac.yaml

@@ -20,6 +20,7 @@ rules:
     - "clustersecretstores"
     - "externalsecrets"
     - "clusterexternalsecrets"
+    - "secretsinks"
     verbs:
     - "get"
     - "list"
@@ -39,6 +40,9 @@ rules:
     - "clusterexternalsecrets"
     - "clusterexternalsecrets/status"
     - "clusterexternalsecrets/finalizers"
+    - "secretsinks"
+    - "secretsinks/status"
+    - "secretsinks/finalizers"
     verbs:
     - "update"
     - "patch"
@@ -115,6 +119,7 @@ rules:
       - "externalsecrets"
       - "secretstores"
       - "clustersecretstores"
+      - "secretsinks"
     verbs:
       - "get"
       - "watch"
@@ -142,6 +147,7 @@ rules:
       - "externalsecrets"
       - "secretstores"
       - "clustersecretstores"
+      - "secretsinks"
     verbs:
       - "create"
       - "delete"

+ 159 - 0
deploy/crds/bundle.yaml

@@ -1358,6 +1358,12 @@ spec:
         - jsonPath: .metadata.creationTimestamp
           name: AGE
           type: date
+        - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+          name: Status
+          type: string
+        - jsonPath: .status.capabilities
+          name: Capabilities
+          type: string
       name: v1beta1
       schema:
         openAPIV3Schema:
@@ -2456,6 +2462,9 @@ spec:
             status:
               description: SecretStoreStatus defines the observed state of the SecretStore.
               properties:
+                capabilities:
+                  description: SecretStoreCapabilities defines the possible operations a SecretStore can do.
+                  type: string
                 conditions:
                   items:
                     properties:
@@ -3001,6 +3010,150 @@ spec:
 ---
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.0
+  creationTimestamp: null
+  name: secretsinks.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+      - secretsinks
+    kind: SecretSink
+    listKind: SecretSinkList
+    plural: secretsinks
+    singular: secretsink
+  scope: Namespaced
+  versions:
+    - additionalPrinterColumns:
+        - jsonPath: .metadata.creationTimestamp
+          name: AGE
+          type: date
+        - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+          name: Status
+          type: string
+      name: v1alpha1
+      schema:
+        openAPIV3Schema:
+          properties:
+            apiVersion:
+              description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+              type: string
+            kind:
+              description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+              type: string
+            metadata:
+              type: object
+            spec:
+              description: SecretSinkSpec configures the behavior of the SecretSink.
+              properties:
+                data:
+                  items:
+                    properties:
+                      match:
+                        items:
+                          properties:
+                            remoteRefs:
+                              items:
+                                properties:
+                                  remoteKey:
+                                    type: string
+                                required:
+                                  - remoteKey
+                                type: object
+                              type: array
+                            secretKey:
+                              type: string
+                          required:
+                            - remoteRefs
+                            - secretKey
+                          type: object
+                        type: array
+                    required:
+                      - match
+                    type: object
+                  type: array
+                secretStoreRefs:
+                  items:
+                    properties:
+                      kind:
+                        description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore`
+                        type: string
+                      name:
+                        description: Name of the SecretStore resource
+                        type: string
+                    required:
+                      - name
+                    type: object
+                  type: array
+                selector:
+                  properties:
+                    secret:
+                      properties:
+                        name:
+                          type: string
+                      required:
+                        - name
+                      type: object
+                  required:
+                    - secret
+                  type: object
+              required:
+                - secretStoreRefs
+                - selector
+              type: object
+            status:
+              description: SecretSinkStatus indicates the history of the status of SecretSink.
+              properties:
+                conditions:
+                  items:
+                    description: SecretSinkStatusCondition indicates the status of the SecretSink.
+                    properties:
+                      lastTransitionTime:
+                        format: date-time
+                        type: string
+                      message:
+                        type: string
+                      reason:
+                        type: string
+                      status:
+                        type: string
+                      type:
+                        description: SecretSinkConditionType indicates the condition of the SecretSink.
+                        type: string
+                    required:
+                      - status
+                      - type
+                    type: object
+                  type: array
+                refreshTime:
+                  description: refreshTime is the time and date the external secret was fetched and the target secret updated
+                  format: date-time
+                  nullable: true
+                  type: string
+                syncedResourceVersion:
+                  description: SyncedResourceVersion keeps track of the last synced version.
+                  type: string
+              type: object
+          type: object
+      served: true
+      storage: true
+      subresources:
+        status: {}
+  conversion:
+    strategy: Webhook
+    webhook:
+      conversionReviewVersions:
+        - v1
+      clientConfig:
+        service:
+          name: kubernetes
+          namespace: default
+          path: /convert
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
 metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.9.0
@@ -4030,6 +4183,9 @@ spec:
         - jsonPath: .status.conditions[?(@.type=="Ready")].reason
           name: Status
           type: string
+        - jsonPath: .status.capabilities
+          name: Capabilities
+          type: string
       name: v1beta1
       schema:
         openAPIV3Schema:
@@ -5128,6 +5284,9 @@ spec:
             status:
               description: SecretStoreStatus defines the observed state of the SecretStore.
               properties:
+                capabilities:
+                  description: SecretStoreCapabilities defines the possible operations a SecretStore can do.
+                  type: string
                 conditions:
                   items:
                     properties:

+ 784 - 0
pkg/controllers/secretsink/internal/fakes/client.go

@@ -0,0 +1,784 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package fakes
+
+import (
+	"context"
+	"sync"
+
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type Client struct {
+	CreateStub        func(context.Context, client.Object, ...client.CreateOption) error
+	createMutex       sync.RWMutex
+	createArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.CreateOption
+	}
+	createReturns struct {
+		result1 error
+	}
+	createReturnsOnCall map[int]struct {
+		result1 error
+	}
+	DeleteStub        func(context.Context, client.Object, ...client.DeleteOption) error
+	deleteMutex       sync.RWMutex
+	deleteArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.DeleteOption
+	}
+	deleteReturns struct {
+		result1 error
+	}
+	deleteReturnsOnCall map[int]struct {
+		result1 error
+	}
+	DeleteAllOfStub        func(context.Context, client.Object, ...client.DeleteAllOfOption) error
+	deleteAllOfMutex       sync.RWMutex
+	deleteAllOfArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.DeleteAllOfOption
+	}
+	deleteAllOfReturns struct {
+		result1 error
+	}
+	deleteAllOfReturnsOnCall map[int]struct {
+		result1 error
+	}
+	GetStub        func(context.Context, types.NamespacedName, client.Object) error
+	getMutex       sync.RWMutex
+	getArgsForCall []struct {
+		arg1 context.Context
+		arg2 types.NamespacedName
+		arg3 client.Object
+	}
+	getReturns struct {
+		result1 error
+	}
+	getReturnsOnCall map[int]struct {
+		result1 error
+	}
+	ListStub        func(context.Context, client.ObjectList, ...client.ListOption) error
+	listMutex       sync.RWMutex
+	listArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.ObjectList
+		arg3 []client.ListOption
+	}
+	listReturns struct {
+		result1 error
+	}
+	listReturnsOnCall map[int]struct {
+		result1 error
+	}
+	PatchStub        func(context.Context, client.Object, client.Patch, ...client.PatchOption) error
+	patchMutex       sync.RWMutex
+	patchArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 client.Patch
+		arg4 []client.PatchOption
+	}
+	patchReturns struct {
+		result1 error
+	}
+	patchReturnsOnCall map[int]struct {
+		result1 error
+	}
+	RESTMapperStub        func() meta.RESTMapper
+	rESTMapperMutex       sync.RWMutex
+	rESTMapperArgsForCall []struct {
+	}
+	rESTMapperReturns struct {
+		result1 meta.RESTMapper
+	}
+	rESTMapperReturnsOnCall map[int]struct {
+		result1 meta.RESTMapper
+	}
+	SchemeStub        func() *runtime.Scheme
+	schemeMutex       sync.RWMutex
+	schemeArgsForCall []struct {
+	}
+	schemeReturns struct {
+		result1 *runtime.Scheme
+	}
+	schemeReturnsOnCall map[int]struct {
+		result1 *runtime.Scheme
+	}
+	StatusStub        func() client.StatusWriter
+	statusMutex       sync.RWMutex
+	statusArgsForCall []struct {
+	}
+	statusReturns struct {
+		result1 client.StatusWriter
+	}
+	statusReturnsOnCall map[int]struct {
+		result1 client.StatusWriter
+	}
+	UpdateStub        func(context.Context, client.Object, ...client.UpdateOption) error
+	updateMutex       sync.RWMutex
+	updateArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.UpdateOption
+	}
+	updateReturns struct {
+		result1 error
+	}
+	updateReturnsOnCall map[int]struct {
+		result1 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Client) Create(arg1 context.Context, arg2 client.Object, arg3 ...client.CreateOption) error {
+	fake.createMutex.Lock()
+	ret, specificReturn := fake.createReturnsOnCall[len(fake.createArgsForCall)]
+	fake.createArgsForCall = append(fake.createArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.CreateOption
+	}{arg1, arg2, arg3})
+	stub := fake.CreateStub
+	fakeReturns := fake.createReturns
+	fake.recordInvocation("Create", []interface{}{arg1, arg2, arg3})
+	fake.createMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) CreateCallCount() int {
+	fake.createMutex.RLock()
+	defer fake.createMutex.RUnlock()
+	return len(fake.createArgsForCall)
+}
+
+func (fake *Client) CreateCalls(stub func(context.Context, client.Object, ...client.CreateOption) error) {
+	fake.createMutex.Lock()
+	defer fake.createMutex.Unlock()
+	fake.CreateStub = stub
+}
+
+func (fake *Client) CreateArgsForCall(i int) (context.Context, client.Object, []client.CreateOption) {
+	fake.createMutex.RLock()
+	defer fake.createMutex.RUnlock()
+	argsForCall := fake.createArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Client) CreateReturns(result1 error) {
+	fake.createMutex.Lock()
+	defer fake.createMutex.Unlock()
+	fake.CreateStub = nil
+	fake.createReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) CreateReturnsOnCall(i int, result1 error) {
+	fake.createMutex.Lock()
+	defer fake.createMutex.Unlock()
+	fake.CreateStub = nil
+	if fake.createReturnsOnCall == nil {
+		fake.createReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.createReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) Delete(arg1 context.Context, arg2 client.Object, arg3 ...client.DeleteOption) error {
+	fake.deleteMutex.Lock()
+	ret, specificReturn := fake.deleteReturnsOnCall[len(fake.deleteArgsForCall)]
+	fake.deleteArgsForCall = append(fake.deleteArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.DeleteOption
+	}{arg1, arg2, arg3})
+	stub := fake.DeleteStub
+	fakeReturns := fake.deleteReturns
+	fake.recordInvocation("Delete", []interface{}{arg1, arg2, arg3})
+	fake.deleteMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) DeleteCallCount() int {
+	fake.deleteMutex.RLock()
+	defer fake.deleteMutex.RUnlock()
+	return len(fake.deleteArgsForCall)
+}
+
+func (fake *Client) DeleteCalls(stub func(context.Context, client.Object, ...client.DeleteOption) error) {
+	fake.deleteMutex.Lock()
+	defer fake.deleteMutex.Unlock()
+	fake.DeleteStub = stub
+}
+
+func (fake *Client) DeleteArgsForCall(i int) (context.Context, client.Object, []client.DeleteOption) {
+	fake.deleteMutex.RLock()
+	defer fake.deleteMutex.RUnlock()
+	argsForCall := fake.deleteArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Client) DeleteReturns(result1 error) {
+	fake.deleteMutex.Lock()
+	defer fake.deleteMutex.Unlock()
+	fake.DeleteStub = nil
+	fake.deleteReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) DeleteReturnsOnCall(i int, result1 error) {
+	fake.deleteMutex.Lock()
+	defer fake.deleteMutex.Unlock()
+	fake.DeleteStub = nil
+	if fake.deleteReturnsOnCall == nil {
+		fake.deleteReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.deleteReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) DeleteAllOf(arg1 context.Context, arg2 client.Object, arg3 ...client.DeleteAllOfOption) error {
+	fake.deleteAllOfMutex.Lock()
+	ret, specificReturn := fake.deleteAllOfReturnsOnCall[len(fake.deleteAllOfArgsForCall)]
+	fake.deleteAllOfArgsForCall = append(fake.deleteAllOfArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.DeleteAllOfOption
+	}{arg1, arg2, arg3})
+	stub := fake.DeleteAllOfStub
+	fakeReturns := fake.deleteAllOfReturns
+	fake.recordInvocation("DeleteAllOf", []interface{}{arg1, arg2, arg3})
+	fake.deleteAllOfMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) DeleteAllOfCallCount() int {
+	fake.deleteAllOfMutex.RLock()
+	defer fake.deleteAllOfMutex.RUnlock()
+	return len(fake.deleteAllOfArgsForCall)
+}
+
+func (fake *Client) DeleteAllOfCalls(stub func(context.Context, client.Object, ...client.DeleteAllOfOption) error) {
+	fake.deleteAllOfMutex.Lock()
+	defer fake.deleteAllOfMutex.Unlock()
+	fake.DeleteAllOfStub = stub
+}
+
+func (fake *Client) DeleteAllOfArgsForCall(i int) (context.Context, client.Object, []client.DeleteAllOfOption) {
+	fake.deleteAllOfMutex.RLock()
+	defer fake.deleteAllOfMutex.RUnlock()
+	argsForCall := fake.deleteAllOfArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Client) DeleteAllOfReturns(result1 error) {
+	fake.deleteAllOfMutex.Lock()
+	defer fake.deleteAllOfMutex.Unlock()
+	fake.DeleteAllOfStub = nil
+	fake.deleteAllOfReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) DeleteAllOfReturnsOnCall(i int, result1 error) {
+	fake.deleteAllOfMutex.Lock()
+	defer fake.deleteAllOfMutex.Unlock()
+	fake.DeleteAllOfStub = nil
+	if fake.deleteAllOfReturnsOnCall == nil {
+		fake.deleteAllOfReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.deleteAllOfReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) Get(arg1 context.Context, arg2 types.NamespacedName, arg3 client.Object) error {
+	fake.getMutex.Lock()
+	ret, specificReturn := fake.getReturnsOnCall[len(fake.getArgsForCall)]
+	fake.getArgsForCall = append(fake.getArgsForCall, struct {
+		arg1 context.Context
+		arg2 types.NamespacedName
+		arg3 client.Object
+	}{arg1, arg2, arg3})
+	stub := fake.GetStub
+	fakeReturns := fake.getReturns
+	fake.recordInvocation("Get", []interface{}{arg1, arg2, arg3})
+	fake.getMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) GetCallCount() int {
+	fake.getMutex.RLock()
+	defer fake.getMutex.RUnlock()
+	return len(fake.getArgsForCall)
+}
+
+func (fake *Client) GetCalls(stub func(context.Context, types.NamespacedName, client.Object) error) {
+	fake.getMutex.Lock()
+	defer fake.getMutex.Unlock()
+	fake.GetStub = stub
+}
+
+func (fake *Client) GetArgsForCall(i int) (context.Context, types.NamespacedName, client.Object) {
+	fake.getMutex.RLock()
+	defer fake.getMutex.RUnlock()
+	argsForCall := fake.getArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Client) GetReturns(result1 error) {
+	fake.getMutex.Lock()
+	defer fake.getMutex.Unlock()
+	fake.GetStub = nil
+	fake.getReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) GetReturnsOnCall(i int, result1 error) {
+	fake.getMutex.Lock()
+	defer fake.getMutex.Unlock()
+	fake.GetStub = nil
+	if fake.getReturnsOnCall == nil {
+		fake.getReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.getReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) List(arg1 context.Context, arg2 client.ObjectList, arg3 ...client.ListOption) error {
+	fake.listMutex.Lock()
+	ret, specificReturn := fake.listReturnsOnCall[len(fake.listArgsForCall)]
+	fake.listArgsForCall = append(fake.listArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.ObjectList
+		arg3 []client.ListOption
+	}{arg1, arg2, arg3})
+	stub := fake.ListStub
+	fakeReturns := fake.listReturns
+	fake.recordInvocation("List", []interface{}{arg1, arg2, arg3})
+	fake.listMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) ListCallCount() int {
+	fake.listMutex.RLock()
+	defer fake.listMutex.RUnlock()
+	return len(fake.listArgsForCall)
+}
+
+func (fake *Client) ListCalls(stub func(context.Context, client.ObjectList, ...client.ListOption) error) {
+	fake.listMutex.Lock()
+	defer fake.listMutex.Unlock()
+	fake.ListStub = stub
+}
+
+func (fake *Client) ListArgsForCall(i int) (context.Context, client.ObjectList, []client.ListOption) {
+	fake.listMutex.RLock()
+	defer fake.listMutex.RUnlock()
+	argsForCall := fake.listArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Client) ListReturns(result1 error) {
+	fake.listMutex.Lock()
+	defer fake.listMutex.Unlock()
+	fake.ListStub = nil
+	fake.listReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) ListReturnsOnCall(i int, result1 error) {
+	fake.listMutex.Lock()
+	defer fake.listMutex.Unlock()
+	fake.ListStub = nil
+	if fake.listReturnsOnCall == nil {
+		fake.listReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.listReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) Patch(arg1 context.Context, arg2 client.Object, arg3 client.Patch, arg4 ...client.PatchOption) error {
+	fake.patchMutex.Lock()
+	ret, specificReturn := fake.patchReturnsOnCall[len(fake.patchArgsForCall)]
+	fake.patchArgsForCall = append(fake.patchArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 client.Patch
+		arg4 []client.PatchOption
+	}{arg1, arg2, arg3, arg4})
+	stub := fake.PatchStub
+	fakeReturns := fake.patchReturns
+	fake.recordInvocation("Patch", []interface{}{arg1, arg2, arg3, arg4})
+	fake.patchMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) PatchCallCount() int {
+	fake.patchMutex.RLock()
+	defer fake.patchMutex.RUnlock()
+	return len(fake.patchArgsForCall)
+}
+
+func (fake *Client) PatchCalls(stub func(context.Context, client.Object, client.Patch, ...client.PatchOption) error) {
+	fake.patchMutex.Lock()
+	defer fake.patchMutex.Unlock()
+	fake.PatchStub = stub
+}
+
+func (fake *Client) PatchArgsForCall(i int) (context.Context, client.Object, client.Patch, []client.PatchOption) {
+	fake.patchMutex.RLock()
+	defer fake.patchMutex.RUnlock()
+	argsForCall := fake.patchArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
+}
+
+func (fake *Client) PatchReturns(result1 error) {
+	fake.patchMutex.Lock()
+	defer fake.patchMutex.Unlock()
+	fake.PatchStub = nil
+	fake.patchReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) PatchReturnsOnCall(i int, result1 error) {
+	fake.patchMutex.Lock()
+	defer fake.patchMutex.Unlock()
+	fake.PatchStub = nil
+	if fake.patchReturnsOnCall == nil {
+		fake.patchReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.patchReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) RESTMapper() meta.RESTMapper {
+	fake.rESTMapperMutex.Lock()
+	ret, specificReturn := fake.rESTMapperReturnsOnCall[len(fake.rESTMapperArgsForCall)]
+	fake.rESTMapperArgsForCall = append(fake.rESTMapperArgsForCall, struct {
+	}{})
+	stub := fake.RESTMapperStub
+	fakeReturns := fake.rESTMapperReturns
+	fake.recordInvocation("RESTMapper", []interface{}{})
+	fake.rESTMapperMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) RESTMapperCallCount() int {
+	fake.rESTMapperMutex.RLock()
+	defer fake.rESTMapperMutex.RUnlock()
+	return len(fake.rESTMapperArgsForCall)
+}
+
+func (fake *Client) RESTMapperCalls(stub func() meta.RESTMapper) {
+	fake.rESTMapperMutex.Lock()
+	defer fake.rESTMapperMutex.Unlock()
+	fake.RESTMapperStub = stub
+}
+
+func (fake *Client) RESTMapperReturns(result1 meta.RESTMapper) {
+	fake.rESTMapperMutex.Lock()
+	defer fake.rESTMapperMutex.Unlock()
+	fake.RESTMapperStub = nil
+	fake.rESTMapperReturns = struct {
+		result1 meta.RESTMapper
+	}{result1}
+}
+
+func (fake *Client) RESTMapperReturnsOnCall(i int, result1 meta.RESTMapper) {
+	fake.rESTMapperMutex.Lock()
+	defer fake.rESTMapperMutex.Unlock()
+	fake.RESTMapperStub = nil
+	if fake.rESTMapperReturnsOnCall == nil {
+		fake.rESTMapperReturnsOnCall = make(map[int]struct {
+			result1 meta.RESTMapper
+		})
+	}
+	fake.rESTMapperReturnsOnCall[i] = struct {
+		result1 meta.RESTMapper
+	}{result1}
+}
+
+func (fake *Client) Scheme() *runtime.Scheme {
+	fake.schemeMutex.Lock()
+	ret, specificReturn := fake.schemeReturnsOnCall[len(fake.schemeArgsForCall)]
+	fake.schemeArgsForCall = append(fake.schemeArgsForCall, struct {
+	}{})
+	stub := fake.SchemeStub
+	fakeReturns := fake.schemeReturns
+	fake.recordInvocation("Scheme", []interface{}{})
+	fake.schemeMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) SchemeCallCount() int {
+	fake.schemeMutex.RLock()
+	defer fake.schemeMutex.RUnlock()
+	return len(fake.schemeArgsForCall)
+}
+
+func (fake *Client) SchemeCalls(stub func() *runtime.Scheme) {
+	fake.schemeMutex.Lock()
+	defer fake.schemeMutex.Unlock()
+	fake.SchemeStub = stub
+}
+
+func (fake *Client) SchemeReturns(result1 *runtime.Scheme) {
+	fake.schemeMutex.Lock()
+	defer fake.schemeMutex.Unlock()
+	fake.SchemeStub = nil
+	fake.schemeReturns = struct {
+		result1 *runtime.Scheme
+	}{result1}
+}
+
+func (fake *Client) SchemeReturnsOnCall(i int, result1 *runtime.Scheme) {
+	fake.schemeMutex.Lock()
+	defer fake.schemeMutex.Unlock()
+	fake.SchemeStub = nil
+	if fake.schemeReturnsOnCall == nil {
+		fake.schemeReturnsOnCall = make(map[int]struct {
+			result1 *runtime.Scheme
+		})
+	}
+	fake.schemeReturnsOnCall[i] = struct {
+		result1 *runtime.Scheme
+	}{result1}
+}
+
+func (fake *Client) Status() client.StatusWriter {
+	fake.statusMutex.Lock()
+	ret, specificReturn := fake.statusReturnsOnCall[len(fake.statusArgsForCall)]
+	fake.statusArgsForCall = append(fake.statusArgsForCall, struct {
+	}{})
+	stub := fake.StatusStub
+	fakeReturns := fake.statusReturns
+	fake.recordInvocation("Status", []interface{}{})
+	fake.statusMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) StatusCallCount() int {
+	fake.statusMutex.RLock()
+	defer fake.statusMutex.RUnlock()
+	return len(fake.statusArgsForCall)
+}
+
+func (fake *Client) StatusCalls(stub func() client.StatusWriter) {
+	fake.statusMutex.Lock()
+	defer fake.statusMutex.Unlock()
+	fake.StatusStub = stub
+}
+
+func (fake *Client) StatusReturns(result1 client.StatusWriter) {
+	fake.statusMutex.Lock()
+	defer fake.statusMutex.Unlock()
+	fake.StatusStub = nil
+	fake.statusReturns = struct {
+		result1 client.StatusWriter
+	}{result1}
+}
+
+func (fake *Client) StatusReturnsOnCall(i int, result1 client.StatusWriter) {
+	fake.statusMutex.Lock()
+	defer fake.statusMutex.Unlock()
+	fake.StatusStub = nil
+	if fake.statusReturnsOnCall == nil {
+		fake.statusReturnsOnCall = make(map[int]struct {
+			result1 client.StatusWriter
+		})
+	}
+	fake.statusReturnsOnCall[i] = struct {
+		result1 client.StatusWriter
+	}{result1}
+}
+
+func (fake *Client) Update(arg1 context.Context, arg2 client.Object, arg3 ...client.UpdateOption) error {
+	fake.updateMutex.Lock()
+	ret, specificReturn := fake.updateReturnsOnCall[len(fake.updateArgsForCall)]
+	fake.updateArgsForCall = append(fake.updateArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.UpdateOption
+	}{arg1, arg2, arg3})
+	stub := fake.UpdateStub
+	fakeReturns := fake.updateReturns
+	fake.recordInvocation("Update", []interface{}{arg1, arg2, arg3})
+	fake.updateMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Client) UpdateCallCount() int {
+	fake.updateMutex.RLock()
+	defer fake.updateMutex.RUnlock()
+	return len(fake.updateArgsForCall)
+}
+
+func (fake *Client) UpdateCalls(stub func(context.Context, client.Object, ...client.UpdateOption) error) {
+	fake.updateMutex.Lock()
+	defer fake.updateMutex.Unlock()
+	fake.UpdateStub = stub
+}
+
+func (fake *Client) UpdateArgsForCall(i int) (context.Context, client.Object, []client.UpdateOption) {
+	fake.updateMutex.RLock()
+	defer fake.updateMutex.RUnlock()
+	argsForCall := fake.updateArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Client) UpdateReturns(result1 error) {
+	fake.updateMutex.Lock()
+	defer fake.updateMutex.Unlock()
+	fake.UpdateStub = nil
+	fake.updateReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) UpdateReturnsOnCall(i int, result1 error) {
+	fake.updateMutex.Lock()
+	defer fake.updateMutex.Unlock()
+	fake.UpdateStub = nil
+	if fake.updateReturnsOnCall == nil {
+		fake.updateReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.updateReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Client) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.createMutex.RLock()
+	defer fake.createMutex.RUnlock()
+	fake.deleteMutex.RLock()
+	defer fake.deleteMutex.RUnlock()
+	fake.deleteAllOfMutex.RLock()
+	defer fake.deleteAllOfMutex.RUnlock()
+	fake.getMutex.RLock()
+	defer fake.getMutex.RUnlock()
+	fake.listMutex.RLock()
+	defer fake.listMutex.RUnlock()
+	fake.patchMutex.RLock()
+	defer fake.patchMutex.RUnlock()
+	fake.rESTMapperMutex.RLock()
+	defer fake.rESTMapperMutex.RUnlock()
+	fake.schemeMutex.RLock()
+	defer fake.schemeMutex.RUnlock()
+	fake.statusMutex.RLock()
+	defer fake.statusMutex.RUnlock()
+	fake.updateMutex.RLock()
+	defer fake.updateMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Client) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ client.Client = new(Client)

+ 1288 - 0
pkg/controllers/secretsink/internal/fakes/manager.go

@@ -0,0 +1,1288 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package fakes
+
+import (
+	"context"
+	"net/http"
+	"sync"
+
+	"github.com/go-logr/logr"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/record"
+	"sigs.k8s.io/controller-runtime/pkg/cache"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+	"sigs.k8s.io/controller-runtime/pkg/healthz"
+	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+type Manager struct {
+	AddStub        func(manager.Runnable) error
+	addMutex       sync.RWMutex
+	addArgsForCall []struct {
+		arg1 manager.Runnable
+	}
+	addReturns struct {
+		result1 error
+	}
+	addReturnsOnCall map[int]struct {
+		result1 error
+	}
+	AddHealthzCheckStub        func(string, healthz.Checker) error
+	addHealthzCheckMutex       sync.RWMutex
+	addHealthzCheckArgsForCall []struct {
+		arg1 string
+		arg2 healthz.Checker
+	}
+	addHealthzCheckReturns struct {
+		result1 error
+	}
+	addHealthzCheckReturnsOnCall map[int]struct {
+		result1 error
+	}
+	AddMetricsExtraHandlerStub        func(string, http.Handler) error
+	addMetricsExtraHandlerMutex       sync.RWMutex
+	addMetricsExtraHandlerArgsForCall []struct {
+		arg1 string
+		arg2 http.Handler
+	}
+	addMetricsExtraHandlerReturns struct {
+		result1 error
+	}
+	addMetricsExtraHandlerReturnsOnCall map[int]struct {
+		result1 error
+	}
+	AddReadyzCheckStub        func(string, healthz.Checker) error
+	addReadyzCheckMutex       sync.RWMutex
+	addReadyzCheckArgsForCall []struct {
+		arg1 string
+		arg2 healthz.Checker
+	}
+	addReadyzCheckReturns struct {
+		result1 error
+	}
+	addReadyzCheckReturnsOnCall map[int]struct {
+		result1 error
+	}
+	ElectedStub        func() <-chan struct{}
+	electedMutex       sync.RWMutex
+	electedArgsForCall []struct {
+	}
+	electedReturns struct {
+		result1 <-chan struct{}
+	}
+	electedReturnsOnCall map[int]struct {
+		result1 <-chan struct{}
+	}
+	GetAPIReaderStub        func() client.Reader
+	getAPIReaderMutex       sync.RWMutex
+	getAPIReaderArgsForCall []struct {
+	}
+	getAPIReaderReturns struct {
+		result1 client.Reader
+	}
+	getAPIReaderReturnsOnCall map[int]struct {
+		result1 client.Reader
+	}
+	GetCacheStub        func() cache.Cache
+	getCacheMutex       sync.RWMutex
+	getCacheArgsForCall []struct {
+	}
+	getCacheReturns struct {
+		result1 cache.Cache
+	}
+	getCacheReturnsOnCall map[int]struct {
+		result1 cache.Cache
+	}
+	GetClientStub        func() client.Client
+	getClientMutex       sync.RWMutex
+	getClientArgsForCall []struct {
+	}
+	getClientReturns struct {
+		result1 client.Client
+	}
+	getClientReturnsOnCall map[int]struct {
+		result1 client.Client
+	}
+	GetConfigStub        func() *rest.Config
+	getConfigMutex       sync.RWMutex
+	getConfigArgsForCall []struct {
+	}
+	getConfigReturns struct {
+		result1 *rest.Config
+	}
+	getConfigReturnsOnCall map[int]struct {
+		result1 *rest.Config
+	}
+	GetControllerOptionsStub        func() v1alpha1.ControllerConfigurationSpec
+	getControllerOptionsMutex       sync.RWMutex
+	getControllerOptionsArgsForCall []struct {
+	}
+	getControllerOptionsReturns struct {
+		result1 v1alpha1.ControllerConfigurationSpec
+	}
+	getControllerOptionsReturnsOnCall map[int]struct {
+		result1 v1alpha1.ControllerConfigurationSpec
+	}
+	GetEventRecorderForStub        func(string) record.EventRecorder
+	getEventRecorderForMutex       sync.RWMutex
+	getEventRecorderForArgsForCall []struct {
+		arg1 string
+	}
+	getEventRecorderForReturns struct {
+		result1 record.EventRecorder
+	}
+	getEventRecorderForReturnsOnCall map[int]struct {
+		result1 record.EventRecorder
+	}
+	GetFieldIndexerStub        func() client.FieldIndexer
+	getFieldIndexerMutex       sync.RWMutex
+	getFieldIndexerArgsForCall []struct {
+	}
+	getFieldIndexerReturns struct {
+		result1 client.FieldIndexer
+	}
+	getFieldIndexerReturnsOnCall map[int]struct {
+		result1 client.FieldIndexer
+	}
+	GetLoggerStub        func() logr.Logger
+	getLoggerMutex       sync.RWMutex
+	getLoggerArgsForCall []struct {
+	}
+	getLoggerReturns struct {
+		result1 logr.Logger
+	}
+	getLoggerReturnsOnCall map[int]struct {
+		result1 logr.Logger
+	}
+	GetRESTMapperStub        func() meta.RESTMapper
+	getRESTMapperMutex       sync.RWMutex
+	getRESTMapperArgsForCall []struct {
+	}
+	getRESTMapperReturns struct {
+		result1 meta.RESTMapper
+	}
+	getRESTMapperReturnsOnCall map[int]struct {
+		result1 meta.RESTMapper
+	}
+	GetSchemeStub        func() *runtime.Scheme
+	getSchemeMutex       sync.RWMutex
+	getSchemeArgsForCall []struct {
+	}
+	getSchemeReturns struct {
+		result1 *runtime.Scheme
+	}
+	getSchemeReturnsOnCall map[int]struct {
+		result1 *runtime.Scheme
+	}
+	GetWebhookServerStub        func() *webhook.Server
+	getWebhookServerMutex       sync.RWMutex
+	getWebhookServerArgsForCall []struct {
+	}
+	getWebhookServerReturns struct {
+		result1 *webhook.Server
+	}
+	getWebhookServerReturnsOnCall map[int]struct {
+		result1 *webhook.Server
+	}
+	SetFieldsStub        func(interface{}) error
+	setFieldsMutex       sync.RWMutex
+	setFieldsArgsForCall []struct {
+		arg1 interface{}
+	}
+	setFieldsReturns struct {
+		result1 error
+	}
+	setFieldsReturnsOnCall map[int]struct {
+		result1 error
+	}
+	StartStub        func(context.Context) error
+	startMutex       sync.RWMutex
+	startArgsForCall []struct {
+		arg1 context.Context
+	}
+	startReturns struct {
+		result1 error
+	}
+	startReturnsOnCall map[int]struct {
+		result1 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Manager) Add(arg1 manager.Runnable) error {
+	fake.addMutex.Lock()
+	ret, specificReturn := fake.addReturnsOnCall[len(fake.addArgsForCall)]
+	fake.addArgsForCall = append(fake.addArgsForCall, struct {
+		arg1 manager.Runnable
+	}{arg1})
+	stub := fake.AddStub
+	fakeReturns := fake.addReturns
+	fake.recordInvocation("Add", []interface{}{arg1})
+	fake.addMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) AddCallCount() int {
+	fake.addMutex.RLock()
+	defer fake.addMutex.RUnlock()
+	return len(fake.addArgsForCall)
+}
+
+func (fake *Manager) AddCalls(stub func(manager.Runnable) error) {
+	fake.addMutex.Lock()
+	defer fake.addMutex.Unlock()
+	fake.AddStub = stub
+}
+
+func (fake *Manager) AddArgsForCall(i int) manager.Runnable {
+	fake.addMutex.RLock()
+	defer fake.addMutex.RUnlock()
+	argsForCall := fake.addArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Manager) AddReturns(result1 error) {
+	fake.addMutex.Lock()
+	defer fake.addMutex.Unlock()
+	fake.AddStub = nil
+	fake.addReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddReturnsOnCall(i int, result1 error) {
+	fake.addMutex.Lock()
+	defer fake.addMutex.Unlock()
+	fake.AddStub = nil
+	if fake.addReturnsOnCall == nil {
+		fake.addReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.addReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddHealthzCheck(arg1 string, arg2 healthz.Checker) error {
+	fake.addHealthzCheckMutex.Lock()
+	ret, specificReturn := fake.addHealthzCheckReturnsOnCall[len(fake.addHealthzCheckArgsForCall)]
+	fake.addHealthzCheckArgsForCall = append(fake.addHealthzCheckArgsForCall, struct {
+		arg1 string
+		arg2 healthz.Checker
+	}{arg1, arg2})
+	stub := fake.AddHealthzCheckStub
+	fakeReturns := fake.addHealthzCheckReturns
+	fake.recordInvocation("AddHealthzCheck", []interface{}{arg1, arg2})
+	fake.addHealthzCheckMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) AddHealthzCheckCallCount() int {
+	fake.addHealthzCheckMutex.RLock()
+	defer fake.addHealthzCheckMutex.RUnlock()
+	return len(fake.addHealthzCheckArgsForCall)
+}
+
+func (fake *Manager) AddHealthzCheckCalls(stub func(string, healthz.Checker) error) {
+	fake.addHealthzCheckMutex.Lock()
+	defer fake.addHealthzCheckMutex.Unlock()
+	fake.AddHealthzCheckStub = stub
+}
+
+func (fake *Manager) AddHealthzCheckArgsForCall(i int) (string, healthz.Checker) {
+	fake.addHealthzCheckMutex.RLock()
+	defer fake.addHealthzCheckMutex.RUnlock()
+	argsForCall := fake.addHealthzCheckArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Manager) AddHealthzCheckReturns(result1 error) {
+	fake.addHealthzCheckMutex.Lock()
+	defer fake.addHealthzCheckMutex.Unlock()
+	fake.AddHealthzCheckStub = nil
+	fake.addHealthzCheckReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddHealthzCheckReturnsOnCall(i int, result1 error) {
+	fake.addHealthzCheckMutex.Lock()
+	defer fake.addHealthzCheckMutex.Unlock()
+	fake.AddHealthzCheckStub = nil
+	if fake.addHealthzCheckReturnsOnCall == nil {
+		fake.addHealthzCheckReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.addHealthzCheckReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddMetricsExtraHandler(arg1 string, arg2 http.Handler) error {
+	fake.addMetricsExtraHandlerMutex.Lock()
+	ret, specificReturn := fake.addMetricsExtraHandlerReturnsOnCall[len(fake.addMetricsExtraHandlerArgsForCall)]
+	fake.addMetricsExtraHandlerArgsForCall = append(fake.addMetricsExtraHandlerArgsForCall, struct {
+		arg1 string
+		arg2 http.Handler
+	}{arg1, arg2})
+	stub := fake.AddMetricsExtraHandlerStub
+	fakeReturns := fake.addMetricsExtraHandlerReturns
+	fake.recordInvocation("AddMetricsExtraHandler", []interface{}{arg1, arg2})
+	fake.addMetricsExtraHandlerMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) AddMetricsExtraHandlerCallCount() int {
+	fake.addMetricsExtraHandlerMutex.RLock()
+	defer fake.addMetricsExtraHandlerMutex.RUnlock()
+	return len(fake.addMetricsExtraHandlerArgsForCall)
+}
+
+func (fake *Manager) AddMetricsExtraHandlerCalls(stub func(string, http.Handler) error) {
+	fake.addMetricsExtraHandlerMutex.Lock()
+	defer fake.addMetricsExtraHandlerMutex.Unlock()
+	fake.AddMetricsExtraHandlerStub = stub
+}
+
+func (fake *Manager) AddMetricsExtraHandlerArgsForCall(i int) (string, http.Handler) {
+	fake.addMetricsExtraHandlerMutex.RLock()
+	defer fake.addMetricsExtraHandlerMutex.RUnlock()
+	argsForCall := fake.addMetricsExtraHandlerArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Manager) AddMetricsExtraHandlerReturns(result1 error) {
+	fake.addMetricsExtraHandlerMutex.Lock()
+	defer fake.addMetricsExtraHandlerMutex.Unlock()
+	fake.AddMetricsExtraHandlerStub = nil
+	fake.addMetricsExtraHandlerReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddMetricsExtraHandlerReturnsOnCall(i int, result1 error) {
+	fake.addMetricsExtraHandlerMutex.Lock()
+	defer fake.addMetricsExtraHandlerMutex.Unlock()
+	fake.AddMetricsExtraHandlerStub = nil
+	if fake.addMetricsExtraHandlerReturnsOnCall == nil {
+		fake.addMetricsExtraHandlerReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.addMetricsExtraHandlerReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddReadyzCheck(arg1 string, arg2 healthz.Checker) error {
+	fake.addReadyzCheckMutex.Lock()
+	ret, specificReturn := fake.addReadyzCheckReturnsOnCall[len(fake.addReadyzCheckArgsForCall)]
+	fake.addReadyzCheckArgsForCall = append(fake.addReadyzCheckArgsForCall, struct {
+		arg1 string
+		arg2 healthz.Checker
+	}{arg1, arg2})
+	stub := fake.AddReadyzCheckStub
+	fakeReturns := fake.addReadyzCheckReturns
+	fake.recordInvocation("AddReadyzCheck", []interface{}{arg1, arg2})
+	fake.addReadyzCheckMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) AddReadyzCheckCallCount() int {
+	fake.addReadyzCheckMutex.RLock()
+	defer fake.addReadyzCheckMutex.RUnlock()
+	return len(fake.addReadyzCheckArgsForCall)
+}
+
+func (fake *Manager) AddReadyzCheckCalls(stub func(string, healthz.Checker) error) {
+	fake.addReadyzCheckMutex.Lock()
+	defer fake.addReadyzCheckMutex.Unlock()
+	fake.AddReadyzCheckStub = stub
+}
+
+func (fake *Manager) AddReadyzCheckArgsForCall(i int) (string, healthz.Checker) {
+	fake.addReadyzCheckMutex.RLock()
+	defer fake.addReadyzCheckMutex.RUnlock()
+	argsForCall := fake.addReadyzCheckArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Manager) AddReadyzCheckReturns(result1 error) {
+	fake.addReadyzCheckMutex.Lock()
+	defer fake.addReadyzCheckMutex.Unlock()
+	fake.AddReadyzCheckStub = nil
+	fake.addReadyzCheckReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) AddReadyzCheckReturnsOnCall(i int, result1 error) {
+	fake.addReadyzCheckMutex.Lock()
+	defer fake.addReadyzCheckMutex.Unlock()
+	fake.AddReadyzCheckStub = nil
+	if fake.addReadyzCheckReturnsOnCall == nil {
+		fake.addReadyzCheckReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.addReadyzCheckReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) Elected() <-chan struct{} {
+	fake.electedMutex.Lock()
+	ret, specificReturn := fake.electedReturnsOnCall[len(fake.electedArgsForCall)]
+	fake.electedArgsForCall = append(fake.electedArgsForCall, struct {
+	}{})
+	stub := fake.ElectedStub
+	fakeReturns := fake.electedReturns
+	fake.recordInvocation("Elected", []interface{}{})
+	fake.electedMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) ElectedCallCount() int {
+	fake.electedMutex.RLock()
+	defer fake.electedMutex.RUnlock()
+	return len(fake.electedArgsForCall)
+}
+
+func (fake *Manager) ElectedCalls(stub func() <-chan struct{}) {
+	fake.electedMutex.Lock()
+	defer fake.electedMutex.Unlock()
+	fake.ElectedStub = stub
+}
+
+func (fake *Manager) ElectedReturns(result1 <-chan struct{}) {
+	fake.electedMutex.Lock()
+	defer fake.electedMutex.Unlock()
+	fake.ElectedStub = nil
+	fake.electedReturns = struct {
+		result1 <-chan struct{}
+	}{result1}
+}
+
+func (fake *Manager) ElectedReturnsOnCall(i int, result1 <-chan struct{}) {
+	fake.electedMutex.Lock()
+	defer fake.electedMutex.Unlock()
+	fake.ElectedStub = nil
+	if fake.electedReturnsOnCall == nil {
+		fake.electedReturnsOnCall = make(map[int]struct {
+			result1 <-chan struct{}
+		})
+	}
+	fake.electedReturnsOnCall[i] = struct {
+		result1 <-chan struct{}
+	}{result1}
+}
+
+func (fake *Manager) GetAPIReader() client.Reader {
+	fake.getAPIReaderMutex.Lock()
+	ret, specificReturn := fake.getAPIReaderReturnsOnCall[len(fake.getAPIReaderArgsForCall)]
+	fake.getAPIReaderArgsForCall = append(fake.getAPIReaderArgsForCall, struct {
+	}{})
+	stub := fake.GetAPIReaderStub
+	fakeReturns := fake.getAPIReaderReturns
+	fake.recordInvocation("GetAPIReader", []interface{}{})
+	fake.getAPIReaderMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetAPIReaderCallCount() int {
+	fake.getAPIReaderMutex.RLock()
+	defer fake.getAPIReaderMutex.RUnlock()
+	return len(fake.getAPIReaderArgsForCall)
+}
+
+func (fake *Manager) GetAPIReaderCalls(stub func() client.Reader) {
+	fake.getAPIReaderMutex.Lock()
+	defer fake.getAPIReaderMutex.Unlock()
+	fake.GetAPIReaderStub = stub
+}
+
+func (fake *Manager) GetAPIReaderReturns(result1 client.Reader) {
+	fake.getAPIReaderMutex.Lock()
+	defer fake.getAPIReaderMutex.Unlock()
+	fake.GetAPIReaderStub = nil
+	fake.getAPIReaderReturns = struct {
+		result1 client.Reader
+	}{result1}
+}
+
+func (fake *Manager) GetAPIReaderReturnsOnCall(i int, result1 client.Reader) {
+	fake.getAPIReaderMutex.Lock()
+	defer fake.getAPIReaderMutex.Unlock()
+	fake.GetAPIReaderStub = nil
+	if fake.getAPIReaderReturnsOnCall == nil {
+		fake.getAPIReaderReturnsOnCall = make(map[int]struct {
+			result1 client.Reader
+		})
+	}
+	fake.getAPIReaderReturnsOnCall[i] = struct {
+		result1 client.Reader
+	}{result1}
+}
+
+func (fake *Manager) GetCache() cache.Cache {
+	fake.getCacheMutex.Lock()
+	ret, specificReturn := fake.getCacheReturnsOnCall[len(fake.getCacheArgsForCall)]
+	fake.getCacheArgsForCall = append(fake.getCacheArgsForCall, struct {
+	}{})
+	stub := fake.GetCacheStub
+	fakeReturns := fake.getCacheReturns
+	fake.recordInvocation("GetCache", []interface{}{})
+	fake.getCacheMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetCacheCallCount() int {
+	fake.getCacheMutex.RLock()
+	defer fake.getCacheMutex.RUnlock()
+	return len(fake.getCacheArgsForCall)
+}
+
+func (fake *Manager) GetCacheCalls(stub func() cache.Cache) {
+	fake.getCacheMutex.Lock()
+	defer fake.getCacheMutex.Unlock()
+	fake.GetCacheStub = stub
+}
+
+func (fake *Manager) GetCacheReturns(result1 cache.Cache) {
+	fake.getCacheMutex.Lock()
+	defer fake.getCacheMutex.Unlock()
+	fake.GetCacheStub = nil
+	fake.getCacheReturns = struct {
+		result1 cache.Cache
+	}{result1}
+}
+
+func (fake *Manager) GetCacheReturnsOnCall(i int, result1 cache.Cache) {
+	fake.getCacheMutex.Lock()
+	defer fake.getCacheMutex.Unlock()
+	fake.GetCacheStub = nil
+	if fake.getCacheReturnsOnCall == nil {
+		fake.getCacheReturnsOnCall = make(map[int]struct {
+			result1 cache.Cache
+		})
+	}
+	fake.getCacheReturnsOnCall[i] = struct {
+		result1 cache.Cache
+	}{result1}
+}
+
+func (fake *Manager) GetClient() client.Client {
+	fake.getClientMutex.Lock()
+	ret, specificReturn := fake.getClientReturnsOnCall[len(fake.getClientArgsForCall)]
+	fake.getClientArgsForCall = append(fake.getClientArgsForCall, struct {
+	}{})
+	stub := fake.GetClientStub
+	fakeReturns := fake.getClientReturns
+	fake.recordInvocation("GetClient", []interface{}{})
+	fake.getClientMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetClientCallCount() int {
+	fake.getClientMutex.RLock()
+	defer fake.getClientMutex.RUnlock()
+	return len(fake.getClientArgsForCall)
+}
+
+func (fake *Manager) GetClientCalls(stub func() client.Client) {
+	fake.getClientMutex.Lock()
+	defer fake.getClientMutex.Unlock()
+	fake.GetClientStub = stub
+}
+
+func (fake *Manager) GetClientReturns(result1 client.Client) {
+	fake.getClientMutex.Lock()
+	defer fake.getClientMutex.Unlock()
+	fake.GetClientStub = nil
+	fake.getClientReturns = struct {
+		result1 client.Client
+	}{result1}
+}
+
+func (fake *Manager) GetClientReturnsOnCall(i int, result1 client.Client) {
+	fake.getClientMutex.Lock()
+	defer fake.getClientMutex.Unlock()
+	fake.GetClientStub = nil
+	if fake.getClientReturnsOnCall == nil {
+		fake.getClientReturnsOnCall = make(map[int]struct {
+			result1 client.Client
+		})
+	}
+	fake.getClientReturnsOnCall[i] = struct {
+		result1 client.Client
+	}{result1}
+}
+
+func (fake *Manager) GetConfig() *rest.Config {
+	fake.getConfigMutex.Lock()
+	ret, specificReturn := fake.getConfigReturnsOnCall[len(fake.getConfigArgsForCall)]
+	fake.getConfigArgsForCall = append(fake.getConfigArgsForCall, struct {
+	}{})
+	stub := fake.GetConfigStub
+	fakeReturns := fake.getConfigReturns
+	fake.recordInvocation("GetConfig", []interface{}{})
+	fake.getConfigMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetConfigCallCount() int {
+	fake.getConfigMutex.RLock()
+	defer fake.getConfigMutex.RUnlock()
+	return len(fake.getConfigArgsForCall)
+}
+
+func (fake *Manager) GetConfigCalls(stub func() *rest.Config) {
+	fake.getConfigMutex.Lock()
+	defer fake.getConfigMutex.Unlock()
+	fake.GetConfigStub = stub
+}
+
+func (fake *Manager) GetConfigReturns(result1 *rest.Config) {
+	fake.getConfigMutex.Lock()
+	defer fake.getConfigMutex.Unlock()
+	fake.GetConfigStub = nil
+	fake.getConfigReturns = struct {
+		result1 *rest.Config
+	}{result1}
+}
+
+func (fake *Manager) GetConfigReturnsOnCall(i int, result1 *rest.Config) {
+	fake.getConfigMutex.Lock()
+	defer fake.getConfigMutex.Unlock()
+	fake.GetConfigStub = nil
+	if fake.getConfigReturnsOnCall == nil {
+		fake.getConfigReturnsOnCall = make(map[int]struct {
+			result1 *rest.Config
+		})
+	}
+	fake.getConfigReturnsOnCall[i] = struct {
+		result1 *rest.Config
+	}{result1}
+}
+
+func (fake *Manager) GetControllerOptions() v1alpha1.ControllerConfigurationSpec {
+	fake.getControllerOptionsMutex.Lock()
+	ret, specificReturn := fake.getControllerOptionsReturnsOnCall[len(fake.getControllerOptionsArgsForCall)]
+	fake.getControllerOptionsArgsForCall = append(fake.getControllerOptionsArgsForCall, struct {
+	}{})
+	stub := fake.GetControllerOptionsStub
+	fakeReturns := fake.getControllerOptionsReturns
+	fake.recordInvocation("GetControllerOptions", []interface{}{})
+	fake.getControllerOptionsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetControllerOptionsCallCount() int {
+	fake.getControllerOptionsMutex.RLock()
+	defer fake.getControllerOptionsMutex.RUnlock()
+	return len(fake.getControllerOptionsArgsForCall)
+}
+
+func (fake *Manager) GetControllerOptionsCalls(stub func() v1alpha1.ControllerConfigurationSpec) {
+	fake.getControllerOptionsMutex.Lock()
+	defer fake.getControllerOptionsMutex.Unlock()
+	fake.GetControllerOptionsStub = stub
+}
+
+func (fake *Manager) GetControllerOptionsReturns(result1 v1alpha1.ControllerConfigurationSpec) {
+	fake.getControllerOptionsMutex.Lock()
+	defer fake.getControllerOptionsMutex.Unlock()
+	fake.GetControllerOptionsStub = nil
+	fake.getControllerOptionsReturns = struct {
+		result1 v1alpha1.ControllerConfigurationSpec
+	}{result1}
+}
+
+func (fake *Manager) GetControllerOptionsReturnsOnCall(i int, result1 v1alpha1.ControllerConfigurationSpec) {
+	fake.getControllerOptionsMutex.Lock()
+	defer fake.getControllerOptionsMutex.Unlock()
+	fake.GetControllerOptionsStub = nil
+	if fake.getControllerOptionsReturnsOnCall == nil {
+		fake.getControllerOptionsReturnsOnCall = make(map[int]struct {
+			result1 v1alpha1.ControllerConfigurationSpec
+		})
+	}
+	fake.getControllerOptionsReturnsOnCall[i] = struct {
+		result1 v1alpha1.ControllerConfigurationSpec
+	}{result1}
+}
+
+func (fake *Manager) GetEventRecorderFor(arg1 string) record.EventRecorder {
+	fake.getEventRecorderForMutex.Lock()
+	ret, specificReturn := fake.getEventRecorderForReturnsOnCall[len(fake.getEventRecorderForArgsForCall)]
+	fake.getEventRecorderForArgsForCall = append(fake.getEventRecorderForArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.GetEventRecorderForStub
+	fakeReturns := fake.getEventRecorderForReturns
+	fake.recordInvocation("GetEventRecorderFor", []interface{}{arg1})
+	fake.getEventRecorderForMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetEventRecorderForCallCount() int {
+	fake.getEventRecorderForMutex.RLock()
+	defer fake.getEventRecorderForMutex.RUnlock()
+	return len(fake.getEventRecorderForArgsForCall)
+}
+
+func (fake *Manager) GetEventRecorderForCalls(stub func(string) record.EventRecorder) {
+	fake.getEventRecorderForMutex.Lock()
+	defer fake.getEventRecorderForMutex.Unlock()
+	fake.GetEventRecorderForStub = stub
+}
+
+func (fake *Manager) GetEventRecorderForArgsForCall(i int) string {
+	fake.getEventRecorderForMutex.RLock()
+	defer fake.getEventRecorderForMutex.RUnlock()
+	argsForCall := fake.getEventRecorderForArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Manager) GetEventRecorderForReturns(result1 record.EventRecorder) {
+	fake.getEventRecorderForMutex.Lock()
+	defer fake.getEventRecorderForMutex.Unlock()
+	fake.GetEventRecorderForStub = nil
+	fake.getEventRecorderForReturns = struct {
+		result1 record.EventRecorder
+	}{result1}
+}
+
+func (fake *Manager) GetEventRecorderForReturnsOnCall(i int, result1 record.EventRecorder) {
+	fake.getEventRecorderForMutex.Lock()
+	defer fake.getEventRecorderForMutex.Unlock()
+	fake.GetEventRecorderForStub = nil
+	if fake.getEventRecorderForReturnsOnCall == nil {
+		fake.getEventRecorderForReturnsOnCall = make(map[int]struct {
+			result1 record.EventRecorder
+		})
+	}
+	fake.getEventRecorderForReturnsOnCall[i] = struct {
+		result1 record.EventRecorder
+	}{result1}
+}
+
+func (fake *Manager) GetFieldIndexer() client.FieldIndexer {
+	fake.getFieldIndexerMutex.Lock()
+	ret, specificReturn := fake.getFieldIndexerReturnsOnCall[len(fake.getFieldIndexerArgsForCall)]
+	fake.getFieldIndexerArgsForCall = append(fake.getFieldIndexerArgsForCall, struct {
+	}{})
+	stub := fake.GetFieldIndexerStub
+	fakeReturns := fake.getFieldIndexerReturns
+	fake.recordInvocation("GetFieldIndexer", []interface{}{})
+	fake.getFieldIndexerMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetFieldIndexerCallCount() int {
+	fake.getFieldIndexerMutex.RLock()
+	defer fake.getFieldIndexerMutex.RUnlock()
+	return len(fake.getFieldIndexerArgsForCall)
+}
+
+func (fake *Manager) GetFieldIndexerCalls(stub func() client.FieldIndexer) {
+	fake.getFieldIndexerMutex.Lock()
+	defer fake.getFieldIndexerMutex.Unlock()
+	fake.GetFieldIndexerStub = stub
+}
+
+func (fake *Manager) GetFieldIndexerReturns(result1 client.FieldIndexer) {
+	fake.getFieldIndexerMutex.Lock()
+	defer fake.getFieldIndexerMutex.Unlock()
+	fake.GetFieldIndexerStub = nil
+	fake.getFieldIndexerReturns = struct {
+		result1 client.FieldIndexer
+	}{result1}
+}
+
+func (fake *Manager) GetFieldIndexerReturnsOnCall(i int, result1 client.FieldIndexer) {
+	fake.getFieldIndexerMutex.Lock()
+	defer fake.getFieldIndexerMutex.Unlock()
+	fake.GetFieldIndexerStub = nil
+	if fake.getFieldIndexerReturnsOnCall == nil {
+		fake.getFieldIndexerReturnsOnCall = make(map[int]struct {
+			result1 client.FieldIndexer
+		})
+	}
+	fake.getFieldIndexerReturnsOnCall[i] = struct {
+		result1 client.FieldIndexer
+	}{result1}
+}
+
+func (fake *Manager) GetLogger() logr.Logger {
+	fake.getLoggerMutex.Lock()
+	ret, specificReturn := fake.getLoggerReturnsOnCall[len(fake.getLoggerArgsForCall)]
+	fake.getLoggerArgsForCall = append(fake.getLoggerArgsForCall, struct {
+	}{})
+	stub := fake.GetLoggerStub
+	fakeReturns := fake.getLoggerReturns
+	fake.recordInvocation("GetLogger", []interface{}{})
+	fake.getLoggerMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetLoggerCallCount() int {
+	fake.getLoggerMutex.RLock()
+	defer fake.getLoggerMutex.RUnlock()
+	return len(fake.getLoggerArgsForCall)
+}
+
+func (fake *Manager) GetLoggerCalls(stub func() logr.Logger) {
+	fake.getLoggerMutex.Lock()
+	defer fake.getLoggerMutex.Unlock()
+	fake.GetLoggerStub = stub
+}
+
+func (fake *Manager) GetLoggerReturns(result1 logr.Logger) {
+	fake.getLoggerMutex.Lock()
+	defer fake.getLoggerMutex.Unlock()
+	fake.GetLoggerStub = nil
+	fake.getLoggerReturns = struct {
+		result1 logr.Logger
+	}{result1}
+}
+
+func (fake *Manager) GetLoggerReturnsOnCall(i int, result1 logr.Logger) {
+	fake.getLoggerMutex.Lock()
+	defer fake.getLoggerMutex.Unlock()
+	fake.GetLoggerStub = nil
+	if fake.getLoggerReturnsOnCall == nil {
+		fake.getLoggerReturnsOnCall = make(map[int]struct {
+			result1 logr.Logger
+		})
+	}
+	fake.getLoggerReturnsOnCall[i] = struct {
+		result1 logr.Logger
+	}{result1}
+}
+
+func (fake *Manager) GetRESTMapper() meta.RESTMapper {
+	fake.getRESTMapperMutex.Lock()
+	ret, specificReturn := fake.getRESTMapperReturnsOnCall[len(fake.getRESTMapperArgsForCall)]
+	fake.getRESTMapperArgsForCall = append(fake.getRESTMapperArgsForCall, struct {
+	}{})
+	stub := fake.GetRESTMapperStub
+	fakeReturns := fake.getRESTMapperReturns
+	fake.recordInvocation("GetRESTMapper", []interface{}{})
+	fake.getRESTMapperMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetRESTMapperCallCount() int {
+	fake.getRESTMapperMutex.RLock()
+	defer fake.getRESTMapperMutex.RUnlock()
+	return len(fake.getRESTMapperArgsForCall)
+}
+
+func (fake *Manager) GetRESTMapperCalls(stub func() meta.RESTMapper) {
+	fake.getRESTMapperMutex.Lock()
+	defer fake.getRESTMapperMutex.Unlock()
+	fake.GetRESTMapperStub = stub
+}
+
+func (fake *Manager) GetRESTMapperReturns(result1 meta.RESTMapper) {
+	fake.getRESTMapperMutex.Lock()
+	defer fake.getRESTMapperMutex.Unlock()
+	fake.GetRESTMapperStub = nil
+	fake.getRESTMapperReturns = struct {
+		result1 meta.RESTMapper
+	}{result1}
+}
+
+func (fake *Manager) GetRESTMapperReturnsOnCall(i int, result1 meta.RESTMapper) {
+	fake.getRESTMapperMutex.Lock()
+	defer fake.getRESTMapperMutex.Unlock()
+	fake.GetRESTMapperStub = nil
+	if fake.getRESTMapperReturnsOnCall == nil {
+		fake.getRESTMapperReturnsOnCall = make(map[int]struct {
+			result1 meta.RESTMapper
+		})
+	}
+	fake.getRESTMapperReturnsOnCall[i] = struct {
+		result1 meta.RESTMapper
+	}{result1}
+}
+
+func (fake *Manager) GetScheme() *runtime.Scheme {
+	fake.getSchemeMutex.Lock()
+	ret, specificReturn := fake.getSchemeReturnsOnCall[len(fake.getSchemeArgsForCall)]
+	fake.getSchemeArgsForCall = append(fake.getSchemeArgsForCall, struct {
+	}{})
+	stub := fake.GetSchemeStub
+	fakeReturns := fake.getSchemeReturns
+	fake.recordInvocation("GetScheme", []interface{}{})
+	fake.getSchemeMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetSchemeCallCount() int {
+	fake.getSchemeMutex.RLock()
+	defer fake.getSchemeMutex.RUnlock()
+	return len(fake.getSchemeArgsForCall)
+}
+
+func (fake *Manager) GetSchemeCalls(stub func() *runtime.Scheme) {
+	fake.getSchemeMutex.Lock()
+	defer fake.getSchemeMutex.Unlock()
+	fake.GetSchemeStub = stub
+}
+
+func (fake *Manager) GetSchemeReturns(result1 *runtime.Scheme) {
+	fake.getSchemeMutex.Lock()
+	defer fake.getSchemeMutex.Unlock()
+	fake.GetSchemeStub = nil
+	fake.getSchemeReturns = struct {
+		result1 *runtime.Scheme
+	}{result1}
+}
+
+func (fake *Manager) GetSchemeReturnsOnCall(i int, result1 *runtime.Scheme) {
+	fake.getSchemeMutex.Lock()
+	defer fake.getSchemeMutex.Unlock()
+	fake.GetSchemeStub = nil
+	if fake.getSchemeReturnsOnCall == nil {
+		fake.getSchemeReturnsOnCall = make(map[int]struct {
+			result1 *runtime.Scheme
+		})
+	}
+	fake.getSchemeReturnsOnCall[i] = struct {
+		result1 *runtime.Scheme
+	}{result1}
+}
+
+func (fake *Manager) GetWebhookServer() *webhook.Server {
+	fake.getWebhookServerMutex.Lock()
+	ret, specificReturn := fake.getWebhookServerReturnsOnCall[len(fake.getWebhookServerArgsForCall)]
+	fake.getWebhookServerArgsForCall = append(fake.getWebhookServerArgsForCall, struct {
+	}{})
+	stub := fake.GetWebhookServerStub
+	fakeReturns := fake.getWebhookServerReturns
+	fake.recordInvocation("GetWebhookServer", []interface{}{})
+	fake.getWebhookServerMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) GetWebhookServerCallCount() int {
+	fake.getWebhookServerMutex.RLock()
+	defer fake.getWebhookServerMutex.RUnlock()
+	return len(fake.getWebhookServerArgsForCall)
+}
+
+func (fake *Manager) GetWebhookServerCalls(stub func() *webhook.Server) {
+	fake.getWebhookServerMutex.Lock()
+	defer fake.getWebhookServerMutex.Unlock()
+	fake.GetWebhookServerStub = stub
+}
+
+func (fake *Manager) GetWebhookServerReturns(result1 *webhook.Server) {
+	fake.getWebhookServerMutex.Lock()
+	defer fake.getWebhookServerMutex.Unlock()
+	fake.GetWebhookServerStub = nil
+	fake.getWebhookServerReturns = struct {
+		result1 *webhook.Server
+	}{result1}
+}
+
+func (fake *Manager) GetWebhookServerReturnsOnCall(i int, result1 *webhook.Server) {
+	fake.getWebhookServerMutex.Lock()
+	defer fake.getWebhookServerMutex.Unlock()
+	fake.GetWebhookServerStub = nil
+	if fake.getWebhookServerReturnsOnCall == nil {
+		fake.getWebhookServerReturnsOnCall = make(map[int]struct {
+			result1 *webhook.Server
+		})
+	}
+	fake.getWebhookServerReturnsOnCall[i] = struct {
+		result1 *webhook.Server
+	}{result1}
+}
+
+func (fake *Manager) SetFields(arg1 interface{}) error {
+	fake.setFieldsMutex.Lock()
+	ret, specificReturn := fake.setFieldsReturnsOnCall[len(fake.setFieldsArgsForCall)]
+	fake.setFieldsArgsForCall = append(fake.setFieldsArgsForCall, struct {
+		arg1 interface{}
+	}{arg1})
+	stub := fake.SetFieldsStub
+	fakeReturns := fake.setFieldsReturns
+	fake.recordInvocation("SetFields", []interface{}{arg1})
+	fake.setFieldsMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) SetFieldsCallCount() int {
+	fake.setFieldsMutex.RLock()
+	defer fake.setFieldsMutex.RUnlock()
+	return len(fake.setFieldsArgsForCall)
+}
+
+func (fake *Manager) SetFieldsCalls(stub func(interface{}) error) {
+	fake.setFieldsMutex.Lock()
+	defer fake.setFieldsMutex.Unlock()
+	fake.SetFieldsStub = stub
+}
+
+func (fake *Manager) SetFieldsArgsForCall(i int) interface{} {
+	fake.setFieldsMutex.RLock()
+	defer fake.setFieldsMutex.RUnlock()
+	argsForCall := fake.setFieldsArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Manager) SetFieldsReturns(result1 error) {
+	fake.setFieldsMutex.Lock()
+	defer fake.setFieldsMutex.Unlock()
+	fake.SetFieldsStub = nil
+	fake.setFieldsReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) SetFieldsReturnsOnCall(i int, result1 error) {
+	fake.setFieldsMutex.Lock()
+	defer fake.setFieldsMutex.Unlock()
+	fake.SetFieldsStub = nil
+	if fake.setFieldsReturnsOnCall == nil {
+		fake.setFieldsReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.setFieldsReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) Start(arg1 context.Context) error {
+	fake.startMutex.Lock()
+	ret, specificReturn := fake.startReturnsOnCall[len(fake.startArgsForCall)]
+	fake.startArgsForCall = append(fake.startArgsForCall, struct {
+		arg1 context.Context
+	}{arg1})
+	stub := fake.StartStub
+	fakeReturns := fake.startReturns
+	fake.recordInvocation("Start", []interface{}{arg1})
+	fake.startMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) StartCallCount() int {
+	fake.startMutex.RLock()
+	defer fake.startMutex.RUnlock()
+	return len(fake.startArgsForCall)
+}
+
+func (fake *Manager) StartCalls(stub func(context.Context) error) {
+	fake.startMutex.Lock()
+	defer fake.startMutex.Unlock()
+	fake.StartStub = stub
+}
+
+func (fake *Manager) StartArgsForCall(i int) context.Context {
+	fake.startMutex.RLock()
+	defer fake.startMutex.RUnlock()
+	argsForCall := fake.startArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Manager) StartReturns(result1 error) {
+	fake.startMutex.Lock()
+	defer fake.startMutex.Unlock()
+	fake.StartStub = nil
+	fake.startReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) StartReturnsOnCall(i int, result1 error) {
+	fake.startMutex.Lock()
+	defer fake.startMutex.Unlock()
+	fake.StartStub = nil
+	if fake.startReturnsOnCall == nil {
+		fake.startReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.startReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.addMutex.RLock()
+	defer fake.addMutex.RUnlock()
+	fake.addHealthzCheckMutex.RLock()
+	defer fake.addHealthzCheckMutex.RUnlock()
+	fake.addMetricsExtraHandlerMutex.RLock()
+	defer fake.addMetricsExtraHandlerMutex.RUnlock()
+	fake.addReadyzCheckMutex.RLock()
+	defer fake.addReadyzCheckMutex.RUnlock()
+	fake.electedMutex.RLock()
+	defer fake.electedMutex.RUnlock()
+	fake.getAPIReaderMutex.RLock()
+	defer fake.getAPIReaderMutex.RUnlock()
+	fake.getCacheMutex.RLock()
+	defer fake.getCacheMutex.RUnlock()
+	fake.getClientMutex.RLock()
+	defer fake.getClientMutex.RUnlock()
+	fake.getConfigMutex.RLock()
+	defer fake.getConfigMutex.RUnlock()
+	fake.getControllerOptionsMutex.RLock()
+	defer fake.getControllerOptionsMutex.RUnlock()
+	fake.getEventRecorderForMutex.RLock()
+	defer fake.getEventRecorderForMutex.RUnlock()
+	fake.getFieldIndexerMutex.RLock()
+	defer fake.getFieldIndexerMutex.RUnlock()
+	fake.getLoggerMutex.RLock()
+	defer fake.getLoggerMutex.RUnlock()
+	fake.getRESTMapperMutex.RLock()
+	defer fake.getRESTMapperMutex.RUnlock()
+	fake.getSchemeMutex.RLock()
+	defer fake.getSchemeMutex.RUnlock()
+	fake.getWebhookServerMutex.RLock()
+	defer fake.getWebhookServerMutex.RUnlock()
+	fake.setFieldsMutex.RLock()
+	defer fake.setFieldsMutex.RUnlock()
+	fake.startMutex.RLock()
+	defer fake.startMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Manager) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ manager.Manager = new(Manager)

+ 196 - 0
pkg/controllers/secretsink/internal/fakes/statuswriter.go

@@ -0,0 +1,196 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package fakes
+
+import (
+	"context"
+	"sync"
+
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type StatusWriter struct {
+	PatchStub        func(context.Context, client.Object, client.Patch, ...client.PatchOption) error
+	patchMutex       sync.RWMutex
+	patchArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 client.Patch
+		arg4 []client.PatchOption
+	}
+	patchReturns struct {
+		result1 error
+	}
+	patchReturnsOnCall map[int]struct {
+		result1 error
+	}
+	UpdateStub        func(context.Context, client.Object, ...client.UpdateOption) error
+	updateMutex       sync.RWMutex
+	updateArgsForCall []struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.UpdateOption
+	}
+	updateReturns struct {
+		result1 error
+	}
+	updateReturnsOnCall map[int]struct {
+		result1 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *StatusWriter) Patch(arg1 context.Context, arg2 client.Object, arg3 client.Patch, arg4 ...client.PatchOption) error {
+	fake.patchMutex.Lock()
+	ret, specificReturn := fake.patchReturnsOnCall[len(fake.patchArgsForCall)]
+	fake.patchArgsForCall = append(fake.patchArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 client.Patch
+		arg4 []client.PatchOption
+	}{arg1, arg2, arg3, arg4})
+	stub := fake.PatchStub
+	fakeReturns := fake.patchReturns
+	fake.recordInvocation("Patch", []interface{}{arg1, arg2, arg3, arg4})
+	fake.patchMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *StatusWriter) PatchCallCount() int {
+	fake.patchMutex.RLock()
+	defer fake.patchMutex.RUnlock()
+	return len(fake.patchArgsForCall)
+}
+
+func (fake *StatusWriter) PatchCalls(stub func(context.Context, client.Object, client.Patch, ...client.PatchOption) error) {
+	fake.patchMutex.Lock()
+	defer fake.patchMutex.Unlock()
+	fake.PatchStub = stub
+}
+
+func (fake *StatusWriter) PatchArgsForCall(i int) (context.Context, client.Object, client.Patch, []client.PatchOption) {
+	fake.patchMutex.RLock()
+	defer fake.patchMutex.RUnlock()
+	argsForCall := fake.patchArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
+}
+
+func (fake *StatusWriter) PatchReturns(result1 error) {
+	fake.patchMutex.Lock()
+	defer fake.patchMutex.Unlock()
+	fake.PatchStub = nil
+	fake.patchReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *StatusWriter) PatchReturnsOnCall(i int, result1 error) {
+	fake.patchMutex.Lock()
+	defer fake.patchMutex.Unlock()
+	fake.PatchStub = nil
+	if fake.patchReturnsOnCall == nil {
+		fake.patchReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.patchReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *StatusWriter) Update(arg1 context.Context, arg2 client.Object, arg3 ...client.UpdateOption) error {
+	fake.updateMutex.Lock()
+	ret, specificReturn := fake.updateReturnsOnCall[len(fake.updateArgsForCall)]
+	fake.updateArgsForCall = append(fake.updateArgsForCall, struct {
+		arg1 context.Context
+		arg2 client.Object
+		arg3 []client.UpdateOption
+	}{arg1, arg2, arg3})
+	stub := fake.UpdateStub
+	fakeReturns := fake.updateReturns
+	fake.recordInvocation("Update", []interface{}{arg1, arg2, arg3})
+	fake.updateMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3...)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *StatusWriter) UpdateCallCount() int {
+	fake.updateMutex.RLock()
+	defer fake.updateMutex.RUnlock()
+	return len(fake.updateArgsForCall)
+}
+
+func (fake *StatusWriter) UpdateCalls(stub func(context.Context, client.Object, ...client.UpdateOption) error) {
+	fake.updateMutex.Lock()
+	defer fake.updateMutex.Unlock()
+	fake.UpdateStub = stub
+}
+
+func (fake *StatusWriter) UpdateArgsForCall(i int) (context.Context, client.Object, []client.UpdateOption) {
+	fake.updateMutex.RLock()
+	defer fake.updateMutex.RUnlock()
+	argsForCall := fake.updateArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *StatusWriter) UpdateReturns(result1 error) {
+	fake.updateMutex.Lock()
+	defer fake.updateMutex.Unlock()
+	fake.UpdateStub = nil
+	fake.updateReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *StatusWriter) UpdateReturnsOnCall(i int, result1 error) {
+	fake.updateMutex.Lock()
+	defer fake.updateMutex.Unlock()
+	fake.UpdateStub = nil
+	if fake.updateReturnsOnCall == nil {
+		fake.updateReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.updateReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *StatusWriter) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.patchMutex.RLock()
+	defer fake.patchMutex.RUnlock()
+	fake.updateMutex.RLock()
+	defer fake.updateMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *StatusWriter) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ client.StatusWriter = new(StatusWriter)

+ 232 - 0
pkg/controllers/secretsink/secretsink_controller.go

@@ -0,0 +1,232 @@
+/*
+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 secretsink
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/go-logr/logr"
+	v1 "k8s.io/api/core/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/tools/record"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	v1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+)
+
+const (
+	errFailedGetSecret        = "could not get source secret"
+	errPatchStatus            = "error merging"
+	errGetSecretStore         = "could not get SecretStore %q, %w"
+	errGetClusterSecretStore  = "could not get ClusterSecretStore %q, %w"
+	errGetProviderFailed      = "could not start provider"
+	errGetSecretsClientFailed = "could not start secrets client"
+	errCloseStoreClient       = "error when calling provider close method"
+	errSetSecretFailed        = "could not write remote ref %v to target secretstore %v: %v"
+	errFailedSetSecret        = "set secret failed: %v"
+)
+
+type Reconciler struct {
+	client.Client
+	Log             logr.Logger
+	Scheme          *runtime.Scheme
+	recorder        record.EventRecorder
+	RequeueInterval time.Duration
+	ControllerClass string
+}
+
+func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+	log := r.Log.WithValues("secretsink", req.NamespacedName)
+	var ss esapi.SecretSink
+	err := r.Get(ctx, req.NamespacedName, &ss)
+	if apierrors.IsNotFound(err) {
+		return ctrl.Result{}, nil
+	} else if err != nil {
+		log.Error(err, "unable to get SecretSink")
+		return ctrl.Result{}, fmt.Errorf("get resource: %w", err)
+	}
+
+	p := client.MergeFrom(ss.DeepCopy())
+	defer func() {
+		err := r.Client.Status().Patch(ctx, &ss, p)
+		if err != nil {
+			log.Error(err, errPatchStatus)
+		}
+	}()
+	secret, err := r.GetSecret(ctx, ss)
+	if err != nil {
+		cond := NewSecretSinkCondition(esapi.SecretSinkReady, v1.ConditionFalse, "SecretSyncFailed", errFailedGetSecret)
+		ss = SetSecretSinkCondition(ss, *cond)
+		return ctrl.Result{}, err
+	}
+	secretStores, err := r.GetSecretStores(ctx, ss)
+	if err != nil {
+		cond := NewSecretSinkCondition(esapi.SecretSinkReady, v1.ConditionFalse, "SecretSyncFailed", err.Error())
+		ss = SetSecretSinkCondition(ss, *cond)
+	}
+	err = r.SetSecretToProviders(ctx, secretStores, ss, secret)
+	if err != nil {
+		msg := fmt.Sprintf(errFailedSetSecret, err)
+		cond := NewSecretSinkCondition(esapi.SecretSinkReady, v1.ConditionFalse, "SecretSyncFailed", msg)
+		ss = SetSecretSinkCondition(ss, *cond)
+		return ctrl.Result{}, err
+	}
+	cond := NewSecretSinkCondition(esapi.SecretSinkReady, v1.ConditionTrue, "SecretSynced", "SecretSink synced successfully")
+	ss = SetSecretSinkCondition(ss, *cond)
+	// Set status for SecretSink
+	return ctrl.Result{}, nil
+}
+
+func (r *Reconciler) SetSecretToProviders(ctx context.Context, stores []v1beta1.GenericStore, ss esapi.SecretSink, secret *v1.Secret) error {
+	for _, store := range stores {
+		provider, err := v1beta1.GetProvider(store)
+		if err != nil {
+			return fmt.Errorf(errGetProviderFailed)
+		}
+		client, err := provider.NewClient(ctx, store, r.Client, ss.Namespace)
+		if err != nil {
+			return fmt.Errorf(errGetSecretsClientFailed)
+		}
+		defer func() {
+			err := client.Close(ctx)
+			if err != nil {
+				r.Log.Error(err, errCloseStoreClient)
+			}
+		}()
+		var secretKey string
+		var remoteKey string
+		for _, ref := range ss.Spec.Data {
+			for _, match := range ref.Match {
+				secretKey = match.SecretKey
+				secretValue, ok := secret.Data[secretKey]
+				if !ok {
+					return fmt.Errorf("secret key %v does not exist", secretKey)
+				}
+				for _, rK := range match.RemoteRefs {
+					remoteKey = rK.RemoteKey
+				}
+				err := client.SetSecret(remoteKey, string(secretValue))
+				if err != nil {
+					return fmt.Errorf(errSetSecretFailed, match.SecretKey, store.GetName(), err)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func (r *Reconciler) GetSecret(ctx context.Context, ss esapi.SecretSink) (*v1.Secret, error) {
+	secretName := types.NamespacedName{Name: ss.Spec.Selector.Secret.Name, Namespace: ss.Namespace}
+	secret := &v1.Secret{}
+	err := r.Client.Get(ctx, secretName, secret)
+	if err != nil {
+		return nil, err
+	}
+	return secret, nil
+}
+
+func (r *Reconciler) GetSecretStores(ctx context.Context, ss esapi.SecretSink) ([]v1beta1.GenericStore, error) {
+	stores := make([]v1beta1.GenericStore, 0)
+	for _, refStore := range ss.Spec.SecretStoreRefs {
+		ref := types.NamespacedName{
+			Name: refStore.Name,
+		}
+
+		if refStore.Kind == v1beta1.ClusterSecretStoreKind {
+			var store v1beta1.ClusterSecretStore
+			err := r.Get(ctx, ref, &store)
+			if err != nil {
+				return nil, fmt.Errorf(errGetClusterSecretStore, ref.Name, err)
+			}
+			stores = append(stores, &store)
+		} else {
+			ref.Namespace = ss.Namespace
+
+			var store v1beta1.SecretStore
+			err := r.Get(ctx, ref, &store)
+			if err != nil {
+				return nil, fmt.Errorf(errGetSecretStore, ref.Name, err)
+			}
+			stores = append(stores, &store)
+		}
+	}
+	return stores, nil
+}
+
+func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
+	r.recorder = mgr.GetEventRecorderFor("secret-sink")
+
+	return ctrl.NewControllerManagedBy(mgr).
+		For(&esapi.SecretSink{}).
+		Complete(r)
+}
+
+func NewSecretSinkCondition(condType esapi.SecretSinkConditionType, status v1.ConditionStatus, reason, message string) *esapi.SecretSinkStatusCondition {
+	return &esapi.SecretSinkStatusCondition{
+		Type:               condType,
+		Status:             status,
+		LastTransitionTime: metav1.Now(),
+		Reason:             reason,
+		Message:            message,
+	}
+}
+
+func SetSecretSinkCondition(gs esapi.SecretSink, condition esapi.SecretSinkStatusCondition) esapi.SecretSink {
+	status := gs.Status
+	currentCond := GetSecretSinkCondition(status, condition.Type)
+	if currentCond != nil && currentCond.Status == condition.Status &&
+		currentCond.Reason == condition.Reason && currentCond.Message == condition.Message {
+		return gs
+	}
+
+	// Do not update lastTransitionTime if the status of the condition doesn't change.
+	if currentCond != nil && currentCond.Status == condition.Status {
+		condition.LastTransitionTime = currentCond.LastTransitionTime
+	}
+
+	status.Conditions = append(filterOutCondition(status.Conditions, condition.Type), condition)
+	gs.Status = status
+	return gs
+}
+
+// filterOutCondition returns an empty set of conditions with the provided type.
+func filterOutCondition(conditions []esapi.SecretSinkStatusCondition, condType esapi.SecretSinkConditionType) []esapi.SecretSinkStatusCondition {
+	newConditions := make([]esapi.SecretSinkStatusCondition, 0, len(conditions))
+	for _, c := range conditions {
+		if c.Type == condType {
+			continue
+		}
+		newConditions = append(newConditions, c)
+	}
+	return newConditions
+}
+
+// GetSecretStoreCondition returns the condition with the provided type.
+func GetSecretSinkCondition(status esapi.SecretSinkStatus, condType esapi.SecretSinkConditionType) *esapi.SecretSinkStatusCondition {
+	for i := range status.Conditions {
+		c := status.Conditions[i]
+		if c.Type == condType {
+			return &c
+		}
+	}
+	return nil
+}

+ 316 - 0
pkg/controllers/secretsink/secretsink_controller_test.go

@@ -0,0 +1,316 @@
+/*
+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 secretsink
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"github.com/go-logr/logr"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/types"
+	ctrl "sigs.k8s.io/controller-runtime"
+	kubeclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	v1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/controllers/secretsink/internal/fakes"
+	"github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
+)
+
+var fakeProvider *fake.Client
+
+var _ = Describe("secretsink", func() {
+	var (
+		reconciler *Reconciler
+		client     *fakes.Client
+	)
+	BeforeEach(func() {
+		client = new(fakes.Client)
+		reconciler = &Reconciler{client, logr.Discard(), nil, nil, 0, ""}
+	})
+	Describe("#Reconcile", func() {
+		var (
+			statusWriter *fakes.StatusWriter
+		)
+
+		BeforeEach(func() {
+			statusWriter = new(fakes.StatusWriter)
+			client.StatusReturns(statusWriter)
+		})
+
+		It("succeeds", func() {
+			namspacedName := types.NamespacedName{Namespace: "foo", Name: "Bar"}
+			_, err := reconciler.Reconcile(context.Background(), ctrl.Request{NamespacedName: namspacedName})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(client.GetCallCount()).To(Equal(2))
+			Expect(client.StatusCallCount()).To(Equal(1))
+
+			_, gotNamespacedName, _ := client.GetArgsForCall(0)
+			Expect(gotNamespacedName).To(Equal(namspacedName))
+
+			Expect(statusWriter.PatchCallCount()).To(Equal(1))
+			_, _, patch, _ := statusWriter.PatchArgsForCall(0)
+			Expect(patch.Type()).To(Equal(types.MergePatchType))
+		})
+
+		When("an error returns in get", func() {
+			BeforeEach(func() {
+				client.GetReturns(errors.New("UnknownError"))
+			})
+
+			It("returns the error", func() {
+				namspacedName := types.NamespacedName{Namespace: "foo", Name: "Bar"}
+				_, err := reconciler.Reconcile(context.Background(), ctrl.Request{NamespacedName: namspacedName})
+
+				Expect(err).To(MatchError("get resource: UnknownError"))
+				Expect(client.GetCallCount()).To(Equal(1))
+				Expect(client.StatusCallCount()).To(Equal(0))
+			})
+		})
+
+		When("an object is not found", func() {
+			BeforeEach(func() {
+				client.GetReturns(statusErrorNotFound{})
+			})
+
+			It("returns an empty result without error", func() {
+				namspacedName := types.NamespacedName{Namespace: "foo", Name: "Bar"}
+				_, err := reconciler.Reconcile(context.Background(), ctrl.Request{NamespacedName: namspacedName})
+
+				Expect(err).NotTo(HaveOccurred())
+			})
+		})
+	})
+
+	Describe("#GetSecretSinkCondition", func() {
+		It("returns nil for empty secret sink status", func() {
+			secretSinkStatus := new(esapi.SecretSinkStatus)
+			secretSinkConditionType := new(esapi.SecretSinkConditionType)
+
+			Expect(GetSecretSinkCondition(*secretSinkStatus, *secretSinkConditionType)).To(BeNil())
+		})
+
+		It("returns correct condition for secret sink status", func() {
+			secretSinkStatusCondition := esapi.SecretSinkStatusCondition{Type: esapi.SecretSinkReady}
+			secretSinkStatus := esapi.SecretSinkStatus{Conditions: []esapi.SecretSinkStatusCondition{secretSinkStatusCondition}}
+			secretSinkConditionType := esapi.SecretSinkReady
+
+			Expect(GetSecretSinkCondition(secretSinkStatus, secretSinkConditionType)).To(Equal(&secretSinkStatusCondition))
+		})
+	})
+
+	Describe("#SetSecretSinkCondition", func() {
+		It("appends a condition", func() {
+			secretSink := esapi.SecretSink{}
+
+			secretSinkStatusCondition := esapi.SecretSinkStatusCondition{}
+			secretSinkStatus := esapi.SecretSinkStatus{Conditions: []esapi.SecretSinkStatusCondition{secretSinkStatusCondition}}
+			expected := esapi.SecretSink{Status: secretSinkStatus}
+			Expect(SetSecretSinkCondition(secretSink, secretSinkStatusCondition)).To(Equal(expected))
+		})
+
+		It("changes an existing condition", func() {
+			conditionStatusTrue := v1.ConditionTrue
+			secretSinkWithCondition := esapi.SecretSink{Status: esapi.SecretSinkStatus{Conditions: []esapi.SecretSinkStatusCondition{
+				{
+					Status: conditionStatusTrue,
+					Type:   esapi.SecretSinkReady,
+				},
+			}},
+			}
+			secretSinkStatusConditionTrue := esapi.SecretSinkStatusCondition{Status: conditionStatusTrue,
+				Type:    esapi.SecretSinkReady,
+				Message: "Update status",
+			}
+
+			got := SetSecretSinkCondition(secretSinkWithCondition, secretSinkStatusConditionTrue)
+			Expect(len(got.Status.Conditions)).To(Equal(1))
+			Expect(got.Status.Conditions[0]).To(Equal(secretSinkStatusConditionTrue))
+		})
+	})
+	Describe("#GetSecret", func() {
+		It("returns a secret if it exists", func() {
+			sink := esapi.SecretSink{
+				Spec: esapi.SecretSinkSpec{
+					Selector: esapi.SecretSinkSelector{
+						Secret: esapi.SecretSinkSecret{
+							Name: "foo",
+						},
+					},
+				},
+			}
+			sink.Namespace = "foobar"
+			_, err := reconciler.GetSecret(context.TODO(), sink)
+			Expect(err).To(BeNil())
+			_, name, _ := client.GetArgsForCall(0)
+			Expect(name.Namespace).To(Equal("foobar"))
+			Expect(name.Name).To(Equal("foo"))
+
+		})
+
+		It("returns an error if it doesn't exist", func() {
+			client.GetReturns(errors.New("secret not found"))
+			_, err := reconciler.GetSecret(context.TODO(), esapi.SecretSink{})
+			Expect(err).To(HaveOccurred())
+		})
+	})
+
+	Describe("#GetSecretStore", func() {
+		sink := esapi.SecretSink{
+			Spec: esapi.SecretSinkSpec{
+				SecretStoreRefs: []esapi.SecretSinkStoreRef{
+					{
+						Name: "foo",
+					},
+				},
+			},
+		}
+		sink.Namespace = "bar"
+
+		clusterSink := esapi.SecretSink{
+			Spec: esapi.SecretSinkSpec{
+				SecretStoreRefs: []esapi.SecretSinkStoreRef{
+					{
+						Name: "foo",
+						Kind: "ClusterSecretStore",
+					},
+				},
+			},
+		}
+
+		It("returns a secretstore if it exists", func() {
+			_, err := reconciler.GetSecretStores(context.TODO(), sink)
+			Expect(err).To(BeNil())
+			Expect(client.GetCallCount()).To(Equal(1))
+			_, name, store := client.GetArgsForCall(0)
+			Expect(name.Namespace).To(Equal("bar"))
+			Expect(name.Name).To(Equal("foo"))
+			Expect(store).To(BeAssignableToTypeOf(&v1beta1.SecretStore{}))
+		})
+
+		It("returns an error if it doesn't exist", func() {
+			client.GetReturns(errors.New("secretstore not found"))
+			_, err := reconciler.GetSecretStores(context.TODO(), sink)
+			Expect(err).To(HaveOccurred())
+		})
+
+		It("returns a clustersecretstore if it exists", func() {
+			_, err := reconciler.GetSecretStores(context.TODO(), clusterSink)
+			Expect(err).To(BeNil())
+			Expect(client.GetCallCount()).To(Equal(1))
+			_, name, store := client.GetArgsForCall(0)
+			Expect(store).To(BeAssignableToTypeOf(&v1beta1.ClusterSecretStore{}))
+			Expect(name.Name).To(Equal("foo"))
+		})
+	})
+	Describe("#SetSecretToProviders", func() {
+		val := "supersecret"
+		secret := &v1.Secret{
+			Data: map[string][]byte{
+				"foo": []byte(val),
+			},
+		}
+		sink := esapi.SecretSink{
+			Spec: esapi.SecretSinkSpec{
+				SecretStoreRefs: []esapi.SecretSinkStoreRef{
+					{
+						Name: "foo",
+					},
+				},
+				Data: []esapi.SecretSinkData{
+					{
+						Match: []esapi.SecretSinkMatch{
+							{
+								SecretKey: "foo",
+								RemoteRefs: []esapi.SecretSinkRemoteRefs{
+									{
+										RemoteKey: "bar",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+		sink.Namespace = "bar"
+
+		secretStore := v1beta1.SecretStore{}
+		stores := make([]v1beta1.GenericStore, 0)
+		stores = append(stores, &secretStore)
+
+		It("gets the provider and client and then sets the secret", func() {
+
+			Expect(reconciler.SetSecretToProviders(context.TODO(), []v1beta1.GenericStore{}, sink, secret)).To(BeNil())
+		})
+
+		It("returns an error if it can't get a provider", func() {
+			err := reconciler.SetSecretToProviders(context.TODO(), stores, sink, secret)
+
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(Equal(errGetProviderFailed))
+		})
+
+		It("returns an if it can't get a client", func() {
+			specWithProvider := v1beta1.SecretStoreSpec{
+				Provider: &v1beta1.SecretStoreProvider{
+					Fake: &v1beta1.FakeProvider{},
+				},
+			}
+			fakeProvider.WithNew(func(context.Context, v1beta1.GenericStore, kubeclient.Client,
+				string) (v1beta1.SecretsClient, error) {
+				return nil, fmt.Errorf("Something went wrong")
+			})
+			secretStore = v1beta1.SecretStore{
+				Spec: specWithProvider,
+			}
+
+			stores[0] = &secretStore
+			err := reconciler.SetSecretToProviders(context.TODO(), stores, sink, secret)
+
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(Equal(errGetSecretsClientFailed))
+		})
+		It("returns an error if set secret fails", func() {
+			specWithProvider := v1beta1.SecretStoreSpec{
+				Provider: &v1beta1.SecretStoreProvider{
+					Fake: &v1beta1.FakeProvider{},
+				},
+			}
+			fakeProvider.Reset()
+			fakeProvider.WithSetSecret(fmt.Errorf("something went wrong"))
+			secretStore = v1beta1.SecretStore{
+				Spec: specWithProvider,
+			}
+
+			stores[0] = &secretStore
+			err := reconciler.SetSecretToProviders(context.TODO(), stores, sink, secret)
+
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(Equal(fmt.Sprintf(errSetSecretFailed, "foo", "", "something went wrong")))
+		})
+	})
+})
+
+func init() {
+	fakeProvider = fake.New()
+	v1beta1.ForceRegister(fakeProvider, &v1beta1.SecretStoreProvider{
+		Fake: &v1beta1.FakeProvider{},
+	})
+}

+ 44 - 0
pkg/controllers/secretsink/suite_test.go

@@ -0,0 +1,44 @@
+/*
+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 secretsink
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	"k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestAPIs(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "Controller Suite")
+}
+
+type statusErrorNotFound struct {
+}
+
+func (statusErrorNotFound) Status() metav1.Status {
+	return metav1.Status{
+		Reason: metav1.StatusReasonNotFound,
+	}
+}
+
+func (statusErrorNotFound) Error() string {
+	return "Blurb"
+}
+
+var _ errors.APIStatus = statusErrorNotFound{}

+ 9 - 0
pkg/controllers/secretstore/common.go

@@ -67,6 +67,15 @@ func reconcile(ctx context.Context, req ctrl.Request, ss esapi.GenericStore, cl
 		log.Error(err, "unable to validate store")
 		return ctrl.Result{}, err
 	}
+	storeProvider, err := esapi.GetProvider(ss)
+	if err != nil {
+		return ctrl.Result{}, err
+	}
+	capStatus := esapi.SecretStoreStatus{
+		Capabilities: storeProvider.Capabilities(),
+		Conditions:   ss.GetStatus().Conditions,
+	}
+	ss.SetStatus(capStatus)
 
 	recorder.Event(ss, v1.EventTypeNormal, esapi.ReasonStoreValid, msgStoreValidated)
 	cond := NewSecretStoreCondition(esapi.SecretStoreReady, v1.ConditionTrue, esapi.ReasonStoreValid, msgStoreValidated)

+ 33 - 0
pkg/controllers/secretstore/common_test.go

@@ -125,6 +125,37 @@ var _ = Describe("SecretStore reconcile", func() {
 
 	}
 
+	readOnly := func(tc *testCase) {
+		spc := tc.store.GetSpec()
+		spc.Provider.Vault = nil
+		spc.Provider.Fake = &esapi.FakeProvider{
+			Data: []esapi.FakeProviderData{},
+		}
+
+		tc.assert = func() {
+			Eventually(func() bool {
+				ss := tc.store.Copy()
+				err := k8sClient.Get(context.Background(), types.NamespacedName{
+					Name:      defaultStoreName,
+					Namespace: ss.GetNamespace(),
+				}, ss)
+				if err != nil {
+					return false
+				}
+
+				if ss.GetStatus().Capabilities != esapi.SecretStoreReadOnly {
+					return false
+				}
+
+				return true
+			}).
+				WithTimeout(time.Second * 10).
+				WithPolling(time.Second).
+				Should(BeTrue())
+		}
+
+	}
+
 	DescribeTable("Controller Reconcile logic", func(muts ...func(tc *testCase)) {
 		for _, mut := range muts {
 			mut(test)
@@ -137,11 +168,13 @@ var _ = Describe("SecretStore reconcile", func() {
 		Entry("[namespace] invalid provider with secretStore should set InvalidStore condition", invalidProvider),
 		Entry("[namespace] ignore stores with non-matching class", ignoreControllerClass),
 		Entry("[namespace] valid provider has status=ready", validProvider),
+		Entry("[namespace] valid provider has capabilities=ReadOnly", readOnly),
 
 		// cluster store
 		Entry("[cluster] invalid provider with secretStore should set InvalidStore condition", invalidProvider, useClusterStore),
 		Entry("[cluster] ignore stores with non-matching class", ignoreControllerClass, useClusterStore),
 		Entry("[cluster] valid provider has status=ready", validProvider, useClusterStore),
+		Entry("[cluster] valid provider has capabilities=ReadOnly", validProvider, useClusterStore),
 	)
 
 })

+ 9 - 0
pkg/provider/akeyless/akeyless.go

@@ -66,6 +66,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	return newClient(ctx, store, kube, namespace)
@@ -165,6 +170,10 @@ func (a *Akeyless) Validate() (esv1beta1.ValidationResult, error) {
 	return esv1beta1.ValidationResultReady, nil
 }
 
+func (a *Akeyless) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Implements store.Client.GetSecret Interface.
 // Retrieves a secret with the secret name defined in ref.Name.
 func (a *Akeyless) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {

+ 9 - 0
pkg/provider/alibaba/kms.go

@@ -114,6 +114,10 @@ func (c *Client) setAuth(ctx context.Context) error {
 	return nil
 }
 
+func (kms *KeyManagementService) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (kms *KeyManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented
@@ -168,6 +172,11 @@ func (kms *KeyManagementService) GetSecretMap(ctx context.Context, ref esv1beta1
 	return secretData, nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (kms *KeyManagementService) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (kms *KeyManagementService) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()

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

@@ -60,7 +60,12 @@ func New(sess *session.Session) (*ParameterStore, error) {
 	}, nil
 }
 
-// Empty GetAllSecrets.
+// Not Implemented SetSecret.
+func (pm *ParameterStore) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
+// GetAllSecrets fetches information from multiple secrets into a single kubernetes secret.
 func (pm *ParameterStore) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {
 		return pm.findByName(ref)

+ 5 - 0
pkg/provider/aws/provider.go

@@ -41,6 +41,11 @@ const (
 	errRegionNotFound         = "region not found: %s"
 )
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	return newClient(ctx, store, kube, namespace, awsauth.DefaultSTSProvider)

+ 5 - 0
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -104,6 +104,11 @@ func (sm *SecretsManager) fetch(_ context.Context, ref esv1beta1.ExternalSecretD
 	return secretOut, nil
 }
 
+// Not Implemented SetSecret.
+func (sm *SecretsManager) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // GetAllSecrets syncs multiple secrets from aws provider into a single Kubernetes Secret.
 func (sm *SecretsManager) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {

+ 10 - 0
pkg/provider/azure/keyvault/keyvault.go

@@ -107,6 +107,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (a *Azure) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (a *Azure) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	return newClient(ctx, store, kube, namespace)
@@ -196,6 +201,11 @@ func (a *Azure) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (a *Azure) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Implements store.Client.GetAllSecrets Interface.
 // Retrieves a map[string][]byte with the secret names as key and the secret itself as the calue.
 func (a *Azure) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {

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

@@ -31,16 +31,32 @@ var (
 )
 
 type Provider struct {
-	config *esv1beta1.FakeProvider
+	config   *esv1beta1.FakeProvider
+	database map[string]*esv1beta1.FakeProvider
+}
+
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
 }
 
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
+	if p.database == nil {
+		p.database = make(map[string]*esv1beta1.FakeProvider)
+	}
 	cfg, err := getProvider(store)
 	if err != nil {
 		return nil, err
 	}
+	prov, ok := p.database[store.GetName()]
+	if !ok {
+		p.database[store.GetName()] = cfg
+		return &Provider{
+			config: cfg,
+		}, nil
+	}
 	return &Provider{
-		config: cfg,
+		config: prov,
 	}, nil
 }
 
@@ -55,6 +71,22 @@ func getProvider(store esv1beta1.GenericStore) (*esv1beta1.FakeProvider, error)
 	return spc.Provider.Fake, nil
 }
 
+// Not Implemented SetSecret.
+func (p *Provider) SetSecret(key, value string) error {
+	newData := esv1beta1.FakeProviderData{
+		Key:   key,
+		Value: value,
+	}
+	for i, data := range p.config.Data {
+		if data.Key == key {
+			p.config.Data[i] = newData
+			return nil
+		}
+	}
+	p.config.Data = append(p.config.Data, newData)
+	return nil
+}
+
 // Empty GetAllSecrets.
 func (p *Provider) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 9 - 2
pkg/provider/fake/fake_test.go

@@ -19,6 +19,7 @@ import (
 	"testing"
 
 	"github.com/onsi/gomega"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 )
@@ -123,9 +124,12 @@ func TestGetSecret(t *testing.T) {
 		},
 	}
 
-	for _, row := range tbl {
+	for i, row := range tbl {
 		t.Run(row.name, func(t *testing.T) {
 			cl, err := p.NewClient(context.Background(), &esv1beta1.SecretStore{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: fmt.Sprintf("secret-store-%v", i),
+				},
 				Spec: esv1beta1.SecretStoreSpec{
 					Provider: &esv1beta1.SecretStoreProvider{
 						Fake: &esv1beta1.FakeProvider{
@@ -204,9 +208,12 @@ func TestGetSecretMap(t *testing.T) {
 		},
 	}
 
-	for _, row := range tbl {
+	for i, row := range tbl {
 		t.Run(row.name, func(t *testing.T) {
 			cl, err := p.NewClient(context.Background(), &esv1beta1.SecretStore{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: fmt.Sprintf("secret-store-%v", i),
+				},
 				Spec: esv1beta1.SecretStoreSpec{
 					Provider: &esv1beta1.SecretStoreProvider{
 						Fake: &esv1beta1.FakeProvider{

+ 10 - 0
pkg/provider/gcp/secretmanager/secretsmanager.go

@@ -160,6 +160,11 @@ func serviceAccountTokenSource(ctx context.Context, store esv1beta1.GenericStore
 	return config.TokenSource(ctx), nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (sm *ProviderGCP) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a GCP Provider.
 func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -214,6 +219,11 @@ func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1beta1.GenericSto
 	return sm, nil
 }
 
+// Not Implemented SetSecret.
+func (sm *ProviderGCP) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // GetAllSecrets syncs multiple secrets from gcp provider into a single Kubernetes Secret.
 func (sm *ProviderGCP) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {

+ 10 - 0
pkg/provider/gitlab/gitlab.go

@@ -114,6 +114,11 @@ func NewGitlabProvider() *Gitlab {
 	return &Gitlab{}
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (g *Gitlab) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // Method on Gitlab Provider to set up client with credentials and populate projectID.
 func (g *Gitlab) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -156,6 +161,11 @@ func (g *Gitlab) NewClient(ctx context.Context, store esv1beta1.GenericStore, ku
 	return g, nil
 }
 
+// Not Implemented SetSecret.
+func (g *Gitlab) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (g *Gitlab) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 10 - 0
pkg/provider/ibm/provider.go

@@ -100,6 +100,11 @@ func (c *client) setAuth(ctx context.Context) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (ibm *providerIBM) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (ibm *providerIBM) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented
@@ -564,6 +569,11 @@ func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (ibm *providerIBM) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (ibm *providerIBM) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
 	ibmSpec := storeSpec.Provider.IBM

+ 10 - 0
pkg/provider/kubernetes/kubernetes.go

@@ -79,6 +79,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (k *ProviderKubernetes) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a Kubernetes Provider.
 func (k *ProviderKubernetes) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -125,6 +130,11 @@ func (k *ProviderKubernetes) Close(ctx context.Context) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (k *ProviderKubernetes) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 func (k *ProviderKubernetes) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	if ref.Property == "" {
 		return nil, fmt.Errorf(errPropertyNotFound)

+ 10 - 0
pkg/provider/onepassword/onepassword.go

@@ -69,6 +69,11 @@ type ProviderOnePassword struct {
 var _ esv1beta1.SecretsClient = &ProviderOnePassword{}
 var _ esv1beta1.Provider = &ProviderOnePassword{}
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (provider *ProviderOnePassword) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a 1Password Provider.
 func (provider *ProviderOnePassword) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	config := store.GetSpec().Provider.OnePassword
@@ -148,6 +153,11 @@ func validateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (provider *ProviderOnePassword) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // GetSecret returns a single secret from the provider.
 func (provider *ProviderOnePassword) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	if ref.Version != "" {

+ 10 - 0
pkg/provider/oracle/oracle.go

@@ -65,6 +65,11 @@ type VMInterface interface {
 	GetSecretBundleByName(ctx context.Context, request secrets.GetSecretBundleByNameRequest) (secrets.GetSecretBundleByNameResponse, error)
 }
 
+// Not Implemented SetSecret.
+func (vms *VaultManagementService) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (vms *VaultManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented
@@ -125,6 +130,11 @@ func (vms *VaultManagementService) GetSecretMap(ctx context.Context, ref esv1bet
 	return secretData, nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (vms *VaultManagementService) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (vms *VaultManagementService) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()

+ 5 - 0
pkg/provider/senhasegura/dsm/dsm.go

@@ -90,6 +90,11 @@ func New(isoSession *senhaseguraAuth.SenhaseguraIsoSession) (*DSM, error) {
 	}, nil
 }
 
+// Not Implemented SetSecret.
+func (dsm *DSM) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 /*
 	GetSecret implements ESO interface and get a single secret from senhasegura provider with DSM service
 */

+ 5 - 0
pkg/provider/senhasegura/provider.go

@@ -43,6 +43,11 @@ const (
 	errMissingClientID            = "missing senhasegura authentication Client ID"
 )
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 /*
 	Construct a new secrets client based on provided store
 */

+ 22 - 0
pkg/provider/testing/fake/fake.go

@@ -30,6 +30,7 @@ type Client struct {
 	GetSecretFn     func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error)
 	GetSecretMapFn  func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
 	GetAllSecretsFn func(context.Context, esv1beta1.ExternalSecretFind) (map[string][]byte, error)
+	SetSecretFn     func() error
 }
 
 // New returns a fake provider/client.
@@ -44,6 +45,9 @@ func New() *Client {
 		GetAllSecretsFn: func(context.Context, esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 			return nil, nil
 		},
+		SetSecretFn: func() error {
+			return nil
+		},
 	}
 
 	v.NewFn = func(context.Context, esv1beta1.GenericStore, client.Client, string) (esv1beta1.SecretsClient, error) {
@@ -63,6 +67,11 @@ func (v *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecret
 	return v.GetAllSecretsFn(ctx, ref)
 }
 
+// Not Implemented SetSecret.
+func (v *Client) SetSecret(secretKey, remoteKey string) error {
+	return v.SetSecretFn()
+}
+
 // GetSecret implements the provider.Provider interface.
 func (v *Client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	return v.GetSecretFn(ctx, ref)
@@ -109,6 +118,14 @@ func (v *Client) WithGetAllSecrets(secData map[string][]byte, err error) *Client
 	return v
 }
 
+// WithSetSecret wraps the secret response to the fake provider.
+func (v *Client) WithSetSecret(err error) *Client {
+	v.SetSecretFn = func() error {
+		return err
+	}
+	return v
+}
+
 // WithNew wraps the fake provider factory function.
 func (v *Client) WithNew(f func(context.Context, esv1beta1.GenericStore, client.Client,
 	string) (esv1beta1.SecretsClient, error)) *Client {
@@ -116,6 +133,11 @@ func (v *Client) WithNew(f func(context.Context, esv1beta1.GenericStore, client.
 	return v
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (v *Client) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient returns a new fake provider.
 func (v *Client) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	c, err := v.NewFn(ctx, store, kube, namespace)

+ 12 - 3
pkg/provider/vault/vault.go

@@ -224,6 +224,11 @@ type connector struct {
 	newVaultClient func(c *vault.Config) (Client, error)
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (c *connector) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (c *connector) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	// controller-runtime/client does not support TokenRequest or other subresource APIs
 	// so we need to construct our own client and use it to fetch tokens
@@ -355,9 +360,13 @@ func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
-// Empty GetAllSecrets.
-// GetAllSecrets
-// First load all secrets from secretStore path configuration.
+// Not Implemented SetSecret.
+func (v *client) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
+// 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.
 func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if v.store.Version == esv1beta1.VaultKVStoreV1 {

+ 10 - 0
pkg/provider/webhook/webhook.go

@@ -61,6 +61,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	whClient := &WebHook{
 		kube:      kube,
@@ -111,6 +116,11 @@ func (w *WebHook) getStoreSecret(ctx context.Context, ref esmeta.SecretKeySelect
 	return secret, nil
 }
 
+// Not Implemented SetSecret.
+func (w *WebHook) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (w *WebHook) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 6 - 1
pkg/provider/yandex/common/provider.go

@@ -88,6 +88,7 @@ func InitYandexCloudProvider(
 	return provider
 }
 
+type NewSecretSetterFunc func()
 type AdaptInputFunc func(store esv1beta1.GenericStore) (*SecretsClientInput, error)
 type NewSecretGetterFunc func(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (SecretGetter, error)
 type NewIamTokenFunc func(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (*IamToken, error)
@@ -103,6 +104,10 @@ type SecretsClientInput struct {
 	CACertificate *esmeta.SecretKeySelector
 }
 
+func (p *YandexCloudProvider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a Yandex.Cloud Provider.
 func (p *YandexCloudProvider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	input, err := p.adaptInputFunc(store)
@@ -177,7 +182,7 @@ func (p *YandexCloudProvider) NewClient(ctx context.Context, store esv1beta1.Gen
 		return nil, fmt.Errorf("failed to create IAM token: %w", err)
 	}
 
-	return &yandexCloudSecretsClient{secretGetter, iamToken.Token}, nil
+	return &yandexCloudSecretsClient{secretGetter, nil, iamToken.Token}, nil
 }
 
 func (p *YandexCloudProvider) getOrCreateSecretGetter(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (SecretGetter, error) {

+ 14 - 9
pkg/provider/yandex/common/secretsclient.go

@@ -26,26 +26,31 @@ var _ esv1beta1.SecretsClient = &yandexCloudSecretsClient{}
 // Implementation of v1beta1.SecretsClient.
 type yandexCloudSecretsClient struct {
 	secretGetter SecretGetter
+	secretSetter SecretSetter
 	iamToken     string
 }
 
-func (c *yandexCloudSecretsClient) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
-	// TO be implemented
-	return nil, fmt.Errorf("GetAllSecrets not supported")
-}
-
 func (c *yandexCloudSecretsClient) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	return c.secretGetter.GetSecret(ctx, c.iamToken, ref.Key, ref.Version, ref.Property)
 }
 
+func (c *yandexCloudSecretsClient) SetSecret(secretKey, remoteKey string) error {
+	return fmt.Errorf("not implemented")
+}
+
+func (c *yandexCloudSecretsClient) Validate() (esv1beta1.ValidationResult, error) {
+	return esv1beta1.ValidationResultReady, nil
+}
+
 func (c *yandexCloudSecretsClient) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
 	return c.secretGetter.GetSecretMap(ctx, c.iamToken, ref.Key, ref.Version)
 }
 
-func (c *yandexCloudSecretsClient) Close(ctx context.Context) error {
-	return nil
+func (c *yandexCloudSecretsClient) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
+	// TO be implemented
+	return nil, fmt.Errorf("GetAllSecrets not supported")
 }
 
-func (c *yandexCloudSecretsClient) Validate() (esv1beta1.ValidationResult, error) {
-	return esv1beta1.ValidationResultReady, nil
+func (c *yandexCloudSecretsClient) Close(ctx context.Context) error {
+	return nil
 }

+ 18 - 0
pkg/provider/yandex/common/secretsetter.go

@@ -0,0 +1,18 @@
+/*
+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 common
+
+type SecretSetter interface {
+	SetSecret() error
+}