1
0
forked from baron/baron-sso

린트 적용

This commit is contained in:
2026-03-05 17:20:46 +09:00
parent 3113fc09ff
commit c2b55081a6
8 changed files with 144 additions and 31 deletions

View File

@@ -83,7 +83,7 @@ func (h *AuditHandler) ListLogs(c *fiber.Ctx) error {
if profile.TenantID != nil {
filterTenantID = *profile.TenantID
}
// If they requested a specific tenant, verify they can manage it
if requestedTenantID != "" && requestedTenantID != filterTenantID {
canManage := false

View File

@@ -171,6 +171,7 @@ func (m *AsyncMockTenantService) ListTenants(ctx context.Context, limit, offset
func (m *AsyncMockTenantService) ListManageableTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
return nil, nil
}
func (m *AsyncMockTenantService) IsDomainAllowed(ctx context.Context, domainName string) (bool, error) {
return false, nil
}

View File

@@ -148,24 +148,24 @@ func (h *TenantHandler) ListTenants(c *fiber.Ctx) error {
tenantIDs = append(tenantIDs, t.ID)
slugs = append(slugs, t.Slug)
}
idCounts, _ := h.UserRepo.CountByTenantIDs(c.Context(), tenantIDs)
slugCounts, _ := h.UserRepo.CountByCompanyCodes(c.Context(), slugs)
items := make([]tenantSummary, 0, len(tenants))
for _, t := range tenants {
summary := mapTenantSummary(t)
// Combine counts from both ID and Slug (Max to avoid double counting if some have one or the other)
idCount := idCounts[t.ID]
slugCount := slugCounts[strings.ToLower(t.Slug)]
if idCount > slugCount {
summary.MemberCount = idCount
} else {
summary.MemberCount = slugCount
}
items = append(items, summary)
}
@@ -195,7 +195,7 @@ func (h *TenantHandler) GetTenant(c *fiber.Ctx) error {
idCount := idCounts[tenant.ID]
slugCount := slugCounts[strings.ToLower(tenant.Slug)]
count := idCount
if slugCount > idCount {
count = slugCount

View File

@@ -226,7 +226,7 @@ func (h *UserHandler) GetUser(c *fiber.Ctx) error {
requester, _ := c.Locals("user_profile").(*domain.UserProfileResponse)
if requester != nil && requester.Role == domain.RoleTenantAdmin {
compCode := strings.ToLower(extractTraitString(identity.Traits, "companyCode"))
// Check if the target user's companyCode is in requester's manageable tenants
allowed := false
for _, t := range requester.ManageableTenants {
@@ -539,7 +539,6 @@ func (h *UserHandler) BulkCreateUsers(c *fiber.Ctx) error {
PhoneNumber: normalizePhoneNumber(item.Phone),
Attributes: attributes,
}, password)
if err != nil {
results = append(results, bulkUserResult{Email: email, Success: false, Message: err.Error()})
continue
@@ -561,7 +560,7 @@ func (h *UserHandler) BulkCreateUsers(c *fiber.Ctx) error {
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if tItem.ID != "" {
localUser.TenantID = &tItem.ID
}
@@ -575,11 +574,11 @@ func (h *UserHandler) BulkCreateUsers(c *fiber.Ctx) error {
if err := h.UserRepo.Update(c.Context(), localUser); err != nil {
slog.Error("Failed to sync bulk user to local DB", "email", email, "error", err)
}
if h.KetoOutboxRepo != nil {
// 1. Sync Role based relationship
h.syncKetoRole(c.Context(), localUser.ID, role, "", "", localUser.TenantID)
// 2. Sync direct membership to the Tenant (for count)
if localUser.TenantID != nil && *localUser.TenantID != "" {
_ = h.KetoOutboxRepo.Create(c.Context(), &domain.KetoOutbox{
@@ -803,7 +802,7 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
}
if req.CompanyCode != nil {
traits["companyCode"] = *req.CompanyCode
// Resolve and update tenant_id in traits if changed
if tItem, exists := tenantCache[*req.CompanyCode]; exists {
traits["tenant_id"] = tItem.ID
@@ -841,11 +840,19 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
oldRole := extractTraitString(identity.Traits, "grade")
oldTenantID := extractTraitString(identity.Traits, "tenant_id")
if req.Role != nil { localUser.Role = *req.Role }
if req.Status != nil { localUser.Status = *req.Status }
if req.CompanyCode != nil { localUser.CompanyCode = *req.CompanyCode }
if req.Department != nil { localUser.Department = *req.Department }
if req.Role != nil {
localUser.Role = *req.Role
}
if req.Status != nil {
localUser.Status = *req.Status
}
if req.CompanyCode != nil {
localUser.CompanyCode = *req.CompanyCode
}
if req.Department != nil {
localUser.Department = *req.Department
}
// Resolve TenantID if changing companyCode
if req.CompanyCode != nil && h.TenantService != nil {
if tenant, err := h.TenantService.GetTenantBySlug(c.Context(), *req.CompanyCode); err == nil && tenant != nil {
@@ -857,7 +864,7 @@ func (h *UserHandler) BulkUpdateUsers(c *fiber.Ctx) error {
// [Keto Sync]
if h.KetoOutboxRepo != nil {
h.syncKetoRole(c.Context(), localUser.ID,
h.syncKetoRole(c.Context(), localUser.ID,
localUser.Role, oldRole, oldTenantID, localUser.TenantID)
}
}
@@ -992,12 +999,12 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
// [Validation] Based on Tenant Schema (Multi-tenant aware)
isAdmin := requester != nil && (requester.Role == domain.RoleSuperAdmin || requester.Role == domain.RoleTenantAdmin)
// If metadata is namespaced (key is tenant ID), validate each namespace
// If it's flat, validate using schemaCompCode
for key, val := range req.Metadata {
// Basic check if key looks like a UUID (tenant ID)
if len(key) >= 32 {
if len(key) >= 32 {
// Namespaced metadata
if h.TenantService != nil {
tenant, err := h.TenantService.GetTenant(c.Context(), key)

View File

@@ -26,10 +26,12 @@ func (m *MockKratosAdmin) ListIdentities(ctx context.Context) ([]service.KratosI
args := m.Called(ctx)
return args.Get(0).([]service.KratosIdentity), args.Error(1)
}
func (m *MockKratosAdmin) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
args := m.Called(ctx, identifier)
return args.String(0), args.Error(1)
}
func (m *MockKratosAdmin) GetIdentity(ctx context.Context, id string) (*service.KratosIdentity, error) {
args := m.Called(ctx, id)
if args.Get(0) == nil {
@@ -37,6 +39,7 @@ func (m *MockKratosAdmin) GetIdentity(ctx context.Context, id string) (*service.
}
return args.Get(0).(*service.KratosIdentity), args.Error(1)
}
func (m *MockKratosAdmin) UpdateIdentity(ctx context.Context, id string, traits map[string]interface{}, state string) (*service.KratosIdentity, error) {
args := m.Called(ctx, id, traits, state)
if args.Get(0) == nil {
@@ -44,9 +47,11 @@ func (m *MockKratosAdmin) UpdateIdentity(ctx context.Context, id string, traits
}
return args.Get(0).(*service.KratosIdentity), args.Error(1)
}
func (m *MockKratosAdmin) UpdateIdentityPassword(ctx context.Context, id, pw string) error {
return m.Called(ctx, id, pw).Error(0)
}
func (m *MockKratosAdmin) DeleteIdentity(ctx context.Context, id string) error {
return m.Called(ctx, id).Error(0)
}
@@ -59,9 +64,11 @@ func (m *MockOryProvider) CreateUser(user *domain.BrokerUser, password string) (
args := m.Called(user, password)
return args.String(0), args.Error(1)
}
func (m *MockOryProvider) UpdateUserPassword(loginID, newPassword string, r *http.Request) error {
return m.Called(loginID, newPassword, r).Error(0)
}
func (m *MockOryProvider) GetPasswordPolicy() (*domain.PasswordPolicy, error) {
args := m.Called()
return args.Get(0).(*domain.PasswordPolicy), args.Error(1)
@@ -162,7 +169,7 @@ func TestUserHandler_BulkCreateUsers(t *testing.T) {
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
results := result["results"].([]interface{})
assert.False(t, results[0].(map[string]interface{})["success"].(bool))
assert.Contains(t, results[0].(map[string]interface{})["message"].(string), "tenant not found")
})
@@ -250,7 +257,7 @@ func TestUserHandler_BulkUpdateUsers(t *testing.T) {
mockKratos.On("GetIdentity", mock.Anything, "u-1").Return(&service.KratosIdentity{
ID: "u-1", Traits: map[string]interface{}{"email": "u1@test.com"}, State: "active",
}, nil).Once()
mockKratos.On("UpdateIdentity", mock.Anything, "u-1", mock.Anything, "inactive").Return(&service.KratosIdentity{}, nil).Once()
status := "inactive"
@@ -264,7 +271,7 @@ func TestUserHandler_BulkUpdateUsers(t *testing.T) {
resp, _ := app.Test(req)
assert.Equal(t, 200, resp.StatusCode)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
results := result["results"].([]interface{})
@@ -285,7 +292,7 @@ func TestUserHandler_BulkDeleteUsers(t *testing.T) {
t.Run("Success - Delete multiple", func(t *testing.T) {
mockKratos.On("GetIdentity", mock.Anything, "u-1").Return(&service.KratosIdentity{ID: "u-1"}, nil).Once()
mockKratos.On("GetIdentity", mock.Anything, "u-2").Return(&service.KratosIdentity{ID: "u-2"}, nil).Once()
mockKratos.On("DeleteIdentity", mock.Anything, "u-1").Return(nil).Once()
mockKratos.On("DeleteIdentity", mock.Anything, "u-2").Return(nil).Once()