CVE-2024-36106: Insufficient Information (NVD-CWE-noinfo)
value: Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. It’s possible for authenticated users to enumerate clusters by name by inspecting error messages. It’s also possible to enumerate the names of projects with project-scoped clusters if you know the names of the clusters. This vulnerability is fixed in 2.11.3, 2.10.12, and 2.9.17.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-06-06T15:15Z
Repository: https://github.com/argoproj/argo-cd
Language: Go
Files changed: server/cluster/cluster.go, server/cluster/cluster_test.go
Commit date: 2024-06-06 11:30:10 +0300
Commit message: Merge pull request from GHSA-3cqf-953p-h5cp

* fix: prevent enumerating by cluster name, return exact error for case when cluster exists and not

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: prevent cluster enumeration by name

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: prevent cluster enumeration by name

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
Diff: diff --git a/server/cluster/cluster.go b/server/cluster/cluster.go
index cfcadd762e..cee0435f10 100644
--- a/server/cluster/cluster.go
+++ b/server/cluster/cluster.go
@@ -185,19 +185,15 @@ func (s *Server) Create(ctx context.Context, q *cluster.ClusterCreateRequest) (*
 	return s.toAPIResponse(clust), err
 }
 
 // Get returns a cluster from a query
 func (s *Server) Get(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
-	c, err := s.getClusterWith403IfNotExist(ctx, q)
+	c, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionGet)
 	if err != nil {
 		return nil, err
 	}
 
-	if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionGet, CreateClusterRBACObject(c.Project, q.Server)); err != nil {
-		return nil, err
-	}
-
 	return s.toAPIResponse(c), nil
 }
 
 func (s *Server) getClusterWith403IfNotExist(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
 	repo, err := s.getCluster(ctx, q)
@@ -205,10 +201,25 @@ func (s *Server) getClusterWith403IfNotExist(ctx context.Context, q *cluster.Clu
 		return nil, common.PermissionDeniedAPIError
 	}
 	return repo, nil
 }
 
+func (s *Server) getClusterAndVerifyAccess(ctx context.Context, q *cluster.ClusterQuery, action string) (*appv1.Cluster, error) {
+	c, err := s.getClusterWith403IfNotExist(ctx, q)
+	if err != nil {
+		return nil, err
+	}
+
+	// verify that user can do the specified action inside project where cluster is located
+	if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, action, CreateClusterRBACObject(c.Project, c.Server)) {
+		log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
+		return nil, common.PermissionDeniedAPIError
+	}
+
+	return c, nil
+}
+
 func (s *Server) getCluster(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
 	if q.Id != nil {
 		q.Server = ""
 		q.Name = ""
 		if q.Id.Type == "name" {
@@ -276,24 +287,20 @@ var clusterFieldsByPath = map[string]func(updated *appv1.Cluster, existing *appv
 	},
 }
 
 // Update updates a cluster
 func (s *Server) Update(ctx context.Context, q *cluster.ClusterUpdateRequest) (*appv1.Cluster, error) {
-	c, err := s.getClusterWith403IfNotExist(ctx, &cluster.ClusterQuery{
+	c, err := s.getClusterAndVerifyAccess(ctx, &cluster.ClusterQuery{
 		Server: q.Cluster.Server,
 		Name:   q.Cluster.Name,
 		Id:     q.Id,
-	})
+	}, rbacpolicy.ActionUpdate)
+
 	if err != nil {
 		return nil, err
 	}
 
-	// verify that user can do update inside project where cluster is located
-	if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(c.Project, c.Server)) {
-		return nil, common.PermissionDeniedAPIError
-	}
-
 	if len(q.UpdatedFields) == 0 || sets.NewString(q.UpdatedFields...).Has("project") {
 		// verify that user can do update inside project where cluster will be located
 		if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(q.Cluster.Project, c.Server)) {
 			return nil, common.PermissionDeniedAPIError
 		}
@@ -339,11 +346,12 @@ func (s *Server) Delete(ctx context.Context, q *cluster.ClusterQuery) (*cluster.
 	}
 
 	if q.Name != "" {
 		servers, err := s.db.GetClusterServersByName(ctx, q.Name)
 		if err != nil {
-			return nil, err
+			log.WithField("cluster", q.Name).Warnf("failed to get cluster servers by name: %v", err)
+			return nil, common.PermissionDeniedAPIError
 		}
 		for _, server := range servers {
 			if err := enforceAndDelete(s, ctx, server, c.Project); err != nil {
 				return nil, err
 			}
@@ -357,11 +365,12 @@ func (s *Server) Delete(ctx context.Context, q *cluster.ClusterQuery) (*cluster.
 	return &cluster.ClusterResponse{}, nil
 }
 
 func enforceAndDelete(s *Server, ctx context.Context, server, project string) error {
 	if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionDelete, CreateClusterRBACObject(project, server)); err != nil {
-		return err
+		log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
+		return common.PermissionDeniedAPIError
 	}
 	if err := s.db.DeleteCluster(ctx, server); err != nil {
 		return err
 	}
 	return nil
@@ -376,20 +385,23 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
 
 	var servers []string
 	if q.Name != "" {
 		servers, err = s.db.GetClusterServersByName(ctx, q.Name)
 		if err != nil {
-			return nil, status.Errorf(codes.NotFound, "failed to get cluster servers by name: %v", err)
+			log.WithField("cluster", q.Name).Warnf("failed to get cluster servers by name: %v", err)
+			return nil, common.PermissionDeniedAPIError
 		}
 		for _, server := range servers {
 			if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(clust.Project, server)); err != nil {
-				return nil, status.Errorf(codes.PermissionDenied, "encountered permissions issue while processing request: %v", err)
+				log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
+				return nil, common.PermissionDeniedAPIError
 			}
 		}
 	} else {
 		if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(clust.Project, q.Server)); err != nil {
-			return nil, status.Errorf(codes.PermissionDenied, "encountered permissions issue while processing request: %v", err)
+			log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
+			return nil, common.PermissionDeniedAPIError
 		}
 		servers = append(servers, q.Server)
 	}
 
 	for _, server := range servers {
@@ -465,17 +477,14 @@ func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
 	return clust
 }
 
 // InvalidateCache invalidates cluster cache
 func (s *Server) InvalidateCache(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
-	cls, err := s.getClusterWith403IfNotExist(ctx, q)
+	cls, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionUpdate)
 	if err != nil {
 		return nil, err
 	}
-	if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(cls.Project, q.Server)); err != nil {
-		return nil, err
-	}
 	now := v1.Now()
 	cls.RefreshRequestedAt = &now
 	cls, err = s.db.UpdateCluster(ctx, cls)
 	if err != nil {
 		return nil, err
diff --git a/server/cluster/cluster_test.go b/server/cluster/cluster_test.go
index 077452cf49..943718bcf7 100644
--- a/server/cluster/cluster_test.go
+++ b/server/cluster/cluster_test.go
@@ -2,10 +2,13 @@ package cluster
 
 import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
+	"github.com/argoproj/argo-cd/v2/util/assets"
+	"github.com/golang-jwt/jwt/v4"
 	"reflect"
 	"testing"
 	"time"
 
 	"github.com/argoproj/argo-cd/v2/common"
@@ -49,10 +52,20 @@ func newNoopEnforcer() *rbac.Enforcer {
 	enf := rbac.NewEnforcer(fake.NewSimpleClientset(test.NewFakeConfigMap()), test.FakeArgoCDNamespace, common.ArgoCDConfigMapName, nil)
 	enf.EnableEnforce(false)
 	return enf
 }
 
+func newEnforcer() *rbac.Enforcer {
+	enforcer := rbac.NewEnforcer(fake.NewSimpleClientset(test.NewFakeConfigMap()), test.FakeArgoCDNamespace, common.ArgoCDRBACConfigMapName, nil)
+	_ = enforcer.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
+	enforcer.SetDefaultRole("role:test")
+	enforcer.SetClaimsEnforcerFunc(func(claims jwt.Claims, rvals ...interface{}) bool {
+		return true
+	})
+	return enforcer
+}
+
 func TestUpdateCluster_RejectInvalidParams(t *testing.T) {
 	testCases := []struct {
 		name    string
 		request clusterapi.ClusterUpdateRequest
 	}{
@@ -602,5 +615,154 @@ func TestListCluster(t *testing.T) {
 				t.Errorf("Server.List() = %v, want %v", got, tt.want)
 			}
 		})
 	}
 }
+
+func TestGetClusterAndVerifyAccess(t *testing.T) {
+	t.Run("GetClusterAndVerifyAccess - No Cluster", func(t *testing.T) {
+		db := &dbmocks.ArgoDB{}
+
+		mockCluster := v1alpha1.Cluster{
+			Name:       "test/ing",
+			Server:     "https://127.0.0.1",
+			Namespaces: []string{"default", "kube-system"},
+		}
+		mockClusterList := v1alpha1.ClusterList{
+			ListMeta: v1.ListMeta{},
+			Items: []v1alpha1.Cluster{
+				mockCluster,
+			},
+		}
+
+		db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
+
+		server := NewServer(db, newNoopEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
+		cluster, err := server.getClusterAndVerifyAccess(context.Background(), &clusterapi.ClusterQuery{
+			Name: "test/not-exists",
+		}, rbacpolicy.ActionGet)
+
+		assert.Nil(t, cluster)
+		assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
+	})
+
+	t.Run("GetClusterAndVerifyAccess - Permissions Denied", func(t *testing.T) {
+		db := &dbmocks.ArgoDB{}
+
+		mockCluster := v1alpha1.Cluster{
+			Name:       "test/ing",
+			Server:     "https://127.0.0.1",
+			Namespaces: []string{"default", "kube-system"},
+		}
+		mockClusterList := v1alpha1.ClusterList{
+			ListMeta: v1.ListMeta{},
+			Items: []v1alpha1.Cluster{
+				mockCluster,
+			},
+		}
+
+		db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
+
+		server := NewServer(db, newEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
+		cluster, err := server.getClusterAndVerifyAccess(context.Background(), &clusterapi.ClusterQuery{
+			Name: "test/ing",
+		}, rbacpolicy.ActionGet)
+
+		assert.Nil(t, cluster)
+		assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
+	})
+}
+
+func TestNoClusterEnumeration(t *testing.T) {
+	db := &dbmocks.ArgoDB{}
+
+	mockCluster := v1alpha1.Cluster{
+		Name:       "test/ing",
+		Server:     "https://127.0.0.1",
+		Namespaces: []string{"default", "kube-system"},
+	}
+	mockClusterList := v1alpha1.ClusterList{
+		ListMeta: v1.ListMeta{},
+		Items: []v1alpha1.Cluster{
+			mockCluster,
+		},
+	}
+
+	db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
+	db.On("GetCluster", mock.Anything, mock.Anything).Return(&mockCluster, nil)
+
+	server := NewServer(db, newEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
+
+	t.Run("Get", func(t *testing.T) {
+		_, err := server.Get(context.Background(), &clusterapi.ClusterQuery{
+			Name: "cluster-not-exists",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+
+		_, err = server.Get(context.Background(), &clusterapi.ClusterQuery{
+			Name: "test/ing",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+	})
+
+	t.Run("Update", func(t *testing.T) {
+		_, err := server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{
+			Cluster: &v1alpha1.Cluster{
+				Name: "cluster-not-exists",
+			},
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+
+		_, err = server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{
+			Cluster: &v1alpha1.Cluster{
+				Name: "test/ing",
+			},
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+	})
+
+	t.Run("Delete", func(t *testing.T) {
+		_, err := server.Delete(context.Background(), &clusterapi.ClusterQuery{
+			Server: "https://127.0.0.2",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+
+		_, err = server.Delete(context.Background(), &clusterapi.ClusterQuery{
+			Server: "https://127.0.0.1",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+	})
+
+	t.Run("RotateAuth", func(t *testing.T) {
+		_, err := server.RotateAuth(context.Background(), &clusterapi.ClusterQuery{
+			Server: "https://127.0.0.2",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+
+		_, err = server.RotateAuth(context.Background(), &clusterapi.ClusterQuery{
+			Server: "https://127.0.0.1",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+	})
+
+	t.Run("InvalidateCache", func(t *testing.T) {
+		_, err := server.InvalidateCache(context.Background(), &clusterapi.ClusterQuery{
+			Server: "https://127.0.0.2",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+
+		_, err = server.InvalidateCache(context.Background(), &clusterapi.ClusterQuery{
+			Server: "https://127.0.0.1",
+		})
+		assert.Error(t, err)
+		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
+	})
+}

Vulnerable code: 	c, err := s.getClusterWith403IfNotExist(ctx, q)
	if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionGet, CreateClusterRBACObject(c.Project, q.Server)); err != nil {
		return nil, err
	}

	c, err := s.getClusterWith403IfNotExist(ctx, &cluster.ClusterQuery{
	})
	// verify that user can do update inside project where cluster is located
	if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(c.Project, c.Server)) {
		return nil, common.PermissionDeniedAPIError
	}

			return nil, err
		return err
			return nil, status.Errorf(codes.NotFound, "failed to get cluster servers by name: %v", err)
				return nil, status.Errorf(codes.PermissionDenied, "encountered permissions issue while processing request: %v", err)
			return nil, status.Errorf(codes.PermissionDenied, "encountered permissions issue while processing request: %v", err)
	cls, err := s.getClusterWith403IfNotExist(ctx, q)
	if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(cls.Project, q.Server)); err != nil {
		return nil, err
	}
Fixed code: 	c, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionGet)
func (s *Server) getClusterAndVerifyAccess(ctx context.Context, q *cluster.ClusterQuery, action string) (*appv1.Cluster, error) {
	c, err := s.getClusterWith403IfNotExist(ctx, q)
	if err != nil {
		return nil, err
	}

	// verify that user can do the specified action inside project where cluster is located
	if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, action, CreateClusterRBACObject(c.Project, c.Server)) {
		log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
		return nil, common.PermissionDeniedAPIError
	}

	return c, nil
}

	c, err := s.getClusterAndVerifyAccess(ctx, &cluster.ClusterQuery{
	}, rbacpolicy.ActionUpdate)

			log.WithField("cluster", q.Name).Warnf("failed to get cluster servers by name: %v", err)
			return nil, common.PermissionDeniedAPIError
		log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
		return common.PermissionDeniedAPIError
			log.WithField("cluster", q.Name).Warnf("failed to get cluster servers by name: %v", err)
			return nil, common.PermissionDeniedAPIError
				log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
				return nil, common.PermissionDeniedAPIError
			log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
			return nil, common.PermissionDeniedAPIError
	cls, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionUpdate)
	"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
	"github.com/argoproj/argo-cd/v2/util/assets"
	"github.com/golang-jwt/jwt/v4"
func newEnforcer() *rbac.Enforcer {
	enforcer := rbac.NewEnforcer(fake.NewSimpleClientset(test.NewFakeConfigMap()), test.FakeArgoCDNamespace, common.ArgoCDRBACConfigMapName, nil)
	_ = enforcer.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
	enforcer.SetDefaultRole("role:test")
	enforcer.SetClaimsEnforcerFunc(func(claims jwt.Claims, rvals ...interface{}) bool {
		return true
	})
	return enforcer
}


func TestGetClusterAndVerifyAccess(t *testing.T) {
	t.Run("GetClusterAndVerifyAccess - No Cluster", func(t *testing.T) {
		db := &dbmocks.ArgoDB{}

		mockCluster := v1alpha1.Cluster{
			Name:       "test/ing",
			Server:     "https://127.0.0.1",
			Namespaces: []string{"default", "kube-system"},
		}
		mockClusterList := v1alpha1.ClusterList{
			ListMeta: v1.ListMeta{},
			Items: []v1alpha1.Cluster{
				mockCluster,
			},
		}

		db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)

		server := NewServer(db, newNoopEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
		cluster, err := server.getClusterAndVerifyAccess(context.Background(), &clusterapi.ClusterQuery{
			Name: "test/not-exists",
		}, rbacpolicy.ActionGet)

		assert.Nil(t, cluster)
		assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
	})

	t.Run("GetClusterAndVerifyAccess - Permissions Denied", func(t *testing.T) {
		db := &dbmocks.ArgoDB{}

		mockCluster := v1alpha1.Cluster{
			Name:       "test/ing",
			Server:     "https://127.0.0.1",
			Namespaces: []string{"default", "kube-system"},
		}
		mockClusterList := v1alpha1.ClusterList{
			ListMeta: v1.ListMeta{},
			Items: []v1alpha1.Cluster{
				mockCluster,
			},
		}

		db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)

		server := NewServer(db, newEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
		cluster, err := server.getClusterAndVerifyAccess(context.Background(), &clusterapi.ClusterQuery{
			Name: "test/ing",
		}, rbacpolicy.ActionGet)

		assert.Nil(t, cluster)
		assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
	})
}

func TestNoClusterEnumeration(t *testing.T) {
	db := &dbmocks.ArgoDB{}

	mockCluster := v1alpha1.Cluster{
		Name:       "test/ing",
		Server:     "https://127.0.0.1",
		Namespaces: []string{"default", "kube-system"},
	}
	mockClusterList := v1alpha1.ClusterList{
		ListMeta: v1.ListMeta{},
		Items: []v1alpha1.Cluster{
			mockCluster,
		},
	}

	db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
	db.On("GetCluster", mock.Anything, mock.Anything).Return(&mockCluster, nil)

	server := NewServer(db, newEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})

	t.Run("Get", func(t *testing.T) {
		_, err := server.Get(context.Background(), &clusterapi.ClusterQuery{
			Name: "cluster-not-exists",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")

		_, err = server.Get(context.Background(), &clusterapi.ClusterQuery{
			Name: "test/ing",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
	})

	t.Run("Update", func(t *testing.T) {
		_, err := server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{
			Cluster: &v1alpha1.Cluster{
				Name: "cluster-not-exists",
			},
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")

		_, err = server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{
			Cluster: &v1alpha1.Cluster{
				Name: "test/ing",
			},
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
	})

	t.Run("Delete", func(t *testing.T) {
		_, err := server.Delete(context.Background(), &clusterapi.ClusterQuery{
			Server: "https://127.0.0.2",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")

		_, err = server.Delete(context.Background(), &clusterapi.ClusterQuery{
			Server: "https://127.0.0.1",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
	})

	t.Run("RotateAuth", func(t *testing.T) {
		_, err := server.RotateAuth(context.Background(), &clusterapi.ClusterQuery{
			Server: "https://127.0.0.2",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")

		_, err = server.RotateAuth(context.Background(), &clusterapi.ClusterQuery{
			Server: "https://127.0.0.1",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
	})

	t.Run("InvalidateCache", func(t *testing.T) {
		_, err := server.InvalidateCache(context.Background(), &clusterapi.ClusterQuery{
			Server: "https://127.0.0.2",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")

		_, err = server.InvalidateCache(context.Background(), &clusterapi.ClusterQuery{
			Server: "https://127.0.0.1",
		})
		assert.Error(t, err)
		assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
	})
}