Skip to content

Commit b2758d6

Browse files
committed
refactor(api,cli): migrate membership management to dedicated collection
- Migrate from embedded namespace.members to standalone membership_invitations collection - Add environment-specific prefixes ([cloud] vs [community|enterprise]) to member service tests - Update AddNamespaceMember tests to use MembershipInvitationResolve for cloud environments - Refactor addMember tests to validate MembershipInvitationCreate instead of direct membership - Add cloud-specific UpdateNamespaceMember tests for invitation management - Update RemoveNamespaceMember tests with invitation cancellation logic using MembershipInvitationStatusCancelled - Fix mock.MatchedBy matchers to validate invitation status changes - Add envMock.AssertExpectations to all refactored test functions - Create audit trail for all membership operations across environments
1 parent dc1798d commit b2758d6

29 files changed

+1850
-629
lines changed

api/services/auth.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,8 @@ func (s *service) AuthLocalUser(ctx context.Context, req *requests.AuthLocalUser
309309

310310
tenantID := ""
311311
role := ""
312-
// Populate the tenant and role when the user is associated with a namespace. If the member status is pending, we
313-
// ignore the namespace.
314312
if ns, _ := s.store.NamespaceGetPreferred(ctx, user.ID); ns != nil && ns.TenantID != "" {
315-
if m, _ := ns.FindMember(user.ID); m.Status != models.MemberStatusPending {
313+
if m, _ := ns.FindMember(user.ID); m != nil {
316314
tenantID = ns.TenantID
317315
role = m.Role.String()
318316
}
@@ -393,10 +391,8 @@ func (s *service) CreateUserToken(ctx context.Context, req *requests.CreateUserT
393391
return nil, NewErrNamespaceMemberNotFound(user.ID, nil)
394392
}
395393

396-
if member.Status != models.MemberStatusPending {
397-
tenantID = namespace.TenantID
398-
role = member.Role.String()
399-
}
394+
tenantID = namespace.TenantID
395+
role = member.Role.String()
400396
default:
401397
namespace, err := s.store.NamespaceResolve(ctx, store.NamespaceTenantIDResolver, req.TenantID)
402398
if err != nil {
@@ -408,10 +404,6 @@ func (s *service) CreateUserToken(ctx context.Context, req *requests.CreateUserT
408404
return nil, NewErrNamespaceMemberNotFound(user.ID, nil)
409405
}
410406

411-
if member.Status == models.MemberStatusPending {
412-
return nil, NewErrNamespaceMemberNotFound(user.ID, nil)
413-
}
414-
415407
tenantID = namespace.TenantID
416408
role = member.Role.String()
417409

api/services/auth_test.go

Lines changed: 4 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,134 +1890,6 @@ func TestService_AuthLocalUser(t *testing.T) {
18901890
err: nil,
18911891
},
18921892
},
1893-
{
1894-
description: "succeeds to authenticate with a namespace (and member status 'pending')",
1895-
sourceIP: "127.0.0.1",
1896-
req: &requests.AuthLocalUser{
1897-
Identifier: "john_doe",
1898-
Password: "secret",
1899-
},
1900-
requiredMocks: func() {
1901-
user := &models.User{
1902-
ID: "65fdd16b5f62f93184ec8a39",
1903-
Origin: models.UserOriginLocal,
1904-
Status: models.UserStatusConfirmed,
1905-
LastLogin: now,
1906-
MFA: models.UserMFA{
1907-
Enabled: false,
1908-
},
1909-
UserData: models.UserData{
1910-
Username: "john_doe",
1911-
1912-
Name: "john doe",
1913-
},
1914-
Password: models.UserPassword{
1915-
Hash: "$2a$10$V/6N1wsjheBVvWosPfv02uf4WAOb9lmp8YWQCIa2UYuFV4OJby7Yi",
1916-
},
1917-
Preferences: models.UserPreferences{
1918-
PreferredNamespace: "00000000-0000-4000-0000-000000000000",
1919-
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
1920-
},
1921-
}
1922-
updatedUser := &models.User{
1923-
ID: "65fdd16b5f62f93184ec8a39",
1924-
Origin: models.UserOriginLocal,
1925-
Status: models.UserStatusConfirmed,
1926-
LastLogin: now,
1927-
MFA: models.UserMFA{
1928-
Enabled: false,
1929-
},
1930-
UserData: models.UserData{
1931-
Username: "john_doe",
1932-
1933-
Name: "john doe",
1934-
},
1935-
Password: models.UserPassword{
1936-
Hash: "$2a$10$V/6N1wsjheBVvWosPfv02uf4WAOb9lmp8YWQCIa2UYuFV4OJby7Yi",
1937-
},
1938-
Preferences: models.UserPreferences{
1939-
PreferredNamespace: "",
1940-
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
1941-
},
1942-
}
1943-
1944-
mock.
1945-
On("SystemGet", ctx).
1946-
Return(
1947-
&models.System{
1948-
Authentication: &models.SystemAuthentication{
1949-
Local: &models.SystemAuthenticationLocal{
1950-
Enabled: true,
1951-
},
1952-
},
1953-
},
1954-
nil,
1955-
).
1956-
Once()
1957-
mock.
1958-
On("UserResolve", ctx, store.UserUsernameResolver, "john_doe").
1959-
Return(user, nil).
1960-
Once()
1961-
cacheMock.
1962-
On("HasAccountLockout", ctx, "127.0.0.1", "65fdd16b5f62f93184ec8a39").
1963-
Return(int64(0), 0, nil).
1964-
Once()
1965-
hashMock.
1966-
On("CompareWith", "secret", "$2a$10$V/6N1wsjheBVvWosPfv02uf4WAOb9lmp8YWQCIa2UYuFV4OJby7Yi").
1967-
Return(true).
1968-
Once()
1969-
cacheMock.
1970-
On("ResetLoginAttempts", ctx, "127.0.0.1", "65fdd16b5f62f93184ec8a39").
1971-
Return(nil).
1972-
Once()
1973-
1974-
ns := &models.Namespace{
1975-
TenantID: "00000000-0000-4000-0000-000000000000",
1976-
Members: []models.Member{
1977-
{
1978-
ID: "65fdd16b5f62f93184ec8a39",
1979-
Role: "owner",
1980-
Status: models.MemberStatusPending,
1981-
},
1982-
},
1983-
}
1984-
1985-
mock.
1986-
On("NamespaceGetPreferred", ctx, "65fdd16b5f62f93184ec8a39").
1987-
Return(ns, nil).
1988-
Once()
1989-
1990-
clockMock := new(clockmock.Clock)
1991-
clock.DefaultBackend = clockMock
1992-
clockMock.On("Now").Return(now)
1993-
1994-
cacheMock.
1995-
On("Set", ctx, "token_65fdd16b5f62f93184ec8a39", testifymock.Anything, time.Hour*72).
1996-
Return(nil).
1997-
Once()
1998-
1999-
mock.
2000-
On("UserUpdate", ctx, updatedUser).
2001-
Return(nil).
2002-
Once()
2003-
},
2004-
expected: Expected{
2005-
res: &models.UserAuthResponse{
2006-
ID: "65fdd16b5f62f93184ec8a39",
2007-
Origin: models.UserOriginLocal.String(),
2008-
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
2009-
Name: "john doe",
2010-
User: "john_doe",
2011-
2012-
Tenant: "",
2013-
Role: "",
2014-
Token: "must ignore",
2015-
},
2016-
lockout: 0,
2017-
mfaToken: "",
2018-
err: nil,
2019-
},
2020-
},
20211893
{
20221894
description: "succeeds to authenticate with a namespace (and empty preferred namespace)",
20231895
sourceIP: "127.0.0.1",
@@ -2391,57 +2263,6 @@ func TestCreateUserToken(t *testing.T) {
23912263
err: NewErrNamespaceMemberNotFound("000000000000000000000000", nil),
23922264
},
23932265
},
2394-
{
2395-
description: "[with-tenant] fails when user membership is pending",
2396-
req: &requests.CreateUserToken{UserID: "000000000000000000000000", TenantID: "00000000-0000-4000-0000-000000000000"},
2397-
requiredMocks: func(ctx context.Context) {
2398-
storeMock.
2399-
On("UserResolve", ctx, store.UserIDResolver, "000000000000000000000000").
2400-
Return(
2401-
&models.User{
2402-
ID: "000000000000000000000000",
2403-
Status: models.UserStatusConfirmed,
2404-
LastLogin: now,
2405-
MFA: models.UserMFA{
2406-
Enabled: false,
2407-
},
2408-
UserData: models.UserData{
2409-
Username: "john_doe",
2410-
2411-
Name: "john doe",
2412-
},
2413-
Password: models.UserPassword{
2414-
Hash: "$2a$10$V/6N1wsjheBVvWosPfv02uf4WAOb9lmp8YWQCIa2UYuFV4OJby7Yi",
2415-
},
2416-
Preferences: models.UserPreferences{
2417-
PreferredNamespace: "",
2418-
},
2419-
},
2420-
nil,
2421-
).
2422-
Once()
2423-
storeMock.
2424-
On("NamespaceResolve", ctx, store.NamespaceTenantIDResolver, "00000000-0000-4000-0000-000000000000").
2425-
Return(
2426-
&models.Namespace{
2427-
TenantID: "00000000-0000-4000-0000-000000000000",
2428-
Members: []models.Member{
2429-
{
2430-
ID: "000000000000000000000000",
2431-
Role: "administrator",
2432-
Status: models.MemberStatusPending,
2433-
},
2434-
},
2435-
},
2436-
nil,
2437-
).
2438-
Once()
2439-
},
2440-
expected: Expected{
2441-
res: nil,
2442-
err: NewErrNamespaceMemberNotFound("000000000000000000000000", nil),
2443-
},
2444-
},
24452266
{
24462267
description: "[with-tenant] succeeds",
24472268
req: &requests.CreateUserToken{UserID: "000000000000000000000000", TenantID: "00000000-0000-4000-0000-000000000000"},
@@ -2496,9 +2317,8 @@ func TestCreateUserToken(t *testing.T) {
24962317
TenantID: "00000000-0000-4000-0000-000000000000",
24972318
Members: []models.Member{
24982319
{
2499-
ID: "000000000000000000000000",
2500-
Role: "owner",
2501-
Status: models.MemberStatusAccepted,
2320+
ID: "000000000000000000000000",
2321+
Role: "owner",
25022322
},
25032323
},
25042324
},
@@ -2566,9 +2386,8 @@ func TestCreateUserToken(t *testing.T) {
25662386
TenantID: "00000000-0000-4000-0000-000000000000",
25672387
Members: []models.Member{
25682388
{
2569-
ID: "000000000000000000000000",
2570-
Role: "owner",
2571-
Status: models.MemberStatusAccepted,
2389+
ID: "000000000000000000000000",
2390+
Role: "owner",
25722391
},
25732392
},
25742393
},

0 commit comments

Comments
 (0)