From cd788d062d5a6d138e5a3bf483662f25478a549d Mon Sep 17 00:00:00 2001 From: Tiago Silva Date: Sun, 1 Dec 2024 12:47:19 +0000 Subject: [PATCH] deflake `TestListUnifiedResources_WithLogins` This PR tries to fix the flakiness of the `TestListUnifiedResources_WithLogins` test. The primary issue identified was that the role was first created and then updated via a separate update call. Since the role, by default, grants wildcard access to all labels, the resources were being returned after the role was created but before the cache had synchronized with the updated role event. As a result, the system failed to return the expected logins, except for the SSH logins, which were created during the initial role creation event. Close #45086 Signed-off-by: Tiago Silva --- lib/auth/auth_with_roles_test.go | 48 +++++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/auth/auth_with_roles_test.go b/lib/auth/auth_with_roles_test.go index ea78686937d05..8381c0781bf91 100644 --- a/lib/auth/auth_with_roles_test.go +++ b/lib/auth/auth_with_roles_test.go @@ -1078,6 +1078,7 @@ func TestGenerateUserCertsWithMFAVerification(t *testing.T) { }) } } + func TestGenerateUserCertsWithRoleRequest(t *testing.T) { ctx := context.Background() srv := newTestTLSServer(t) @@ -5077,6 +5078,19 @@ func TestListUnifiedResources_WithLogins(t *testing.T) { return srv.Auth().UnifiedResourceCache.IsInitialized() }, 5*time.Second, 200*time.Millisecond, "unified resource watcher never initialized") + // create user and client + logins := []string{"llama", "fish"} + user, _, err := CreateUserAndRole(srv.Auth(), "user", nil /*mutated with role mutator*/, nil, + WithRoleMutator( + func(role types.Role) { + role.SetLogins(types.Allow, logins) + role.SetWindowsLogins(types.Allow, logins) + role.SetWindowsDesktopLabels(types.Allow, types.Labels{types.Wildcard: []string{types.Wildcard}}) + role.SetAWSRoleARNs(types.Allow, logins) + }), + ) + require.NoError(t, err) + for i := 0; i < 5; i++ { name := uuid.New().String() node, err := types.NewServerWithLabels( @@ -5134,32 +5148,18 @@ func TestListUnifiedResources_WithLogins(t *testing.T) { require.NoError(t, err) } - // create user and client - logins := []string{"llama", "fish"} - user, role, err := CreateUserAndRole(srv.Auth(), "user", logins, nil) - require.NoError(t, err) - role.SetWindowsDesktopLabels(types.Allow, types.Labels{types.Wildcard: []string{types.Wildcard}}) - role.SetWindowsLogins(types.Allow, logins) - role.SetAppLabels(types.Allow, types.Labels{types.Wildcard: []string{types.Wildcard}}) - role.SetAWSRoleARNs(types.Allow, logins) - _, err = srv.Auth().UpdateRole(ctx, role) - require.NoError(t, err) - clt, err := srv.NewClient(TestUser(user.GetName())) require.NoError(t, err) - var results []*proto.PaginatedResource + resultsC := make(chan []*proto.PaginatedResource, 1) // Immediately listing resources can be problematic, given that not all were // necessarily replicated in the unified resources cache. To cover this // scenario, perform multiple attempts (if necessary) to read the complete // list of resources. require.EventuallyWithT(t, func(t *assert.CollectT) { - // Reset the resources list to avoid having items from previous - // iterations. - results = nil - var start string + var results []*proto.PaginatedResource for { resp, err := clt.ListUnifiedResources(ctx, &proto.ListUnifiedResourcesRequest{ Limit: 5, @@ -5180,13 +5180,21 @@ func TestListUnifiedResources_WithLogins(t *testing.T) { // Note: this number should be updated in case we add more resources to // the setup loop. - assert.Len(t, results, 20) - }, 10*time.Second, 100*time.Millisecond, "unable to list all resources, expected 20 but got %d", len(results)) + if !assert.Len(t, results, 20) { + return + } + resultsC <- results + }, 10*time.Second, 100*time.Millisecond, "unable to list all resources") + results := <-resultsC // Check that only server, desktop, and app server resources contain the expected logins - for _, resource := range results { + expectPrincipals := func(resource *proto.PaginatedResource) bool { isAWSConsoleApp := resource.GetAppServer() != nil && resource.GetAppServer().GetApp().IsAWSConsole() - if resource.GetNode() != nil || resource.GetWindowsDesktop() != nil || isAWSConsoleApp { + return resource.GetNode() != nil || resource.GetWindowsDesktop() != nil || isAWSConsoleApp + } + + for _, resource := range results { + if expectPrincipals(resource) { require.Empty(t, cmp.Diff(resource.Logins, logins, cmpopts.SortSlices(func(a, b string) bool { return strings.Compare(a, b) < 0 })), "mismatch on expected logins list for resource %T", resource.Resource)