Przeglądaj źródła

feat: add provider store v2 APIs and CRDs

Moritz Johner 1 miesiąc temu
rodzic
commit
88a481f3dc
88 zmienionych plików z 5614 dodań i 451 usunięć
  1. 28 0
      apis/externalsecrets/v1/authscope_types.go
  2. 116 0
      apis/externalsecrets/v1/externalsecret_crd_test.go
  3. 2 2
      apis/externalsecrets/v1/externalsecret_types.go
  4. 2 2
      apis/externalsecrets/v1/provider.go
  5. 6 6
      apis/externalsecrets/v1/provider_schema.go
  6. 6 0
      apis/externalsecrets/v1/register.go
  7. 1 0
      apis/externalsecrets/v1/secretstore_aws_types.go
  8. 2 0
      apis/externalsecrets/v1/secretstore_github_types.go
  9. 39 0
      apis/externalsecrets/v1/secretstore_runtime_ref_test.go
  10. 20 0
      apis/externalsecrets/v1/secretstore_types.go
  11. 1 1
      apis/externalsecrets/v1/secretstore_validator_test.go
  12. 1 0
      apis/externalsecrets/v1/secretstore_vault_types.go
  13. 20 0
      apis/externalsecrets/v1/zz_generated.deepcopy.go
  14. 53 0
      apis/externalsecrets/v1alpha1/clusterproviderclass_types.go
  15. 38 0
      apis/externalsecrets/v1alpha1/clusterproviderclass_types_test.go
  16. 192 0
      apis/externalsecrets/v1alpha1/pushsecret_crd_test.go
  17. 7 3
      apis/externalsecrets/v1alpha1/pushsecret_types.go
  18. 1 0
      apis/externalsecrets/v1alpha1/register.go
  19. 96 0
      apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go
  20. 116 0
      apis/externalsecrets/v1beta1/externalsecret_crd_test.go
  21. 2 2
      apis/externalsecrets/v1beta1/externalsecret_types.go
  22. 2 2
      apis/externalsecrets/v1beta1/provider.go
  23. 6 6
      apis/externalsecrets/v1beta1/provider_schema.go
  24. 1 0
      apis/externalsecrets/v1beta1/secretstore_aws_types.go
  25. 2 0
      apis/externalsecrets/v1beta1/secretstore_github_types.go
  26. 19 0
      apis/externalsecrets/v1beta1/secretstore_types.go
  27. 1 1
      apis/externalsecrets/v1beta1/secretstore_validator_test.go
  28. 1 0
      apis/externalsecrets/v1beta1/secretstore_vault_types.go
  29. 20 0
      apis/externalsecrets/v1beta1/zz_generated.deepcopy.go
  30. 21 0
      apis/externalsecrets/v2alpha1/doc.go
  31. 120 0
      apis/externalsecrets/v2alpha1/generic_store.go
  32. 184 0
      apis/externalsecrets/v2alpha1/providerstore_types.go
  33. 58 0
      apis/externalsecrets/v2alpha1/providerstore_types_test.go
  34. 84 0
      apis/externalsecrets/v2alpha1/providerstore_validator.go
  35. 85 0
      apis/externalsecrets/v2alpha1/providerstore_validator_test.go
  36. 35 0
      apis/externalsecrets/v2alpha1/providerstore_webhook.go
  37. 68 0
      apis/externalsecrets/v2alpha1/register.go
  38. 313 0
      apis/externalsecrets/v2alpha1/zz_generated.deepcopy.go
  39. 37 36
      apis/go.mod
  40. 84 83
      apis/go.sum
  41. 20 0
      apis/provider/aws/v2alpha1/doc.go
  42. 39 0
      apis/provider/aws/v2alpha1/groupversion_info.go
  43. 93 0
      apis/provider/aws/v2alpha1/parameterstore_types.go
  44. 97 0
      apis/provider/aws/v2alpha1/secretsmanager_types.go
  45. 268 0
      apis/provider/aws/v2alpha1/zz_generated.deepcopy.go
  46. 21 0
      apis/provider/fake/v2alpha1/doc.go
  47. 36 0
      apis/provider/fake/v2alpha1/groupversion_info.go
  48. 75 0
      apis/provider/fake/v2alpha1/types.go
  49. 123 0
      apis/provider/fake/v2alpha1/zz_generated.deepcopy.go
  50. 21 0
      apis/provider/kubernetes/v2alpha1/doc.go
  51. 36 0
      apis/provider/kubernetes/v2alpha1/groupversion_info.go
  52. 51 0
      apis/provider/kubernetes/v2alpha1/types.go
  53. 83 0
      apis/provider/kubernetes/v2alpha1/zz_generated.deepcopy.go
  54. 18 6
      config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml
  55. 122 0
      config/crds/bases/external-secrets.io_clusterproviderclasses.yaml
  56. 212 0
      config/crds/bases/external-secrets.io_clusterproviderstores.yaml
  57. 18 6
      config/crds/bases/external-secrets.io_clusterpushsecrets.yaml
  58. 40 9
      config/crds/bases/external-secrets.io_clustersecretstores.yaml
  59. 18 6
      config/crds/bases/external-secrets.io_externalsecrets.yaml
  60. 144 0
      config/crds/bases/external-secrets.io_providerstores.yaml
  61. 18 6
      config/crds/bases/external-secrets.io_pushsecrets.yaml
  62. 40 9
      config/crds/bases/external-secrets.io_secretstores.yaml
  63. 0 2
      config/crds/bases/generators.external-secrets.io_clustergenerators.yaml
  64. 0 2
      config/crds/bases/generators.external-secrets.io_vaultdynamicsecrets.yaml
  65. 7 0
      config/crds/bases/kustomization.yaml
  66. 75 0
      config/crds/bases/provider.external-secrets.io_fakes.yaml
  67. 265 0
      config/crds/bases/provider.external-secrets.io_kubernetes.yaml
  68. 294 0
      config/crds/bases/provider.external-secrets.io_parameterstores.yaml
  69. 315 0
      config/crds/bases/provider.external-secrets.io_secretsmanagers.yaml
  70. 601 41
      deploy/crds/bundle.yaml
  71. 472 198
      docs/api/spec.md
  72. 3 3
      tests/__snapshot__/clusterexternalsecret-v1.yaml
  73. 3 3
      tests/__snapshot__/clusterexternalsecret-v1beta1.yaml
  74. 28 0
      tests/__snapshot__/clusterproviderstore-v2alpha1.yaml
  75. 3 0
      tests/__snapshot__/clustersecretstore-v1.yaml
  76. 3 0
      tests/__snapshot__/clustersecretstore-v1beta1.yaml
  77. 3 3
      tests/__snapshot__/externalsecret-v1.yaml
  78. 3 3
      tests/__snapshot__/externalsecret-v1beta1.yaml
  79. 0 6
      tests/__snapshot__/fake-v1alpha1.yaml
  80. 9 0
      tests/__snapshot__/fake-v2alpha1.yaml
  81. 19 0
      tests/__snapshot__/providerstore-v2alpha1.yaml
  82. 4 2
      tests/__snapshot__/pushsecret-v1alpha1.yaml
  83. 3 0
      tests/__snapshot__/secretstore-v1.yaml
  84. 3 0
      tests/__snapshot__/secretstore-v1beta1.yaml
  85. 7 0
      tests/clusterproviderstore_test.yaml
  86. 2 1
      tests/clustersecretstore_test.yaml
  87. 7 0
      tests/providerstore_test.yaml
  88. 2 1
      tests/secretstore_test.yaml

+ 28 - 0
apis/externalsecrets/v1/authscope_types.go

@@ -0,0 +1,28 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1
+
+// AuthenticationScope defines which namespace should be used when resolving
+// provider-owned backend configuration for out-of-process test scenarios.
+type AuthenticationScope string
+
+const (
+	// AuthenticationScopeProviderNamespace uses the provider/backend namespace.
+	AuthenticationScopeProviderNamespace AuthenticationScope = "ProviderNamespace"
+	// AuthenticationScopeManifestNamespace uses the ExternalSecret/PushSecret namespace.
+	AuthenticationScopeManifestNamespace AuthenticationScope = "ManifestNamespace"
+)

+ 116 - 0
apis/externalsecrets/v1/externalsecret_crd_test.go

@@ -0,0 +1,116 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1
+
+import (
+	"os"
+	"path/filepath"
+	"slices"
+	"testing"
+
+	"sigs.k8s.io/yaml"
+)
+
+func TestExternalSecretCRDSecretStoreRefKindOmitsProviderKinds(t *testing.T) {
+	kindEnum := externalSecretCRDKindEnum(t, "v1")
+
+	assertContains := func(value string) {
+		t.Helper()
+		if slices.Contains(kindEnum, value) {
+			return
+		}
+		t.Fatalf("kind enum does not contain %q: %v", value, kindEnum)
+	}
+
+	assertNotContains := func(value string) {
+		t.Helper()
+		if slices.Contains(kindEnum, value) {
+			t.Fatalf("kind enum unexpectedly contains %q: %v", value, kindEnum)
+		}
+	}
+
+	assertContains("ProviderStore")
+	assertContains("ClusterProviderStore")
+	assertNotContains("Provider")
+	assertNotContains("ClusterProvider")
+}
+
+func externalSecretCRDKindEnum(t *testing.T, versionName string) []string {
+	t.Helper()
+
+	crdPath := filepath.Join("..", "..", "..", "config", "crds", "bases", "external-secrets.io_externalsecrets.yaml")
+	data, err := os.ReadFile(crdPath)
+	if err != nil {
+		t.Fatalf("read CRD: %v", err)
+	}
+
+	var crd map[string]any
+	if err := yaml.Unmarshal(data, &crd); err != nil {
+		t.Fatalf("unmarshal CRD: %v", err)
+	}
+
+	versions := asSlice(t, asMap(t, crd["spec"], "spec")["versions"], "spec.versions")
+	for _, version := range versions {
+		versionMap := asMap(t, version, "spec.versions[]")
+		if versionMap["name"] != versionName {
+			continue
+		}
+
+		schema := asMap(t, versionMap["schema"], "spec.versions[].schema")
+		openAPIV3 := asMap(t, schema["openAPIV3Schema"], "spec.versions[].schema.openAPIV3Schema")
+		properties := asMap(t, openAPIV3["properties"], "spec.versions[].schema.openAPIV3Schema.properties")
+		specProperties := asMap(t, asMap(t, properties["spec"], "spec property")["properties"], "spec.properties")
+		secretStoreRef := asMap(t, asMap(t, specProperties["secretStoreRef"], "spec.properties.secretStoreRef")["properties"], "spec.properties.secretStoreRef.properties")
+		kindSchema := asMap(t, secretStoreRef["kind"], "spec.properties.secretStoreRef.properties.kind")
+		return asStringSlice(t, kindSchema["enum"], "spec.properties.secretStoreRef.properties.kind.enum")
+	}
+
+	t.Fatalf("did not find %s secretStoreRef.kind enum", versionName)
+	return nil
+}
+
+func asMap(t *testing.T, v any, path string) map[string]any {
+	t.Helper()
+	m, ok := v.(map[string]any)
+	if !ok {
+		t.Fatalf("%s is %T, want map[string]any", path, v)
+	}
+	return m
+}
+
+func asSlice(t *testing.T, v any, path string) []any {
+	t.Helper()
+	s, ok := v.([]any)
+	if !ok {
+		t.Fatalf("%s is %T, want []any", path, v)
+	}
+	return s
+}
+
+func asStringSlice(t *testing.T, v any, path string) []string {
+	t.Helper()
+	s := asSlice(t, v, path)
+	out := make([]string, 0, len(s))
+	for i, entry := range s {
+		str, ok := entry.(string)
+		if !ok {
+			t.Fatalf("%s[%d] is %T, want string", path, i, entry)
+		}
+		out = append(out, str)
+	}
+	return out
+}

+ 2 - 2
apis/externalsecrets/v1/externalsecret_types.go

@@ -29,10 +29,10 @@ type SecretStoreRef struct {
 	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
 	Name string `json:"name,omitempty"`
 
-	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+	// Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
 	// Defaults to `SecretStore`
 	// +optional
-	// +kubebuilder:validation:Enum=SecretStore;ClusterSecretStore
+	// +kubebuilder:validation:Enum=SecretStore;ClusterSecretStore;ProviderStore;ClusterProviderStore
 	Kind string `json:"kind,omitempty"`
 }
 

+ 2 - 2
apis/externalsecrets/v1/provider.go

