@@ -43,6 +43,8 @@ import (
4343 socai_repository "github.com/utmstack/utmstack/backend/modules/socai/repository"
4444 "github.com/utmstack/utmstack/backend/modules/storage"
4545 "github.com/utmstack/utmstack/backend/modules/tenant"
46+ tenant_domain "github.com/utmstack/utmstack/backend/modules/tenant/domain"
47+ tenant_dto "github.com/utmstack/utmstack/backend/modules/tenant/dto"
4648 "github.com/utmstack/utmstack/backend/modules/threatintel"
4749 "github.com/utmstack/utmstack/backend/pkg/agentmanager"
4850 "github.com/utmstack/utmstack/backend/pkg/env"
@@ -129,7 +131,24 @@ func initModules(db *gorm.DB, cfg *config) *modules {
129131 _ = catcher .Error ("failed to register tenancy callbacks" , err , nil )
130132 panic (err )
131133 }
132- configMod := appconfig .NewModule (db , cipher , cfg .uploadDir )
134+ // ponytail: late-bound lister so configMod can be constructed before tenantMod exists;
135+ // tenantMod is always set before the first HTTP request reaches the handler.
136+ var tenantMod * tenant.Module
137+ tenantLister := func (ctx context.Context ) ([]string , error ) {
138+ tenants , _ , err := tenantMod .GetTenantUsecase ().List (ctx , tenant_dto.Filter {Size : 10000 , Status : tenant_domain .StatusActive })
139+ if err != nil {
140+ return nil , err
141+ }
142+ ids := make ([]string , 0 , len (tenants ))
143+ for _ , t := range tenants {
144+ ids = append (ids , t .ID .String ())
145+ }
146+ return ids , nil
147+ }
148+ var tenantListerForConfig func (context.Context ) ([]string , error )
149+ configMod := appconfig .NewModule (db , cipher , cfg .uploadDir , func (ctx context.Context ) ([]string , error ) {
150+ return tenantListerForConfig (ctx )
151+ })
133152 mailMod := mail .NewModule (configMod .Store ())
134153 configMod .SetMailer (mailMod .Service ())
135154 // White-labeling renders only under an Enterprise license (resolved from billing).
@@ -142,7 +161,7 @@ func initModules(db *gorm.DB, cfg *config) *modules {
142161 complianceEventReader = events
143162 }
144163 complianceMod := compliance .NewModule (db , complianceEventReader , mailMod .Service (), complianceBranding {uc : brand , uploadDir : cfg .uploadDir },
145- func () bool { return billingMod .License ().Current ().IsEnterprise () })
164+ func () bool { return billingMod .License ().Current ().IsEnterprise () }, tenantLister )
146165 var eventReader dash_usecase.Reader
147166 if events != nil {
148167 eventReader = events
@@ -175,7 +194,7 @@ func initModules(db *gorm.DB, cfg *config) *modules {
175194 agentClient = nil
176195 }
177196
178- soarMod := soar .NewModule (db , agentClient , signer , cipher )
197+ soarMod := soar .NewModule (db , agentClient , signer , cipher , tenantLister )
179198 eventProcessingMod := eventprocessing .NewModule (db , events , auditMod .Logger (), cfg .playgroundBaseURL , cfg .internalKey )
180199
181200 alertsMod .SetCorrelationResolver (eventProcessingMod )
@@ -195,11 +214,11 @@ func initModules(db *gorm.DB, cfg *config) *modules {
195214 env .Int ("NOTIFICATIONS_RETENTION_DAYS" , 365 , false ))
196215
197216 iam_handler .AppBaseURL = env .String ("APP_BASE_URL" , "" , false )
198- iamMod := iam .NewModule (authUsecase , userUsecase , roleUsecase , tfaUsecase , apiKeyUsecase , idpUsecase , federationUsecase , cfg .uploadDir )
217+ tenantMod = tenant .NewModule (db , userUsecase )
218+ tenantListerForConfig = tenantLister
219+ iamMod := iam .NewModule (authUsecase , userUsecase , roleUsecase , tfaUsecase , apiKeyUsecase , idpUsecase , federationUsecase , cfg .uploadDir , tenantLister )
199220 iamMod .SetSessionPurger (iam_usecase .NewSessionPurger (refreshRepo , joblease .New (db )))
200221
201- tenantMod := tenant .NewModule (db , userUsecase )
202-
203222 aiUsage := socai_repository .NewUsageRepo (db )
204223 aiQuota := & socai.AIQuota {
205224 LimitOf : func (ctx context.Context , tenantID string ) (int , error ) {
0 commit comments