diff --git a/api/appbean/AppDetail.go b/api/appbean/AppDetail.go index d44108eff81..ba6a101f575 100644 --- a/api/appbean/AppDetail.go +++ b/api/appbean/AppDetail.go @@ -8,21 +8,21 @@ import ( ) type AppDetail struct { - Metadata *AppMetadata `json:"metadata,notnull" validate:"required"` - GitMaterials []*GitMaterial `json:"gitMaterials,notnull"` - DockerConfig *DockerConfig `json:"dockerConfig"` - GlobalDeploymentTemplate *DeploymentTemplate `json:"globalDeploymentTemplate,notnull"` - AppWorkflows []*AppWorkflow `json:"workflows"` - GlobalConfigMaps []*ConfigMap `json:"globalConfigMaps"` - GlobalSecrets []*Secret `json:"globalSecrets"` - EnvironmentOverrides map[string]*EnvironmentOverride `json:"environmentOverride"` + Metadata *AppMetadata `json:"metadata,notnull" validate:"dive,required"` + GitMaterials []*GitMaterial `json:"gitMaterials,notnull" validate:"dive,min=1"` + DockerConfig *DockerConfig `json:"dockerConfig" validate:"dive"` + GlobalDeploymentTemplate *DeploymentTemplate `json:"globalDeploymentTemplate,notnull" validate:"dive"` + AppWorkflows []*AppWorkflow `json:"workflows,omitempty" validate:"dive"` + GlobalConfigMaps []*ConfigMap `json:"globalConfigMaps,omitempty" validate:"dive"` + GlobalSecrets []*Secret `json:"globalSecrets,omitempty" validate:"dive"` + EnvironmentOverrides map[string]*EnvironmentOverride `json:"environmentOverride,omitempty" validate:"dive"` } type AppWorkflowCloneDto struct { AppId int `json:"appId"` - AppName string `json:"appName"` - AppWorkflows []*AppWorkflow `json:"workflows"` - EnvironmentOverrides map[string]*EnvironmentOverride `json:"environmentOverride"` + AppName string `json:"appName" validate:"required"` + AppWorkflows []*AppWorkflow `json:"workflows,omitempty" validate:"dive"` + EnvironmentOverrides map[string]*EnvironmentOverride `json:"environmentOverride,omitempty" validate:"dive"` } type AppMetadata struct { @@ -71,15 +71,15 @@ type DeploymentTemplate struct { } type AppWorkflow struct { - Name string `json:"name"` - CiPipeline *CiPipelineDetails `json:"ciPipeline"` - CdPipelines []*CdPipelineDetails `json:"cdPipelines"` + Name string `json:"name" validate:"required"` + CiPipeline *CiPipelineDetails `json:"ciPipeline" validate:"dive,required"` + CdPipelines []*CdPipelineDetails `json:"cdPipelines,omitempty" validate:"dive"` } type CiPipelineDetails struct { Name string `json:"name" validate:"required"` //name suffix of corresponding pipeline - IsManual bool `json:"isManual" validate:"required"` - CiPipelineMaterialsConfig []*CiPipelineMaterialConfig `json:"ciPipelineMaterialsConfig"` + IsManual bool `json:"isManual"` + CiPipelineMaterialsConfig []*CiPipelineMaterialConfig `json:"ciPipelineMaterialsConfig" validate:"dive,min=1"` DockerBuildArgs map[string]string `json:"dockerBuildArgs"` BeforeDockerBuildScripts []*BuildScript `json:"beforeDockerBuildScripts"` AfterDockerBuildScripts []*BuildScript `json:"afterDockerBuildScripts"` @@ -93,7 +93,7 @@ type CiPipelineDetails struct { } type CiPipelineMaterialConfig struct { - Type pipelineConfig.SourceType `json:"type,omitempty" validate:"oneof=SOURCE_TYPE_BRANCH_FIXED WEBHOOK"` + Type pipelineConfig.SourceType `json:"type,omitempty" validate:"oneof=SOURCE_TYPE_BRANCH_FIXED SOURCE_TYPE_BRANCH_REGEX SOURCE_TYPE_TAG_ANY WEBHOOK"` Value string `json:"value,omitempty" ` CheckoutPath string `json:"checkoutPath"` GitMaterialId int `json:"gitMaterialId"` @@ -107,9 +107,9 @@ type BuildScript struct { } type CdPipelineDetails struct { - Name string `json:"name"` //pipelineName - EnvironmentName string `json:"environmentName" ` - TriggerType pipelineConfig.TriggerType `json:"triggerType" validate:"required"` + Name string `json:"name" validate:"required"` //pipelineName + EnvironmentName string `json:"environmentName" validate:"required"` + TriggerType pipelineConfig.TriggerType `json:"triggerType" validate:"oneof=AUTOMATIC MANUAL"` DeploymentAppType string `json:"deploymentAppType"` DeploymentStrategyType chartRepoRepository.DeploymentStrategy `json:"deploymentType,omitempty"` // DeploymentStrategies []*DeploymentStrategy `json:"deploymentStrategies"` diff --git a/api/restHandler/CoreAppRestHandler.go b/api/restHandler/CoreAppRestHandler.go index d2f90dd0661..2b7ec9edaf0 100644 --- a/api/restHandler/CoreAppRestHandler.go +++ b/api/restHandler/CoreAppRestHandler.go @@ -51,6 +51,7 @@ import ( "github.com/hashicorp/go-multierror" "go.uber.org/zap" "gopkg.in/go-playground/validator.v9" + "k8s.io/utils/strings/slices" "net/http" "strconv" "strings" @@ -96,6 +97,7 @@ type CoreAppRestHandlerImpl struct { teamService team.TeamService argoUserService argo.ArgoUserService pipelineStageService pipeline.PipelineStageService + ciPipelineRepository pipelineConfig.CiPipelineRepository } func NewCoreAppRestHandlerImpl(logger *zap.SugaredLogger, userAuthService user.UserService, validator *validator.Validate, enforcerUtil rbac.EnforcerUtil, @@ -105,7 +107,7 @@ func NewCoreAppRestHandlerImpl(logger *zap.SugaredLogger, userAuthService user.U materialRepository pipelineConfig.MaterialRepository, gitProviderRepo repository.GitProviderRepository, appWorkflowRepository appWorkflow2.AppWorkflowRepository, environmentRepository repository2.EnvironmentRepository, configMapRepository chartConfig.ConfigMapRepository, envConfigRepo chartConfig.EnvConfigOverrideRepository, chartRepo chartRepoRepository.ChartRepository, teamService team.TeamService, - argoUserService argo.ArgoUserService, pipelineStageService pipeline.PipelineStageService) *CoreAppRestHandlerImpl { + argoUserService argo.ArgoUserService, pipelineStageService pipeline.PipelineStageService, ciPipelineRepository pipelineConfig.CiPipelineRepository) *CoreAppRestHandlerImpl { handler := &CoreAppRestHandlerImpl{ logger: logger, userAuthService: userAuthService, @@ -130,6 +132,7 @@ func NewCoreAppRestHandlerImpl(logger *zap.SugaredLogger, userAuthService user.U teamService: teamService, argoUserService: argoUserService, pipelineStageService: pipelineStageService, + ciPipelineRepository: ciPipelineRepository, } return handler } @@ -297,6 +300,19 @@ func (handler CoreAppRestHandlerImpl) CreateApp(w http.ResponseWriter, r *http.R handler.logger.Infow("creating app v2", "createAppRequest", createAppRequest) + // validate payload starts + createAppWorkflowReq := appBean.AppWorkflowCloneDto{ + AppName: createAppRequest.Metadata.AppName, + AppWorkflows: createAppRequest.AppWorkflows, + EnvironmentOverrides: createAppRequest.EnvironmentOverrides, + } + err, statusCode := handler.ValidateAppWorkflowRequest(&createAppWorkflowReq, token) + if err != nil { + common.WriteJsonResp(w, err, nil, statusCode) + return + } + // validate payload ends + //creating blank app starts createBlankAppResp, err, statusCode := handler.createBlankApp(createAppRequest.Metadata, userId) if err != nil { @@ -387,7 +403,7 @@ func (handler CoreAppRestHandlerImpl) CreateApp(w http.ResponseWriter, r *http.R //creating workflow starts if createAppRequest.AppWorkflows != nil { - err, statusCode = handler.createWorkflows(ctx, appId, userId, createAppRequest.AppWorkflows, token, createAppRequest.Metadata.AppName) + err, statusCode = handler.createWorkflows(ctx, appId, userId, createAppRequest.AppWorkflows) if err != nil { errResp = multierror.Append(errResp, err) errInAppDelete := handler.deleteApp(ctx, appId, userId) @@ -402,7 +418,7 @@ func (handler CoreAppRestHandlerImpl) CreateApp(w http.ResponseWriter, r *http.R //creating environment override starts if createAppRequest.EnvironmentOverrides != nil { - err, statusCode = handler.createEnvOverrides(ctx, appId, userId, createAppRequest.EnvironmentOverrides, token) + err, statusCode = handler.createEnvOverrides(ctx, appId, userId, createAppRequest.EnvironmentOverrides) if err != nil { errResp = multierror.Append(errResp, err) errInAppDelete := handler.deleteApp(ctx, appId, userId) @@ -1522,7 +1538,7 @@ func (handler CoreAppRestHandlerImpl) createGlobalSecrets(appId int, userId int3 } // create app workflows -func (handler CoreAppRestHandlerImpl) createWorkflows(ctx context.Context, appId int, userId int32, workflows []*appBean.AppWorkflow, token string, appName string) (error, int) { +func (handler CoreAppRestHandlerImpl) createWorkflows(ctx context.Context, appId int, userId int32, workflows []*appBean.AppWorkflow) (error, int) { handler.logger.Infow("Create App - creating workflows", "appId", appId, "workflows size", len(workflows)) for _, workflow := range workflows { //Create workflow starts (we need to create workflow with given name) @@ -1542,7 +1558,7 @@ func (handler CoreAppRestHandlerImpl) createWorkflows(ctx context.Context, appId //Creating CI pipeline ends //Creating CD pipeline starts - err = handler.createCdPipelines(ctx, appId, userId, workflowId, ciPipelineId, workflow.CdPipelines, token, appName) + err = handler.createCdPipelines(ctx, appId, userId, workflowId, ciPipelineId, workflow.CdPipelines) if err != nil { handler.logger.Errorw("err in saving cd pipelines", err, "appId", appId) return err, http.StatusInternalServerError @@ -1591,8 +1607,8 @@ func (handler CoreAppRestHandlerImpl) createCiPipeline(appId int, userId int32, //finding gitMaterial by appId and checkoutPath gitMaterial, err = handler.materialRepository.FindByAppIdAndCheckoutPath(appId, ciMaterial.CheckoutPath) } else { - //if linkedci find git material by it's id - gitMaterial, err = handler.materialRepository.FindById(ciMaterial.GitMaterialId) + //if linked CI find git material by it's parentAppId and Id + gitMaterial, err = handler.materialRepository.FindByAppIdAndGitMaterialId(ciPipelineData.ParentAppId, ciMaterial.GitMaterialId) } if err != nil { handler.logger.Errorw("service err, FindByAppIdAndCheckoutPath in CreateWorkflows", "err", err, "appId", appId) @@ -1652,7 +1668,7 @@ func (handler CoreAppRestHandlerImpl) createCiPipeline(appId int, userId int32, return res.CiPipelines[0].Id, nil } -func (handler CoreAppRestHandlerImpl) createCdPipelines(ctx context.Context, appId int, userId int32, workflowId int, ciPipelineId int, cdPipelines []*appBean.CdPipelineDetails, token string, appName string) error { +func (handler CoreAppRestHandlerImpl) createCdPipelines(ctx context.Context, appId int, userId int32, workflowId int, ciPipelineId int, cdPipelines []*appBean.CdPipelineDetails) error { var cdPipelineRequestConfigs []*bean.CDPipelineConfigObject for _, cdPipeline := range cdPipelines { @@ -1670,12 +1686,7 @@ func (handler CoreAppRestHandlerImpl) createCdPipelines(ctx context.Context, app return err } - // RBAC starts - object := handler.enforcerUtil.GetAppRBACByAppNameAndEnvId(appName, envModel.Id) - if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionCreate, object); !ok { - return errors.New("unauthorized User") - } - // RBAC ends + // RBAC has already been verified in Validation function // build model cdPipelineRequestConfig := &bean.CDPipelineConfigObject{ @@ -1722,7 +1733,7 @@ func (handler CoreAppRestHandlerImpl) createCdPipelines(ctx context.Context, app } // create environment overrides -func (handler CoreAppRestHandlerImpl) createEnvOverrides(ctx context.Context, appId int, userId int32, environmentOverrides map[string]*appBean.EnvironmentOverride, token string) (error, int) { +func (handler CoreAppRestHandlerImpl) createEnvOverrides(ctx context.Context, appId int, userId int32, environmentOverrides map[string]*appBean.EnvironmentOverride) (error, int) { handler.logger.Infow("Create App - creating env overrides", "appId", appId) for envName, envOverrideValues := range environmentOverrides { @@ -1739,12 +1750,7 @@ func (handler CoreAppRestHandlerImpl) createEnvOverrides(ctx context.Context, ap return err, http.StatusInternalServerError } - // RBAC starts - object := handler.enforcerUtil.GetEnvRBACNameByAppId(appId, envModel.Id) - if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionUpdate, object); !ok { - return fmt.Errorf("unauthorized user"), http.StatusForbidden - } - // RBAC ends + // RBAC has already been verified in Validation function envId := envModel.Id @@ -2088,6 +2094,109 @@ func ExtractErrorType(err error) int { } } +func (handler CoreAppRestHandlerImpl) validateCdPipelines(cdPipelines []*appBean.CdPipelineDetails, appName, token string) (error, int) { + for _, cdPipeline := range cdPipelines { + envName := cdPipeline.EnvironmentName + envModel, err := handler.environmentRepository.FindByName(envName) + if err != nil || envModel == nil { + return fmt.Errorf("invalid environment name %s for cd pipeline", envName), http.StatusBadRequest + } + if envModel.IsVirtualEnvironment { + return fmt.Errorf("virtual environment '%s' for cd pipeline is not supported yet", envName), http.StatusUnprocessableEntity + } + // validation RBAC starts + object := handler.enforcerUtil.GetAppRBACByAppNameAndEnvId(appName, envModel.Id) + if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionCreate, object); !ok { + return fmt.Errorf("unauthorized user for the environment %s", envName), http.StatusForbidden + } + // validation RBAC ends + + // validate deploymentStrategy for each cd pipeline + for _, deploymentStrategy := range cdPipeline.DeploymentStrategies { + _, err = json.Marshal(deploymentStrategy.Config) + if err != nil { + return fmt.Errorf("err in converting deployment strategies for creating the cd pipeline %s", cdPipeline.Name), http.StatusBadRequest + } + } + } + return nil, http.StatusOK +} + +func (handler CoreAppRestHandlerImpl) ValidateAppWorkflowRequest(createAppWorkflowRequest *appBean.AppWorkflowCloneDto, token string) (error, int) { + // validation for app workflow request + if createAppWorkflowRequest.AppWorkflows != nil { + for _, workflow := range createAppWorkflowRequest.AppWorkflows { + // if ci pipeline is of external type, then throw error as we are not supporting it as of now + if workflow.CiPipeline.ParentCiPipeline == 0 && workflow.CiPipeline.ParentAppId == 0 && workflow.CiPipeline.IsExternal { + return fmt.Errorf("external ci pipeline creation is not supported yet"), http.StatusUnprocessableEntity + } + // for linked CI, parentCiPipeline should be a valid ciPipelineId and the given ParentAppId should be matched + if workflow.CiPipeline.ParentCiPipeline != 0 && workflow.CiPipeline.ParentAppId != 0 { + if !workflow.CiPipeline.IsExternal { + return fmt.Errorf("invalid value of isExternal '%v', for linked CI isExternal must be TRUE", workflow.CiPipeline.IsExternal), http.StatusBadRequest + } + ciPipeline, err := handler.ciPipelineRepository.FindById(workflow.CiPipeline.ParentCiPipeline) + if err != nil { + return fmt.Errorf("error in finding ci pipeline with the given parentCiPipeline '%v'", workflow.CiPipeline.ParentCiPipeline), http.StatusBadRequest + } + if ciPipeline.AppId != workflow.CiPipeline.ParentAppId { + return fmt.Errorf("invalid parentAppId '%v' for the given parentCiPipeline '%v'", workflow.CiPipeline.ParentAppId, workflow.CiPipeline.ParentCiPipeline), http.StatusBadRequest + } + } + ciMaterialCheckoutPaths := make([]string, 0) + for _, ciPipelineMaterialConfig := range workflow.CiPipeline.CiPipelineMaterialsConfig { + // value for webhook type CiPipelineMaterial should be a valid json string + if ciPipelineMaterialConfig.Type == pipelineConfig.SOURCE_TYPE_WEBHOOK { + var jsonValueMap map[string]interface{} + err := json.Unmarshal([]byte(ciPipelineMaterialConfig.Value), &jsonValueMap) + if err != nil { + return fmt.Errorf("invalid value for the ciPipelineMaterialsConfig type %s", string(ciPipelineMaterialConfig.Type)), http.StatusBadRequest + } + if _, ok := jsonValueMap["eventId"]; !ok { + return fmt.Errorf("invalid value for the ciPipelineMaterialsConfig type %s, eventId not found", string(ciPipelineMaterialConfig.Type)), http.StatusBadRequest + } + + if _, ok := jsonValueMap["condition"]; !ok { + return fmt.Errorf("invalid value for the ciPipelineMaterialsConfig type %s, condition not found", string(ciPipelineMaterialConfig.Type)), http.StatusBadRequest + } + } + // CiPipelineMaterial checkout paths should be unique + if slices.Contains(ciMaterialCheckoutPaths, ciPipelineMaterialConfig.CheckoutPath) { + return fmt.Errorf(""), http.StatusBadRequest + } + ciMaterialCheckoutPaths = append(ciMaterialCheckoutPaths, ciPipelineMaterialConfig.CheckoutPath) + } + // validate environment name and rbac object of payload + if workflow.CdPipelines != nil { + err, statusCode := handler.validateCdPipelines(workflow.CdPipelines, createAppWorkflowRequest.AppName, token) + if err != nil { + return err, statusCode + } + } + } + } + // validation for environment override request + if createAppWorkflowRequest.EnvironmentOverrides != nil { + for envName, _ := range createAppWorkflowRequest.EnvironmentOverrides { + envModel, err := handler.environmentRepository.FindByName(envName) + + if err != nil || envModel == nil { + return fmt.Errorf("invalid environment name '%s' for environment override", envName), http.StatusBadRequest + } + if envModel.IsVirtualEnvironment { + return fmt.Errorf("virtual environment '%s' for cd pipeline is not supported yet", envName), http.StatusUnprocessableEntity + } + // validate RBAC starts + object := handler.enforcerUtil.GetAppRBACByAppNameAndEnvId(createAppWorkflowRequest.AppName, envModel.Id) + if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionUpdate, object); !ok { + return fmt.Errorf("unauthorized user for the environment '%s'", envName), http.StatusForbidden + } + // validate RBAC ends + } + } + return nil, http.StatusOK +} + func (handler CoreAppRestHandlerImpl) CreateAppWorkflow(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) @@ -2134,8 +2243,15 @@ func (handler CoreAppRestHandlerImpl) CreateAppWorkflow(w http.ResponseWriter, r } //rbac ends + // validate payload starts + err, statusCode := handler.ValidateAppWorkflowRequest(&createAppRequest, token) + if err != nil { + common.WriteJsonResp(w, err, nil, statusCode) + return + } + // validate payload ends + handler.logger.Infow("creating app workflow created ", "createAppRequest", createAppRequest) - var statusCode int //creating workflow starts if createAppRequest.AppWorkflows != nil { @@ -2143,7 +2259,7 @@ func (handler CoreAppRestHandlerImpl) CreateAppWorkflow(w http.ResponseWriter, r common.WriteJsonResp(w, err, "please provide only one workflow at one time", http.StatusBadRequest) return } - err, statusCode = handler.createWorkflows(ctx, createAppRequest.AppId, userId, createAppRequest.AppWorkflows, token, app.AppName) + err, statusCode = handler.createWorkflows(ctx, createAppRequest.AppId, userId, createAppRequest.AppWorkflows) if err != nil { common.WriteJsonResp(w, err, nil, statusCode) return @@ -2153,7 +2269,7 @@ func (handler CoreAppRestHandlerImpl) CreateAppWorkflow(w http.ResponseWriter, r //creating environment override starts if createAppRequest.EnvironmentOverrides != nil && len(createAppRequest.EnvironmentOverrides) > 0 { - err, statusCode = handler.createEnvOverrides(ctx, createAppRequest.AppId, userId, createAppRequest.EnvironmentOverrides, token) + err, statusCode = handler.createEnvOverrides(ctx, createAppRequest.AppId, userId, createAppRequest.EnvironmentOverrides) if err != nil { common.WriteJsonResp(w, err, nil, statusCode) return diff --git a/internal/sql/repository/pipelineConfig/MaterialRepository.go b/internal/sql/repository/pipelineConfig/MaterialRepository.go index eb1e4ed152c..5dc8b4456e2 100644 --- a/internal/sql/repository/pipelineConfig/MaterialRepository.go +++ b/internal/sql/repository/pipelineConfig/MaterialRepository.go @@ -57,6 +57,7 @@ type MaterialRepository interface { Update(materials []*GitMaterial) error FindByAppId(appId int) ([]*GitMaterial, error) FindById(Id int) (*GitMaterial, error) + FindByAppIdAndGitMaterialId(appId, id int) (*GitMaterial, error) UpdateMaterialScmId(material *GitMaterial) error FindByAppIdAndCheckoutPath(appId int, checkoutPath string) (*GitMaterial, error) FindByGitProviderId(gitProviderId int) (materials []*GitMaterial, err error) @@ -92,6 +93,17 @@ func (repo MaterialRepositoryImpl) FindById(Id int) (*GitMaterial, error) { return material, err } +func (repo MaterialRepositoryImpl) FindByAppIdAndGitMaterialId(appId, id int) (*GitMaterial, error) { + material := &GitMaterial{} + err := repo.dbConnection.Model(material). + Column("git_material.*", "GitProvider"). + Where("app_id = ? ", appId). + Where("git_material.id =? ", id). + Where("git_material.active =? ", true). + Select() + return material, err +} + func (repo MaterialRepositoryImpl) MaterialExists(url string) (bool, error) { material := &GitMaterial{} exists, err := repo.dbConnection. diff --git a/wire_gen.go b/wire_gen.go index ad48a60c14e..e82526fd914 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -678,7 +678,7 @@ func InitializeApp() (*App, error) { webhookListenerRouterImpl := router.NewWebhookListenerRouterImpl(webhookEventHandlerImpl) appRestHandlerImpl := restHandler.NewAppRestHandlerImpl(sugaredLogger, appCrudOperationServiceImpl, userServiceImpl, validate, enforcerUtilImpl, enforcerImpl, helmAppServiceImpl, enforcerUtilHelmImpl, genericNoteServiceImpl) appRouterImpl := router.NewAppRouterImpl(sugaredLogger, appRestHandlerImpl) - coreAppRestHandlerImpl := restHandler.NewCoreAppRestHandlerImpl(sugaredLogger, userServiceImpl, validate, enforcerUtilImpl, enforcerImpl, appCrudOperationServiceImpl, pipelineBuilderImpl, gitRegistryConfigImpl, chartServiceImpl, configMapServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, appWorkflowServiceImpl, materialRepositoryImpl, gitProviderRepositoryImpl, appWorkflowRepositoryImpl, environmentRepositoryImpl, configMapRepositoryImpl, envConfigOverrideRepositoryImpl, chartRepositoryImpl, teamServiceImpl, argoUserServiceImpl, pipelineStageServiceImpl) + coreAppRestHandlerImpl := restHandler.NewCoreAppRestHandlerImpl(sugaredLogger, userServiceImpl, validate, enforcerUtilImpl, enforcerImpl, appCrudOperationServiceImpl, pipelineBuilderImpl, gitRegistryConfigImpl, chartServiceImpl, configMapServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, appWorkflowServiceImpl, materialRepositoryImpl, gitProviderRepositoryImpl, appWorkflowRepositoryImpl, environmentRepositoryImpl, configMapRepositoryImpl, envConfigOverrideRepositoryImpl, chartRepositoryImpl, teamServiceImpl, argoUserServiceImpl, pipelineStageServiceImpl, ciPipelineRepositoryImpl) coreAppRouterImpl := router.NewCoreAppRouterImpl(coreAppRestHandlerImpl) helmAppRestHandlerImpl := client3.NewHelmAppRestHandlerImpl(sugaredLogger, helmAppServiceImpl, enforcerImpl, clusterServiceImplExtended, enforcerUtilHelmImpl, appStoreDeploymentCommonServiceImpl, userServiceImpl, attributesServiceImpl, serverEnvConfigServerEnvConfig) helmAppRouterImpl := client3.NewHelmAppRouterImpl(helmAppRestHandlerImpl)