Bladeren bron

test(gcp): add provider v2 e2e coverage

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Moritz Johner 2 maanden geleden
bovenliggende
commit
e61f4f7fe0

+ 106 - 0
e2e/suites/provider/cases/gcp/clusterprovider_v2.go

@@ -0,0 +1,106 @@
+/*
+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 gcp
+
+import (
+	. "github.com/onsi/ginkgo/v2"
+
+	"github.com/external-secrets/external-secrets-e2e/framework"
+	frameworkv2 "github.com/external-secrets/external-secrets-e2e/framework/v2"
+	"github.com/external-secrets/external-secrets-e2e/suites/provider/cases/common"
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	gcpsmv2alpha1 "github.com/external-secrets/external-secrets/apis/provider/gcp/v2alpha1"
+)
+
+var _ = Describe("[gcp] v2 cluster provider", Label("gcp", "secretsmanager", "v2", "cluster-provider"), func() {
+	f := framework.New("eso-gcp-v2-clusterprovider")
+	prov := NewProviderV2(f)
+	harness := newGCPClusterProviderExternalSecretHarness(f, prov)
+
+	BeforeEach(func() {
+		if !framework.IsV2ProviderMode() {
+			Skip("v2 mode only")
+		}
+	})
+
+	DescribeTable("cluster provider external secrets",
+		framework.TableFuncWithExternalSecret(f, prov),
+		Entry(common.ClusterProviderManifestNamespace(f, harness)),
+		Entry(common.ClusterProviderProviderNamespace(f, harness)),
+		Entry(common.ClusterProviderDeniedByConditions(f, harness)),
+	)
+})
+
+type clusterProviderScenario struct {
+	common  v2ClusterProviderScenario
+	access  gcpAccessConfig
+	backend *GcpProvider
+	f       *framework.Framework
+}
+
+func newClusterProviderScenario(f *framework.Framework, prefix string, authScope esv1.AuthenticationScope, access gcpAccessConfig, backend *GcpProvider) *clusterProviderScenario {
+	shared := newV2ClusterProviderScenario(f.Namespace.Name, prefix, authScope, func(prefix string) string {
+		return common.CreateProviderCaseNamespace(f, prefix, defaultV2PollInterval)
+	})
+	s := &clusterProviderScenario{
+		common:  shared,
+		access:  access,
+		backend: backend,
+		f:       f,
+	}
+	createSecretManagerV2StaticConfig(s.f, s.common.ConfigNamespace, s.common.ConfigName, s.access)
+	return s
+}
+
+func (s *clusterProviderScenario) createClusterProvider(conditions []esv1.ClusterSecretStoreCondition) string {
+	clusterProviderName := s.common.ClusterProviderName()
+	frameworkv2.CreateClusterProviderConnection(
+		s.f,
+		clusterProviderName,
+		frameworkv2.ProviderAddress("gcp"),
+		gcpsmv2alpha1.GroupVersion.String(),
+		gcpsmv2alpha1.SecretManagerKind,
+		s.common.ConfigName,
+		s.common.ProviderRefNamespace,
+		s.common.AuthScope,
+		conditions,
+	)
+	return clusterProviderName
+}
+
+func (s *clusterProviderScenario) CreateSecret(key string, val framework.SecretEntry) {
+	s.backend.CreateSecret(key, val)
+}
+
+func (s *clusterProviderScenario) DeleteSecret(key string) {
+	s.backend.DeleteSecret(key)
+}
+
+func newGCPClusterProviderExternalSecretHarness(f *framework.Framework, prov *ProviderV2) common.ClusterProviderExternalSecretHarness {
+	return common.ClusterProviderExternalSecretHarness{
+		Prepare: func(_ *framework.TestCase, cfg common.ClusterProviderConfig) *common.ClusterProviderExternalSecretRuntime {
+			s := newClusterProviderScenario(f, cfg.Name, cfg.AuthScope, prov.access, prov.backend)
+			clusterProviderName := s.createClusterProvider(cfg.Conditions)
+			frameworkv2.WaitForClusterProviderReady(f, clusterProviderName, defaultV2WaitTimeout)
+
+			return &common.ClusterProviderExternalSecretRuntime{
+				ClusterProviderName: clusterProviderName,
+				Provider:            s,
+			}
+		},
+	}
+}

+ 254 - 0
e2e/suites/provider/cases/gcp/provider_support_v2.go

@@ -0,0 +1,254 @@
+/*
+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 gcp
+
+import (
+	"fmt"
+	"time"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	utilpointer "k8s.io/utils/pointer"
+
+	"github.com/external-secrets/external-secrets-e2e/framework"
+	frameworkv2 "github.com/external-secrets/external-secrets-e2e/framework/v2"
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	gcpsmv2alpha1 "github.com/external-secrets/external-secrets/apis/provider/gcp/v2alpha1"
+)
+
+const (
+	defaultV2WaitTimeout  = 60 * time.Second
+	defaultV2PollInterval = 2 * time.Second
+	withWorkloadIdentity  = "with workload identity"
+)
+
+type ProviderV2 struct {
+	access    gcpAccessConfig
+	backend   *GcpProvider
+	framework *framework.Framework
+}
+
+type v2ClusterProviderScenario struct {
+	AuthScope            esv1.AuthenticationScope
+	ConfigName           string
+	ConfigNamespace      string
+	NamePrefix           string
+	ProviderNamespace    string
+	ProviderRefNamespace string
+	WorkloadNamespace    string
+}
+
+func NewProviderV2(f *framework.Framework) *ProviderV2 {
+	access := newGCPAccessConfigFromEnv()
+	backend := &GcpProvider{
+		ServiceAccountName:      access.ServiceAccountName,
+		ServiceAccountNamespace: "default",
+		framework:               f,
+		credentials:             access.Credentials,
+		projectID:               access.ProjectID,
+		clusterLocation:         access.ClusterLocation,
+		clusterName:             access.ClusterName,
+		access:                  access,
+	}
+	prov := &ProviderV2{
+		access:    access,
+		backend:   backend,
+		framework: f,
+	}
+
+	BeforeEach(func() {
+		if !framework.IsV2ProviderMode() {
+			return
+		}
+		skipIfGCPStaticEnvMissing(access)
+	})
+
+	return prov
+}
+
+func (p *ProviderV2) CreateSecret(key string, val framework.SecretEntry) {
+	p.backend.CreateSecret(key, val)
+}
+
+func (p *ProviderV2) DeleteSecret(key string) {
+	p.backend.DeleteSecret(key)
+}
+
+func useV2StaticAuth(prov *ProviderV2) func(*framework.TestCase) {
+	return func(tc *framework.TestCase) {
+		tc.Prepare = prov.prepareNamespacedProviderWithStaticAuth(frameworkv2.ProviderAddress("gcp"))
+	}
+}
+
+func useV2WorkloadIdentity(prov *ProviderV2) func(*framework.TestCase) {
+	return func(tc *framework.TestCase) {
+		tc.Prepare = prov.prepareNamespacedProviderWithWorkloadIdentity(frameworkv2.ProviderAddress("gcp"))
+	}
+}
+
+func (p *ProviderV2) prepareNamespacedProviderWithStaticAuth(address string) func(*framework.TestCase, framework.SecretStoreProvider) {
+	return func(_ *framework.TestCase, _ framework.SecretStoreProvider) {
+		createSecretManagerV2StaticConfig(p.framework, p.framework.Namespace.Name, p.framework.Namespace.Name, p.access)
+		frameworkv2.CreateProviderConnection(
+			p.framework,
+			p.framework.Namespace.Name,
+			p.framework.Namespace.Name,
+			address,
+			gcpsmv2alpha1.GroupVersion.String(),
+			gcpsmv2alpha1.SecretManagerKind,
+			p.framework.Namespace.Name,
+			p.framework.Namespace.Name,
+		)
+		frameworkv2.WaitForProviderConnectionReady(p.framework, p.framework.Namespace.Name, p.framework.Namespace.Name, defaultV2WaitTimeout)
+	}
+}
+
+func (p *ProviderV2) prepareNamespacedProviderWithWorkloadIdentity(address string) func(*framework.TestCase, framework.SecretStoreProvider) {
+	return func(_ *framework.TestCase, _ framework.SecretStoreProvider) {
+		skipIfGCPManagedEnvMissing(p.access)
+
+		createSecretManagerV2WorkloadIdentityConfig(
+			p.framework,
+			p.framework.Namespace.Name,
+			p.framework.Namespace.Name,
+			p.access,
+			p.backend.ServiceAccountNamespace,
+		)
+		frameworkv2.CreateProviderConnection(
+			p.framework,
+			p.framework.Namespace.Name,
+			p.framework.Namespace.Name,
+			address,
+			gcpsmv2alpha1.GroupVersion.String(),
+			gcpsmv2alpha1.SecretManagerKind,
+			p.framework.Namespace.Name,
+			p.framework.Namespace.Name,
+		)
+		frameworkv2.WaitForProviderConnectionReady(p.framework, p.framework.Namespace.Name, p.framework.Namespace.Name, defaultV2WaitTimeout)
+	}
+}
+
+func newSecretManagerV2StaticConfig(namespace, name string, access gcpAccessConfig) *gcpsmv2alpha1.SecretManager {
+	return &gcpsmv2alpha1.SecretManager{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: gcpsmv2alpha1.GroupVersion.String(),
+			Kind:       gcpsmv2alpha1.SecretManagerKind,
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      name,
+			Namespace: namespace,
+		},
+		Spec: gcpsmv2alpha1.SecretManagerSpec{
+			ProjectID: access.ProjectID,
+			Auth: esv1.GCPSMAuth{
+				SecretRef: &esv1.GCPSMAuthSecretRef{
+					SecretAccessKey: esmeta.SecretKeySelector{
+						Name: staticCredentialsSecretName,
+						Key:  serviceAccountKey,
+					},
+				},
+			},
+		},
+	}
+}
+
+func createSecretManagerV2StaticConfig(f *framework.Framework, namespace, name string, access gcpAccessConfig) *gcpsmv2alpha1.SecretManager {
+	secret := &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      staticCredentialsSecretName,
+			Namespace: namespace,
+		},
+		StringData: map[string]string{
+			serviceAccountKey: access.Credentials,
+		},
+	}
+	Expect(f.CreateObjectWithRetry(secret)).To(Succeed())
+
+	cfg := newSecretManagerV2StaticConfig(namespace, name, access)
+	Expect(f.CreateObjectWithRetry(cfg)).To(Succeed())
+	return cfg
+}
+
+func newSecretManagerV2WorkloadIdentityConfig(namespace, name string, access gcpAccessConfig, serviceAccountNamespace string) *gcpsmv2alpha1.SecretManager {
+	return &gcpsmv2alpha1.SecretManager{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: gcpsmv2alpha1.GroupVersion.String(),
+			Kind:       gcpsmv2alpha1.SecretManagerKind,
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      name,
+			Namespace: namespace,
+		},
+		Spec: gcpsmv2alpha1.SecretManagerSpec{
+			ProjectID: access.ProjectID,
+			Auth: esv1.GCPSMAuth{
+				WorkloadIdentity: &esv1.GCPWorkloadIdentity{
+					ClusterLocation: access.ClusterLocation,
+					ClusterName:     access.ClusterName,
+					ServiceAccountRef: esmeta.ServiceAccountSelector{
+						Name:      access.ServiceAccountName,
+						Namespace: utilpointer.String(serviceAccountNamespace),
+					},
+				},
+			},
+		},
+	}
+}
+
+func createSecretManagerV2WorkloadIdentityConfig(f *framework.Framework, namespace, name string, access gcpAccessConfig, serviceAccountNamespace string) *gcpsmv2alpha1.SecretManager {
+	cfg := newSecretManagerV2WorkloadIdentityConfig(namespace, name, access, serviceAccountNamespace)
+	Expect(f.CreateObjectWithRetry(cfg)).To(Succeed())
+	return cfg
+}
+
+func providerConfigNamespace(authScope esv1.AuthenticationScope, providerNamespace, workloadNamespace string) string {
+	if authScope == esv1.AuthenticationScopeProviderNamespace {
+		return providerNamespace
+	}
+	return workloadNamespace
+}
+
+func providerReferenceNamespace(authScope esv1.AuthenticationScope, providerNamespace string) string {
+	if authScope == esv1.AuthenticationScopeProviderNamespace {
+		return providerNamespace
+	}
+	return ""
+}
+
+func newV2ClusterProviderScenario(workloadNamespace, prefix string, authScope esv1.AuthenticationScope, createProviderNamespace func(prefix string) string) v2ClusterProviderScenario {
+	providerNamespace := workloadNamespace
+	if authScope == esv1.AuthenticationScopeProviderNamespace && createProviderNamespace != nil {
+		providerNamespace = createProviderNamespace(prefix + "-provider")
+	}
+
+	return v2ClusterProviderScenario{
+		AuthScope:            authScope,
+		ConfigName:           fmt.Sprintf("%s-config", prefix),
+		ConfigNamespace:      providerConfigNamespace(authScope, providerNamespace, workloadNamespace),
+		NamePrefix:           fmt.Sprintf("%s-%s", workloadNamespace, prefix),
+		ProviderNamespace:    providerNamespace,
+		ProviderRefNamespace: providerReferenceNamespace(authScope, providerNamespace),
+		WorkloadNamespace:    workloadNamespace,
+	}
+}
+
+func (s v2ClusterProviderScenario) ClusterProviderName() string {
+	return fmt.Sprintf("%s-cluster-provider", s.NamePrefix)
+}

+ 140 - 0
e2e/suites/provider/cases/gcp/provider_support_v2_test.go

@@ -0,0 +1,140 @@
+/*
+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 gcp
+
+import (
+	"testing"
+
+	frameworkv2 "github.com/external-secrets/external-secrets-e2e/framework/v2"
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	gcpsmv2alpha1 "github.com/external-secrets/external-secrets/apis/provider/gcp/v2alpha1"
+)
+
+func TestNewSecretManagerV2StaticConfig(t *testing.T) {
+	t.Parallel()
+
+	cfg := newSecretManagerV2StaticConfig("workload-ns", "gcp-config", gcpAccessConfig{
+		Credentials: "service-account-json",
+		ProjectID:   "project-1",
+	})
+
+	if cfg.APIVersion != gcpsmv2alpha1.GroupVersion.String() {
+		t.Fatalf("unexpected apiVersion: %q", cfg.APIVersion)
+	}
+	if cfg.Kind != gcpsmv2alpha1.SecretManagerKind {
+		t.Fatalf("unexpected kind: %q", cfg.Kind)
+	}
+	if cfg.Namespace != "workload-ns" || cfg.Name != "gcp-config" {
+		t.Fatalf("unexpected object metadata: %s/%s", cfg.Namespace, cfg.Name)
+	}
+	if cfg.Spec.ProjectID != "project-1" {
+		t.Fatalf("unexpected project ID: %q", cfg.Spec.ProjectID)
+	}
+	if cfg.Spec.Auth.SecretRef == nil {
+		t.Fatal("expected static auth secretRef")
+	}
+	if got := cfg.Spec.Auth.SecretRef.SecretAccessKey.Name; got != staticCredentialsSecretName {
+		t.Fatalf("unexpected secret ref name: %q", got)
+	}
+	if got := cfg.Spec.Auth.SecretRef.SecretAccessKey.Key; got != serviceAccountKey {
+		t.Fatalf("unexpected secret ref key: %q", got)
+	}
+}
+
+func TestNewSecretManagerV2WorkloadIdentityConfig(t *testing.T) {
+	t.Parallel()
+
+	cfg := newSecretManagerV2WorkloadIdentityConfig("provider-ns", "gcp-config", gcpAccessConfig{
+		ProjectID:          "project-1",
+		ServiceAccountName: "provider-sa",
+		ClusterLocation:    "europe-west3",
+		ClusterName:        "cluster-1",
+	}, "external-secrets-system")
+
+	if cfg.Spec.Auth.WorkloadIdentity == nil {
+		t.Fatal("expected workload identity auth")
+	}
+	if got := cfg.Spec.Auth.WorkloadIdentity.ServiceAccountRef.Name; got != "provider-sa" {
+		t.Fatalf("unexpected service account name: %q", got)
+	}
+	if cfg.Spec.Auth.WorkloadIdentity.ServiceAccountRef.Namespace == nil || *cfg.Spec.Auth.WorkloadIdentity.ServiceAccountRef.Namespace != "external-secrets-system" {
+		t.Fatalf("unexpected service account namespace: %#v", cfg.Spec.Auth.WorkloadIdentity.ServiceAccountRef.Namespace)
+	}
+	if got := cfg.Spec.Auth.WorkloadIdentity.ClusterLocation; got != "europe-west3" {
+		t.Fatalf("unexpected cluster location: %q", got)
+	}
+	if got := cfg.Spec.Auth.WorkloadIdentity.ClusterName; got != "cluster-1" {
+		t.Fatalf("unexpected cluster name: %q", got)
+	}
+}
+
+func TestProviderAddressInNamespace(t *testing.T) {
+	t.Parallel()
+
+	got := frameworkv2.ProviderAddressInNamespace("gcp", "gcp-provider-system")
+	if got != "provider-gcp.gcp-provider-system.svc:8080" {
+		t.Fatalf("unexpected address: %s", got)
+	}
+}
+
+func TestNewV2ClusterProviderScenarioManifestScope(t *testing.T) {
+	t.Parallel()
+
+	got := newV2ClusterProviderScenario("workload-ns", "case", esv1.AuthenticationScopeManifestNamespace, func(string) string {
+		t.Fatal("createProviderNamespace should not be called for manifest scope")
+		return ""
+	})
+
+	if got.ConfigNamespace != "workload-ns" {
+		t.Fatalf("unexpected config namespace: %q", got.ConfigNamespace)
+	}
+	if got.ProviderNamespace != "workload-ns" {
+		t.Fatalf("unexpected provider namespace: %q", got.ProviderNamespace)
+	}
+	if got.ProviderRefNamespace != "" {
+		t.Fatalf("expected empty provider ref namespace, got %q", got.ProviderRefNamespace)
+	}
+	if got.NamePrefix != "workload-ns-case" {
+		t.Fatalf("unexpected name prefix: %q", got.NamePrefix)
+	}
+}
+
+func TestNewV2ClusterProviderScenarioProviderScope(t *testing.T) {
+	t.Parallel()
+
+	var createArg string
+	got := newV2ClusterProviderScenario("workload-ns", "case", esv1.AuthenticationScopeProviderNamespace, func(prefix string) string {
+		createArg = prefix
+		return "provider-ns"
+	})
+
+	if createArg != "case-provider" {
+		t.Fatalf("unexpected provider namespace prefix: %q", createArg)
+	}
+	if got.ConfigNamespace != "provider-ns" {
+		t.Fatalf("unexpected config namespace: %q", got.ConfigNamespace)
+	}
+	if got.ProviderNamespace != "provider-ns" {
+		t.Fatalf("unexpected provider namespace: %q", got.ProviderNamespace)
+	}
+	if got.ProviderRefNamespace != "provider-ns" {
+		t.Fatalf("unexpected provider ref namespace: %q", got.ProviderRefNamespace)
+	}
+	if got.ClusterProviderName() != "workload-ns-case-cluster-provider" {
+		t.Fatalf("unexpected cluster provider name: %q", got.ClusterProviderName())
+	}
+}

+ 96 - 0
e2e/suites/provider/cases/gcp/provider_v2.go

@@ -0,0 +1,96 @@
+/*
+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 gcp
+
+import (
+	"time"
+
+	. "github.com/onsi/ginkgo/v2"
+
+	"github.com/external-secrets/external-secrets-e2e/framework"
+	"github.com/external-secrets/external-secrets-e2e/suites/provider/cases/common"
+)
+
+var _ = Describe("[gcp] v2 namespaced provider", Label("gcp", "secretsmanager", "v2", "namespaced-provider"), func() {
+	f := framework.New("eso-gcp-v2")
+	prov := NewProviderV2(f)
+
+	BeforeEach(func() {
+		if !framework.IsV2ProviderMode() {
+			Skip("v2 mode only")
+		}
+	})
+
+	DescribeTable("namespaced provider",
+		framework.TableFuncWithExternalSecret(f, prov),
+		framework.Compose(withStaticAuth, f, func(f *framework.Framework) (string, func(*framework.TestCase)) {
+			return common.NamespacedProviderSync(f, common.NamespacedProviderSyncConfig{
+				Description:        "[gcp] should sync through a namespaced Provider using static credentials",
+				ExternalSecretName: "gcp-v2-static-es",
+				TargetSecretName:   "gcp-v2-static-target",
+				RemoteKey:          f.MakeRemoteRefKey("gcp-v2-static-remote"),
+				RemoteSecretValue:  `{"value":"gcp-v2-static-value"}`,
+				RemoteProperty:     "value",
+				SecretKey:          "value",
+				ExpectedValue:      "gcp-v2-static-value",
+			})
+		}, useV2StaticAuth(prov)),
+		framework.Compose(withWorkloadIdentity, f, func(f *framework.Framework) (string, func(*framework.TestCase)) {
+			return common.NamespacedProviderSync(f, common.NamespacedProviderSyncConfig{
+				Description:        "[gcp] should sync through a namespaced Provider using workload identity",
+				ExternalSecretName: "gcp-v2-wi-es",
+				TargetSecretName:   "gcp-v2-wi-target",
+				RemoteKey:          f.MakeRemoteRefKey("gcp-v2-wi-remote"),
+				RemoteSecretValue:  `{"value":"gcp-v2-wi-value"}`,
+				RemoteProperty:     "value",
+				SecretKey:          "value",
+				ExpectedValue:      "gcp-v2-wi-value",
+			})
+		}, useV2WorkloadIdentity(prov)),
+		framework.Compose(withStaticAuth, f, func(f *framework.Framework) (string, func(*framework.TestCase)) {
+			return common.NamespacedProviderRefresh(f, common.NamespacedProviderRefreshConfig{
+				Description:         "[gcp] should refresh synced secrets after the remote secret changes",
+				ExternalSecretName:  "gcp-v2-refresh-es",
+				TargetSecretName:    "gcp-v2-refresh-target",
+				RemoteKey:           f.MakeRemoteRefKey("gcp-v2-refresh-remote"),
+				InitialSecretValue:  `{"value":"gcp-v2-initial"}`,
+				UpdatedSecretValue:  `{"value":"gcp-v2-updated"}`,
+				RemoteProperty:      "value",
+				SecretKey:           "value",
+				InitialExpectedData: "gcp-v2-initial",
+				UpdatedExpectedData: "gcp-v2-updated",
+				RefreshInterval:     10 * time.Second,
+				WaitTimeout:         30 * time.Second,
+			})
+		}, useV2StaticAuth(prov)),
+		framework.Compose(withStaticAuth, f, func(f *framework.Framework) (string, func(*framework.TestCase)) {
+			return common.NamespacedProviderFind(f, common.NamespacedProviderFindConfig{
+				Description:        "[gcp] should sync dataFrom.find through a namespaced Provider",
+				ExternalSecretName: "gcp-v2-find-es",
+				TargetSecretName:   "gcp-v2-find-target",
+				MatchRegExp:        "^gcp-v2-find-(one|two)$",
+				MatchingSecrets: map[string]string{
+					"gcp-v2-find-one": "gcp-v2-one",
+					"gcp-v2-find-two": "gcp-v2-two",
+				},
+				IgnoredSecrets: map[string]string{
+					"gcp-v2-ignore": "gcp-v2-ignore",
+				},
+			})
+		}, useV2StaticAuth(prov)),
+	)
+})