@@ -49,8 +49,8 @@ func (v ValidationResult) String() string {
 // +k8s:deepcopy-gen:interfaces=nil
 // +k8s:deepcopy-gen=nil
 
-// Provider is a common interface for interacting with secret backends.
-type Provider interface {
+// ProviderInterface is a common interface for interacting with secret backends.
+type ProviderInterface interface {
 	// NewClient constructs a SecretsManager Provider
 	NewClient(ctx context.Context, store GenericStore, kube client.Client, namespace string) (SecretsClient, error)
 

+ 6 - 6
apis/externalsecrets/v1/provider_schema.go

@@ -23,16 +23,16 @@ import (
 	"sync"
 )
 
-var builder map[string]Provider
+var builder map[string]ProviderInterface
 var buildlock sync.RWMutex
 
 func init() {
-	builder = make(map[string]Provider)
+	builder = make(map[string]ProviderInterface)
 }
 
 // Register a store backend type. Register panics if a
 // backend with the same store is already registered.
-func Register(s Provider, storeSpec *SecretStoreProvider, maintenanceStatus MaintenanceStatus) {
+func Register(s ProviderInterface, storeSpec *SecretStoreProvider, maintenanceStatus MaintenanceStatus) {
 	storeName, err := getProviderName(storeSpec)
 	if err != nil {
 		panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
@@ -51,7 +51,7 @@ func Register(s Provider, storeSpec *SecretStoreProvider, maintenanceStatus Main
 
 // ForceRegister adds to store schema, overwriting a store if
 // already registered. Should only be used for testing.
-func ForceRegister(s Provider, storeSpec *SecretStoreProvider, maintenanceStatus MaintenanceStatus) {
+func ForceRegister(s ProviderInterface, storeSpec *SecretStoreProvider, maintenanceStatus MaintenanceStatus) {
 	storeName, err := getProviderName(storeSpec)
 	if err != nil {
 		panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
@@ -64,7 +64,7 @@ func ForceRegister(s Provider, storeSpec *SecretStoreProvider, maintenanceStatus
 }
 
 // GetProviderByName returns the provider implementation by name.
-func GetProviderByName(name string) (Provider, bool) {
+func GetProviderByName(name string) (ProviderInterface, bool) {
 	buildlock.RLock()
 	f, ok := builder[name]
 	buildlock.RUnlock()
@@ -72,7 +72,7 @@ func GetProviderByName(name string) (Provider, bool) {
 }
 
 // GetProvider returns the provider from the generic store.
-func GetProvider(s GenericStore) (Provider, error) {
+func GetProvider(s GenericStore) (ProviderInterface, error) {
 	if s == nil {
 		return nil, nil
 	}

+ 6 - 0
apis/externalsecrets/v1/register.go

@@ -72,6 +72,12 @@ var (
 	ClusterSecretStoreGroupVersionKind = SchemeGroupVersion.WithKind(ClusterSecretStoreKind)
 )
 
+// Provider kind string constants for use in SecretStoreRef.
+const (
+	ProviderStoreKindStr        = "ProviderStore"
+	ClusterProviderStoreKindStr = "ClusterProviderStore"
+)
+
 func init() {
 	SchemeBuilder.Register(&ExternalSecret{}, &ExternalSecretList{})
 	SchemeBuilder.Register(&ClusterExternalSecret{}, &ClusterExternalSecretList{})

+ 1 - 0
apis/externalsecrets/v1/secretstore_aws_types.go

@@ -82,6 +82,7 @@ type SecretsManager struct {
 	// then by default Secrets Manager uses a 30-day recovery window.
 	// see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
 	// +optional
+	// +kubebuilder:validation:Format=""
 	RecoveryWindowInDays int64 `json:"recoveryWindowInDays,omitempty"`
 }
 

+ 2 - 0
apis/externalsecrets/v1/secretstore_github_types.go

@@ -32,9 +32,11 @@ type GithubProvider struct {
 	Auth GithubAppAuth `json:"auth"`
 
 	// appID specifies the Github APP that will be used to authenticate the client
+	// +kubebuilder:validation:Format=""
 	AppID int64 `json:"appID"`
 
 	// installationID specifies the Github APP installation that will be used to authenticate the client
+	// +kubebuilder:validation:Format=""
 	InstallationID int64 `json:"installationID"`
 
 	// organization will be used to fetch secrets from the Github organization

+ 39 - 0
apis/externalsecrets/v1/secretstore_runtime_ref_test.go

@@ -0,0 +1,39 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1
+
+import "testing"
+
+func TestSecretStoreSpecDeepCopyPreservesRuntimeRef(t *testing.T) {
+	spec := &SecretStoreSpec{
+		RuntimeRef: &StoreRuntimeRef{
+			Kind: "ClusterProviderClass",
+			Name: "aws",
+		},
+	}
+
+	out := spec.DeepCopy()
+	if out.RuntimeRef == nil {
+		t.Fatalf("expected RuntimeRef to be copied")
+	}
+	if out.RuntimeRef.Name != "aws" || out.RuntimeRef.Kind != "ClusterProviderClass" {
+		t.Fatalf("unexpected RuntimeRef copy: %#v", out.RuntimeRef)
+	}
+	if out.RuntimeRef == spec.RuntimeRef {
+		t.Fatalf("expected RuntimeRef to be deep-copied")
+	}
+}

+ 20 - 0
apis/externalsecrets/v1/secretstore_types.go

@@ -21,6 +21,21 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// StoreRuntimeRef identifies the runtime configuration used by a store.
+type StoreRuntimeRef struct {
+	// Kind identifies the runtime resource type referenced by this store.
+	// +kubebuilder:validation:Enum=ClusterProviderClass
+	// +kubebuilder:default=ClusterProviderClass
+	// +optional
+	Kind string `json:"kind,omitempty"`
+
+	// Name is the runtime resource name referenced by this store.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+	Name string `json:"name"`
+}
+
 // SecretStoreSpec defines the desired state of SecretStore.
 type SecretStoreSpec struct {
 	// Used to select the correct ESO controller (think: ingress.ingressClassName)
@@ -42,6 +57,10 @@ type SecretStoreSpec struct {
 	// Used to constrain a ClusterSecretStore to specific namespaces. Relevant only to ClusterSecretStore.
 	// +optional
 	Conditions []ClusterSecretStoreCondition `json:"conditions,omitempty"`
+
+	// RuntimeRef points to runtime configuration for this store.
+	// +optional
+	RuntimeRef *StoreRuntimeRef `json:"runtimeRef,omitempty"`
 }
 
 // ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in
@@ -271,6 +290,7 @@ type CAProvider struct {
 
 // SecretStoreRetrySettings defines the retry settings for accessing external secrets manager stores.
 type SecretStoreRetrySettings struct {
+	// +kubebuilder:validation:Format=""
 	MaxRetries    *int32  `json:"maxRetries,omitempty"`
 	RetryInterval *string `json:"retryInterval,omitempty"`
 }

+ 1 - 1
apis/externalsecrets/v1/secretstore_validator_test.go

@@ -27,7 +27,7 @@ import (
 
 // ValidationProvider is a simple provider that we can use without cyclic import.
 type ValidationProvider struct {
-	Provider
+	ProviderInterface
 }
 
 func (v *ValidationProvider) ValidateStore(_ GenericStore) (admission.Warnings, error) {

+ 1 - 0
apis/externalsecrets/v1/secretstore_vault_types.go

@@ -301,6 +301,7 @@ type VaultKubernetesServiceAccountTokenAuth struct {
 	// Deprecated: this will be removed in the future.
 	// Defaults to 10 minutes.
 	// +optional
+	// +kubebuilder:validation:Format=""
 	ExpirationSeconds *int64 `json:"expirationSeconds,omitempty"`
 }
 

+ 20 - 0
apis/externalsecrets/v1/zz_generated.deepcopy.go

@@ -3723,6 +3723,11 @@ func (in *SecretStoreSpec) DeepCopyInto(out *SecretStoreSpec) {
 			(*in)[i].DeepCopyInto(&(*out)[i])
 		}
 	}
+	if in.RuntimeRef != nil {
+		in, out := &in.RuntimeRef, &out.RuntimeRef
+		*out = new(StoreRuntimeRef)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreSpec.
@@ -3845,6 +3850,21 @@ func (in *StoreGeneratorSourceRef) DeepCopy() *StoreGeneratorSourceRef {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StoreRuntimeRef) DeepCopyInto(out *StoreRuntimeRef) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreRuntimeRef.
+func (in *StoreRuntimeRef) DeepCopy() *StoreRuntimeRef {
+	if in == nil {
+		return nil
+	}
+	out := new(StoreRuntimeRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *StoreSourceRef) DeepCopyInto(out *StoreSourceRef) {
 	*out = *in

+ 53 - 0
apis/externalsecrets/v1alpha1/clusterproviderclass_types.go

@@ -0,0 +1,53 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+// ClusterProviderClassSpec defines the desired state of ClusterProviderClass.
+type ClusterProviderClassSpec struct {
+	// +kubebuilder:validation:MinLength:=1
+	Address string `json:"address"`
+}
+
+// ClusterProviderClassStatus defines the observed state of ClusterProviderClass.
+type ClusterProviderClassStatus struct {
+	Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Cluster,categories={externalsecrets},shortName=cpc
+// +kubebuilder:printcolumn:name="Address",type=string,JSONPath=`.spec.address`
+
+// ClusterProviderClass is a cluster-scoped store runtime class.
+type ClusterProviderClass struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   ClusterProviderClassSpec   `json:"spec"`
+	Status ClusterProviderClassStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ClusterProviderClassList contains a list of ClusterProviderClass.
+type ClusterProviderClassList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []ClusterProviderClass `json:"items"`
+}

+ 38 - 0
apis/externalsecrets/v1alpha1/clusterproviderclass_types_test.go

@@ -0,0 +1,38 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	"testing"
+
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+func TestAddToSchemeRegistersClusterProviderClass(t *testing.T) {
+	s := runtime.NewScheme()
+	if err := AddToScheme(s); err != nil {
+		t.Fatalf("AddToScheme() error = %v", err)
+	}
+
+	obj, err := s.New(SchemeGroupVersion.WithKind("ClusterProviderClass"))
+	if err != nil {
+		t.Fatalf("scheme.New() error = %v", err)
+	}
+	if _, ok := obj.(*ClusterProviderClass); !ok {
+		t.Fatalf("expected *ClusterProviderClass, got %T", obj)
+	}
+}

+ 192 - 0
apis/externalsecrets/v1alpha1/pushsecret_crd_test.go

@@ -0,0 +1,192 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	"os"
+	"path/filepath"
+	"slices"
+	"testing"
+
+	"sigs.k8s.io/yaml"
+)
+
+func TestPushSecretCRDDoesNotDefaultSecretStoreRefKind(t *testing.T) {
+	crdPath := filepath.Join("..", "..", "..", "config", "crds", "bases", "external-secrets.io_pushsecrets.yaml")
+	data, err := os.ReadFile(crdPath)
+	if err != nil {
+		t.Fatalf("read CRD: %v", err)
+	}
+
+	var crd map[string]any
+	if err := yaml.Unmarshal(data, &crd); err != nil {
+		t.Fatalf("unmarshal CRD: %v", err)
+	}
+
+	versions := asSlice(t, asMap(t, crd["spec"], "spec")["versions"], "spec.versions")
+	var kindSchema map[string]any
+	for _, version := range versions {
+		versionMap := asMap(t, version, "spec.versions[]")
+		if versionMap["name"] != Version {
+			continue
+		}
+
+		schema := asMap(t, versionMap["schema"], "spec.versions[].schema")
+		openAPIV3 := asMap(t, schema["openAPIV3Schema"], "spec.versions[].schema.openAPIV3Schema")
+		properties := asMap(t, openAPIV3["properties"], "spec.versions[].schema.openAPIV3Schema.properties")
+		specProperties := asMap(t, asMap(t, properties["spec"], "spec property")["properties"], "spec.properties")
+		secretStoreRefs := asMap(t, specProperties["secretStoreRefs"], "spec.properties.secretStoreRefs")
+		items := asMap(t, secretStoreRefs["items"], "spec.properties.secretStoreRefs.items")
+		itemProperties := asMap(t, items["properties"], "spec.properties.secretStoreRefs.items.properties")
+		kindSchema = asMap(t, itemProperties["kind"], "spec.properties.secretStoreRefs.items.properties.kind")
+		break
+	}
+
+	if kindSchema == nil {
+		t.Fatal("did not find v1alpha1 secretStoreRefs.kind schema")
+	}
+	if def, ok := kindSchema["default"]; ok {
+		t.Fatalf("secretStoreRefs.kind must not define a CRD default, got %v", def)
+	}
+}
+
+func TestPushSecretCRDSecretStoreRefKindIncludesProviderStoreKinds(t *testing.T) {
+	crdPath := filepath.Join("..", "..", "..", "config", "crds", "bases", "external-secrets.io_pushsecrets.yaml")
+	data, err := os.ReadFile(crdPath)
+	if err != nil {
+		t.Fatalf("read CRD: %v", err)
+	}
+
+	var crd map[string]any
+	if err := yaml.Unmarshal(data, &crd); err != nil {
+		t.Fatalf("unmarshal CRD: %v", err)
+	}
+
+	versions := asSlice(t, asMap(t, crd["spec"], "spec")["versions"], "spec.versions")
+	var kindEnum []string
+	for _, version := range versions {
+		versionMap := asMap(t, version, "spec.versions[]")
+		if versionMap["name"] != Version {
+			continue
+		}
+
+		schema := asMap(t, versionMap["schema"], "spec.versions[].schema")
+		openAPIV3 := asMap(t, schema["openAPIV3Schema"], "spec.versions[].schema.openAPIV3Schema")
+		properties := asMap(t, openAPIV3["properties"], "spec.versions[].schema.openAPIV3Schema.properties")
+		specProperties := asMap(t, asMap(t, properties["spec"], "spec property")["properties"], "spec.properties")
+		secretStoreRefs := asMap(t, specProperties["secretStoreRefs"], "spec.properties.secretStoreRefs")
+		items := asMap(t, secretStoreRefs["items"], "spec.properties.secretStoreRefs.items")
+		itemProperties := asMap(t, items["properties"], "spec.properties.secretStoreRefs.items.properties")
+		kindSchema := asMap(t, itemProperties["kind"], "spec.properties.secretStoreRefs.items.properties.kind")
+		kindEnum = asStringSlice(t, kindSchema["enum"], "spec.properties.secretStoreRefs.items.properties.kind.enum")
+		break
+	}
+	if kindEnum == nil {
+		t.Fatal("did not find v1alpha1 secretStoreRefs.kind enum")
+	}
+
+	assertContains := func(value string) {
+		t.Helper()
+		if slices.Contains(kindEnum, value) {
+			return
+		}
+		t.Fatalf("kind enum does not contain %q: %v", value, kindEnum)
+	}
+
+	assertContains("ProviderStore")
+	assertContains("ClusterProviderStore")
+	assertNotContains := func(value string) {
+		t.Helper()
+		if slices.Contains(kindEnum, value) {
+			t.Fatalf("kind enum unexpectedly contains %q: %v", value, kindEnum)
+		}
+	}
+
+	assertNotContains("Provider")
+	assertNotContains("ClusterProvider")
+}
+
+func TestPushSecretCRDDoesNotDefaultSecretStoreRefAPIVersion(t *testing.T) {
+	crdPath := filepath.Join("..", "..", "..", "config", "crds", "bases", "external-secrets.io_pushsecrets.yaml")
+	data, err := os.ReadFile(crdPath)
+	if err != nil {
+		t.Fatalf("read CRD: %v", err)
+	}
+
+	var crd map[string]any
+	if err := yaml.Unmarshal(data, &crd); err != nil {
+		t.Fatalf("unmarshal CRD: %v", err)
+	}
+
+	versions := asSlice(t, asMap(t, crd["spec"], "spec")["versions"], "spec.versions")
+	var apiVersionSchema map[string]any
+	for _, version := range versions {
+		versionMap := asMap(t, version, "spec.versions[]")
+		if versionMap["name"] != Version {
+			continue
+		}
+
+		schema := asMap(t, versionMap["schema"], "spec.versions[].schema")
+		openAPIV3 := asMap(t, schema["openAPIV3Schema"], "spec.versions[].schema.openAPIV3Schema")
+		properties := asMap(t, openAPIV3["properties"], "spec.versions[].schema.openAPIV3Schema.properties")
+		specProperties := asMap(t, asMap(t, properties["spec"], "spec property")["properties"], "spec.properties")
+		secretStoreRefs := asMap(t, specProperties["secretStoreRefs"], "spec.properties.secretStoreRefs")
+		items := asMap(t, secretStoreRefs["items"], "spec.properties.secretStoreRefs.items")
+		itemProperties := asMap(t, items["properties"], "spec.properties.secretStoreRefs.items.properties")
+		apiVersionSchema = asMap(t, itemProperties["apiVersion"], "spec.properties.secretStoreRefs.items.properties.apiVersion")
+		break
+	}
+
+	if apiVersionSchema == nil {
+		t.Fatal("did not find v1alpha1 secretStoreRefs.apiVersion schema")
+	}
+	if def, ok := apiVersionSchema["default"]; ok {
+		t.Fatalf("secretStoreRefs.apiVersion must not define a CRD default, got %v", def)
+	}
+}
+
+func asMap(t *testing.T, v any, path string) map[string]any {
+	t.Helper()
+	m, ok := v.(map[string]any)
+	if !ok {
+		t.Fatalf("%s is %T, want map[string]any", path, v)
+	}
+	return m
+}
+
+func asSlice(t *testing.T, v any, path string) []any {
+	t.Helper()
+	s, ok := v.([]any)
+	if !ok {
+		t.Fatalf("%s is %T, want []any", path, v)
+	}
+	return s
+}
+
+func asStringSlice(t *testing.T, v any, path string) []string {
+	t.Helper()
+	s := asSlice(t, v, path)
+	out := make([]string, 0, len(s))
+	for i, entry := range s {
+		str, ok := entry.(string)
+		if !ok {
+			t.Fatalf("%s[%d] is %T, want string", path, i, entry)
+		}
+		out = append(out, str)
+	}
+	return out
+}

+ 7 - 3
apis/externalsecrets/v1alpha1/pushsecret_types.go

@@ -47,11 +47,15 @@ type PushSecretStoreRef struct {
 	// +optional
 	LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
 
-	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+	// Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
 	// +optional
-	// +kubebuilder:default="SecretStore"
-	// +kubebuilder:validation:Enum=SecretStore;ClusterSecretStore
+	// +kubebuilder:validation:Enum=SecretStore;ClusterSecretStore;ProviderStore;ClusterProviderStore
 	Kind string `json:"kind,omitempty"`
+
+	// APIVersion of the referenced store resource.
+	// This field is optional and depends on the selected store kind.
+	// +optional
+	APIVersion string `json:"apiVersion,omitempty"`
 }
 
 // PushSecretUpdatePolicy defines how push secrets are updated in the provider.

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

@@ -62,6 +62,7 @@ var (
 )
 
 func init() {
+	SchemeBuilder.Register(&ClusterProviderClass{}, &ClusterProviderClassList{})
 	SchemeBuilder.Register(&PushSecret{}, &PushSecretList{})
 	SchemeBuilder.Register(&ClusterPushSecret{}, &ClusterPushSecretList{})
 }

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

@@ -27,6 +27,102 @@ import (
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClusterProviderClass) DeepCopyInto(out *ClusterProviderClass) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	out.Spec = in.Spec
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderClass.
+func (in *ClusterProviderClass) DeepCopy() *ClusterProviderClass {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderClass)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterProviderClass) 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 *ClusterProviderClassList) DeepCopyInto(out *ClusterProviderClassList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]ClusterProviderClass, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderClassList.
+func (in *ClusterProviderClassList) DeepCopy() *ClusterProviderClassList {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderClassList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterProviderClassList) 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 *ClusterProviderClassSpec) DeepCopyInto(out *ClusterProviderClassSpec) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderClassSpec.
+func (in *ClusterProviderClassSpec) DeepCopy() *ClusterProviderClassSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderClassSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClusterProviderClassStatus) DeepCopyInto(out *ClusterProviderClassStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]v1.Condition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderClassStatus.
+func (in *ClusterProviderClassStatus) DeepCopy() *ClusterProviderClassStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderClassStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ClusterPushSecret) DeepCopyInto(out *ClusterPushSecret) {
 	*out = *in

+ 116 - 0
apis/externalsecrets/v1beta1/externalsecret_crd_test.go

@@ -0,0 +1,116 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1beta1
+
+import (
+	"os"
+	"path/filepath"
+	"slices"
+	"testing"
+
+	"sigs.k8s.io/yaml"
+)
+
+func TestExternalSecretCRDSecretStoreRefKindOmitsProviderKinds(t *testing.T) {
+	kindEnum := externalSecretCRDKindEnum(t, "v1beta1")
+
+	assertContains := func(value string) {
+		t.Helper()
+		if slices.Contains(kindEnum, value) {
+			return
+		}
+		t.Fatalf("kind enum does not contain %q: %v", value, kindEnum)
+	}
+
+	assertNotContains := func(value string) {
+		t.Helper()
+		if slices.Contains(kindEnum, value) {
+			t.Fatalf("kind enum unexpectedly contains %q: %v", value, kindEnum)
+		}
+	}
+
+	assertContains("ProviderStore")
+	assertContains("ClusterProviderStore")
+	assertNotContains("Provider")
+	assertNotContains("ClusterProvider")
+}
+
+func externalSecretCRDKindEnum(t *testing.T, versionName string) []string {
+	t.Helper()
+
+	crdPath := filepath.Join("..", "..", "..", "config", "crds", "bases", "external-secrets.io_externalsecrets.yaml")
+	data, err := os.ReadFile(crdPath)
+	if err != nil {
+		t.Fatalf("read CRD: %v", err)
+	}
+
+	var crd map[string]any
+	if err := yaml.Unmarshal(data, &crd); err != nil {
+		t.Fatalf("unmarshal CRD: %v", err)
+	}
+
+	versions := asSlice(t, asMap(t, crd["spec"], "spec")["versions"], "spec.versions")
+	for _, version := range versions {
+		versionMap := asMap(t, version, "spec.versions[]")
+		if versionMap["name"] != versionName {
+			continue
+		}
+
+		schema := asMap(t, versionMap["schema"], "spec.versions[].schema")
+		openAPIV3 := asMap(t, schema["openAPIV3Schema"], "spec.versions[].schema.openAPIV3Schema")
+		properties := asMap(t, openAPIV3["properties"], "spec.versions[].schema.openAPIV3Schema.properties")
+		specProperties := asMap(t, asMap(t, properties["spec"], "spec property")["properties"], "spec.properties")
+		secretStoreRef := asMap(t, asMap(t, specProperties["secretStoreRef"], "spec.properties.secretStoreRef")["properties"], "spec.properties.secretStoreRef.properties")
+		kindSchema := asMap(t, secretStoreRef["kind"], "spec.properties.secretStoreRef.properties.kind")
+		return asStringSlice(t, kindSchema["enum"], "spec.properties.secretStoreRef.properties.kind.enum")
+	}
+
+	t.Fatalf("did not find %s secretStoreRef.kind enum", versionName)
+	return nil
+}
+
+func asMap(t *testing.T, v any, path string) map[string]any {
+	t.Helper()
+	m, ok := v.(map[string]any)
+	if !ok {
+		t.Fatalf("%s is %T, want map[string]any", path, v)
+	}
+	return m
+}
+
+func asSlice(t *testing.T, v any, path string) []any {
+	t.Helper()
+	s, ok := v.([]any)
+	if !ok {
+		t.Fatalf("%s is %T, want []any", path, v)
+	}
+	return s
+}
+
+func asStringSlice(t *testing.T, v any, path string) []string {
+	t.Helper()
+	s := asSlice(t, v, path)
+	out := make([]string, 0, len(s))
+	for i, entry := range s {
+		str, ok := entry.(string)
+		if !ok {
+			t.Fatalf("%s[%d] is %T, want string", path, i, entry)
+		}
+		out = append(out, str)
+	}
+	return out
+}

+ 2 - 2
apis/externalsecrets/v1beta1/externalsecret_types.go

@@ -29,10 +29,10 @@ type SecretStoreRef struct {
 	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
 	Name string `json:"name,omitempty"`
 
-	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+	// Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
 	// Defaults to `SecretStore`
 	// +optional
-	// +kubebuilder:validation:Enum=SecretStore;ClusterSecretStore
+	// +kubebuilder:validation:Enum=SecretStore;ClusterSecretStore;ProviderStore;ClusterProviderStore
 	Kind string `json:"kind,omitempty"`
 }
 

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

@@ -47,8 +47,8 @@ func (v ValidationResult) String() string {
 // +k8s:deepcopy-gen:interfaces=nil
 // +k8s:deepcopy-gen=nil
 
-// Provider is a common interface for interacting with secret backends.
-type Provider interface {
+// ProviderInterface is a common interface for interacting with secret backends.
+type ProviderInterface interface {
 	// NewClient constructs a SecretsManager Provider
 	NewClient(ctx context.Context, store GenericStore, kube client.Client, namespace string) (SecretsClient, error)
 

+ 6 - 6
apis/externalsecrets/v1beta1/provider_schema.go

@@ -23,16 +23,16 @@ import (
 	"sync"
 )
 
-var builder map[string]Provider
+var builder map[string]ProviderInterface
 var buildlock sync.RWMutex
 
 func init() {
-	builder = make(map[string]Provider)
+	builder = make(map[string]ProviderInterface)
 }
 
 // Register a store backend type. Register panics if a
 // backend with the same store is already registered.
-func Register(s Provider, storeSpec *SecretStoreProvider) {
+func Register(s ProviderInterface, storeSpec *SecretStoreProvider) {
 	storeName, err := getProviderName(storeSpec)
 	if err != nil {
 		panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
@@ -50,7 +50,7 @@ func Register(s Provider, storeSpec *SecretStoreProvider) {
 
 // ForceRegister adds to store schema, overwriting a store if
 // already registered. Should only be used for testing.
-func ForceRegister(s Provider, storeSpec *SecretStoreProvider) {
+func ForceRegister(s ProviderInterface, storeSpec *SecretStoreProvider) {
 	storeName, err := getProviderName(storeSpec)
 	if err != nil {
 		panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
@@ -62,7 +62,7 @@ func ForceRegister(s Provider, storeSpec *SecretStoreProvider) {
 }
 
 // GetProviderByName returns the provider implementation by name.
-func GetProviderByName(name string) (Provider, bool) {
+func GetProviderByName(name string) (ProviderInterface, bool) {
 	buildlock.RLock()
 	f, ok := builder[name]
 	buildlock.RUnlock()
@@ -70,7 +70,7 @@ func GetProviderByName(name string) (Provider, bool) {
 }
 
 // GetProvider returns the provider from the generic store.
-func GetProvider(s GenericStore) (Provider, error) {
+func GetProvider(s GenericStore) (ProviderInterface, error) {
 	if s == nil {
 		return nil, nil
 	}

+ 1 - 0
apis/externalsecrets/v1beta1/secretstore_aws_types.go

@@ -82,6 +82,7 @@ type SecretsManager struct {
 	// then by default Secrets Manager uses a 30 day recovery window.
 	// see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
 	// +optional
+	// +kubebuilder:validation:Format=""
 	RecoveryWindowInDays int64 `json:"recoveryWindowInDays,omitempty"`
 }
 

+ 2 - 0
apis/externalsecrets/v1beta1/secretstore_github_types.go

@@ -32,9 +32,11 @@ type GithubProvider struct {
 	Auth GithubAppAuth `json:"auth"`
 
 	// appID specifies the Github APP that will be used to authenticate the client
+	// +kubebuilder:validation:Format=""
 	AppID int64 `json:"appID"`
 
 	// installationID specifies the Github APP installation that will be used to authenticate the client
+	// +kubebuilder:validation:Format=""
 	InstallationID int64 `json:"installationID"`
 
 	// organization will be used to fetch secrets from the Github organization

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

@@ -21,6 +21,21 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// StoreRuntimeRef identifies the runtime configuration used by a store.
+type StoreRuntimeRef struct {
+	// Kind identifies the runtime resource type referenced by this store.
+	// +kubebuilder:validation:Enum=ClusterProviderClass
+	// +kubebuilder:default=ClusterProviderClass
+	// +optional
+	Kind string `json:"kind,omitempty"`
+
+	// Name is the runtime resource name referenced by this store.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+	Name string `json:"name"`
+}
+
 // SecretStoreSpec defines the desired state of SecretStore.
 type SecretStoreSpec struct {
 	// Used to select the correct ESO controller (think: ingress.ingressClassName)
@@ -42,6 +57,10 @@ type SecretStoreSpec struct {
 	// Used to constrain a ClusterSecretStore to specific namespaces. Relevant only to ClusterSecretStore.
 	// +optional
 	Conditions []ClusterSecretStoreCondition `json:"conditions,omitempty"`
+
+	// RuntimeRef points to runtime configuration for this store.
+	// +optional
+	RuntimeRef *StoreRuntimeRef `json:"runtimeRef,omitempty"`
 }
 
 // ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in

+ 1 - 1
apis/externalsecrets/v1beta1/secretstore_validator_test.go

@@ -26,7 +26,7 @@ import (
 
 // ValidationProvider is a simple provider that we can use without cyclic import.
 type ValidationProvider struct {
-	Provider
+	ProviderInterface
 }
 
 func (v *ValidationProvider) ValidateStore(_ GenericStore) (admission.Warnings, error) {

+ 1 - 0
apis/externalsecrets/v1beta1/secretstore_vault_types.go

@@ -290,6 +290,7 @@ type VaultKubernetesServiceAccountTokenAuth struct {
 	// Deprecated: this will be removed in the future.
 	// Defaults to 10 minutes.
 	// +optional
+	// +kubebuilder:validation:Format=""
 	ExpirationSeconds *int64 `json:"expirationSeconds,omitempty"`
 }
 

+ 20 - 0
apis/externalsecrets/v1beta1/zz_generated.deepcopy.go

@@ -2932,6 +2932,11 @@ func (in *SecretStoreSpec) DeepCopyInto(out *SecretStoreSpec) {
 			(*in)[i].DeepCopyInto(&(*out)[i])
 		}
 	}
+	if in.RuntimeRef != nil {
+		in, out := &in.RuntimeRef, &out.RuntimeRef
+		*out = new(StoreRuntimeRef)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreSpec.
@@ -3054,6 +3059,21 @@ func (in *StoreGeneratorSourceRef) DeepCopy() *StoreGeneratorSourceRef {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StoreRuntimeRef) DeepCopyInto(out *StoreRuntimeRef) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreRuntimeRef.
+func (in *StoreRuntimeRef) DeepCopy() *StoreRuntimeRef {
+	if in == nil {
+		return nil
+	}
+	out := new(StoreRuntimeRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *StoreSourceRef) DeepCopyInto(out *StoreSourceRef) {
 	*out = *in

+ 21 - 0
apis/externalsecrets/v2alpha1/doc.go

@@ -0,0 +1,21 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v2alpha1 contains clean store resources for external-secrets.
+// +kubebuilder:object:generate=true
+// +groupName=external-secrets.io
+// +versionName=v2alpha1
+package v2alpha1

+ 120 - 0
apis/externalsecrets/v2alpha1/generic_store.go

@@ -0,0 +1,120 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+// +kubebuilder:object:root=false
+// +kubebuilder:object:generate:false
+// +k8s:deepcopy-gen:interfaces=nil
+// +k8s:deepcopy-gen=nil
+
+// GenericStore is a common interface for interacting with ProviderStore
+// or ClusterProviderStore resources.
+type GenericStore interface {
+	runtime.Object
+	metav1.Object
+
+	GetKind() string
+	GetRuntimeRef() StoreRuntimeRef
+	GetBackendRef() BackendObjectReference
+	GetConditions() []StoreNamespaceCondition
+	GetStoreStatus() ProviderStoreStatus
+	SetStoreStatus(ProviderStoreStatus)
+	Copy() GenericStore
+}
+
+// +kubebuilder:object:root=false
+// +kubebuilder:object:generate:false
+var _ GenericStore = &ProviderStore{}
+
+// GetKind returns the resource kind for this ProviderStore.
+func (s *ProviderStore) GetKind() string {
+	return ProviderStoreKindStr
+}
+
+// GetRuntimeRef returns the runtime reference configured for this ProviderStore.
+func (s *ProviderStore) GetRuntimeRef() StoreRuntimeRef {
+	return s.Spec.RuntimeRef
+}
+
+// GetBackendRef returns the backend reference configured for this ProviderStore.
+func (s *ProviderStore) GetBackendRef() BackendObjectReference {
+	return s.Spec.BackendRef
+}
+
+// GetConditions returns namespace conditions for this store.
+func (s *ProviderStore) GetConditions() []StoreNamespaceCondition {
+	return nil
+}
+
+// GetStoreStatus returns the current status for this ProviderStore.
+func (s *ProviderStore) GetStoreStatus() ProviderStoreStatus {
+	return s.Status
+}
+
+// SetStoreStatus updates the current status for this ProviderStore.
+func (s *ProviderStore) SetStoreStatus(status ProviderStoreStatus) {
+	s.Status = status
+}
+
+// Copy returns a deep-copied GenericStore instance for this ProviderStore.
+func (s *ProviderStore) Copy() GenericStore {
+	return s.DeepCopy()
+}
+
+// +kubebuilder:object:root=false
+// +kubebuilder:object:generate:false
+var _ GenericStore = &ClusterProviderStore{}
+
+// GetKind returns the resource kind for this ClusterProviderStore.
+func (s *ClusterProviderStore) GetKind() string {
+	return ClusterProviderStoreKindStr
+}
+
+// GetRuntimeRef returns the runtime reference configured for this ClusterProviderStore.
+func (s *ClusterProviderStore) GetRuntimeRef() StoreRuntimeRef {
+	return s.Spec.RuntimeRef
+}
+
+// GetBackendRef returns the backend reference configured for this ClusterProviderStore.
+func (s *ClusterProviderStore) GetBackendRef() BackendObjectReference {
+	return s.Spec.BackendRef
+}
+
+// GetConditions returns namespace conditions for this store.
+func (s *ClusterProviderStore) GetConditions() []StoreNamespaceCondition {
+	return s.Spec.Conditions
+}
+
+// GetStoreStatus returns the current status for this ClusterProviderStore.
+func (s *ClusterProviderStore) GetStoreStatus() ProviderStoreStatus {
+	return s.Status
+}
+
+// SetStoreStatus updates the current status for this ClusterProviderStore.
+func (s *ClusterProviderStore) SetStoreStatus(status ProviderStoreStatus) {
+	s.Status = status
+}
+
+// Copy returns a deep-copied GenericStore instance for this ClusterProviderStore.
+func (s *ClusterProviderStore) Copy() GenericStore {
+	return s.DeepCopy()
+}

+ 184 - 0
apis/externalsecrets/v2alpha1/providerstore_types.go

@@ -0,0 +1,184 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// StoreRuntimeRef identifies the runtime configuration used by a store.
+type StoreRuntimeRef struct {
+	// Kind identifies the runtime resource type referenced by this store.
+	// +kubebuilder:validation:Enum=ClusterProviderClass
+	// +kubebuilder:default=ClusterProviderClass
+	// +optional
+	Kind string `json:"kind,omitempty"`
+
+	// Name is the runtime resource name referenced by this store.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+	Name string `json:"name"`
+}
+
+// BackendObjectReference identifies the provider-owned backend configuration object for a store.
+type BackendObjectReference struct {
+	// APIVersion of the referenced backend resource.
+	// +kubebuilder:validation:MinLength:=1
+	APIVersion string `json:"apiVersion"`
+
+	// Kind of the referenced backend resource.
+	// +kubebuilder:validation:MinLength:=1
+	Kind string `json:"kind"`
+
+	// Name of the referenced backend resource.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+	Name string `json:"name"`
+
+	// Namespace of the referenced backend resource.
+	// +optional
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=63
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+	Namespace string `json:"namespace,omitempty"`
+}
+
+// StoreNamespaceCondition describes conditions that constrain where a cluster store can be used from.
+type StoreNamespaceCondition struct {
+	// Choose namespace using a labelSelector.
+	// +optional
+	NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
+
+	// Choose namespaces by name.
+	// +optional
+	// +kubebuilder:validation:items:MinLength:=1
+	// +kubebuilder:validation:items:MaxLength:=63
+	// +kubebuilder:validation:items:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+	Namespaces []string `json:"namespaces,omitempty"`
+
+	// Choose namespaces by using regex matching.
+	// +optional
+	NamespaceRegexes []string `json:"namespaceRegexes,omitempty"`
+}
+
+// ProviderStoreConditionType is the type of a ProviderStore status condition.
+type ProviderStoreConditionType string
+
+const (
+	// ProviderStoreReady indicates that the store is ready and able to serve requests.
+	ProviderStoreReady ProviderStoreConditionType = "Ready"
+)
+
+// ProviderStoreCondition describes the state of a store at a certain point.
+type ProviderStoreCondition struct {
+	Type   ProviderStoreConditionType `json:"type"`
+	Status corev1.ConditionStatus     `json:"status"`
+
+	// +optional
+	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
+
+	// +optional
+	Reason string `json:"reason,omitempty"`
+
+	// +optional
+	Message string `json:"message,omitempty"`
+}
+
+// ProviderStoreStatus defines the observed state of a provider store.
+type ProviderStoreStatus struct {
+	// +optional
+	Conditions []ProviderStoreCondition `json:"conditions,omitempty"`
+}
+
+// ProviderStoreSpec defines the desired state of ProviderStore.
+type ProviderStoreSpec struct {
+	// RuntimeRef points to the runtime configuration used by this store.
+	RuntimeRef StoreRuntimeRef `json:"runtimeRef"`
+
+	// BackendRef references the provider-owned backend configuration object.
+	BackendRef BackendObjectReference `json:"backendRef"`
+}
+
+// ClusterProviderStoreSpec defines the desired state of ClusterProviderStore.
+type ClusterProviderStoreSpec struct {
+	// RuntimeRef points to the runtime configuration used by this store.
+	RuntimeRef StoreRuntimeRef `json:"runtimeRef"`
+
+	// BackendRef references the provider-owned backend configuration object.
+	BackendRef BackendObjectReference `json:"backendRef"`
+
+	// Conditions constrain where this ClusterProviderStore can be used from.
+	// +optional
+	Conditions []StoreNamespaceCondition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={externalsecrets},shortName=pstore
+// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
+// +kubebuilder:printcolumn:name="Runtime",type=string,JSONPath=`.spec.runtimeRef.name`
+// +kubebuilder:printcolumn:name="Backend",type=string,JSONPath=`.spec.backendRef.name`
+// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
+
+// ProviderStore is the namespaced clean store API.
+type ProviderStore struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   ProviderStoreSpec   `json:"spec,omitempty"`
+	Status ProviderStoreStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ProviderStoreList contains a list of ProviderStore.
+type ProviderStoreList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []ProviderStore `json:"items"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Cluster,categories={externalsecrets},shortName=cpstore
+// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
+// +kubebuilder:printcolumn:name="Runtime",type=string,JSONPath=`.spec.runtimeRef.name`
+// +kubebuilder:printcolumn:name="Backend",type=string,JSONPath=`.spec.backendRef.name`
+// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
+
+// ClusterProviderStore is the cluster-scoped clean store API.
+type ClusterProviderStore struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   ClusterProviderStoreSpec `json:"spec,omitempty"`
+	Status ProviderStoreStatus      `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ClusterProviderStoreList contains a list of ClusterProviderStore.
+type ClusterProviderStoreList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []ClusterProviderStore `json:"items"`
+}

+ 58 - 0
apis/externalsecrets/v2alpha1/providerstore_types_test.go

@@ -0,0 +1,58 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"testing"
+
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+func TestAddToSchemeRegistersProviderStores(t *testing.T) {
+	s := runtime.NewScheme()
+	if err := AddToScheme(s); err != nil {
+		t.Fatalf("AddToScheme() error = %v", err)
+	}
+
+	tests := []struct {
+		kind string
+	}{
+		{
+			kind: "ProviderStore",
+		},
+		{
+			kind: "ClusterProviderStore",
+		},
+	}
+
+	for _, tt := range tests {
+		obj, err := s.New(SchemeGroupVersion.WithKind(tt.kind))
+		if err != nil {
+			t.Fatalf("scheme.New(%q) error = %v", tt.kind, err)
+		}
+		switch tt.kind {
+		case "ProviderStore":
+			if _, ok := obj.(*ProviderStore); !ok {
+				t.Fatalf("expected *ProviderStore, got %T", obj)
+			}
+		case "ClusterProviderStore":
+			if _, ok := obj.(*ClusterProviderStore); !ok {
+				t.Fatalf("expected *ClusterProviderStore, got %T", obj)
+			}
+		}
+	}
+}

+ 84 - 0
apis/externalsecrets/v2alpha1/providerstore_validator.go

@@ -0,0 +1,84 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"regexp"
+
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// Ensures validators implement the admission.CustomValidator interface correctly.
+var _ admission.Validator[*ProviderStore] = &ProviderStoreValidator{}
+var _ admission.Validator[*ClusterProviderStore] = &ClusterProviderStoreValidator{}
+
+// ProviderStoreValidator implements webhook validation for ProviderStore resources.
+type ProviderStoreValidator struct{}
+
+// ClusterProviderStoreValidator implements webhook validation for ClusterProviderStore resources.
+type ClusterProviderStoreValidator struct{}
+
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
+func (r *ProviderStoreValidator) ValidateCreate(_ context.Context, obj *ProviderStore) (admission.Warnings, error) {
+	return nil, validateProviderStoreSpec(obj.Namespace, obj.Spec.BackendRef, nil)
+}
+
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
+func (r *ProviderStoreValidator) ValidateUpdate(_ context.Context, _, newObj *ProviderStore) (admission.Warnings, error) {
+	return nil, validateProviderStoreSpec(newObj.Namespace, newObj.Spec.BackendRef, nil)
+}
+
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
+func (r *ProviderStoreValidator) ValidateDelete(_ context.Context, _ *ProviderStore) (admission.Warnings, error) {
+	return nil, nil
+}
+
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
+func (r *ClusterProviderStoreValidator) ValidateCreate(_ context.Context, obj *ClusterProviderStore) (admission.Warnings, error) {
+	return nil, validateProviderStoreSpec("", obj.Spec.BackendRef, obj.Spec.Conditions)
+}
+
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
+func (r *ClusterProviderStoreValidator) ValidateUpdate(_ context.Context, _, newObj *ClusterProviderStore) (admission.Warnings, error) {
+	return nil, validateProviderStoreSpec("", newObj.Spec.BackendRef, newObj.Spec.Conditions)
+}
+
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
+func (r *ClusterProviderStoreValidator) ValidateDelete(_ context.Context, _ *ClusterProviderStore) (admission.Warnings, error) {
+	return nil, nil
+}
+
+func validateProviderStoreSpec(namespace string, backendRef BackendObjectReference, conditions []StoreNamespaceCondition) error {
+	var errs error
+
+	if namespace != "" && backendRef.Namespace != "" && backendRef.Namespace != namespace {
+		errs = errors.Join(errs, fmt.Errorf("backendRef.namespace %q must match metadata.namespace %q", backendRef.Namespace, namespace))
+	}
+
+	for ci, condition := range conditions {
+		for ri, expr := range condition.NamespaceRegexes {
+			if _, err := regexp.Compile(expr); err != nil {
+				errs = errors.Join(errs, fmt.Errorf("failed to compile %dth namespace regex in %dth condition: %w", ri, ci, err))
+			}
+		}
+	}
+
+	return errs
+}

+ 85 - 0
apis/externalsecrets/v2alpha1/providerstore_validator_test.go

@@ -0,0 +1,85 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"context"
+	"strings"
+	"testing"
+)
+
+func TestProviderStoreValidateCreateRejectsCrossNamespaceBackendRef(t *testing.T) {
+	store := &ProviderStore{
+		Spec: ProviderStoreSpec{
+			RuntimeRef: StoreRuntimeRef{Name: "runtime"},
+			BackendRef: BackendObjectReference{
+				APIVersion: "provider.aws.external-secrets.io/v2alpha1",
+				Kind:       "SecretsManagerStore",
+				Name:       "team-a-backend",
+				Namespace:  "team-b",
+			},
+		},
+	}
+	store.Namespace = "team-a"
+
+	if _, err := (&ProviderStoreValidator{}).ValidateCreate(context.Background(), store); err == nil {
+		t.Fatal("expected cross-namespace backendRef to be rejected")
+	}
+}
+
+func TestClusterProviderStoreValidateCreateAllowsOmittedBackendNamespace(t *testing.T) {
+	store := &ClusterProviderStore{
+		Spec: ClusterProviderStoreSpec{
+			RuntimeRef: StoreRuntimeRef{Name: "runtime"},
+			BackendRef: BackendObjectReference{
+				APIVersion: "provider.aws.external-secrets.io/v2alpha1",
+				Kind:       "SecretsManagerStore",
+				Name:       "shared-backend",
+			},
+		},
+	}
+
+	if _, err := (&ClusterProviderStoreValidator{}).ValidateCreate(context.Background(), store); err != nil {
+		t.Fatalf("expected omitted backendRef.namespace to be allowed: %v", err)
+	}
+}
+
+func TestClusterProviderStoreValidateCreateRejectsInvalidNamespaceRegex(t *testing.T) {
+	store := &ClusterProviderStore{
+		Spec: ClusterProviderStoreSpec{
+			RuntimeRef: StoreRuntimeRef{Name: "runtime"},
+			BackendRef: BackendObjectReference{
+				APIVersion: "provider.aws.external-secrets.io/v2alpha1",
+				Kind:       "SecretsManagerStore",
+				Name:       "shared-backend",
+			},
+			Conditions: []StoreNamespaceCondition{
+				{
+					NamespaceRegexes: []string{`\1`},
+				},
+			},
+		},
+	}
+
+	_, err := (&ClusterProviderStoreValidator{}).ValidateCreate(context.Background(), store)
+	if err == nil {
+		t.Fatal("expected invalid namespace regex to be rejected")
+	}
+	if !strings.Contains(err.Error(), "failed to compile 0th namespace regex in 0th condition") {
+		t.Fatalf("expected regex compilation failure, got: %v", err)
+	}
+}

+ 35 - 0
apis/externalsecrets/v2alpha1/providerstore_webhook.go

@@ -0,0 +1,35 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	ctrl "sigs.k8s.io/controller-runtime"
+)
+
+// SetupWebhookWithManager registers the ProviderStore webhook with the controller manager.
+func (s *ProviderStore) SetupWebhookWithManager(mgr ctrl.Manager) error {
+	return ctrl.NewWebhookManagedBy(mgr, s).
+		WithValidator(&ProviderStoreValidator{}).
+		Complete()
+}
+
+// SetupWebhookWithManager registers the ClusterProviderStore webhook with the controller manager.
+func (s *ClusterProviderStore) SetupWebhookWithManager(mgr ctrl.Manager) error {
+	return ctrl.NewWebhookManagedBy(mgr, s).
+		WithValidator(&ClusterProviderStoreValidator{}).
+		Complete()
+}

+ 68 - 0
apis/externalsecrets/v2alpha1/register.go

@@ -0,0 +1,68 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"reflect"
+
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+// Package type metadata.
+const (
+	Group   = "external-secrets.io"
+	Version = "v2alpha1"
+)
+
+var (
+	// SchemeGroupVersion is group version used to register these objects.
+	SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version}
+
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
+
+	// AddToScheme adds the types in this group version to the given scheme.
+	AddToScheme = SchemeBuilder.AddToScheme
+)
+
+// ProviderStore type metadata.
+var (
+	ProviderStoreKind             = reflect.TypeFor[ProviderStore]().Name()
+	ProviderStoreGroupKind        = schema.GroupKind{Group: Group, Kind: ProviderStoreKind}.String()
+	ProviderStoreKindAPIVersion   = ProviderStoreKind + "." + SchemeGroupVersion.String()
+	ProviderStoreGroupVersionKind = SchemeGroupVersion.WithKind(ProviderStoreKind)
+)
+
+// ClusterProviderStore type metadata.
+var (
+	ClusterProviderStoreKind             = reflect.TypeFor[ClusterProviderStore]().Name()
+	ClusterProviderStoreGroupKind        = schema.GroupKind{Group: Group, Kind: ClusterProviderStoreKind}.String()
+	ClusterProviderStoreKindAPIVersion   = ClusterProviderStoreKind + "." + SchemeGroupVersion.String()
+	ClusterProviderStoreGroupVersionKind = SchemeGroupVersion.WithKind(ClusterProviderStoreKind)
+)
+
+// Provider store kind string constants for consumer refs.
+const (
+	ProviderStoreKindStr        = "ProviderStore"
+	ClusterProviderStoreKindStr = "ClusterProviderStore"
+)
+
+func init() {
+	SchemeBuilder.Register(&ProviderStore{}, &ProviderStoreList{})
+	SchemeBuilder.Register(&ClusterProviderStore{}, &ClusterProviderStoreList{})
+}

+ 313 - 0
apis/externalsecrets/v2alpha1/zz_generated.deepcopy.go

@@ -0,0 +1,313 @@
+//go:build !ignore_autogenerated
+
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BackendObjectReference) DeepCopyInto(out *BackendObjectReference) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendObjectReference.
+func (in *BackendObjectReference) DeepCopy() *BackendObjectReference {
+	if in == nil {
+		return nil
+	}
+	out := new(BackendObjectReference)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClusterProviderStore) DeepCopyInto(out *ClusterProviderStore) {
+	*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 ClusterProviderStore.
+func (in *ClusterProviderStore) DeepCopy() *ClusterProviderStore {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderStore)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterProviderStore) 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 *ClusterProviderStoreList) DeepCopyInto(out *ClusterProviderStoreList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]ClusterProviderStore, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderStoreList.
+func (in *ClusterProviderStoreList) DeepCopy() *ClusterProviderStoreList {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderStoreList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterProviderStoreList) 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 *ClusterProviderStoreSpec) DeepCopyInto(out *ClusterProviderStoreSpec) {
+	*out = *in
+	out.RuntimeRef = in.RuntimeRef
+	out.BackendRef = in.BackendRef
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]StoreNamespaceCondition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderStoreSpec.
+func (in *ClusterProviderStoreSpec) DeepCopy() *ClusterProviderStoreSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderStoreSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClusterProviderStoreValidator) DeepCopyInto(out *ClusterProviderStoreValidator) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderStoreValidator.
+func (in *ClusterProviderStoreValidator) DeepCopy() *ClusterProviderStoreValidator {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterProviderStoreValidator)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ProviderStore) DeepCopyInto(out *ProviderStore) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	out.Spec = in.Spec
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderStore.
+func (in *ProviderStore) DeepCopy() *ProviderStore {
+	if in == nil {
+		return nil
+	}
+	out := new(ProviderStore)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ProviderStore) 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 *ProviderStoreCondition) DeepCopyInto(out *ProviderStoreCondition) {
+	*out = *in
+	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderStoreCondition.
+func (in *ProviderStoreCondition) DeepCopy() *ProviderStoreCondition {
+	if in == nil {
+		return nil
+	}
+	out := new(ProviderStoreCondition)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ProviderStoreList) DeepCopyInto(out *ProviderStoreList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]ProviderStore, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderStoreList.
+func (in *ProviderStoreList) DeepCopy() *ProviderStoreList {
+	if in == nil {
+		return nil
+	}
+	out := new(ProviderStoreList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ProviderStoreList) 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 *ProviderStoreSpec) DeepCopyInto(out *ProviderStoreSpec) {
+	*out = *in
+	out.RuntimeRef = in.RuntimeRef
+	out.BackendRef = in.BackendRef
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderStoreSpec.
+func (in *ProviderStoreSpec) DeepCopy() *ProviderStoreSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(ProviderStoreSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ProviderStoreStatus) DeepCopyInto(out *ProviderStoreStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]ProviderStoreCondition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderStoreStatus.
+func (in *ProviderStoreStatus) DeepCopy() *ProviderStoreStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(ProviderStoreStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ProviderStoreValidator) DeepCopyInto(out *ProviderStoreValidator) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderStoreValidator.
+func (in *ProviderStoreValidator) DeepCopy() *ProviderStoreValidator {
+	if in == nil {
+		return nil
+	}
+	out := new(ProviderStoreValidator)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StoreNamespaceCondition) DeepCopyInto(out *StoreNamespaceCondition) {
+	*out = *in
+	if in.NamespaceSelector != nil {
+		in, out := &in.NamespaceSelector, &out.NamespaceSelector
+		*out = new(v1.LabelSelector)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.Namespaces != nil {
+		in, out := &in.Namespaces, &out.Namespaces
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.NamespaceRegexes != nil {
+		in, out := &in.NamespaceRegexes, &out.NamespaceRegexes
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreNamespaceCondition.
+func (in *StoreNamespaceCondition) DeepCopy() *StoreNamespaceCondition {
+	if in == nil {
+		return nil
+	}
+	out := new(StoreNamespaceCondition)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StoreRuntimeRef) DeepCopyInto(out *StoreRuntimeRef) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreRuntimeRef.
+func (in *StoreRuntimeRef) DeepCopy() *StoreRuntimeRef {
+	if in == nil {
+		return nil
+	}
+	out := new(StoreRuntimeRef)
+	in.DeepCopyInto(out)
+	return out
+}

+ 37 - 36
apis/go.mod

@@ -5,70 +5,71 @@ go 1.26.2
 require (
 	github.com/google/go-cmp v0.7.0
 	github.com/stretchr/testify v1.11.1
-	k8s.io/api v0.35.0
-	k8s.io/apiextensions-apiserver v0.35.0
-	k8s.io/apimachinery v0.35.0
-	sigs.k8s.io/controller-runtime v0.23.1
+	k8s.io/api v0.35.2
+	k8s.io/apiextensions-apiserver v0.35.2
+	k8s.io/apimachinery v0.35.2
+	sigs.k8s.io/controller-runtime v0.23.3
+	sigs.k8s.io/yaml v1.6.0
 )
 
 require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/emicklei/go-restful/v3 v3.13.0 // indirect
 	github.com/evanphx/json-patch/v5 v5.9.11 // indirect
 	github.com/fsnotify/fsnotify v1.9.0 // indirect
 	github.com/fxamacker/cbor/v2 v2.9.0 // indirect
 	github.com/go-logr/logr v1.4.3 // indirect
-	github.com/go-openapi/jsonpointer v0.22.4 // indirect
-	github.com/go-openapi/jsonreference v0.21.4 // indirect
-	github.com/go-openapi/swag v0.25.4 // indirect
-	github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
-	github.com/go-openapi/swag/conv v0.25.4 // indirect
-	github.com/go-openapi/swag/fileutils v0.25.4 // indirect
-	github.com/go-openapi/swag/jsonname v0.25.4 // indirect
-	github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
-	github.com/go-openapi/swag/loading v0.25.4 // indirect
-	github.com/go-openapi/swag/mangling v0.25.4 // indirect
-	github.com/go-openapi/swag/netutils v0.25.4 // indirect
-	github.com/go-openapi/swag/stringutils v0.25.4 // indirect
-	github.com/go-openapi/swag/typeutils v0.25.4 // indirect
-	github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
+	github.com/go-openapi/jsonpointer v0.22.5 // indirect
+	github.com/go-openapi/jsonreference v0.21.5 // indirect
+	github.com/go-openapi/swag v0.25.5 // indirect
+	github.com/go-openapi/swag/cmdutils v0.25.5 // indirect
+	github.com/go-openapi/swag/conv v0.25.5 // indirect
+	github.com/go-openapi/swag/fileutils v0.25.5 // indirect
+	github.com/go-openapi/swag/jsonname v0.25.5 // indirect
+	github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
+	github.com/go-openapi/swag/loading v0.25.5 // indirect
+	github.com/go-openapi/swag/mangling v0.25.5 // indirect
+	github.com/go-openapi/swag/netutils v0.25.5 // indirect
+	github.com/go-openapi/swag/stringutils v0.25.5 // indirect
+	github.com/go-openapi/swag/typeutils v0.25.5 // indirect
+	github.com/go-openapi/swag/yamlutils v0.25.5 // indirect
 	github.com/google/btree v1.1.3 // indirect
 	github.com/google/gnostic-models v0.7.1 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/kr/text v0.2.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
-	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/onsi/ginkgo/v2 v2.28.0 // indirect
+	github.com/onsi/gomega v1.39.1 // indirect
+	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/prometheus/client_golang v1.23.2 // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
 	github.com/prometheus/common v0.67.5 // indirect
-	github.com/prometheus/procfs v0.19.2 // indirect
+	github.com/prometheus/procfs v0.20.1 // indirect
 	github.com/spf13/pflag v1.0.10 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
-	go.yaml.in/yaml/v2 v2.4.3 // indirect
+	go.yaml.in/yaml/v2 v2.4.4 // indirect
 	go.yaml.in/yaml/v3 v3.0.4 // indirect
-	golang.org/x/net v0.49.0 // indirect
-	golang.org/x/oauth2 v0.34.0 // indirect
-	golang.org/x/sync v0.19.0 // indirect
-	golang.org/x/sys v0.40.0 // indirect
-	golang.org/x/term v0.39.0 // indirect
-	golang.org/x/text v0.33.0 // indirect
-	golang.org/x/time v0.14.0 // indirect
+	golang.org/x/net v0.52.0 // indirect
+	golang.org/x/oauth2 v0.36.0 // indirect
+	golang.org/x/sync v0.20.0 // indirect
+	golang.org/x/sys v0.42.0 // indirect
+	golang.org/x/term v0.41.0 // indirect
+	golang.org/x/text v0.35.0 // indirect
+	golang.org/x/time v0.15.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
 	google.golang.org/protobuf v1.36.11 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	k8s.io/client-go v0.35.0 // indirect
-	k8s.io/klog/v2 v2.130.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect
-	k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
+	k8s.io/client-go v0.35.2 // indirect
+	k8s.io/klog/v2 v2.140.0 // indirect
+	k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf // indirect
+	k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
 	sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect
-	sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
-	sigs.k8s.io/yaml v1.6.0 // indirect
+	sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
 )

+ 84 - 83
apis/go.sum

@@ -4,10 +4,10 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
 github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
 github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
@@ -22,40 +22,40 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
 github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
 github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=
-github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=
-github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
-github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
-github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
-github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
-github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
-github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
-github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
-github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
-github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
-github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
-github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
-github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
-github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
-github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
-github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
-github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
-github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
-github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
-github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
-github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
-github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
-github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
-github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
-github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
-github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
-github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
-github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
-github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
-github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
-github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
+github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
+github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
+github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
+github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
+github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
+github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
+github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
+github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
+github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
+github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
+github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
+github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
+github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
+github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
+github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
+github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=
+github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
+github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
+github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=
+github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=
+github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=
+github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=
+github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
+github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
+github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
+github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
+github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
+github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM=
+github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM=
+github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
 github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
@@ -67,8 +67,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
+github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
+github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -89,22 +89,23 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
 github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
-github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
-github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
-github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
+github.com/onsi/ginkgo/v2 v2.28.0 h1:Rrf+lVLmtlBIKv6KrIGJCjyY8N36vDVcutbGJkyqjJc=
+github.com/onsi/ginkgo/v2 v2.28.0/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
+github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
+github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
 github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
 github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
 github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
 github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
 github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
-github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
-github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
+github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
+github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
 github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
 github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
 github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
@@ -123,28 +124,28 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
 go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
-go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
-go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
+go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
+go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
 go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
-golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
-golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
-golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
-golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
-golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
-golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
-golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
-golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
-golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
-golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
-golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
-golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
-golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
+golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
+golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
+golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
+golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
+golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
+golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
+golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
+golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
+golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
+golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
+golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
 gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
@@ -158,27 +159,27 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY=
-k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA=
-k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4=
-k8s.io/apiextensions-apiserver v0.35.0/go.mod h1:E1Ahk9SADaLQ4qtzYFkwUqusXTcaV2uw3l14aqpL2LU=
-k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8=
-k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
-k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE=
-k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o=
-k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
-k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY=
-k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
-k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=
-k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
-sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE=
-sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
+k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
+k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
+k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0=
+k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU=
+k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
+k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
+k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
+k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
+k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
+k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
+k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf h1:btPscg4cMql0XdYK2jLsJcNEKmACJz8l+U7geC06FiM=
+k8s.io/kube-openapi v0.0.0-20260304202019-5b3e3fdb0acf/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
+k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
+k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
+sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
 sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
+sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
 sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
 sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

+ 20 - 0
apis/provider/aws/v2alpha1/doc.go

@@ -0,0 +1,20 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v2alpha1 contains API Schema definitions for the AWS provider v2alpha1 API group.
+// +kubebuilder:object:generate=true
+// +groupName=provider.external-secrets.io
+package v2alpha1

+ 39 - 0
apis/provider/aws/v2alpha1/groupversion_info.go

@@ -0,0 +1,39 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+	// GroupVersion is group version used to register these objects.
+	GroupVersion = schema.GroupVersion{Group: "provider.external-secrets.io", Version: "v2alpha1"}
+
+	// SecretsManagerKind is the kind name used for SecretsManager resources.
+	SecretsManagerKind = "SecretsManager"
+
+	// ParameterStoreKind is the kind name used for ParameterStore resources.
+	ParameterStoreKind = "ParameterStore"
+
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+	// AddToScheme adds the types in this group-version to the given scheme.
+	AddToScheme = SchemeBuilder.AddToScheme
+)

+ 93 - 0
apis/provider/aws/v2alpha1/parameterstore_types.go

@@ -0,0 +1,93 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	v1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+// ParameterStoreSpec defines the desired state of ParameterStore.
+type ParameterStoreSpec struct {
+	// Auth defines the information necessary to authenticate against AWS
+	// if not set aws sdk will infer credentials from your environment
+	// see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+	// +optional
+	Auth v1.AWSAuth `json:"auth,omitempty"`
+
+	// Role is a Role ARN which the provider will assume
+	// +optional
+	Role string `json:"role,omitempty"`
+
+	// AWS Region to be used for the provider
+	Region string `json:"region"`
+
+	// AdditionalRoles is a chained list of Role ARNs which the provider will sequentially assume before assuming the Role
+	// +optional
+	AdditionalRoles []string `json:"additionalRoles,omitempty"`
+
+	// AWS External ID set on assumed IAM roles
+	ExternalID string `json:"externalID,omitempty"`
+
+	// AWS STS assume role session tags
+	// +optional
+	SessionTags []*v1.Tag `json:"sessionTags,omitempty"`
+
+	// AWS STS assume role transitive session tags. Required when multiple rules are used with the provider
+	// +optional
+	TransitiveTagKeys []string `json:"transitiveTagKeys,omitempty"`
+
+	// Prefix adds a prefix to all retrieved values.
+	// +optional
+	Prefix string `json:"prefix,omitempty"`
+}
+
+// ParameterStoreStatus defines the observed state of ParameterStore.
+type ParameterStoreStatus struct {
+	// Conditions represent the latest available observations of the resource's state.
+	// +optional
+	Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={externalsecrets},shortName=ssm
+// +kubebuilder:printcolumn:name="Region",type=string,JSONPath=`.spec.region`
+// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
+
+// ParameterStore is the Schema for AWS Parameter Store provider configuration.
+type ParameterStore struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   ParameterStoreSpec   `json:"spec,omitempty"`
+	Status ParameterStoreStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ParameterStoreList contains a list of ParameterStore.
+type ParameterStoreList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []ParameterStore `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&ParameterStore{}, &ParameterStoreList{})
+}

+ 97 - 0
apis/provider/aws/v2alpha1/secretsmanager_types.go

@@ -0,0 +1,97 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	v1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+// SecretsManagerSpec defines the desired state of SecretsManager.
+type SecretsManagerSpec struct {
+	// Auth defines the information necessary to authenticate against AWS
+	// if not set aws sdk will infer credentials from your environment
+	// see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+	// +optional
+	Auth v1.AWSAuth `json:"auth,omitempty"`
+
+	// Role is a Role ARN which the provider will assume
+	// +optional
+	Role string `json:"role,omitempty"`
+
+	// AWS Region to be used for the provider
+	Region string `json:"region"`
+
+	// AdditionalRoles is a chained list of Role ARNs which the provider will sequentially assume before assuming the Role
+	// +optional
+	AdditionalRoles []string `json:"additionalRoles,omitempty"`
+
+	// AWS External ID set on assumed IAM roles
+	ExternalID string `json:"externalID,omitempty"`
+
+	// AWS STS assume role session tags
+	// +optional
+	SessionTags []*v1.Tag `json:"sessionTags,omitempty"`
+
+	// SecretsManager defines how the provider behaves when interacting with AWS SecretsManager
+	// +optional
+	SecretsManager *v1.SecretsManager `json:"secretsManager,omitempty"`
+
+	// AWS STS assume role transitive session tags. Required when multiple rules are used with the provider
+	// +optional
+	TransitiveTagKeys []string `json:"transitiveTagKeys,omitempty"`
+
+	// Prefix adds a prefix to all retrieved values.
+	// +optional
+	Prefix string `json:"prefix,omitempty"`
+}
+
+// SecretsManagerStatus defines the observed state of SecretsManager.
+type SecretsManagerStatus struct {
+	// Conditions represent the latest available observations of the resource's state.
+	// +optional
+	Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={externalsecrets},shortName=sm
+// +kubebuilder:printcolumn:name="Region",type=string,JSONPath=`.spec.region`
+// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
+
+// SecretsManager is the Schema for AWS Secrets Manager provider configuration.
+type SecretsManager struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   SecretsManagerSpec   `json:"spec,omitempty"`
+	Status SecretsManagerStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// SecretsManagerList contains a list of SecretsManager.
+type SecretsManagerList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []SecretsManager `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&SecretsManager{}, &SecretsManagerList{})
+}

+ 268 - 0
apis/provider/aws/v2alpha1/zz_generated.deepcopy.go

@@ -0,0 +1,268 @@
+//go:build !ignore_autogenerated
+
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+	"github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ParameterStore) DeepCopyInto(out *ParameterStore) {
+	*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 ParameterStore.
+func (in *ParameterStore) DeepCopy() *ParameterStore {
+	if in == nil {
+		return nil
+	}
+	out := new(ParameterStore)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ParameterStore) 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 *ParameterStoreList) DeepCopyInto(out *ParameterStoreList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]ParameterStore, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterStoreList.
+func (in *ParameterStoreList) DeepCopy() *ParameterStoreList {
+	if in == nil {
+		return nil
+	}
+	out := new(ParameterStoreList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ParameterStoreList) 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 *ParameterStoreSpec) DeepCopyInto(out *ParameterStoreSpec) {
+	*out = *in
+	in.Auth.DeepCopyInto(&out.Auth)
+	if in.AdditionalRoles != nil {
+		in, out := &in.AdditionalRoles, &out.AdditionalRoles
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.SessionTags != nil {
+		in, out := &in.SessionTags, &out.SessionTags
+		*out = make([]*v1.Tag, len(*in))
+		for i := range *in {
+			if (*in)[i] != nil {
+				in, out := &(*in)[i], &(*out)[i]
+				*out = new(v1.Tag)
+				**out = **in
+			}
+		}
+	}
+	if in.TransitiveTagKeys != nil {
+		in, out := &in.TransitiveTagKeys, &out.TransitiveTagKeys
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterStoreSpec.
+func (in *ParameterStoreSpec) DeepCopy() *ParameterStoreSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(ParameterStoreSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ParameterStoreStatus) DeepCopyInto(out *ParameterStoreStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]metav1.Condition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterStoreStatus.
+func (in *ParameterStoreStatus) DeepCopy() *ParameterStoreStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(ParameterStoreStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretsManager) DeepCopyInto(out *SecretsManager) {
+	*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 SecretsManager.
+func (in *SecretsManager) DeepCopy() *SecretsManager {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretsManager)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SecretsManager) 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 *SecretsManagerList) DeepCopyInto(out *SecretsManagerList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]SecretsManager, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretsManagerList.
+func (in *SecretsManagerList) DeepCopy() *SecretsManagerList {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretsManagerList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SecretsManagerList) 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 *SecretsManagerSpec) DeepCopyInto(out *SecretsManagerSpec) {
+	*out = *in
+	in.Auth.DeepCopyInto(&out.Auth)
+	if in.AdditionalRoles != nil {
+		in, out := &in.AdditionalRoles, &out.AdditionalRoles
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.SessionTags != nil {
+		in, out := &in.SessionTags, &out.SessionTags
+		*out = make([]*v1.Tag, len(*in))
+		for i := range *in {
+			if (*in)[i] != nil {
+				in, out := &(*in)[i], &(*out)[i]
+				*out = new(v1.Tag)
+				**out = **in
+			}
+		}
+	}
+	if in.SecretsManager != nil {
+		in, out := &in.SecretsManager, &out.SecretsManager
+		*out = new(v1.SecretsManager)
+		**out = **in
+	}
+	if in.TransitiveTagKeys != nil {
+		in, out := &in.TransitiveTagKeys, &out.TransitiveTagKeys
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretsManagerSpec.
+func (in *SecretsManagerSpec) DeepCopy() *SecretsManagerSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretsManagerSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretsManagerStatus) DeepCopyInto(out *SecretsManagerStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]metav1.Condition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretsManagerStatus.
+func (in *SecretsManagerStatus) DeepCopy() *SecretsManagerStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretsManagerStatus)
+	in.DeepCopyInto(out)
+	return out
+}

+ 21 - 0
apis/provider/fake/v2alpha1/doc.go

@@ -0,0 +1,21 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v2alpha1 contains v2alpha1 API schema definitions for the Fake provider.
+// +kubebuilder:object:generate=true
+// +groupName=provider.external-secrets.io
+// +versionName=v2alpha1
+package v2alpha1

+ 36 - 0
apis/provider/fake/v2alpha1/groupversion_info.go

@@ -0,0 +1,36 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+	// GroupVersion is group version used to register these objects.
+	GroupVersion = schema.GroupVersion{Group: "provider.external-secrets.io", Version: "v2alpha1"}
+
+	// Kind is the kind name used for Fake resources.
+	Kind = "Fake"
+
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+	// AddToScheme adds the types in this group-version to the given scheme.
+	AddToScheme = SchemeBuilder.AddToScheme
+)

+ 75 - 0
apis/provider/fake/v2alpha1/types.go

@@ -0,0 +1,75 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+// Fake defines the configuration for the Fake provider.
+// This provider returns static key-value pairs for testing purposes.
+// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={external-secrets},shortName=fake
+// +genclient.
+type Fake struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec esv1.FakeProvider `json:"spec,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// FakeList contains a list of Fake resources.
+type FakeList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []Fake `json:"items"`
+}
+
+// FakeProviderSpec defines the desired state of Fake provider.
+// It matches the structure of v1.FakeProvider for easy conversion.
+// +kubebuilder:object:generate=true
+type FakeProviderSpec struct {
+	// Data defines the static key-value pairs to return.
+	Data []FakeProviderData `json:"data"`
+
+	// ValidationResult optionally specifies the validation result for testing.
+	// +optional
+	ValidationResult *string `json:"validationResult,omitempty"`
+}
+
+// FakeProviderData defines a key-value pair with optional version.
+// +kubebuilder:object:generate=true
+type FakeProviderData struct {
+	// Key is the secret key.
+	Key string `json:"key"`
+
+	// Value is the secret value.
+	Value string `json:"value"`
+
+	// Version is an optional version identifier.
+	// +optional
+	Version string `json:"version,omitempty"`
+}
+
+func init() {
+	SchemeBuilder.Register(&Fake{}, &FakeList{})
+}

+ 123 - 0
apis/provider/fake/v2alpha1/zz_generated.deepcopy.go

@@ -0,0 +1,123 @@
+//go:build !ignore_autogenerated
+
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+	runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Fake) DeepCopyInto(out *Fake) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Fake.
+func (in *Fake) DeepCopy() *Fake {
+	if in == nil {
+		return nil
+	}
+	out := new(Fake)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Fake) 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 *FakeList) DeepCopyInto(out *FakeList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Fake, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeList.
+func (in *FakeList) DeepCopy() *FakeList {
+	if in == nil {
+		return nil
+	}
+	out := new(FakeList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *FakeList) 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 *FakeProviderData) DeepCopyInto(out *FakeProviderData) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeProviderData.
+func (in *FakeProviderData) DeepCopy() *FakeProviderData {
+	if in == nil {
+		return nil
+	}
+	out := new(FakeProviderData)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *FakeProviderSpec) DeepCopyInto(out *FakeProviderSpec) {
+	*out = *in
+	if in.Data != nil {
+		in, out := &in.Data, &out.Data
+		*out = make([]FakeProviderData, len(*in))
+		copy(*out, *in)
+	}
+	if in.ValidationResult != nil {
+		in, out := &in.ValidationResult, &out.ValidationResult
+		*out = new(string)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeProviderSpec.
+func (in *FakeProviderSpec) DeepCopy() *FakeProviderSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(FakeProviderSpec)
+	in.DeepCopyInto(out)
+	return out
+}

+ 21 - 0
apis/provider/kubernetes/v2alpha1/doc.go

@@ -0,0 +1,21 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v2alpha1 contains resources for external-secrets
+// +kubebuilder:object:generate=true
+// +groupName=provider.external-secrets.io
+// +versionName=v2alpha1
+package v2alpha1

+ 36 - 0
apis/provider/kubernetes/v2alpha1/groupversion_info.go

@@ -0,0 +1,36 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v2alpha1
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+	// GroupVersion is group version used to register these objects.
+	GroupVersion = schema.GroupVersion{Group: "provider.external-secrets.io", Version: "v2alpha1"}
+
+	// Kind is the kind name used for Kubernetes resources.
+	Kind = "Kubernetes"
+
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+	// AddToScheme adds the types in this group-version to the given scheme.
+	AddToScheme = SchemeBuilder.AddToScheme
+)

+ 51 - 0
apis/provider/kubernetes/v2alpha1/types.go

@@ -0,0 +1,51 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v2alpha1 contains the v2alpha1 API definitions for provider resources.
+package v2alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	v1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+)
+
+// Kubernetes defines the configuration for the Kubernetes Secret provider.
+// This provider fetches secrets from Kubernetes Secrets in the same cluster.
+// It's primarily useful for testing and migration scenarios.
+// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={external-secrets}
+type Kubernetes struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec v1.KubernetesProvider `json:"spec,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// KubernetesList contains a list of Kubernetes resources.
+type KubernetesList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []Kubernetes `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&Kubernetes{}, &KubernetesList{})
+}

+ 83 - 0
apis/provider/kubernetes/v2alpha1/zz_generated.deepcopy.go

@@ -0,0 +1,83 @@
+//go:build !ignore_autogenerated
+
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v2alpha1
+
+import (
+	runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Kubernetes) DeepCopyInto(out *Kubernetes) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kubernetes.
+func (in *Kubernetes) DeepCopy() *Kubernetes {
+	if in == nil {
+		return nil
+	}
+	out := new(Kubernetes)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Kubernetes) 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 *KubernetesList) DeepCopyInto(out *KubernetesList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Kubernetes, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesList.
+func (in *KubernetesList) DeepCopy() *KubernetesList {
+	if in == nil {
+		return nil
+	}
+	out := new(KubernetesList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *KubernetesList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}

+ 18 - 6
config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml

@@ -200,11 +200,13 @@ spec:
                               properties:
                                 kind:
                                   description: |-
-                                    Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                    Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                     Defaults to `SecretStore`
                                   enum:
                                   - SecretStore
                                   - ClusterSecretStore
+                                  - ProviderStore
+                                  - ClusterProviderStore
                                   type: string
                                 name:
                                   description: Name of the SecretStore resource
@@ -466,11 +468,13 @@ spec:
                               properties:
                                 kind:
                                   description: |-
-                                    Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                    Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                     Defaults to `SecretStore`
                                   enum:
                                   - SecretStore
                                   - ClusterSecretStore
+                                  - ProviderStore
+                                  - ClusterProviderStore
                                   type: string
                                 name:
                                   description: Name of the SecretStore resource
@@ -509,11 +513,13 @@ spec:
                     properties:
                       kind:
                         description: |-
-                          Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                          Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                           Defaults to `SecretStore`
                         enum:
                         - SecretStore
                         - ClusterSecretStore
+                        - ProviderStore
+                        - ClusterProviderStore
                         type: string
                       name:
                         description: Name of the SecretStore resource
@@ -1081,11 +1087,13 @@ spec:
                               properties:
                                 kind:
                                   description: |-
-                                    Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                    Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                     Defaults to `SecretStore`
                                   enum:
                                   - SecretStore
                                   - ClusterSecretStore
+                                  - ProviderStore
+                                  - ClusterProviderStore
                                   type: string
                                 name:
                                   description: Name of the SecretStore resource
@@ -1285,11 +1293,13 @@ spec:
                               properties:
                                 kind:
                                   description: |-
-                                    Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                    Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                     Defaults to `SecretStore`
                                   enum:
                                   - SecretStore
                                   - ClusterSecretStore
+                                  - ProviderStore
+                                  - ClusterProviderStore
                                   type: string
                                 name:
                                   description: Name of the SecretStore resource
@@ -1328,11 +1338,13 @@ spec:
                     properties:
                       kind:
                         description: |-
-                          Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                          Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                           Defaults to `SecretStore`
                         enum:
                         - SecretStore
                         - ClusterSecretStore
+                        - ProviderStore
+                        - ClusterProviderStore
                         type: string
                       name:
                         description: Name of the SecretStore resource

+ 122 - 0
config/crds/bases/external-secrets.io_clusterproviderclasses.yaml

@@ -0,0 +1,122 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: clusterproviderclasses.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+    - externalsecrets
+    kind: ClusterProviderClass
+    listKind: ClusterProviderClassList
+    plural: clusterproviderclasses
+    shortNames:
+    - cpc
+    singular: clusterproviderclass
+  scope: Cluster
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.address
+      name: Address
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: ClusterProviderClass is a cluster-scoped store runtime class.
+        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: ClusterProviderClassSpec defines the desired state of ClusterProviderClass.
+            properties:
+              address:
+                minLength: 1
+                type: string
+            required:
+            - address
+            type: object
+          status:
+            description: ClusterProviderClassStatus defines the observed state of
+              ClusterProviderClass.
+            properties:
+              conditions:
+                items:
+                  description: Condition contains details for one aspect of the current
+                    state of this API Resource.
+                  properties:
+                    lastTransitionTime:
+                      description: |-
+                        lastTransitionTime is the last time the condition transitioned from one status to another.
+                        This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: |-
+                        message is a human readable message indicating details about the transition.
+                        This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: |-
+                        observedGeneration represents the .metadata.generation that the condition was set based upon.
+                        For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+                        with respect to the current state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: |-
+                        reason contains a programmatic identifier indicating the reason for the condition's last transition.
+                        Producers of specific condition types may define expected values and meanings for this field,
+                        and whether the values are considered a guaranteed API.
+                        The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        required:
+        - spec
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 212 - 0
config/crds/bases/external-secrets.io_clusterproviderstores.yaml

@@ -0,0 +1,212 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: clusterproviderstores.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+    - externalsecrets
+    kind: ClusterProviderStore
+    listKind: ClusterProviderStoreList
+    plural: clusterproviderstores
+    shortNames:
+    - cpstore
+    singular: clusterproviderstore
+  scope: Cluster
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .spec.runtimeRef.name
+      name: Runtime
+      type: string
+    - jsonPath: .spec.backendRef.name
+      name: Backend
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v2alpha1
+    schema:
+      openAPIV3Schema:
+        description: ClusterProviderStore is the cluster-scoped clean store API.
+        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: ClusterProviderStoreSpec defines the desired state of ClusterProviderStore.
+            properties:
+              backendRef:
+                description: BackendRef references the provider-owned backend configuration
+                  object.
+                properties:
+                  apiVersion:
+                    description: APIVersion of the referenced backend resource.
+                    minLength: 1
+                    type: string
+                  kind:
+                    description: Kind of the referenced backend resource.
+                    minLength: 1
+                    type: string
+                  name:
+                    description: Name of the referenced backend resource.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                  namespace:
+                    description: Namespace of the referenced backend resource.
+                    maxLength: 63
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                    type: string
+                required:
+                - apiVersion
+                - kind
+                - name
+                type: object
+              conditions:
+                description: Conditions constrain where this ClusterProviderStore
+                  can be used from.
+                items:
+                  description: StoreNamespaceCondition describes conditions that constrain
+                    where a cluster store can be used from.
+                  properties:
+                    namespaceRegexes:
+                      description: Choose namespaces by using regex matching.
+                      items:
+                        type: string
+                      type: array
+                    namespaceSelector:
+                      description: Choose namespace using a labelSelector.
+                      properties:
+                        matchExpressions:
+                          description: matchExpressions is a list of label selector
+                            requirements. The requirements are ANDed.
+                          items:
+                            description: |-
+                              A label selector requirement is a selector that contains values, a key, and an operator that
+                              relates the key and values.
+                            properties:
+                              key:
+                                description: key is the label key that the selector
+                                  applies to.
+                                type: string
+                              operator:
+                                description: |-
+                                  operator represents a key's relationship to a set of values.
+                                  Valid operators are In, NotIn, Exists and DoesNotExist.
+                                type: string
+                              values:
+                                description: |-
+                                  values is an array of string values. If the operator is In or NotIn,
+                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
+                                  the values array must be empty. This array is replaced during a strategic
+                                  merge patch.
+                                items:
+                                  type: string
+                                type: array
+                                x-kubernetes-list-type: atomic
+                            required:
+                            - key
+                            - operator
+                            type: object
+                          type: array
+                          x-kubernetes-list-type: atomic
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: |-
+                            matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+                            map is equivalent to an element of matchExpressions, whose key field is "key", the
+                            operator is "In", and the values array contains only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                      x-kubernetes-map-type: atomic
+                    namespaces:
+                      description: Choose namespaces by name.
+                      items:
+                        maxLength: 63
+                        minLength: 1
+                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                        type: string
+                      type: array
+                  type: object
+                type: array
+              runtimeRef:
+                description: RuntimeRef points to the runtime configuration used by
+                  this store.
+                properties:
+                  kind:
+                    default: ClusterProviderClass
+                    description: Kind identifies the runtime resource type referenced
+                      by this store.
+                    enum:
+                    - ClusterProviderClass
+                    type: string
+                  name:
+                    description: Name is the runtime resource name referenced by this
+                      store.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                required:
+                - name
+                type: object
+            required:
+            - backendRef
+            - runtimeRef
+            type: object
+          status:
+            description: ProviderStoreStatus defines the observed state of a provider
+              store.
+            properties:
+              conditions:
+                items:
+                  description: ProviderStoreCondition describes the state of a store
+                    at a certain point.
+                  properties:
+                    lastTransitionTime:
+                      format: date-time
+                      type: string
+                    message:
+                      type: string
+                    reason:
+                      type: string
+                    status:
+                      type: string
+                    type:
+                      description: ProviderStoreConditionType is the type of a ProviderStore
+                        status condition.
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 18 - 6
config/crds/bases/external-secrets.io_clusterpushsecrets.yaml

@@ -259,13 +259,19 @@ spec:
                           description: StoreRef specifies which SecretStore to push
                             to. Required.
                           properties:
+                            apiVersion:
+                              description: |-
+                                APIVersion of the referenced store resource.
+                                This field is optional and depends on the selected store kind.
+                              type: string
                             kind:
-                              default: SecretStore
-                              description: Kind of the SecretStore resource (SecretStore
-                                or ClusterSecretStore)
+                              description: Kind of the SecretStore resource (SecretStore,
+                                ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                               enum:
                               - SecretStore
                               - ClusterSecretStore
+                              - ProviderStore
+                              - ClusterProviderStore
                               type: string
                             labelSelector:
                               description: Optionally, sync to secret stores with
@@ -348,13 +354,19 @@ spec:
                       description: PushSecretStoreRef contains a reference on how
                         to sync to a SecretStore.
                       properties:
+                        apiVersion:
+                          description: |-
+                            APIVersion of the referenced store resource.
+                            This field is optional and depends on the selected store kind.
+                          type: string
                         kind:
-                          default: SecretStore
-                          description: Kind of the SecretStore resource (SecretStore
-                            or ClusterSecretStore)
+                          description: Kind of the SecretStore resource (SecretStore,
+                            ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                           enum:
                           - SecretStore
                           - ClusterSecretStore
+                          - ProviderStore
+                          - ClusterProviderStore
                           type: string
                         labelSelector:
                           description: Optionally, sync to secret stores with label

+ 40 - 9
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -544,7 +544,6 @@ spec:
                               ForceDeleteWithoutRecovery in the same call. If you don't use either,
                               then by default Secrets Manager uses a 30-day recovery window.
                               see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
-                            format: int64
                             type: integer
                         type: object
                       service:
@@ -2209,7 +2208,6 @@ spec:
                       appID:
                         description: appID specifies the Github APP that will be used
                           to authenticate the client
-                        format: int64
                         type: integer
                       auth:
                         description: auth configures how secret-manager authenticates
@@ -2254,7 +2252,6 @@ spec:
                       installationID:
                         description: installationID specifies the Github APP installation
                           that will be used to authenticate the client
-                        format: int64
                         type: integer
                       orgSecretVisibility:
                         description: |-
@@ -5328,7 +5325,6 @@ spec:
 
                                       Deprecated: this will be removed in the future.
                                       Defaults to 10 minutes.
-                                    format: int64
                                     type: integer
                                   serviceAccountRef:
                                     description: Service account field containing
@@ -6309,11 +6305,30 @@ spec:
                 description: Used to configure HTTP retries on failures.
                 properties:
                   maxRetries:
-                    format: int32
                     type: integer
                   retryInterval:
                     type: string
                 type: object
+              runtimeRef:
+                description: RuntimeRef points to runtime configuration for this store.
+                properties:
+                  kind:
+                    default: ClusterProviderClass
+                    description: Kind identifies the runtime resource type referenced
+                      by this store.
+                    enum:
+                    - ClusterProviderClass
+                    type: string
+                  name:
+                    description: Name is the runtime resource name referenced by this
+                      store.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                required:
+                - name
+                type: object
             required:
             - provider
             type: object
@@ -6974,7 +6989,6 @@ spec:
                               ForceDeleteWithoutRecovery in the same call. If you don't use either,
                               then by default Secrets Manager uses a 30 day recovery window.
                               see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
-                            format: int64
                             type: integer
                         type: object
                       service:
@@ -8279,7 +8293,6 @@ spec:
                       appID:
                         description: appID specifies the Github APP that will be used
                           to authenticate the client
-                        format: int64
                         type: integer
                       auth:
                         description: auth configures how secret-manager authenticates
@@ -8324,7 +8337,6 @@ spec:
                       installationID:
                         description: installationID specifies the Github APP installation
                           that will be used to authenticate the client
-                        format: int64
                         type: integer
                       organization:
                         description: organization will be used to fetch secrets from
@@ -10017,7 +10029,6 @@ spec:
 
                                       Deprecated: this will be removed in the future.
                                       Defaults to 10 minutes.
-                                    format: int64
                                     type: integer
                                   serviceAccountRef:
                                     description: Service account field containing
@@ -10836,6 +10847,26 @@ spec:
                     description: RetryInterval is the interval between retry attempts.
                     type: string
                 type: object
+              runtimeRef:
+                description: RuntimeRef points to runtime configuration for this store.
+                properties:
+                  kind:
+                    default: ClusterProviderClass
+                    description: Kind identifies the runtime resource type referenced
+                      by this store.
+                    enum:
+                    - ClusterProviderClass
+                    type: string
+                  name:
+                    description: Name is the runtime resource name referenced by this
+                      store.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                required:
+                - name
+                type: object
             required:
             - provider
             type: object

+ 18 - 6
config/crds/bases/external-secrets.io_externalsecrets.yaml

@@ -185,11 +185,13 @@ spec:
                           properties:
                             kind:
                               description: |-
-                                Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                 Defaults to `SecretStore`
                               enum:
                               - SecretStore
                               - ClusterSecretStore
+                              - ProviderStore
+                              - ClusterProviderStore
                               type: string
                             name:
                               description: Name of the SecretStore resource
@@ -449,11 +451,13 @@ spec:
                           properties:
                             kind:
                               description: |-
-                                Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                 Defaults to `SecretStore`
                               enum:
                               - SecretStore
                               - ClusterSecretStore
+                              - ProviderStore
+                              - ClusterProviderStore
                               type: string
                             name:
                               description: Name of the SecretStore resource
@@ -492,11 +496,13 @@ spec:
                 properties:
                   kind:
                     description: |-
-                      Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                      Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                       Defaults to `SecretStore`
                     enum:
                     - SecretStore
                     - ClusterSecretStore
+                    - ProviderStore
+                    - ClusterProviderStore
                     type: string
                   name:
                     description: Name of the SecretStore resource
@@ -932,11 +938,13 @@ spec:
                           properties:
                             kind:
                               description: |-
-                                Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                 Defaults to `SecretStore`
                               enum:
                               - SecretStore
                               - ClusterSecretStore
+                              - ProviderStore
+                              - ClusterProviderStore
                               type: string
                             name:
                               description: Name of the SecretStore resource
@@ -1135,11 +1143,13 @@ spec:
                           properties:
                             kind:
                               description: |-
-                                Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                                Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                                 Defaults to `SecretStore`
                               enum:
                               - SecretStore
                               - ClusterSecretStore
+                              - ProviderStore
+                              - ClusterProviderStore
                               type: string
                             name:
                               description: Name of the SecretStore resource
@@ -1178,11 +1188,13 @@ spec:
                 properties:
                   kind:
                     description: |-
-                      Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+                      Kind of the SecretStore resource (SecretStore, ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                       Defaults to `SecretStore`
                     enum:
                     - SecretStore
                     - ClusterSecretStore
+                    - ProviderStore
+                    - ClusterProviderStore
                     type: string
                   name:
                     description: Name of the SecretStore resource

+ 144 - 0
config/crds/bases/external-secrets.io_providerstores.yaml

@@ -0,0 +1,144 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: providerstores.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+    - externalsecrets
+    kind: ProviderStore
+    listKind: ProviderStoreList
+    plural: providerstores
+    shortNames:
+    - pstore
+    singular: providerstore
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .spec.runtimeRef.name
+      name: Runtime
+      type: string
+    - jsonPath: .spec.backendRef.name
+      name: Backend
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v2alpha1
+    schema:
+      openAPIV3Schema:
+        description: ProviderStore is the namespaced clean store API.
+        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: ProviderStoreSpec defines the desired state of ProviderStore.
+            properties:
+              backendRef:
+                description: BackendRef references the provider-owned backend configuration
+                  object.
+                properties:
+                  apiVersion:
+                    description: APIVersion of the referenced backend resource.
+                    minLength: 1
+                    type: string
+                  kind:
+                    description: Kind of the referenced backend resource.
+                    minLength: 1
+                    type: string
+                  name:
+                    description: Name of the referenced backend resource.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                  namespace:
+                    description: Namespace of the referenced backend resource.
+                    maxLength: 63
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                    type: string
+                required:
+                - apiVersion
+                - kind
+                - name
+                type: object
+              runtimeRef:
+                description: RuntimeRef points to the runtime configuration used by
+                  this store.
+                properties:
+                  kind:
+                    default: ClusterProviderClass
+                    description: Kind identifies the runtime resource type referenced
+                      by this store.
+                    enum:
+                    - ClusterProviderClass
+                    type: string
+                  name:
+                    description: Name is the runtime resource name referenced by this
+                      store.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                required:
+                - name
+                type: object
+            required:
+            - backendRef
+            - runtimeRef
+            type: object
+          status:
+            description: ProviderStoreStatus defines the observed state of a provider
+              store.
+            properties:
+              conditions:
+                items:
+                  description: ProviderStoreCondition describes the state of a store
+                    at a certain point.
+                  properties:
+                    lastTransitionTime:
+                      format: date-time
+                      type: string
+                    message:
+                      type: string
+                    reason:
+                      type: string
+                    status:
+                      type: string
+                    type:
+                      description: ProviderStoreConditionType is the type of a ProviderStore
+                        status condition.
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 18 - 6
config/crds/bases/external-secrets.io_pushsecrets.yaml

@@ -183,13 +183,19 @@ spec:
                       description: StoreRef specifies which SecretStore to push to.
                         Required.
                       properties:
+                        apiVersion:
+                          description: |-
+                            APIVersion of the referenced store resource.
+                            This field is optional and depends on the selected store kind.
+                          type: string
                         kind:
-                          default: SecretStore
-                          description: Kind of the SecretStore resource (SecretStore
-                            or ClusterSecretStore)
+                          description: Kind of the SecretStore resource (SecretStore,
+                            ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                           enum:
                           - SecretStore
                           - ClusterSecretStore
+                          - ProviderStore
+                          - ClusterProviderStore
                           type: string
                         labelSelector:
                           description: Optionally, sync to secret stores with label
@@ -272,13 +278,19 @@ spec:
                   description: PushSecretStoreRef contains a reference on how to sync
                     to a SecretStore.
                   properties:
+                    apiVersion:
+                      description: |-
+                        APIVersion of the referenced store resource.
+                        This field is optional and depends on the selected store kind.
+                      type: string
                     kind:
-                      default: SecretStore
-                      description: Kind of the SecretStore resource (SecretStore or
-                        ClusterSecretStore)
+                      description: Kind of the SecretStore resource (SecretStore,
+                        ClusterSecretStore, ProviderStore, or ClusterProviderStore)
                       enum:
                       - SecretStore
                       - ClusterSecretStore
+                      - ProviderStore
+                      - ClusterProviderStore
                       type: string
                     labelSelector:
                       description: Optionally, sync to secret stores with label selector

+ 40 - 9
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -544,7 +544,6 @@ spec:
                               ForceDeleteWithoutRecovery in the same call. If you don't use either,
                               then by default Secrets Manager uses a 30-day recovery window.
                               see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
-                            format: int64
                             type: integer
                         type: object
                       service:
@@ -2209,7 +2208,6 @@ spec:
                       appID:
                         description: appID specifies the Github APP that will be used
                           to authenticate the client
-                        format: int64
                         type: integer
                       auth:
                         description: auth configures how secret-manager authenticates
@@ -2254,7 +2252,6 @@ spec:
                       installationID:
                         description: installationID specifies the Github APP installation
                           that will be used to authenticate the client
-                        format: int64
                         type: integer
                       orgSecretVisibility:
                         description: |-
@@ -5328,7 +5325,6 @@ spec:
 
                                       Deprecated: this will be removed in the future.
                                       Defaults to 10 minutes.
-                                    format: int64
                                     type: integer
                                   serviceAccountRef:
                                     description: Service account field containing
@@ -6309,11 +6305,30 @@ spec:
                 description: Used to configure HTTP retries on failures.
                 properties:
                   maxRetries:
-                    format: int32
                     type: integer
                   retryInterval:
                     type: string
                 type: object
+              runtimeRef:
+                description: RuntimeRef points to runtime configuration for this store.
+                properties:
+                  kind:
+                    default: ClusterProviderClass
+                    description: Kind identifies the runtime resource type referenced
+                      by this store.
+                    enum:
+                    - ClusterProviderClass
+                    type: string
+                  name:
+                    description: Name is the runtime resource name referenced by this
+                      store.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                required:
+                - name
+                type: object
             required:
             - provider
             type: object
@@ -6974,7 +6989,6 @@ spec:
                               ForceDeleteWithoutRecovery in the same call. If you don't use either,
                               then by default Secrets Manager uses a 30 day recovery window.
                               see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
-                            format: int64
                             type: integer
                         type: object
                       service:
@@ -8279,7 +8293,6 @@ spec:
                       appID:
                         description: appID specifies the Github APP that will be used
                           to authenticate the client
-                        format: int64
                         type: integer
                       auth:
                         description: auth configures how secret-manager authenticates
@@ -8324,7 +8337,6 @@ spec:
                       installationID:
                         description: installationID specifies the Github APP installation
                           that will be used to authenticate the client
-                        format: int64
                         type: integer
                       organization:
                         description: organization will be used to fetch secrets from
@@ -10017,7 +10029,6 @@ spec:
 
                                       Deprecated: this will be removed in the future.
                                       Defaults to 10 minutes.
-                                    format: int64
                                     type: integer
                                   serviceAccountRef:
                                     description: Service account field containing
@@ -10836,6 +10847,26 @@ spec:
                     description: RetryInterval is the interval between retry attempts.
                     type: string
                 type: object
+              runtimeRef:
+                description: RuntimeRef points to runtime configuration for this store.
+                properties:
+                  kind:
+                    default: ClusterProviderClass
+                    description: Kind identifies the runtime resource type referenced
+                      by this store.
+                    enum:
+                    - ClusterProviderClass
+                    type: string
+                  name:
+                    description: Name is the runtime resource name referenced by this
+                      store.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                required:
+                - name
+                type: object
             required:
             - provider
             type: object

+ 0 - 2
config/crds/bases/generators.external-secrets.io_clustergenerators.yaml

@@ -1675,7 +1675,6 @@ spec:
 
                                           Deprecated: this will be removed in the future.
                                           Defaults to 10 minutes.
-                                        format: int64
                                         type: integer
                                       serviceAccountRef:
                                         description: Service account field containing
@@ -2165,7 +2164,6 @@ spec:
                         description: Used to configure http retries if failed
                         properties:
                           maxRetries:
-                            format: int32
                             type: integer
                           retryInterval:
                             type: string

+ 0 - 2
config/crds/bases/generators.external-secrets.io_vaultdynamicsecrets.yaml

@@ -546,7 +546,6 @@ spec:
 
                                   Deprecated: this will be removed in the future.
                                   Defaults to 10 minutes.
-                                format: int64
                                 type: integer
                               serviceAccountRef:
                                 description: Service account field containing the
@@ -1036,7 +1035,6 @@ spec:
                 description: Used to configure http retries if failed
                 properties:
                   maxRetries:
-                    format: int32
                     type: integer
                   retryInterval:
                     type: string

+ 7 - 0
config/crds/bases/kustomization.yaml

@@ -3,9 +3,12 @@ apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 resources:
   - external-secrets.io_clusterexternalsecrets.yaml
+  - external-secrets.io_clusterproviderclasses.yaml
+  - external-secrets.io_clusterproviderstores.yaml
   - external-secrets.io_clusterpushsecrets.yaml
   - external-secrets.io_clustersecretstores.yaml
   - external-secrets.io_externalsecrets.yaml
+  - external-secrets.io_providerstores.yaml
   - external-secrets.io_pushsecrets.yaml
   - external-secrets.io_secretstores.yaml
   - generators.external-secrets.io_acraccesstokens.yaml
@@ -25,3 +28,7 @@ resources:
   - generators.external-secrets.io_uuids.yaml
   - generators.external-secrets.io_vaultdynamicsecrets.yaml
   - generators.external-secrets.io_webhooks.yaml
+  - provider.external-secrets.io_fakes.yaml
+  - provider.external-secrets.io_kubernetes.yaml
+  - provider.external-secrets.io_parameterstores.yaml
+  - provider.external-secrets.io_secretsmanagers.yaml

+ 75 - 0
config/crds/bases/provider.external-secrets.io_fakes.yaml

@@ -0,0 +1,75 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: fakes.provider.external-secrets.io
+spec:
+  group: provider.external-secrets.io
+  names:
+    categories:
+    - external-secrets
+    kind: Fake
+    listKind: FakeList
+    plural: fakes
+    shortNames:
+    - fake
+    singular: fake
+  scope: Namespaced
+  versions:
+  - name: v2alpha1
+    schema:
+      openAPIV3Schema:
+        description: |-
+          Fake defines the configuration for the Fake provider.
+          This provider returns static key-value pairs for testing purposes.
+        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: FakeProvider configures a fake provider that returns static
+              values.
+            properties:
+              data:
+                items:
+                  description: FakeProviderData defines a key-value pair with optional
+                    version for the fake provider.
+                  properties:
+                    key:
+                      type: string
+                    value:
+                      type: string
+                    version:
+                      type: string
+                  required:
+                  - key
+                  - value
+                  type: object
+                type: array
+              validationResult:
+                description: ValidationResult is defined type for the number of validation
+                  results.
+                type: integer
+            required:
+            - data
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 265 - 0
config/crds/bases/provider.external-secrets.io_kubernetes.yaml

@@ -0,0 +1,265 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: kubernetes.provider.external-secrets.io
+spec:
+  group: provider.external-secrets.io
+  names:
+    categories:
+    - external-secrets
+    kind: Kubernetes
+    listKind: KubernetesList
+    plural: kubernetes
+    singular: kubernetes
+  scope: Namespaced
+  versions:
+  - name: v2alpha1
+    schema:
+      openAPIV3Schema:
+        description: |-
+          Kubernetes defines the configuration for the Kubernetes Secret provider.
+          This provider fetches secrets from Kubernetes Secrets in the same cluster.
+          It's primarily useful for testing and migration scenarios.
+        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: KubernetesProvider configures a store to sync secrets with
+              a Kubernetes instance.
+            properties:
+              auth:
+                description: Auth configures how secret-manager authenticates with
+                  a Kubernetes instance.
+                maxProperties: 1
+                minProperties: 1
+                properties:
+                  cert:
+                    description: has both clientCert and clientKey as secretKeySelector
+                    properties:
+                      clientCert:
+                        description: |-
+                          SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                          In some instances, `key` is a required field.
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                      clientKey:
+                        description: |-
+                          SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                          In some instances, `key` is a required field.
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                    type: object
+                  serviceAccount:
+                    description: points to a service account that should be used for
+                      authentication
+                    properties:
+                      audiences:
+                        description: |-
+                          Audience specifies the `aud` claim for the service account token
+                          If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                          then this audiences will be appended to the list
+                        items:
+                          type: string
+                        type: array
+                      name:
+                        description: The name of the ServiceAccount resource being
+                          referred to.
+                        maxLength: 253
+                        minLength: 1
+                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                        type: string
+                      namespace:
+                        description: |-
+                          Namespace of the resource being referred to.
+                          Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                        maxLength: 63
+                        minLength: 1
+                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                        type: string
+                    required:
+                    - name
+                    type: object
+                  token:
+                    description: use static token to authenticate with
+                    properties:
+                      bearerToken:
+                        description: |-
+                          SecretKeySelector is a reference to a specific 'key' within a Secret resource.
+                          In some instances, `key` is a required field.
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                    type: object
+                type: object
+              authRef:
+                description: A reference to a secret that contains the auth information.
+                properties:
+                  key:
+                    description: |-
+                      A key in the referenced Secret.
+                      Some instances of this field may be defaulted, in others it may be required.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[-._a-zA-Z0-9]+$
+                    type: string
+                  name:
+                    description: The name of the Secret resource being referred to.
+                    maxLength: 253
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                  namespace:
+                    description: |-
+                      The namespace of the Secret resource being referred to.
+                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                    maxLength: 63
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                    type: string
+                type: object
+              remoteNamespace:
+                default: default
+                description: Remote namespace to fetch the secrets from
+                maxLength: 63
+                minLength: 1
+                pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                type: string
+              server:
+                description: configures the Kubernetes server Address.
+                properties:
+                  caBundle:
+                    description: CABundle is a base64-encoded CA certificate
+                    format: byte
+                    type: string
+                  caProvider:
+                    description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider'
+                    properties:
+                      key:
+                        description: The key where the CA certificate can be found
+                          in the Secret or ConfigMap.
+                        maxLength: 253
+                        minLength: 1
+                        pattern: ^[-._a-zA-Z0-9]+$
+                        type: string
+                      name:
+                        description: The name of the object located at the provider
+                          type.
+                        maxLength: 253
+                        minLength: 1
+                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                        type: string
+                      namespace:
+                        description: |-
+                          The namespace the Provider type is in.
+                          Can only be defined when used in a ClusterSecretStore.
+                        maxLength: 63
+                        minLength: 1
+                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                        type: string
+                      type:
+                        description: The type of provider to use such as "Secret",
+                          or "ConfigMap".
+                        enum:
+                        - Secret
+                        - ConfigMap
+                        type: string
+                    required:
+                    - name
+                    - type
+                    type: object
+                  url:
+                    default: kubernetes.default
+                    description: configures the Kubernetes server Address.
+                    type: string
+                type: object
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 294 - 0
config/crds/bases/provider.external-secrets.io_parameterstores.yaml

@@ -0,0 +1,294 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: parameterstores.provider.external-secrets.io
+spec:
+  group: provider.external-secrets.io
+  names:
+    categories:
+    - externalsecrets
+    kind: ParameterStore
+    listKind: ParameterStoreList
+    plural: parameterstores
+    shortNames:
+    - ssm
+    singular: parameterstore
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.region
+      name: Region
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v2alpha1
+    schema:
+      openAPIV3Schema:
+        description: ParameterStore is the Schema for AWS Parameter Store provider
+          configuration.
+        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: ParameterStoreSpec defines the desired state of ParameterStore.
+            properties:
+              additionalRoles:
+                description: AdditionalRoles is a chained list of Role ARNs which
+                  the provider will sequentially assume before assuming the Role
+                items:
+                  type: string
+                type: array
+              auth:
+                description: |-
+                  Auth defines the information necessary to authenticate against AWS
+                  if not set aws sdk will infer credentials from your environment
+                  see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+                properties:
+                  jwt:
+                    description: AWSJWTAuth stores reference to Authenticate against
+                      AWS using service account tokens.
+                    properties:
+                      serviceAccountRef:
+                        description: ServiceAccountSelector is a reference to a ServiceAccount
+                          resource.
+                        properties:
+                          audiences:
+                            description: |-
+                              Audience specifies the `aud` claim for the service account token
+                              If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                              then this audiences will be appended to the list
+                            items:
+                              type: string
+                            type: array
+                          name:
+                            description: The name of the ServiceAccount resource being
+                              referred to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              Namespace of the resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        required:
+                        - name
+                        type: object
+                    type: object
+                  secretRef:
+                    description: |-
+                      AWSAuthSecretRef holds secret references for AWS credentials
+                      both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.
+                    properties:
+                      accessKeyIDSecretRef:
+                        description: The AccessKeyID is used for authentication
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                      secretAccessKeySecretRef:
+                        description: The SecretAccessKey is used for authentication
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                      sessionTokenSecretRef:
+                        description: |-
+                          The SessionToken used for authentication
+                          This must be defined if AccessKeyID and SecretAccessKey are temporary credentials
+                          see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                    type: object
+                type: object
+              externalID:
+                description: AWS External ID set on assumed IAM roles
+                type: string
+              prefix:
+                description: Prefix adds a prefix to all retrieved values.
+                type: string
+              region:
+                description: AWS Region to be used for the provider
+                type: string
+              role:
+                description: Role is a Role ARN which the provider will assume
+                type: string
+              sessionTags:
+                description: AWS STS assume role session tags
+                items:
+                  description: |-
+                    Tag is a key-value pair that can be attached to an AWS resource.
+                    see: https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html
+                  properties:
+                    key:
+                      type: string
+                    value:
+                      type: string
+                  required:
+                  - key
+                  - value
+                  type: object
+                type: array
+              transitiveTagKeys:
+                description: AWS STS assume role transitive session tags. Required
+                  when multiple rules are used with the provider
+                items:
+                  type: string
+                type: array
+            required:
+            - region
+            type: object
+          status:
+            description: ParameterStoreStatus defines the observed state of ParameterStore.
+            properties:
+              conditions:
+                description: Conditions represent the latest available observations
+                  of the resource's state.
+                items:
+                  description: Condition contains details for one aspect of the current
+                    state of this API Resource.
+                  properties:
+                    lastTransitionTime:
+                      description: |-
+                        lastTransitionTime is the last time the condition transitioned from one status to another.
+                        This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: |-
+                        message is a human readable message indicating details about the transition.
+                        This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: |-
+                        observedGeneration represents the .metadata.generation that the condition was set based upon.
+                        For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+                        with respect to the current state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: |-
+                        reason contains a programmatic identifier indicating the reason for the condition's last transition.
+                        Producers of specific condition types may define expected values and meanings for this field,
+                        and whether the values are considered a guaranteed API.
+                        The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

+ 315 - 0
config/crds/bases/provider.external-secrets.io_secretsmanagers.yaml

@@ -0,0 +1,315 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.19.0
+  name: secretsmanagers.provider.external-secrets.io
+spec:
+  group: provider.external-secrets.io
+  names:
+    categories:
+    - externalsecrets
+    kind: SecretsManager
+    listKind: SecretsManagerList
+    plural: secretsmanagers
+    shortNames:
+    - sm
+    singular: secretsmanager
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.region
+      name: Region
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v2alpha1
+    schema:
+      openAPIV3Schema:
+        description: SecretsManager is the Schema for AWS Secrets Manager provider
+          configuration.
+        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: SecretsManagerSpec defines the desired state of SecretsManager.
+            properties:
+              additionalRoles:
+                description: AdditionalRoles is a chained list of Role ARNs which
+                  the provider will sequentially assume before assuming the Role
+                items:
+                  type: string
+                type: array
+              auth:
+                description: |-
+                  Auth defines the information necessary to authenticate against AWS
+                  if not set aws sdk will infer credentials from your environment
+                  see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+                properties:
+                  jwt:
+                    description: AWSJWTAuth stores reference to Authenticate against
+                      AWS using service account tokens.
+                    properties:
+                      serviceAccountRef:
+                        description: ServiceAccountSelector is a reference to a ServiceAccount
+                          resource.
+                        properties:
+                          audiences:
+                            description: |-
+                              Audience specifies the `aud` claim for the service account token
+                              If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                              then this audiences will be appended to the list
+                            items:
+                              type: string
+                            type: array
+                          name:
+                            description: The name of the ServiceAccount resource being
+                              referred to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              Namespace of the resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        required:
+                        - name
+                        type: object
+                    type: object
+                  secretRef:
+                    description: |-
+                      AWSAuthSecretRef holds secret references for AWS credentials
+                      both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.
+                    properties:
+                      accessKeyIDSecretRef:
+                        description: The AccessKeyID is used for authentication
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                      secretAccessKeySecretRef:
+                        description: The SecretAccessKey is used for authentication
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                      sessionTokenSecretRef:
+                        description: |-
+                          The SessionToken used for authentication
+                          This must be defined if AccessKeyID and SecretAccessKey are temporary credentials
+                          see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html
+                        properties:
+                          key:
+                            description: |-
+                              A key in the referenced Secret.
+                              Some instances of this field may be defaulted, in others it may be required.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: The name of the Secret resource being referred
+                              to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              The namespace of the Secret resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        type: object
+                    type: object
+                type: object
+              externalID:
+                description: AWS External ID set on assumed IAM roles
+                type: string
+              prefix:
+                description: Prefix adds a prefix to all retrieved values.
+                type: string
+              region:
+                description: AWS Region to be used for the provider
+                type: string
+              role:
+                description: Role is a Role ARN which the provider will assume
+                type: string
+              secretsManager:
+                description: SecretsManager defines how the provider behaves when
+                  interacting with AWS SecretsManager
+                properties:
+                  forceDeleteWithoutRecovery:
+                    description: |-
+                      Specifies whether to delete the secret without any recovery window. You
+                      can't use both this parameter and RecoveryWindowInDays in the same call.
+                      If you don't use either, then by default Secrets Manager uses a 30 day
+                      recovery window.
+                      see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-ForceDeleteWithoutRecovery
+                    type: boolean
+                  recoveryWindowInDays:
+                    description: |-
+                      The number of days from 7 to 30 that Secrets Manager waits before
+                      permanently deleting the secret. You can't use both this parameter and
+                      ForceDeleteWithoutRecovery in the same call. If you don't use either,
+                      then by default Secrets Manager uses a 30-day recovery window.
+                      see: https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html#SecretsManager-DeleteSecret-request-RecoveryWindowInDays
+                    type: integer
+                type: object
+              sessionTags:
+                description: AWS STS assume role session tags
+                items:
+                  description: |-
+                    Tag is a key-value pair that can be attached to an AWS resource.
+                    see: https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html
+                  properties:
+                    key:
+                      type: string
+                    value:
+                      type: string
+                  required:
+                  - key
+                  - value
+                  type: object
+                type: array
+              transitiveTagKeys:
+                description: AWS STS assume role transitive session tags. Required
+                  when multiple rules are used with the provider
+                items:
+                  type: string
+                type: array
+            required:
+            - region
+            type: object
+          status:
+            description: SecretsManagerStatus defines the observed state of SecretsManager.
+            properties:
+              conditions:
+                description: Conditions represent the latest available observations
+                  of the resource's state.
+                items:
+                  description: Condition contains details for one aspect of the current
+                    state of this API Resource.
+                  properties:
+                    lastTransitionTime:
+                      description: |-
+                        lastTransitionTime is the last time the condition transitioned from one status to another.
+                        This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: |-
+                        message is a human readable message indicating details about the transition.
+                        This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: |-
+                        observedGeneration represents the .metadata.generation that the condition was set based upon.
+                        For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+                        with respect to the current state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: |-
+                        reason contains a programmatic identifier indicating the reason for the condition's last transition.
+                        Producers of specific condition types may define expected values and meanings for this field,
+                        and whether the values are considered a guaranteed API.
+                        The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}

Plik diff jest za duży
+ 601 - 41
deploy/crds/bundle.yaml


Plik diff jest za duży
+ 472 - 198
docs/api/spec.md


+ 3 - 3
tests/__snapshot__/clusterexternalsecret-v1.yaml

@@ -23,7 +23,7 @@ spec:
           kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "CloudsmithAccessToken", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana", "MFA"
           name: string
         storeRef:
-          kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+          kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
           name: string
     dataFrom:
     - extract:
@@ -60,12 +60,12 @@ spec:
           kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "CloudsmithAccessToken", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana", "MFA"
           name: string
         storeRef:
-          kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+          kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
           name: string
     refreshInterval: "1h0m0s"
     refreshPolicy: "CreatedOnce" # "CreatedOnce", "Periodic", "OnChange"
     secretStoreRef:
-      kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+      kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
       name: string
     target:
       creationPolicy: "Owner"

+ 3 - 3
tests/__snapshot__/clusterexternalsecret-v1beta1.yaml

@@ -22,7 +22,7 @@ spec:
           kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana"
           name: string
         storeRef:
-          kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+          kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
           name: string
     dataFrom:
     - extract:
@@ -51,12 +51,12 @@ spec:
           kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana"
           name: string
         storeRef:
-          kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+          kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
           name: string
     refreshInterval: "1h0m0s"
     refreshPolicy: "CreatedOnce" # "CreatedOnce", "Periodic", "OnChange"
     secretStoreRef:
-      kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+      kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
       name: string
     target:
       creationPolicy: "Owner"

+ 28 - 0
tests/__snapshot__/clusterproviderstore-v2alpha1.yaml

@@ -0,0 +1,28 @@
+apiVersion: external-secrets.io/v2alpha1
+kind: ClusterProviderStore
+metadata: {}
+spec:
+  backendRef:
+    apiVersion: external-secrets.io/v2alpha1
+    kind: string
+    name: string
+    namespace: string
+  conditions:
+  - namespaceRegexes: [] # minItems 0 of type string
+    namespaceSelector:
+      matchExpressions:
+      - key: string
+        operator: string
+        values: [] # minItems 0 of type string
+      matchLabels: {}
+    namespaces: [] # minItems 0 of type string
+  runtimeRef:
+    kind: "ClusterProviderClass"
+    name: string
+status:
+  conditions:
+  - lastTransitionTime: 2024-10-11T12:48:44Z
+    message: string
+    reason: string
+    status: string
+    type: string

+ 3 - 0
tests/__snapshot__/clustersecretstore-v1.yaml

@@ -950,6 +950,9 @@ spec:
   retrySettings:
     maxRetries: 1
     retryInterval: string
+  runtimeRef:
+    kind: "ClusterProviderClass"
+    name: string
 status:
   capabilities: string
   conditions:

+ 3 - 0
tests/__snapshot__/clustersecretstore-v1beta1.yaml

@@ -690,6 +690,9 @@ spec:
   retrySettings:
     maxRetries: 1
     retryInterval: string
+  runtimeRef:
+    kind: "ClusterProviderClass"
+    name: string
 status:
   capabilities: string
   conditions:

+ 3 - 3
tests/__snapshot__/externalsecret-v1.yaml

@@ -18,7 +18,7 @@ spec:
         kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "CloudsmithAccessToken", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana", "MFA"
         name: string
       storeRef:
-        kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+        kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
         name: string
   dataFrom:
   - extract:
@@ -55,12 +55,12 @@ spec:
         kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "CloudsmithAccessToken", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana", "MFA"
         name: string
       storeRef:
-        kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+        kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
         name: string
   refreshInterval: "1h0m0s"
   refreshPolicy: "CreatedOnce" # "CreatedOnce", "Periodic", "OnChange"
   secretStoreRef:
-    kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+    kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
     name: string
   target:
     creationPolicy: "Owner"

+ 3 - 3
tests/__snapshot__/externalsecret-v1beta1.yaml

@@ -17,7 +17,7 @@ spec:
         kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana"
         name: string
       storeRef:
-        kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+        kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
         name: string
   dataFrom:
   - extract:
@@ -46,12 +46,12 @@ spec:
         kind: "ACRAccessToken" # "ACRAccessToken", "ClusterGenerator", "ECRAuthorizationToken", "Fake", "GCRAccessToken", "GithubAccessToken", "QuayAccessToken", "Password", "SSHKey", "STSSessionToken", "UUID", "VaultDynamicSecret", "Webhook", "Grafana"
         name: string
       storeRef:
-        kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+        kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
         name: string
   refreshInterval: "1h0m0s"
   refreshPolicy: "CreatedOnce" # "CreatedOnce", "Periodic", "OnChange"
   secretStoreRef:
-    kind: "SecretStore" # "SecretStore", "ClusterSecretStore"
+    kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
     name: string
   target:
     creationPolicy: "Owner"

+ 0 - 6
tests/__snapshot__/fake-v1alpha1.yaml

@@ -1,6 +0,0 @@
-apiVersion: generators.external-secrets.io/v1alpha1
-kind: Fake
-metadata: {}
-spec:
-  controller: string
-  data: {}

+ 9 - 0
tests/__snapshot__/fake-v2alpha1.yaml

@@ -0,0 +1,9 @@
+apiVersion: provider.external-secrets.io/v2alpha1
+kind: Fake
+metadata: {}
+spec:
+  data:
+  - key: string
+    value: string
+    version: string
+  validationResult: 1

+ 19 - 0
tests/__snapshot__/providerstore-v2alpha1.yaml

@@ -0,0 +1,19 @@
+apiVersion: external-secrets.io/v2alpha1
+kind: ProviderStore
+metadata: {}
+spec:
+  backendRef:
+    apiVersion: external-secrets.io/v2alpha1
+    kind: string
+    name: string
+    namespace: string
+  runtimeRef:
+    kind: "ClusterProviderClass"
+    name: string
+status:
+  conditions:
+  - lastTransitionTime: 2024-10-11T12:48:44Z
+    message: string
+    reason: string
+    status: string
+    type: string

+ 4 - 2
tests/__snapshot__/pushsecret-v1alpha1.yaml

@@ -23,7 +23,8 @@ spec:
       transform:
         template: string
     storeRef:
-      kind: "SecretStore"
+      apiVersion: external-secrets.io/v1alpha1
+      kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
       labelSelector:
         matchExpressions:
         - key: string
@@ -34,7 +35,8 @@ spec:
   deletionPolicy: "None"
   refreshInterval: "1h0m0s"
   secretStoreRefs:
-  - kind: "SecretStore"
+  - apiVersion: external-secrets.io/v1alpha1
+    kind: "SecretStore" # "SecretStore", "ClusterSecretStore", "ProviderStore", "ClusterProviderStore"
     labelSelector:
       matchExpressions:
       - key: string

+ 3 - 0
tests/__snapshot__/secretstore-v1.yaml

@@ -950,6 +950,9 @@ spec:
   retrySettings:
     maxRetries: 1
     retryInterval: string
+  runtimeRef:
+    kind: "ClusterProviderClass"
+    name: string
 status:
   capabilities: string
   conditions:

+ 3 - 0
tests/__snapshot__/secretstore-v1beta1.yaml

@@ -690,6 +690,9 @@ spec:
   retrySettings:
     maxRetries: 1
     retryInterval: string
+  runtimeRef:
+    kind: "ClusterProviderClass"
+    name: string
 status:
   capabilities: string
   conditions:

+ 7 - 0
tests/clusterproviderstore_test.yaml

@@ -0,0 +1,7 @@
+suite: test ClusterProviderStore
+template: tests/crds/clusterproviderstore.yml
+tests:
+  - it: matches ClusterProviderStore correctly
+    asserts:
+      - matchSnapshot:
+          path: tests/__snapshot__

+ 2 - 1
tests/clustersecretstore_test.yaml

@@ -1,10 +1,11 @@
 suite: test ClusterSecretStore
 template: tests/crds/clustersecretstore.yml
 tests:
-  - it: matches ClusterSecretStore correctly
+  - it: matches ClusterSecretStore correctly (including runtimeRef)
     asserts:
       - matchSnapshot:
           path: tests/__snapshot__
+          # runtimeRef shape is covered via snapshot assertions.
           # We deliberately want to test all the included elements.
           ignoreErrors:
             - "in body should have at most 1 properties"

+ 7 - 0
tests/providerstore_test.yaml

@@ -0,0 +1,7 @@
+suite: test ProviderStore
+template: tests/crds/providerstore.yml
+tests:
+  - it: matches ProviderStore correctly
+    asserts:
+      - matchSnapshot:
+          path: tests/__snapshot__

+ 2 - 1
tests/secretstore_test.yaml

@@ -1,10 +1,11 @@
 suite: test SecretStore
 template: tests/crds/secretstore.yml
 tests:
-  - it: matches SecretStore correctly
+  - it: matches SecretStore correctly (including runtimeRef)
     asserts:
       - matchSnapshot:
           path: tests/__snapshot__
+          # runtimeRef shape is covered via snapshot assertions.
           # We deliberately want to test all the included elements.
           ignoreErrors:
             - "in body should have at most 1 properties"

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików