github.com/argoproj/argo-cd/v3@v3.2.1/server/project/project_test.go (about)

     1  package project
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/argoproj/argo-cd/v3/util/argo"
    10  	"github.com/argoproj/argo-cd/v3/util/db"
    11  
    12  	"github.com/argoproj/pkg/v2/sync"
    13  	"github.com/golang-jwt/jwt/v5"
    14  	"github.com/google/uuid"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  	"google.golang.org/grpc/codes"
    18  	"google.golang.org/grpc/status"
    19  	corev1 "k8s.io/api/core/v1"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  	"k8s.io/client-go/kubernetes/fake"
    22  	k8scache "k8s.io/client-go/tools/cache"
    23  
    24  	"github.com/argoproj/argo-cd/v3/common"
    25  	"github.com/argoproj/argo-cd/v3/pkg/apiclient/project"
    26  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    27  	apps "github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned/fake"
    28  	informer "github.com/argoproj/argo-cd/v3/pkg/client/informers/externalversions"
    29  	"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
    30  	"github.com/argoproj/argo-cd/v3/test"
    31  	"github.com/argoproj/argo-cd/v3/util/assets"
    32  	jwtutil "github.com/argoproj/argo-cd/v3/util/jwt"
    33  	"github.com/argoproj/argo-cd/v3/util/rbac"
    34  	"github.com/argoproj/argo-cd/v3/util/session"
    35  	"github.com/argoproj/argo-cd/v3/util/settings"
    36  )
    37  
    38  const testNamespace = "default"
    39  
    40  var testEnableEventList = argo.DefaultEnableEventList()
    41  
    42  func TestProjectServer(t *testing.T) {
    43  	kubeclientset := fake.NewClientset(&corev1.ConfigMap{
    44  		ObjectMeta: metav1.ObjectMeta{
    45  			Namespace: testNamespace,
    46  			Name:      "argocd-cm",
    47  			Labels: map[string]string{
    48  				"app.kubernetes.io/part-of": "argocd",
    49  			},
    50  		},
    51  	}, &corev1.Secret{
    52  		ObjectMeta: metav1.ObjectMeta{
    53  			Name:      "argocd-secret",
    54  			Namespace: testNamespace,
    55  		},
    56  		Data: map[string][]byte{
    57  			"admin.password":   []byte("test"),
    58  			"server.secretkey": []byte("test"),
    59  		},
    60  	}, &corev1.Secret{
    61  		ObjectMeta: metav1.ObjectMeta{
    62  			Name:      "cluster-1",
    63  			Namespace: testNamespace,
    64  			Labels: map[string]string{
    65  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
    66  			},
    67  		},
    68  		Data: map[string][]byte{
    69  			"name":   []byte("server1"),
    70  			"server": []byte("https://server1"),
    71  		},
    72  	}, &corev1.Secret{
    73  		ObjectMeta: metav1.ObjectMeta{
    74  			Name:      "cluster-2",
    75  			Namespace: testNamespace,
    76  			Labels: map[string]string{
    77  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
    78  			},
    79  		},
    80  		Data: map[string][]byte{
    81  			"name":   []byte("server2"),
    82  			"server": []byte("https://server2"),
    83  		},
    84  	}, &corev1.Secret{
    85  		ObjectMeta: metav1.ObjectMeta{
    86  			Name:      "cluster-3",
    87  			Namespace: testNamespace,
    88  			Labels: map[string]string{
    89  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
    90  			},
    91  		},
    92  		Data: map[string][]byte{
    93  			"name":   []byte("server3"),
    94  			"server": []byte("https://server3"),
    95  		},
    96  	})
    97  	settingsMgr := settings.NewSettingsManager(t.Context(), kubeclientset, testNamespace)
    98  	enforcer := newEnforcer(kubeclientset)
    99  	existingProj := v1alpha1.AppProject{
   100  		ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: testNamespace},
   101  		Spec: v1alpha1.AppProjectSpec{
   102  			Destinations: []v1alpha1.ApplicationDestination{
   103  				{Namespace: "ns1", Server: "https://server1"},
   104  				{Namespace: "ns2", Server: "https://server2"},
   105  			},
   106  			SourceRepos: []string{"https://github.com/argoproj/argo-cd.git"},
   107  		},
   108  	}
   109  	existingApp := v1alpha1.Application{
   110  		ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   111  		Spec:       v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}, Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns3", Server: "https://server3"}},
   112  	}
   113  
   114  	policyTemplate := "p, proj:%s:%s, applications, %s, %s/%s, %s"
   115  
   116  	ctx := t.Context()
   117  	fakeAppsClientset := apps.NewSimpleClientset()
   118  	factory := informer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, informer.WithNamespace(""), informer.WithTweakListOptions(func(_ *metav1.ListOptions) {}))
   119  	projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer()
   120  	go projInformer.Run(ctx.Done())
   121  	if !k8scache.WaitForCacheSync(ctx.Done(), projInformer.HasSynced) {
   122  		panic("Timed out waiting forfff caches to sync")
   123  	}
   124  
   125  	t.Run("TestNormalizeProj", func(t *testing.T) {
   126  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   127  		projectWithRole := existingProj.DeepCopy()
   128  		roleName := "roleName"
   129  		role1 := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   130  		projectWithRole.Spec.Roles = append(projectWithRole.Spec.Roles, role1)
   131  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   132  		projectServer := NewServer("default", fake.NewClientset(), apps.NewSimpleClientset(projectWithRole), enforcer, sync.NewKeyLock(), sessionMgr, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   133  		err := projectServer.NormalizeProjs()
   134  		require.NoError(t, err)
   135  
   136  		appList, err := projectServer.appclientset.ArgoprojV1alpha1().AppProjects(projectWithRole.Namespace).List(t.Context(), metav1.ListOptions{})
   137  		require.NoError(t, err)
   138  		assert.Equal(t, int64(1), appList.Items[0].Status.JWTTokensByRole[roleName].Items[0].IssuedAt)
   139  		assert.ElementsMatch(t, appList.Items[0].Status.JWTTokensByRole[roleName].Items, appList.Items[0].Spec.Roles[0].JWTTokens)
   140  	})
   141  
   142  	t.Run("TestClusterUpdateDenied", func(t *testing.T) {
   143  		enforcer.SetDefaultRole("role:projects")
   144  		_ = enforcer.SetBuiltinPolicy("p, role:projects, projects, update, *, allow")
   145  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   146  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   147  
   148  		updatedProj := existingProj.DeepCopy()
   149  		updatedProj.Spec.Destinations = nil
   150  
   151  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   152  
   153  		assert.Equal(t, status.Error(codes.PermissionDenied, "permission denied: clusters, update, https://server1"), err)
   154  	})
   155  
   156  	t.Run("TestReposUpdateDenied", func(t *testing.T) {
   157  		enforcer.SetDefaultRole("role:projects")
   158  		_ = enforcer.SetBuiltinPolicy("p, role:projects, projects, update, *, allow")
   159  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   160  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   161  
   162  		updatedProj := existingProj.DeepCopy()
   163  		updatedProj.Spec.SourceRepos = nil
   164  
   165  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   166  
   167  		assert.Equal(t, status.Error(codes.PermissionDenied, "permission denied: repositories, update, https://github.com/argoproj/argo-cd.git"), err)
   168  	})
   169  
   170  	t.Run("TestClusterResourceWhitelistUpdateDenied", func(t *testing.T) {
   171  		enforcer.SetDefaultRole("role:projects")
   172  		_ = enforcer.SetBuiltinPolicy("p, role:projects, projects, update, *, allow")
   173  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   174  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   175  
   176  		updatedProj := existingProj.DeepCopy()
   177  		updatedProj.Spec.ClusterResourceWhitelist = []metav1.GroupKind{{}}
   178  
   179  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   180  
   181  		assert.Equal(t, status.Error(codes.PermissionDenied, "permission denied: clusters, update, https://server1"), err)
   182  	})
   183  
   184  	t.Run("TestNamespaceResourceBlacklistUpdateDenied", func(t *testing.T) {
   185  		enforcer.SetDefaultRole("role:projects")
   186  		_ = enforcer.SetBuiltinPolicy("p, role:projects, projects, update, *, allow")
   187  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   188  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   189  
   190  		updatedProj := existingProj.DeepCopy()
   191  		updatedProj.Spec.NamespaceResourceBlacklist = []metav1.GroupKind{{}}
   192  
   193  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   194  
   195  		assert.Equal(t, status.Error(codes.PermissionDenied, "permission denied: clusters, update, https://server1"), err)
   196  	})
   197  
   198  	enforcer = newEnforcer(kubeclientset)
   199  
   200  	t.Run("TestRemoveDestinationSuccessful", func(t *testing.T) {
   201  		existingApp := v1alpha1.Application{
   202  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   203  			Spec:       v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}, Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns3", Server: "https://server3"}},
   204  		}
   205  
   206  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   207  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   208  
   209  		updatedProj := existingProj.DeepCopy()
   210  		updatedProj.Spec.Destinations = updatedProj.Spec.Destinations[1:]
   211  
   212  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   213  
   214  		require.NoError(t, err)
   215  	})
   216  
   217  	t.Run("TestRemoveDestinationUsedByApp", func(t *testing.T) {
   218  		existingApp := v1alpha1.Application{
   219  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   220  			Spec:       v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}, Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns1", Server: "https://server1"}},
   221  		}
   222  
   223  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   224  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   225  
   226  		updatedProj := existingProj.DeepCopy()
   227  		updatedProj.Spec.Destinations = updatedProj.Spec.Destinations[1:]
   228  
   229  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   230  
   231  		require.Error(t, err)
   232  		statusCode, _ := status.FromError(err)
   233  		assert.Equal(t, codes.InvalidArgument, statusCode.Code())
   234  		assert.Equal(t, "as a result of project update 1 applications destination became invalid", statusCode.Message())
   235  	})
   236  
   237  	t.Run("TestRemoveSourceSuccessful", func(t *testing.T) {
   238  		existingApp := v1alpha1.Application{
   239  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   240  			Spec:       v1alpha1.ApplicationSpec{Destination: v1alpha1.ApplicationDestination{Server: "https://server1"}, Source: &v1alpha1.ApplicationSource{}, Project: "test"},
   241  		}
   242  
   243  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   244  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   245  
   246  		updatedProj := existingProj.DeepCopy()
   247  		updatedProj.Spec.SourceRepos = []string{}
   248  
   249  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   250  
   251  		require.NoError(t, err)
   252  	})
   253  
   254  	t.Run("TestRemoveSourceUsedByApp", func(t *testing.T) {
   255  		existingApp := v1alpha1.Application{
   256  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   257  			Spec:       v1alpha1.ApplicationSpec{Destination: v1alpha1.ApplicationDestination{Name: "server1"}, Project: "test", Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argo-cd.git"}},
   258  		}
   259  
   260  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   261  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   262  
   263  		updatedProj := existingProj.DeepCopy()
   264  		updatedProj.Spec.SourceRepos = []string{}
   265  
   266  		_, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   267  
   268  		require.Error(t, err)
   269  		statusCode, _ := status.FromError(err)
   270  		assert.Equalf(t, codes.InvalidArgument, statusCode.Code(), "Got unexpected error code with error: %v", err)
   271  		assert.Equal(t, "as a result of project update 1 applications source became invalid", statusCode.Message())
   272  	})
   273  
   274  	t.Run("TestRemoveSourceUsedByAppSuccessfulIfPermittedByAnotherSrc", func(t *testing.T) {
   275  		proj := existingProj.DeepCopy()
   276  		proj.Spec.SourceRepos = []string{"https://github.com/argoproj/argo-cd.git", "https://github.com/argoproj/*"}
   277  		existingApp := v1alpha1.Application{
   278  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   279  			Spec:       v1alpha1.ApplicationSpec{Destination: v1alpha1.ApplicationDestination{Server: "https://server1"}, Project: "test", Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argo-cd.git"}},
   280  		}
   281  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   282  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(proj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   283  
   284  		updatedProj := proj.DeepCopy()
   285  		updatedProj.Spec.SourceRepos = []string{"https://github.com/argoproj/*"}
   286  
   287  		res, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   288  
   289  		require.NoError(t, err)
   290  		assert.ElementsMatch(t, res.Spec.SourceRepos, updatedProj.Spec.SourceRepos)
   291  	})
   292  
   293  	t.Run("TestRemoveDestinationUsedByAppSuccessfulIfPermittedByAnotherDestination", func(t *testing.T) {
   294  		proj := existingProj.DeepCopy()
   295  		proj.Spec.Destinations = []v1alpha1.ApplicationDestination{
   296  			{Namespace: "org1-team1", Server: "https://server1"},
   297  			{Namespace: "org1-*", Server: "https://server1"},
   298  		}
   299  		existingApp := v1alpha1.Application{
   300  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   301  			Spec: v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}, Project: "test", Destination: v1alpha1.ApplicationDestination{
   302  				Server:    "https://server1",
   303  				Namespace: "org1-team1",
   304  			}},
   305  		}
   306  
   307  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   308  
   309  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(proj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   310  
   311  		updatedProj := proj.DeepCopy()
   312  		updatedProj.Spec.Destinations = []v1alpha1.ApplicationDestination{
   313  			{Namespace: "org1-*", Server: "https://server1"},
   314  		}
   315  
   316  		res, err := projectServer.Update(t.Context(), &project.ProjectUpdateRequest{Project: updatedProj})
   317  
   318  		require.NoError(t, err)
   319  		assert.ElementsMatch(t, res.Spec.Destinations, updatedProj.Spec.Destinations)
   320  	})
   321  
   322  	t.Run("TestDeleteProjectSuccessful", func(t *testing.T) {
   323  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   324  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   325  
   326  		_, err := projectServer.Delete(t.Context(), &project.ProjectQuery{Name: "test"})
   327  
   328  		require.NoError(t, err)
   329  	})
   330  
   331  	t.Run("TestDeleteDefaultProjectFailure", func(t *testing.T) {
   332  		defaultProj := v1alpha1.AppProject{
   333  			ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"},
   334  			Spec:       v1alpha1.AppProjectSpec{},
   335  		}
   336  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   337  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&defaultProj), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   338  
   339  		_, err := projectServer.Delete(t.Context(), &project.ProjectQuery{Name: defaultProj.Name})
   340  		statusCode, _ := status.FromError(err)
   341  		assert.Equal(t, codes.InvalidArgument, statusCode.Code())
   342  	})
   343  
   344  	t.Run("TestDeleteProjectReferencedByApp", func(t *testing.T) {
   345  		existingApp := v1alpha1.Application{
   346  			ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
   347  			Spec:       v1alpha1.ApplicationSpec{Project: "test"},
   348  		}
   349  
   350  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   351  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   352  
   353  		_, err := projectServer.Delete(t.Context(), &project.ProjectQuery{Name: "test"})
   354  
   355  		require.Error(t, err)
   356  		statusCode, _ := status.FromError(err)
   357  		assert.Equal(t, codes.InvalidArgument, statusCode.Code())
   358  		assert.Equal(t, "project is referenced by 1 applications", statusCode.Message())
   359  	})
   360  
   361  	// configure a user named "admin" which is denied by default
   362  	enforcer = newEnforcer(kubeclientset)
   363  	_ = enforcer.SetBuiltinPolicy(`p, *, *, *, *, deny`)
   364  	enforcer.SetClaimsEnforcerFunc(nil)
   365  	//nolint:staticcheck
   366  	ctx = context.WithValue(t.Context(), "claims", &jwt.MapClaims{"groups": []string{"my-group"}})
   367  	policyEnf := rbacpolicy.NewRBACPolicyEnforcer(enforcer, nil)
   368  	policyEnf.SetScopes([]string{"groups"})
   369  
   370  	tokenName := "testToken"
   371  	id := "testId"
   372  
   373  	t.Run("TestCreateTokenDenied", func(t *testing.T) {
   374  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   375  		projectWithRole := existingProj.DeepCopy()
   376  		projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}}
   377  
   378  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   379  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithRole), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   380  		_, err := projectServer.CreateToken(ctx, &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1})
   381  		assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = permission denied: projects, update, test")
   382  	})
   383  
   384  	t.Run("TestCreateTokenSuccessfullyUsingGroup", func(t *testing.T) {
   385  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   386  		projectWithRole := existingProj.DeepCopy()
   387  		projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName, Groups: []string{"my-group"}}}
   388  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   389  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithRole), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   390  		_, err := projectServer.CreateToken(ctx, &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1})
   391  		require.NoError(t, err)
   392  	})
   393  
   394  	_ = enforcer.SetBuiltinPolicy(`p, role:admin, projects, update, *, allow`)
   395  
   396  	t.Run("TestCreateTokenSuccessfully", func(t *testing.T) {
   397  		projectWithRole := existingProj.DeepCopy()
   398  		projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}}
   399  		clientset := apps.NewSimpleClientset(projectWithRole)
   400  
   401  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", nil, session.NewUserStateStorage(nil))
   402  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   403  		projectServer := NewServer("default", fake.NewSimpleClientset(), clientset, enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   404  		tokenResponse, err := projectServer.CreateToken(t.Context(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 100})
   405  		require.NoError(t, err)
   406  		claims, _, err := sessionMgr.Parse(tokenResponse.Token)
   407  		require.NoError(t, err)
   408  
   409  		mapClaims, err := jwtutil.MapClaims(claims)
   410  		subject, ok := mapClaims["sub"].(string)
   411  		assert.True(t, ok)
   412  		expectedSubject := fmt.Sprintf(JWTTokenSubFormat, projectWithRole.Name, tokenName)
   413  		assert.Equal(t, expectedSubject, subject)
   414  		require.NoError(t, err)
   415  	})
   416  
   417  	t.Run("TestCreateTokenWithIDSuccessfully", func(t *testing.T) {
   418  		projectWithRole := existingProj.DeepCopy()
   419  		projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}}
   420  		clientset := apps.NewSimpleClientset(projectWithRole)
   421  
   422  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", nil, session.NewUserStateStorage(nil))
   423  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   424  		projectServer := NewServer("default", fake.NewSimpleClientset(), clientset, enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   425  		tokenResponse, err := projectServer.CreateToken(t.Context(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1, Id: id})
   426  		require.NoError(t, err)
   427  		claims, _, err := sessionMgr.Parse(tokenResponse.Token)
   428  		require.NoError(t, err)
   429  
   430  		mapClaims, err := jwtutil.MapClaims(claims)
   431  		subject, ok := mapClaims["sub"].(string)
   432  		assert.True(t, ok)
   433  		expectedSubject := fmt.Sprintf(JWTTokenSubFormat, projectWithRole.Name, tokenName)
   434  		assert.Equal(t, expectedSubject, subject)
   435  		require.NoError(t, err)
   436  	})
   437  
   438  	t.Run("TestCreateTokenWithSameIdDeny", func(t *testing.T) {
   439  		projectWithRole := existingProj.DeepCopy()
   440  		projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}}
   441  		clientset := apps.NewSimpleClientset(projectWithRole)
   442  
   443  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", nil, session.NewUserStateStorage(nil))
   444  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   445  		projectServer := NewServer("default", fake.NewSimpleClientset(), clientset, enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   446  		tokenResponse, err := projectServer.CreateToken(t.Context(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1, Id: id})
   447  
   448  		require.NoError(t, err)
   449  		claims, _, err := sessionMgr.Parse(tokenResponse.Token)
   450  		require.NoError(t, err)
   451  
   452  		mapClaims, err := jwtutil.MapClaims(claims)
   453  		subject, ok := mapClaims["sub"].(string)
   454  		assert.True(t, ok)
   455  		expectedSubject := fmt.Sprintf(JWTTokenSubFormat, projectWithRole.Name, tokenName)
   456  		assert.Equal(t, expectedSubject, subject)
   457  		require.NoError(t, err)
   458  
   459  		_, err1 := projectServer.CreateToken(t.Context(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1, Id: id})
   460  		expectedErr := fmt.Sprintf("rpc error: code = InvalidArgument desc = rpc error: code = InvalidArgument desc = Token id '%s' has been used. ", id)
   461  		assert.EqualError(t, err1, expectedErr)
   462  	})
   463  
   464  	_ = enforcer.SetBuiltinPolicy(`p, *, *, *, *, deny`)
   465  
   466  	t.Run("TestDeleteTokenDenied", func(t *testing.T) {
   467  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   468  		projWithToken := existingProj.DeepCopy()
   469  		issuedAt := int64(1)
   470  		secondIssuedAt := issuedAt + 1
   471  		token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: issuedAt}, {IssuedAt: secondIssuedAt}}}
   472  		projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
   473  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   474  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   475  		_, err := projectServer.DeleteToken(ctx, &project.ProjectTokenDeleteRequest{Project: projWithToken.Name, Role: tokenName, Iat: issuedAt})
   476  		assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = permission denied: projects, update, test")
   477  	})
   478  
   479  	t.Run("TestDeleteTokenSuccessfullyWithGroup", func(t *testing.T) {
   480  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   481  		projWithToken := existingProj.DeepCopy()
   482  		issuedAt := int64(1)
   483  		secondIssuedAt := issuedAt + 1
   484  		token := v1alpha1.ProjectRole{Name: tokenName, Groups: []string{"my-group"}, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: issuedAt}, {IssuedAt: secondIssuedAt}}}
   485  		projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
   486  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   487  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   488  		_, err := projectServer.DeleteToken(ctx, &project.ProjectTokenDeleteRequest{Project: projWithToken.Name, Role: tokenName, Iat: issuedAt})
   489  		require.NoError(t, err)
   490  	})
   491  
   492  	_ = enforcer.SetBuiltinPolicy(`p, role:admin, projects, get, *, allow
   493  p, role:admin, projects, update, *, allow`)
   494  
   495  	t.Run("TestDeleteTokenSuccessfully", func(t *testing.T) {
   496  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   497  		projWithToken := existingProj.DeepCopy()
   498  		issuedAt := int64(1)
   499  		secondIssuedAt := issuedAt + 1
   500  		token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: issuedAt}, {IssuedAt: secondIssuedAt}}}
   501  		projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
   502  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   503  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   504  		_, err := projectServer.DeleteToken(ctx, &project.ProjectTokenDeleteRequest{Project: projWithToken.Name, Role: tokenName, Iat: issuedAt})
   505  		require.NoError(t, err)
   506  		projWithoutToken, err := projectServer.Get(t.Context(), &project.ProjectQuery{Name: projWithToken.Name})
   507  		require.NoError(t, err)
   508  		assert.Len(t, projWithoutToken.Spec.Roles, 1)
   509  		assert.Len(t, projWithoutToken.Spec.Roles[0].JWTTokens, 1)
   510  		assert.Equal(t, projWithoutToken.Spec.Roles[0].JWTTokens[0].IssuedAt, secondIssuedAt)
   511  	})
   512  
   513  	_ = enforcer.SetBuiltinPolicy(`p, role:admin, projects, get, *, allow
   514  p, role:admin, projects, update, *, allow`)
   515  
   516  	t.Run("TestDeleteTokenByIdSuccessfully", func(t *testing.T) {
   517  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   518  		projWithToken := existingProj.DeepCopy()
   519  		issuedAt := int64(1)
   520  		secondIssuedAt := issuedAt + 1
   521  		id := "testId"
   522  		uniqueId, _ := uuid.NewRandom()
   523  		secondId := uniqueId.String()
   524  		token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: issuedAt, ID: id}, {IssuedAt: secondIssuedAt, ID: secondId}}}
   525  		projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
   526  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   527  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   528  		_, err := projectServer.DeleteToken(ctx, &project.ProjectTokenDeleteRequest{Project: projWithToken.Name, Role: tokenName, Iat: secondIssuedAt, Id: id})
   529  		require.NoError(t, err)
   530  		projWithoutToken, err := projectServer.Get(t.Context(), &project.ProjectQuery{Name: projWithToken.Name})
   531  		require.NoError(t, err)
   532  		assert.Len(t, projWithoutToken.Spec.Roles, 1)
   533  		assert.Len(t, projWithoutToken.Spec.Roles[0].JWTTokens, 1)
   534  		assert.Equal(t, projWithoutToken.Spec.Roles[0].JWTTokens[0].IssuedAt, secondIssuedAt)
   535  	})
   536  
   537  	enforcer = newEnforcer(kubeclientset)
   538  
   539  	t.Run("TestCreateTwoTokensInRoleSuccess", func(t *testing.T) {
   540  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   541  		projWithToken := existingProj.DeepCopy()
   542  		tokenName := "testToken"
   543  		token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   544  		projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
   545  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   546  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   547  		_, err := projectServer.CreateToken(t.Context(), &project.ProjectTokenCreateRequest{Project: projWithToken.Name, Role: tokenName})
   548  		require.NoError(t, err)
   549  		projWithTwoTokens, err := projectServer.Get(t.Context(), &project.ProjectQuery{Name: projWithToken.Name})
   550  		require.NoError(t, err)
   551  		assert.Len(t, projWithTwoTokens.Spec.Roles, 1)
   552  		assert.Len(t, projWithTwoTokens.Spec.Roles[0].JWTTokens, 2)
   553  	})
   554  
   555  	t.Run("TestAddWildcardSource", func(t *testing.T) {
   556  		proj := existingProj.DeepCopy()
   557  		wildSourceRepo := "*"
   558  		proj.Spec.SourceRepos = append(proj.Spec.SourceRepos, wildSourceRepo)
   559  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   560  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(proj), enforcer, sync.NewKeyLock(), nil, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   561  		request := &project.ProjectUpdateRequest{Project: proj}
   562  		updatedProj, err := projectServer.Update(t.Context(), request)
   563  		require.NoError(t, err)
   564  		assert.Equal(t, wildSourceRepo, updatedProj.Spec.SourceRepos[1])
   565  	})
   566  
   567  	t.Run("TestCreateRolePolicySuccessfully", func(t *testing.T) {
   568  		action := "create"
   569  		object := "testApplication"
   570  		roleName := "testRole"
   571  		effect := "allow"
   572  
   573  		projWithRole := existingProj.DeepCopy()
   574  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   575  		policy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
   576  		role.Policies = append(role.Policies, policy)
   577  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   578  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   579  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, policyEnf, projInformer, settingsMgr, argoDB, testEnableEventList)
   580  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   581  		_, err := projectServer.Update(t.Context(), request)
   582  		require.NoError(t, err)
   583  		t.Log(projWithRole.Spec.Roles[0].Policies[0])
   584  		expectedPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, role.Name, action, projWithRole.Name, object, effect)
   585  		assert.Equal(t, expectedPolicy, projWithRole.Spec.Roles[0].Policies[0])
   586  	})
   587  
   588  	t.Run("TestValidatePolicyDuplicatePolicyFailure", func(t *testing.T) {
   589  		action := "create"
   590  		object := "testApplication"
   591  		roleName := "testRole"
   592  		effect := "allow"
   593  
   594  		projWithRole := existingProj.DeepCopy()
   595  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   596  		policy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
   597  		role.Policies = append(role.Policies, policy)
   598  		role.Policies = append(role.Policies, policy)
   599  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   600  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   601  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   602  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   603  		_, err := projectServer.Update(t.Context(), request)
   604  		expectedErr := fmt.Sprintf("rpc error: code = AlreadyExists desc = policy '%s' already exists for role '%s'", policy, roleName)
   605  		assert.EqualError(t, err, expectedErr)
   606  	})
   607  
   608  	t.Run("TestValidateProjectAccessToSeparateProjectObjectFailure", func(t *testing.T) {
   609  		action := "create"
   610  		object := "testApplication"
   611  		roleName := "testRole"
   612  		otherProject := "other-project"
   613  		effect := "allow"
   614  
   615  		projWithRole := existingProj.DeepCopy()
   616  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   617  		policy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, otherProject, object, effect)
   618  		role.Policies = append(role.Policies, policy)
   619  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   620  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   621  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   622  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   623  		_, err := projectServer.Update(t.Context(), request)
   624  		assert.ErrorContains(t, err, "object must be of form 'test/*', 'test[/<NAMESPACE>]/<APPNAME>' or 'test/<APPNAME>'")
   625  	})
   626  
   627  	t.Run("TestValidateProjectIncorrectProjectInRoleFailure", func(t *testing.T) {
   628  		action := "create"
   629  		object := "testApplication"
   630  		roleName := "testRole"
   631  		otherProject := "other-project"
   632  		effect := "allow"
   633  
   634  		projWithRole := existingProj.DeepCopy()
   635  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   636  		invalidPolicy := fmt.Sprintf(policyTemplate, otherProject, roleName, action, projWithRole.Name, object, effect)
   637  		role.Policies = append(role.Policies, invalidPolicy)
   638  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   639  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   640  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   641  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   642  		_, err := projectServer.Update(t.Context(), request)
   643  		assert.ErrorContains(t, err, "policy subject must be: 'proj:test:testRole'")
   644  	})
   645  
   646  	t.Run("TestValidateProjectIncorrectTokenInRoleFailure", func(t *testing.T) {
   647  		action := "create"
   648  		object := "testApplication"
   649  		roleName := "testRole"
   650  		otherToken := "other-token"
   651  		effect := "allow"
   652  
   653  		projWithRole := existingProj.DeepCopy()
   654  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   655  		invalidPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, otherToken, action, projWithRole.Name, object, effect)
   656  		role.Policies = append(role.Policies, invalidPolicy)
   657  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   658  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   659  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   660  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   661  		_, err := projectServer.Update(t.Context(), request)
   662  		assert.ErrorContains(t, err, "policy subject must be: 'proj:test:testRole'")
   663  	})
   664  
   665  	t.Run("TestValidateProjectInvalidEffectFailure", func(t *testing.T) {
   666  		action := "create"
   667  		object := "testApplication"
   668  		roleName := "testRole"
   669  		effect := "testEffect"
   670  
   671  		projWithRole := existingProj.DeepCopy()
   672  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   673  		invalidPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
   674  		role.Policies = append(role.Policies, invalidPolicy)
   675  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   676  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   677  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   678  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   679  		_, err := projectServer.Update(t.Context(), request)
   680  		assert.ErrorContains(t, err, "effect must be: 'allow' or 'deny'")
   681  	})
   682  
   683  	t.Run("TestNormalizeProjectRolePolicies", func(t *testing.T) {
   684  		action := "create"
   685  		object := "testApplication"
   686  		roleName := "testRole"
   687  		effect := "allow"
   688  
   689  		projWithRole := existingProj.DeepCopy()
   690  		role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
   691  		noSpacesPolicyTemplate := strings.ReplaceAll(policyTemplate, " ", "")
   692  		invalidPolicy := fmt.Sprintf(noSpacesPolicyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
   693  		role.Policies = append(role.Policies, invalidPolicy)
   694  		projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
   695  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   696  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, sync.NewKeyLock(), nil, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   697  		request := &project.ProjectUpdateRequest{Project: projWithRole}
   698  		updateProj, err := projectServer.Update(t.Context(), request)
   699  		require.NoError(t, err)
   700  		expectedPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
   701  		assert.Equal(t, expectedPolicy, updateProj.Spec.Roles[0].Policies[0])
   702  	})
   703  
   704  	t.Run("TestSyncWindowsActive", func(t *testing.T) {
   705  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   706  		projectWithSyncWindows := existingProj.DeepCopy()
   707  		projectWithSyncWindows.Spec.SyncWindows = v1alpha1.SyncWindows{}
   708  		win := &v1alpha1.SyncWindow{Kind: "allow", Schedule: "* * * * *", Duration: "1h"}
   709  		projectWithSyncWindows.Spec.SyncWindows = append(projectWithSyncWindows.Spec.SyncWindows, win)
   710  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   711  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithSyncWindows), enforcer, sync.NewKeyLock(), sessionMgr, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   712  		res, err := projectServer.GetSyncWindowsState(ctx, &project.SyncWindowsQuery{Name: projectWithSyncWindows.Name})
   713  		require.NoError(t, err)
   714  		assert.Len(t, res.Windows, 1)
   715  	})
   716  
   717  	t.Run("TestGetSyncWindowsStateCannotGetProjectDetails", func(t *testing.T) {
   718  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   719  		projectWithSyncWindows := existingProj.DeepCopy()
   720  		projectWithSyncWindows.Spec.SyncWindows = v1alpha1.SyncWindows{}
   721  		win := &v1alpha1.SyncWindow{Kind: "allow", Schedule: "* * * * *", Duration: "1h"}
   722  		projectWithSyncWindows.Spec.SyncWindows = append(projectWithSyncWindows.Spec.SyncWindows, win)
   723  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   724  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithSyncWindows), enforcer, sync.NewKeyLock(), sessionMgr, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   725  		res, err := projectServer.GetSyncWindowsState(ctx, &project.SyncWindowsQuery{Name: "incorrect"})
   726  		require.ErrorContains(t, err, "not found")
   727  		assert.Nil(t, res)
   728  	})
   729  
   730  	t.Run("TestGetSyncWindowsStateDenied", func(t *testing.T) {
   731  		enforcer = newEnforcer(kubeclientset)
   732  		_ = enforcer.SetBuiltinPolicy(`p, *, *, *, *, deny`)
   733  		enforcer.SetClaimsEnforcerFunc(nil)
   734  		//nolint:staticcheck
   735  		ctx := context.WithValue(t.Context(), "claims", &jwt.MapClaims{"groups": []string{"my-group"}})
   736  
   737  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   738  		projectWithSyncWindows := existingProj.DeepCopy()
   739  		win := &v1alpha1.SyncWindow{Kind: "allow", Schedule: "* * * * *", Duration: "1h"}
   740  		projectWithSyncWindows.Spec.SyncWindows = append(projectWithSyncWindows.Spec.SyncWindows, win)
   741  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   742  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithSyncWindows), enforcer, sync.NewKeyLock(), sessionMgr, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   743  		_, err := projectServer.GetSyncWindowsState(ctx, &project.SyncWindowsQuery{Name: projectWithSyncWindows.Name})
   744  		assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = permission denied: projects, get, test")
   745  	})
   746  
   747  	t.Run("TestAddSyncWindowWhenAnAppReferencesAClusterThatDoesNotExist", func(t *testing.T) {
   748  		_ = enforcer.SetBuiltinPolicy(`p, role:admin, projects, get, *, allow
   749  p, role:admin, projects, update, *, allow`)
   750  		sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil))
   751  		projectWithAppWithInvalidCluster := existingProj.DeepCopy()
   752  
   753  		argoDB := db.NewDB("default", settingsMgr, kubeclientset)
   754  		invalidApp := v1alpha1.Application{
   755  			ObjectMeta: metav1.ObjectMeta{Name: "test-invalid", Namespace: "default"},
   756  			Spec:       v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}, Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns3", Server: "https://server4"}},
   757  		}
   758  		projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithAppWithInvalidCluster, &invalidApp), enforcer, sync.NewKeyLock(), sessionMgr, nil, projInformer, settingsMgr, argoDB, testEnableEventList)
   759  
   760  		// Add sync window
   761  		syncWindow := v1alpha1.SyncWindow{
   762  			Kind:         "deny",
   763  			Schedule:     "* * * * *",
   764  			Duration:     "1h",
   765  			Applications: []string{"*"},
   766  			Clusters:     []string{"*"},
   767  		}
   768  		projectWithAppWithInvalidCluster.Spec.SyncWindows = append(projectWithAppWithInvalidCluster.Spec.SyncWindows, &syncWindow)
   769  		res, err := projectServer.Update(ctx, &project.ProjectUpdateRequest{
   770  			Project: projectWithAppWithInvalidCluster,
   771  		})
   772  		require.NoError(t, err)
   773  		assert.Len(t, res.Spec.SyncWindows, 1)
   774  	})
   775  }
   776  
   777  func newEnforcer(kubeclientset *fake.Clientset) *rbac.Enforcer {
   778  	enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil)
   779  	_ = enforcer.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
   780  	enforcer.SetDefaultRole("role:admin")
   781  	enforcer.SetClaimsEnforcerFunc(func(_ jwt.Claims, _ ...any) bool {
   782  		return true
   783  	})
   784  	return enforcer
   785  }