Repository: devtron-labs/devtron
Pull request #3966 (2023-09-26 08:38:41)

chore: added CODEOWNERS
<!--
Type of change: Title of the PR should clearly mention which type of PR is this, you can select any of the below mentioned types:


chore: added CODEOWNERS file
-->

# Description
Added CODEOWNERS


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=devtron-labs_devtron&pullRequest=3966)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3966&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=devtron-labs_devtron&pullRequest=3966) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=devtron-labs_devtron&pullRequest=3966&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..53fced7d4
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,12 @@
+#ALL
+* @vikramdevtron @kripanshdevtron @nishant-d
+
+#DOCS
+docs/ @ashokdevtron @uxarya-d @prakarsh-dt
+
+#Helm Charts
+charts/devtron/ @prakarsh-dt @pawan-mehta-dt @nishant-d
+scripts/devtron-reference-helm-charts @prakarsh-dt @pawan-mehta-dt @nishant-d
+
+#Github Specific
+.github/ @prakarsh-dt @nishant-d
diff --git a/.github/workflows/pr-issue-validator.yaml b/.github/workflows/pr-issue-validator.yaml
index b018988f6..a832184ea 100644
--- a/.github/workflows/pr-issue-validator.yaml
+++ b/.github/workflows/pr-issue-validator.yaml
@@ -21,6 +21,10 @@ on:
 jobs:
   validate-PR-issue:
     runs-on: ubuntu-latest
+    permissions:
+      issues: write
+      contents: read
+      pull-requests: write
 
     steps:
     - name: Checkout repository
@@ -28,7 +32,7 @@ jobs:
 
     - name: Validate Issue Reference
       env:
-        GITHUB_TOKEN: ${{ secrets.GIT_TARGET_TOKEN }}
+        GITHUB_TOKEN: ${{ github.token }}
         PR_BODY: ${{ github.event.pull_request.body }}
         url: ${{ github.event.pull_request.url }}
         PRNUM: ${{ github.event.pull_request.number }}
diff --git a/api/appStore/deployment/AppStoreDeploymentRestHandler.go b/api/appStore/deployment/AppStoreDeploymentRestHandler.go
index 0aca96129..7300906b9 100644
--- a/api/appStore/deployment/AppStoreDeploymentRestHandler.go
+++ b/api/appStore/deployment/AppStoreDeploymentRestHandler.go
@@ -35,6 +35,7 @@ import (
 	util2 "github.com/devtron-labs/devtron/util"
 	"github.com/devtron-labs/devtron/util/argo"
 	"github.com/devtron-labs/devtron/util/rbac"
+	"github.com/go-pg/pg"
 	"github.com/gorilla/mux"
 	"go.uber.org/zap"
 	"gopkg.in/go-playground/validator.v9"
@@ -291,6 +292,11 @@ func (handler AppStoreDeploymentRestHandlerImpl) DeleteInstalledApp(w http.Respo
 	installedApp, err := handler.appStoreDeploymentService.GetInstalledApp(installAppId)
 	if err != nil {
 		handler.Logger.Error(err)
+		if err == pg.ErrNoRows {
+			err = &util.ApiError{Code: "404", HttpStatusCode: 404, UserMessage: "App not found in database", InternalMessage: err.Error()}
+			common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
+			return
+		}
 		common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
 		return
 	}
diff --git a/api/bean/ValuesOverrideRequest.go b/api/bean/ValuesOverrideRequest.go
index bca49dc9a..efa712109 100644
--- a/api/bean/ValuesOverrideRequest.go
+++ b/api/bean/ValuesOverrideRequest.go
@@ -20,6 +20,7 @@ package bean
 import (
 	"encoding/json"
 	"github.com/devtron-labs/devtron/internal/sql/models"
+	"github.com/devtron-labs/devtron/pkg/pipeline/repository"
 	"time"
 )
 
@@ -39,6 +40,17 @@ const (
 	DEPLOYMENT_CONFIG_TYPE_SPECIFIC_TRIGGER DeploymentConfigurationType = "SPECIFIC_TRIGGER_CONFIG"
 )
 
+func (workflowType WorkflowType) WorkflowTypeToStageType() repository.PipelineStageType {
+	switch workflowType {
+	case CD_WORKFLOW_TYPE_PRE:
+		return repository.PIPELINE_STAGE_TYPE_PRE_CD
+	case CD_WORKFLOW_TYPE_POST:
+		return repository.PIPELINE_STAGE_TYPE_POST_CD
+	default:
+		return ""
+	}
+}
+
 type ValuesOverrideRequest struct {
 	PipelineId                            int                         `json:"pipelineId" validate:"required"`
 	AppId                                 int                         `json:"appId" validate:"required"`
diff --git a/api/cluster/EnvironmentRestHandler.go b/api/cluster/EnvironmentRestHandler.go
index 60776699c..ab5872533 100644
--- a/api/cluster/EnvironmentRestHandler.go
+++ b/api/cluster/EnvironmentRestHandler.go
@@ -498,7 +498,7 @@ func (impl EnvironmentRestHandlerImpl) GetEnvironmentConnection(w http.ResponseW
 		common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
 		return
 	}
-	clusterBean, err := impl.environmentClusterMappingsService.FindClusterByEnvId(bean.ClusterId)
+	clusterBean, err := impl.environmentClusterMappingsService.FindClusterByEnvId(envId)
 	if err != nil {
 		impl.logger.Errorw("request err, FindById", "err", err, "envId", envId)
 		common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
diff --git a/api/restHandler/ChartGroupRestHandler.go b/api/restHandler/ChartGroupRestHandler.go
index 19c95d2e0..107f0e0b2 100644
--- a/api/restHandler/ChartGroupRestHandler.go
+++ b/api/restHandler/ChartGroupRestHandler.go
@@ -169,8 +169,10 @@ func (impl *ChartGroupRestHandlerImpl) SaveChartGroupEntries(w http.ResponseWrit
 	token := r.Header.Get("token")
 	rbacObject := request.Name
 	if ok := impl.enforcer.Enforce(token, casbin.ResourceChartGroup, casbin.ActionCreate, rbacObject); !ok {
-		common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden)
-		return
+		if ok1 := impl.enforcer.Enforce(token, casbin.ResourceChartGroup, casbin.ActionUpdate, rbacObject); !ok1 {
+			common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden)
+			return
+		}
 	}
 	//RBAC block ends here
 	res, err := impl.ChartGroupService.SaveChartGroupEntries(&request)
diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go
index 2908cf13d..10673f8ba 100644
--- a/api/restHandler/app/BuildPipelineRestHandler.go
+++ b/api/restHandler/app/BuildPipelineRestHandler.go
@@ -44,6 +44,7 @@ type DevtronAppBuildRestHandler interface {
 	GetExternalCiById(w http.ResponseWriter, r *http.Request)
 	PatchCiPipelines(w http.ResponseWriter, r *http.Request)
 	PatchCiMaterialSourceWithAppIdAndEnvironmentId(w http.ResponseWriter, r *http.Request)
+	PatchCiMaterialSourceWithAppIdsAndEnvironmentId(w http.ResponseWriter, r *http.Request)
 	TriggerCiPipeline(w http.ResponseWriter, r *http.Request)
 	GetCiPipelineMin(w http.ResponseWriter, r *http.Request)
 	GetCIPipelineById(w http.ResponseWriter, r *http.Request)
@@ -249,6 +250,29 @@ func (handler PipelineConfigRestHandlerImpl) parseSourceChangeRequest(w http.Res
 	return &patchRequest, userId, nil
 }
 
+func (handler PipelineConfigRestHandlerImpl) parseBulkSourceChangeRequest(w http.ResponseWriter, r *http.Request) (*bean.CiMaterialBulkPatchRequest, int32, error) {
+	decoder := json.NewDecoder(r.Body)
+	userId, err := handler.userAuthService.GetLoggedInUser(r)
+	if userId == 0 || err != nil {
+		common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
+		return nil, 0, err
+	}
+	var patchRequest bean.CiMaterialBulkPatchRequest
+	err = decoder.Decode(&patchRequest)
+	if err != nil {
+		handler.Logger.Errorw("request err, BulkPatchCiPipeline", "err", err, "BulkPatchCiPipeline", patchRequest)
+		common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
+		return nil, 0, err
+	}
+	err = handler.validator.Struct(patchRequest)
+	if err != nil {
+		handler.Logger.Errorw("request err, BulkPatchCiPipeline", "err", err, "BulkPatchCiPipeline", patchRequest)
+		common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
+		return nil, 0, err
+	}
+	return &patchRequest, userId, nil
+}
+
 func (handler PipelineConfigRestHandlerImpl) authorizeCiSourceChangeRequest(w http.ResponseWriter, patchRequest *bean.CiMaterialPatchRequest, token string) error {
 	handler.Logger.Debugw("update request ", "req", patchRequest)
 	app, err := handler.pipelineBuilder.GetApp(patchRequest.AppId)
@@ -304,6 +328,23 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiMaterialSourceWithAppIdAndEn
 	common.WriteJsonResp(w, err, createResp, http.StatusOK)
 }
 
+func (handler PipelineConfigRestHandlerImpl) PatchCiMaterialSourceWithAppIdsAndEnvironmentId(w http.ResponseWriter, r *http.Request) {
+	bulkPatchRequest, userId, err := handler.parseBulkSourceChangeRequest(w, r)
+	if err != nil {
+		handler.Logger.Errorw("Parse error, PatchCiMaterialSource", "err", err, "PatchCiMaterialSource", bulkPatchRequest)
+		return
+	}
+	token := r.Header.Get("token")
+	// Here passing the checkAppSpecificAccess func to check RBAC
+	bulkPatchResponse, err := handler.pipelineBuilder.BulkPatchCiMaterialSource(bulkPatchRequest, userId, token, handler.checkAppSpecificAccess)
+	if err != nil {
+		handler.Logger.Errorw("service err, BulkPatchCiPipelines", "err", err, "BulkPatchCiPipelines", bulkPatchRequest)
+		common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
+		return
+	}
+	common.WriteJsonResp(w, err, bulkPatchResponse, http.StatusOK)
+}
+
 func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWriter, r *http.Request) {
 	decoder := json.NewDecoder(r.Body)
 	userId, err := handler.userAuthService.GetLoggedInUser(r)
@@ -1891,3 +1932,19 @@ func (handler PipelineConfigRestHandlerImpl) extractCipipelineMetaForImageTags(a
 	}
 	return externalCi, ciPipelineId, appId, nil
 }
+
+func (handler PipelineConfigRestHandlerImpl) checkAppSpecificAccess(token, action string, appId int) (bool, error) {
+	app, err := handler.pipelineBuilder.GetApp(appId)
+	if err != nil {
+		return false, err
+	}
+	if app.AppType != helper.CustomApp {
+		return false, errors.New("only custom apps supported")
+	}
+
+	resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName)
+	if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, action, resourceName); !ok {
+		return false, errors.New(string(bean.CI_PATCH_NOT_AUTHORIZED_MESSAGE))
+	}
+	return true, nil
+}
diff --git a/api/restHandler/app/DeploymentPipelineRestHandler.go b/api/restHandler/app/DeploymentPipelineRestHandler.go
index ae886c1e9..465586433 100644
--- a/api/restHandler/app/DeploymentPipelineRestHandler.go
+++ b/api/restHandler/app/DeploymentPipelineRestHandler.go
@@ -1362,13 +1362,32 @@ func (handler PipelineConfigRestHandlerImpl) GetArtifactsForRollback(w http.Resp
 		return
 	}
 	//rbac block ends here
+	//rbac for edit tags access
+	triggerAccess := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object)
 
-	ciArtifactResponse, err := handler.pipelineBuilder.FetchArtifactForRollback(cdPipelineId, offset, limit)
+	ciArtifactResponse, err := handler.pipelineBuilder.FetchArtifactForRollback(cdPipelineId, app.Id, offset, limit)
 	if err != nil {
 		handler.Logger.Errorw("service err, GetArtifactsForRollback", "err", err, "cdPipelineId", cdPipelineId)
 		common.WriteJsonResp(w, err, "unable to fetch artifacts", http.StatusInternalServerError)
 		return
 	}
+	appTags, err := handler.imageTaggingService.GetUniqueTagsByAppId(app.Id)
+	if err != nil {
+		handler.Logger.Errorw("service err, GetTagsByAppId", "err", err, "appId", app.Id)
+		common.WriteJsonResp(w, err, ciArtifactResponse, http.StatusInternalServerError)
+		return
+	}
+
+	ciArtifactResponse.AppReleaseTagNames = appTags
+
+	prodEnvExists, err := handler.imageTaggingService.GetProdEnvByCdPipelineId(cdPipelineId)
+	ciArtifactResponse.TagsEditable = prodEnvExists && triggerAccess
+	ciArtifactResponse.HideImageTaggingHardDelete = handler.imageTaggingService.GetImageTaggingServiceConfig().HideImageTaggingHardDelete
+	if err != nil {
+		handler.Logger.Errorw("service err, GetProdEnvByCdPipelineId", "err", err, "cdPipelineId", app.Id)
+		common.WriteJsonResp(w, err, ciArtifactResponse, http.StatusInternalServerError)
+		return
+	}
 	common.WriteJsonResp(w, err, ciArtifactResponse, http.StatusOK)
 }
 
diff --git a/api/router/PipelineConfigRouter.go b/api/router/PipelineConfigRouter.go
index 8dd5e4447..6a9b0ba30 100644
--- a/api/router/PipelineConfigRouter.go
+++ b/api/router/PipelineConfigRouter.go
@@ -86,6 +86,7 @@ func (router PipelineConfigRouterImpl) initPipelineConfigRouter(configRouter *mu
 	configRouter.Path("/ci-pipeline/template/patch").HandlerFunc(router.restHandler.UpdateCiTemplate).Methods("POST")
 	configRouter.Path("/ci-pipeline/patch").HandlerFunc(router.restHandler.PatchCiPipelines).Methods("POST")
 	configRouter.Path("/ci-pipeline/patch-source").HandlerFunc(router.restHandler.PatchCiMaterialSourceWithAppIdAndEnvironmentId).Methods("PATCH")
+	configRouter.Path("/ci-pipeline/bulk/branch-update").HandlerFunc(router.restHandler.PatchCiMaterialSourceWithAppIdsAndEnvironmentId).Methods("PUT")
 	configRouter.Path("/ci-pipeline/patch/regex").HandlerFunc(router.restHandler.UpdateBranchCiPipelinesWithRegex).Methods("POST")
 
 	configRouter.Path("/cd-pipeline/{cd_pipeline_id}/material").HandlerFunc(router.restHandler.GetArtifactsByCDPipeline).Methods("GET")
diff --git a/internal/sql/repository/security/ImageScanDeployInfoRepository.go b/internal/sql/repository/security/ImageScanDeployInfoRepository.go
index 6d4a6e6c6..6f421e774 100644
--- a/internal/sql/repository/security/ImageScanDeployInfoRepository.go
+++ b/internal/sql/repository/security/ImageScanDeployInfoRepository.go
@@ -185,7 +185,7 @@ func (impl ImageScanDeployInfoRepositoryImpl) scanListQueryWithoutObject(request
 	}
 	query = query + " INNER JOIN environment env on env.id=info.env_id"
 	query = query + " INNER JOIN cluster clus on clus.id=env.cluster_id"
-	query = query + " WHERE info.scan_object_meta_id > 0 and env.active=true"
+	query = query + " WHERE info.scan_object_meta_id > 0 and env.active=true  and info.image_scan_execution_history_id[1] != -1"
 	if len(deployInfoIds) > 0 {
 		ids := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(deployInfoIds)), ","), "[]")
 		query = query + " AND info.id IN (" + ids + ")"
@@ -232,7 +232,7 @@ func (impl ImageScanDeployInfoRepositoryImpl) scanListQueryWithObject(request *I
 	}
 	query = query + " INNER JOIN environment env on env.id=info.env_id"
 	query = query + " INNER JOIN cluster c on c.id=env.cluster_id"
-	query = query + " WHERE info.scan_object_meta_id > 0 and env.active=true"
+	query = query + " WHERE info.scan_object_meta_id > 0 and env.active=true and info.image_scan_execution_history_id[1] != -1"
 	if len(deployInfoIds) > 0 {
 		ids := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(deployInfoIds)), ","), "[]")
 		query = query + " AND info.id IN (" + ids + ")"
diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go
index df657f44c..232aa69b4 100644
--- a/pkg/app/AppService.go
+++ b/pkg/app/AppService.go
@@ -190,7 +190,7 @@ type AppService interface {
 	GetConfigMapAndSecretJson(appId int, envId int, pipelineId int) ([]byte, error)
 	UpdateCdWorkflowRunnerByACDObject(app *v1alpha1.Application, cdWfrId int, updateTimedOutStatus bool) error
 	GetCmSecretNew(appId int, envId int, isJob bool) (*bean.ConfigMapJson, *bean.ConfigSecretJson, error)
-	MarkImageScanDeployed(appId int, envId int, imageDigest string, clusterId int) error
+	MarkImageScanDeployed(appId int, envId int, imageDigest string, clusterId int, isScanEnabled bool) error
 	UpdateDeploymentStatusForGitOpsPipelines(app *v1alpha1.Application, statusTime time.Time, isAppStore bool) (bool, bool, error)
 	WriteCDSuccessEvent(appId int, envId int, override *chartConfig.PipelineOverride)
 	GetGitOpsRepoPrefix() string
@@ -1833,11 +1833,9 @@ func (impl *AppServiceImpl) TriggerPipeline(overrideRequest *bean.ValuesOverride
 
 	go impl.WriteCDTriggerEvent(overrideRequest, valuesOverrideResponse.Artifact, valuesOverrideResponse.PipelineOverride.PipelineReleaseCounter, valuesOverrideResponse.PipelineOverride.Id)
 
-	if valuesOverrideResponse.Artifact.ScanEnabled {
-		_, span := otel.Tracer("orchestrator").Start(ctx, "MarkImageScanDeployed")
-		_ = impl.MarkImageScanDeployed(overrideRequest.AppId, valuesOverrideResponse.EnvOverride.TargetEnvironment, valuesOverrideResponse.Artifact.ImageDigest, overrideRequest.ClusterId)
-		span.End()
-	}
+	_, spann := otel.Tracer("orchestrator").Start(ctx, "MarkImageScanDeployed")
+	_ = impl.MarkImageScanDeployed(overrideRequest.AppId, valuesOverrideResponse.EnvOverride.TargetEnvironment, valuesOverrideResponse.Artifact.ImageDigest, overrideRequest.ClusterId, valuesOverrideResponse.Artifact.ScanEnabled)
+	spann.End()
 
 	middleware.CdTriggerCounter.WithLabelValues(overrideRequest.AppName, overrideRequest.EnvName).Inc()
 
@@ -1986,7 +1984,7 @@ func (impl *AppServiceImpl) autoHealChartLocationInChart(ctx context.Context, en
 	return nil
 }
 
-func (impl *AppServiceImpl) MarkImageScanDeployed(appId int, envId int, imageDigest string, clusterId int) error {
+func (impl *AppServiceImpl) MarkImageScanDeployed(appId int, envId int, imageDigest string, clusterId int, isScanEnabled bool) error {
 	impl.logger.Debugw("mark image scan deployed for normal app, from cd auto or manual trigger", "imageDigest", imageDigest)
 	executionHistory, err := impl.imageScanHistoryRepository.FindByImageDigest(imageDigest)
 	if err != nil && err != pg.ErrNoRows {
@@ -2004,7 +2002,7 @@ func (impl *AppServiceImpl) MarkImageScanDeployed(appId int, envId int, imageDig
 	ot, err := impl.imageScanDeployInfoRepository.FindByTypeMetaAndTypeId(appId, security.ScanObjectType_APP) //todo insure this touple unique in db
 	if err != nil && err != pg.ErrNoRows {
 		return err
-	} else if err == pg.ErrNoRows {
+	} else if err == pg.ErrNoRows && isScanEnabled {
 		imageScanDeployInfo := &security.ImageScanDeployInfo{
 			ImageScanExecutionHistoryId: ids,
 			ScanObjectMetaId:            appId,
@@ -2025,7 +2023,12 @@ func (impl *AppServiceImpl) MarkImageScanDeployed(appId int, envId int, imageDig
 		}
 	} else {
 		// Updating Execution history for Latest Deployment to fetch out security Vulnerabilities for latest deployed info
-		ot.ImageScanExecutionHistoryId = ids
+		if isScanEnabled {
+			ot.ImageScanExecutionHistoryId = ids
+		} else {
+			arr := []int{-1}
+			ot.ImageScanExecutionHistoryId = arr
+		}
 		err = impl.imageScanDeployInfoRepository.Update(ot)
 		if err != nil {
 			impl.logger.Errorw("error in updating deploy info for latest deployed image", "err", err)
diff --git a/pkg/appStore/deployment/service/AppStoreDeploymentService.go b/pkg/appStore/deployment/service/AppStoreDeploymentService.go
index 138c26604..99b0788d9 100644
--- a/pkg/appStore/deployment/service/AppStoreDeploymentService.go
+++ b/pkg/appStore/deployment/service/AppStoreDeploymentService.go
@@ -692,6 +692,9 @@ func (impl AppStoreDeploymentServiceImpl) DeleteInstalledApp(ctx context.Context
 
 	app, err := impl.appRepository.FindById(installAppVersionRequest.AppId)
 	if err != nil {
+		if err == pg.ErrNoRows {
+			return nil, fmt.Errorf("App not found in database")
+		}
 		return nil, err
 	}
 	model, err := impl.installedAppRepository.GetInstalledApp(installAppVersionRequest.InstalledAppId)
@@ -857,7 +860,7 @@ func (impl AppStoreDeploymentServiceImpl) createEnvironmentIfNotExists(installAp
 	}
 
 	environmentBean := &cluster2.EnvironmentBean{
-		Environment: cluster2.BuildEnvironmentIdentifer(cluster.ClusterName, namespace),
+		Environment: cluster2.BuildEnvironmentName(cluster.ClusterName, namespace),
 		ClusterId:   clusterId,
 		Namespace:   namespace,
 		Default:     false,
@@ -1318,7 +1321,7 @@ func (impl *AppStoreDeploymentServiceImpl) UpdateInstalledApp(ctx context.Contex
 		installedAppVersion, err = impl.installedAppRepository.GetInstalledAppVersion(installAppVersionRequest.Id)
 		if err != nil {
 			impl.logger.Errorw("error in fetching installedAppVersion by installAppVersionRequest id ", "err", err)
-			return nil, err
+			return nil, fmt.Errorf("The values are outdated. Please make your changes to the latest version and try again.")
 		}
 		// version is upgraded if appStoreApplication version from request payload is not equal to installed app version saved in DB
 		if installedAppVersion.AppStoreApplicationVersionId != installAppVersionRequest.AppStoreVersion {
@@ -1519,6 +1522,9 @@ func (impl *AppStoreDeploymentServiceImpl) UpdateInstalledApp(ctx context.Contex
 func (impl AppStoreDeploymentServiceImpl) GetInstalledAppVersion(id int, userId int32) (*appStoreBean.InstallAppVersionDTO, error) {
 	app, err := impl.installedAppRepository.GetInstalledAppVersion(id)
 	if err != nil {
+		if err == pg.ErrNoRows {
+			return nil, fmt.Errorf("values are outdated. please fetch the latest version and try again")
+		}
 		impl.logger.Errorw("error while fetching from db", "error", err)
 		return nil, err
 	}
diff --git a/pkg/appStore/deployment/service/InstalledAppService.go b/pkg/appStore/deployment/service/InstalledAppService.go
index 5cfe88254..30b4d2ebd 100644
--- a/pkg/appStore/deployment/service/InstalledAppService.go
+++ b/pkg/appStore/deployment/service/InstalledAppService.go
@@ -882,8 +882,14 @@ func (impl *InstalledAppServiceImpl) FindAppDetailsForAppstoreApplication(instal
 func (impl *InstalledAppServiceImpl) FetchChartNotes(installedAppId int, envId int, token string, checkNotesAuth func(token string, appName string, envId int) bool) (string, error) {
 	//check notes.txt in db
 	installedApp, err := impl.installedAppRepository.FetchNotes(installedAppId)
+	if err != nil && err != pg.ErrNoRows {
+		return "", err
+	}
 	installedAppVerison, err := impl.installedAppRepository.GetInstalledAppVersionByInstalledAppIdAndEnvId(installedAppId, envId)
 	if err != nil {
+		if err == pg.ErrNoRows {
+			return "", fmt.Errorf("values are outdated. please fetch the latest version and try again")
+		}
 		impl.logger.Errorw("error fetching installed  app version in installed app service", "err", err)
 		return "", err
 	}
diff --git a/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go b/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go
index cce76e06f..dce917a64 100644
--- a/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go
+++ b/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go
@@ -378,6 +378,9 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) GetDeploymentHistory(ctx context
 
 	installedAppVersions, err := impl.installedAppRepository.GetInstalledAppVersionByInstalledAppIdMeta(installedAppDto.InstalledAppId)
 	if err != nil {
+		if err == pg.ErrNoRows {
+			return nil, fmt.Errorf("values are outdated. please fetch the latest version and try again")
+		}
 		impl.Logger.Errorw("error while fetching installed version", "error", err)
 		return result, err
 	}
diff --git a/pkg/bean/app.go b/pkg/bean/app.go
index ffdc2e145..557823f79 100644
--- a/pkg/bean/app.go
+++ b/pkg/bean/app.go
@@ -206,6 +206,23 @@ const (
 	WEBHOOK_EVENT_NON_MERGED_ACTION_TYPE string = "non-merged"
 )
 
+type CiPatchStatus string
+
+const (
+	CI_PATCH_SUCCESS        CiPatchStatus = "Succeeded"
+	CI_PATCH_FAILED         CiPatchStatus = "Failed"
+	CI_PATCH_NOT_AUTHORIZED CiPatchStatus = "Not authorised"
+)
+
+type CiPatchMessage string
+
+const (
+	CI_PATCH_NOT_AUTHORIZED_MESSAGE CiPatchMessage = "You don't have permission to change branch"
+	CI_PATCH_MULTI_GIT_ERROR        CiPatchMessage = "Build pipeline is connected to multiple git repositories"
+	CI_PATCH_REGEX_ERROR            CiPatchMessage = "Provided branch does not match regex "
+	CI_BRANCH_TYPE_ERROR            CiPatchMessage = "Branch cannot be changed for pipeline as source type is “Pull request or Tag”"
+)
+
 func (a PatchAction) String() string {
 	return [...]string{"CREATE", "UPDATE_SOURCE", "DELETE", "DEACTIVATE"}[a]
 
@@ -219,6 +236,27 @@ type CiMaterialPatchRequest struct {
 	Source        *SourceTypeConfig `json:"source" validate:"required"`
 }
 
+type CiMaterialValuePatchRequest struct {
+	AppId         int `json:"appId" validate:"required"`
+	EnvironmentId int `json:"environmentId" validate:"required"`
+}
+
+type CiMaterialBulkPatchRequest struct {
+	AppIds        []int  `json:"appIds" validate:"required"`
+	EnvironmentId int    `json:"environmentId" validate:"required"`
+	Value         string `json:"value,omitempty" validate:"required"`
+}
+
+type CiMaterialBulkPatchResponse struct {
+	Apps []CiMaterialPatchResponse `json:"apps"`
+}
+
+type CiMaterialPatchResponse struct {
+	AppId   int            `json:"appId"`
+	Status  CiPatchStatus  `json:"status"`
+	Message CiPatchMessage `json:"message"`
+}
+
 type CiPatchRequest struct {
 	CiPipeline    *CiPipeline `json:"ciPipeline"`
 	AppId         int         `json:"appId,omitempty"`
diff --git a/pkg/bulkAction/BulkUpdateService.go b/pkg/bulkAction/BulkUpdateService.go
index cc3c4e1ab..1317df13e 100644
--- a/pkg/bulkAction/BulkUpdateService.go
+++ b/pkg/bulkAction/BulkUpdateService.go
@@ -562,7 +562,7 @@ func (impl BulkUpdateServiceImpl) extractAndMapVariables(template string, entity
 	err = impl.variableEntityMappingService.UpdateVariablesForEntity(usedVariables, repository5.Entity{
 		EntityType: entityType,
 		EntityId:   entityId,
-	}, userId)
+	}, userId, nil)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/chart/ChartService.go b/pkg/chart/ChartService.go
index 41257ab7e..fd2c20667 100644
--- a/pkg/chart/ChartService.go
+++ b/pkg/chart/ChartService.go
@@ -483,7 +483,7 @@ func (impl ChartServiceImpl) extractAndMapVariables(template string, entityId in
 	err = impl.variableEntityMappingService.UpdateVariablesForEntity(usedVariables, repository5.Entity{
 		EntityType: entityType,
 		EntityId:   entityId,
-	}, userId)
+	}, userId, nil)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/chartRepo/repository/mocks/ChartRepoRepository.go b/pkg/chartRepo/repository/mocks/ChartRepoRepository.go
index 5aaf2f4f5..4a7b6ae06 100644
--- a/pkg/chartRepo/repository/mocks/ChartRepoRepository.go
+++ b/pkg/chartRepo/repository/mocks/ChartRepoRepository.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.20.0. DO NOT EDIT.
+// Code generated by mockery v2.33.1. DO NOT EDIT.
 
 package mocks
 
@@ -118,6 +118,30 @@ func (_m *ChartRepoRepository) FindByName(name string) (*chartRepoRepository.Cha
 	return r0, r1
 }
 
+// FindDeploymentCountByChartRepoId provides a mock function with given fields: chartId
+func (_m *ChartRepoRepository) FindDeploymentCountByChartRepoId(chartId int) (int, error) {
+	ret := _m.Called(chartId)
+
+	var r0 int
+	var r1 error
+	if rf, ok := ret.Get(0).(func(int) (int, error)); ok {
+		return rf(chartId)
+	}
+	if rf, ok := ret.Get(0).(func(int) int); ok {
+		r0 = rf(chartId)
+	} else {
+		r0 = ret.Get(0).(int)
+	}
+
+	if rf, ok := ret.Get(1).(func(int) error); ok {
+		r1 = rf(chartId)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
 // GetConnection provides a mock function with given fields:
 func (_m *ChartRepoRepository) GetConnection() *pg.DB {
 	ret := _m.Called()
@@ -202,13 +226,12 @@ func (_m *ChartRepoRepository) Update(chartRepo *chartRepoRepository.ChartRepo,
 	return r0
 }
 
-type mockConstructorTestingTNewChartRepoRepository interface {
+// NewChartRepoRepository creates a new instance of ChartRepoRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewChartRepoRepository(t interface {
 	mock.TestingT
 	Cleanup(func())
-}
-
-// NewChartRepoRepository creates a new instance of ChartRepoRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewChartRepoRepository(t mockConstructorTestingTNewChartRepoRepository) *ChartRepoRepository {
+}) *ChartRepoRepository {
 	mock := &ChartRepoRepository{}
 	mock.Mock.Test(t)
 
diff --git a/pkg/cluster/EnvironmentService.go b/pkg/cluster/EnvironmentService.go
index d10eb5fa5..9d4c010e8 100644
--- a/pkg/cluster/EnvironmentService.go
+++ b/pkg/cluster/EnvironmentService.go
@@ -419,6 +419,7 @@ func (impl EnvironmentServiceImpl) GetEnvironmentListForAutocomplete(isDeploymen
 				Description:            model.Description,
 				IsVirtualEnvironment:   model.IsVirtualEnvironment,
 				AllowedDeploymentTypes: allowedDeploymentConfigString,
+				ClusterId:              model.ClusterId,
 			})
 		}
 	} else {
@@ -432,6 +433,7 @@ func (impl EnvironmentServiceImpl) GetEnvironmentListForAutocomplete(isDeploymen
 				ClusterName:           model.Cluster.ClusterName,
 				Description:           model.Description,
 				IsVirtualEnvironment:  model.IsVirtualEnvironment,
+				ClusterId:             model.ClusterId,
 			})
 		}
 	}
diff --git a/pkg/cluster/EnvironmentUtil.go b/pkg/cluster/EnvironmentUtil.go
index bc732d2ca..94d8ca89d 100644
--- a/pkg/cluster/EnvironmentUtil.go
+++ b/pkg/cluster/EnvironmentUtil.go
@@ -17,8 +17,13 @@
 
 package cluster
 
-import "fmt"
+import (
+	"fmt"
+	"strings"
+)
 
-func BuildEnvironmentIdentifer(clusterName string, namespace string) string {
-	return fmt.Sprintf("%s__%s", clusterName, namespace)
-}
\ No newline at end of file
+func BuildEnvironmentName(clusterName string, namespace string) string {
+	// Here we are replacing the (_) with (-) in clusterName as we don't support (_) in environment Name
+	clusterName = strings.ReplaceAll(clusterName, "_", "-")
+	return fmt.Sprintf("%s--%s", clusterName, namespace)
+}
diff --git a/pkg/k8s/application/k8sApplicationService.go b/pkg/k8s/application/k8sApplicationService.go
index 8d098a97f..dc22dc033 100644
--- a/pkg/k8s/application/k8sApplicationService.go
+++ b/pkg/k8s/application/k8sApplicationService.go
@@ -454,6 +454,9 @@ func (impl *K8sApplicationServiceImpl) GetAllApiResourceGVKWithoutAuthorization(
 				k8sEventIndex = index
 			}
 		}
+		if gvk.Kind == "Node" {
+			allApiResources = append(allApiResources[:index], allApiResources[index+1:]...)
+		}
 	}
 	if k8sEventIndex > -1 && v1EventIndex > -1 {
 		allApiResources = append(allApiResources[:v1EventIndex], allApiResources[v1EventIndex+1:]...)
diff --git a/pkg/pipeline/CdHandler.go b/pkg/pipeline/CdHandler.go
index 02b7014ad..64943e58b 100644
--- a/pkg/pipeline/CdHandler.go
+++ b/pkg/pipeline/CdHandler.go
@@ -1371,7 +1371,7 @@ func (impl *CdHandlerImpl) FetchAppWorkflowStatusForTriggerViewForEnvironment(re
 				cdWorkflowStatus.PreStatus = statusMap[item.WfrId]
 			} else if item.WorkflowType == WorklowTypeDeploy {
 				cdWorkflowStatus.DeployStatus = statusMap[item.WfrId]
-			} else if item.WorkflowType == WorklowTypePre {
+			} else if item.WorkflowType == WorklowTypePost {
 				cdWorkflowStatus.PostStatus = statusMap[item.WfrId]
 			}
 			cdMap[item.PipelineId] = cdWorkflowStatus
diff --git a/pkg/pipeline/CiCdPipelineOrchestrator.go b/pkg/pipeline/CiCdPipelineOrchestrator.go
index f47937980..41e89f8b4 100644
--- a/pkg/pipeline/CiCdPipelineOrchestrator.go
+++ b/pkg/pipeline/CiCdPipelineOrchestrator.go
@@ -40,6 +40,7 @@ import (
 	"github.com/devtron-labs/devtron/pkg/sql"
 	"github.com/devtron-labs/devtron/pkg/user"
 	bean3 "github.com/devtron-labs/devtron/pkg/user/bean"
+	"github.com/devtron-labs/devtron/pkg/user/casbin"
 	util2 "github.com/devtron-labs/devtron/util"
 	util3 "github.com/devtron-labs/devtron/util/k8s"
 	"path"
@@ -73,6 +74,8 @@ type CiCdPipelineOrchestrator interface {
 	DeleteCdPipeline(pipelineId int, userId int32, tx *pg.Tx) error
 	PatchMaterialValue(createRequest *bean.CiPipeline, userId int32, oldPipeline *pipelineConfig.CiPipeline) (*bean.CiPipeline, error)
 	PatchCiMaterialSource(ciPipeline *bean.CiMaterialPatchRequest, userId int32) (*bean.CiMaterialPatchRequest, error)
+	PatchCiMaterialSourceValue(patchRequest *bean.CiMaterialValuePatchRequest, userId int32, value string, token string, checkAppSpecificAccess func(token, action string, appId int) (bool, error)) (*pipelineConfig.CiPipelineMaterial, error)
+	UpdateCiPipelineMaterials(materialsUpdate []*pipelineConfig.CiPipelineMaterial) error
 	PipelineExists(name string) (bool, error)
 	GetCdPipelinesForApp(appId int) (cdPipelines *bean.CdPipelines, err error)
 	GetCdPipelinesForAppAndEnv(appId int, envId int) (cdPipelines *bean.CdPipelines, err error)
@@ -187,6 +190,72 @@ func (impl CiCdPipelineOrchestratorImpl) PatchCiMaterialSource(patchRequest *bea
 	return patchRequest, nil
 }
 
+func (impl CiCdPipelineOrchestratorImpl) PatchCiMaterialSourceValue(patchRequest *bean.CiMaterialValuePatchRequest, userId int32, value string, token string, checkAppSpecificAccess func(token, action string, appId int) (bool, error)) (*pipelineConfig.CiPipelineMaterial, error) {
+	pipeline, err := impl.findUniquePipelineForAppIdAndEnvironmentId(patchRequest.AppId, patchRequest.EnvironmentId)
+	if err != nil {
+		impl.logger.Errorw("Error in getting UniquePipelineForAppIdAndEnvironmentId", "appId", patchRequest.AppId, "envId", patchRequest.EnvironmentId, "err", err)
+		return nil, err
+	}
+
+	ciPipelineMaterial, err := impl.findUniqueCiPipelineMaterial(pipeline.CiPipelineId)
+	if err != nil {
+		impl.logger.Errorw("Error in getting UniqueCiPipelineMaterial", "CiPipelineId", pipeline.CiPipelineId, "err", err)
+		if strings.Contains(err.Error(), "ciPipelineMaterial not found") {
+			return nil, errors.New(string(bean.CI_BRANCH_TYPE_ERROR))
+		}
+		return nil, err
+	}
+
+	err = impl.validateCiPipelineMaterial(ciPipelineMaterial, value, token, checkAppSpecificAccess, patchRequest.AppId)
+	if err != nil {
+		impl.logger.Errorw("Validation failed on CiPipelineMaterial", "err", err)
+		return nil, err
+	}
+
+	ciPipelineMaterial.Value = value
+	ciPipelineMaterial.AuditLog.UpdatedBy = userId
+	ciPipelineMaterial.AuditLog.UpdatedOn = time.Now()
+	return ciPipelineMaterial, nil
+}
+
+func (impl CiCdPipelineOrchestratorImpl) UpdateCiPipelineMaterials(materialsUpdate []*pipelineConfig.CiPipelineMaterial) error {
+	if err := impl.saveUpdatedMaterial(materialsUpdate); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (impl CiCdPipelineOrchestratorImpl) validateCiPipelineMaterial(ciPipelineMaterial *pipelineConfig.CiPipelineMaterial, value string, token string, checkAppSpecificAccess func(token, action string, appId int) (bool, error), appId int) error {
+	// Change branch source is supported for SOURCE_TYPE_BRANCH_FIXED and SOURCE_TYPE_BRANCH_REGEX
+	if ciPipelineMaterial.Type != pipelineConfig.SOURCE_TYPE_BRANCH_FIXED && ciPipelineMaterial.Type != pipelineConfig.SOURCE_TYPE_BRANCH_REGEX {
+		return errors.New(string(bean.CI_BRANCH_TYPE_ERROR))
+	}
+
+	if ciPipelineMaterial.Regex != "" {
+		// Checking Trigger Access for Regex branch
+		if ok, err := checkAppSpecificAccess(token, casbin.ActionTrigger, appId); !ok {
+			return err
+		}
+	} else {
+		// Checking Admin Access for Fixed branch
+		if ok, err := checkAppSpecificAccess(token, casbin.ActionUpdate, appId); !ok {
+			return err
+		}
+	}
+
+	// In case of regex we are check if the branch match the regex
+	if ciPipelineMaterial.Regex != "" {
+		ok, err := regexp.MatchString(ciPipelineMaterial.Regex, value)
+		if err != nil {
+			return err
+		}
+		if !ok {
+			return errors.New(string(bean.CI_PATCH_REGEX_ERROR) + "“" + ciPipelineMaterial.Regex + "”")
+		}
+	}
+	return nil
+}
+
 func (impl CiCdPipelineOrchestratorImpl) findUniquePipelineForAppIdAndEnvironmentId(appId, environmentId int) (*pipelineConfig.Pipeline, error) {
 	pipeline, err := impl.pipelineRepository.FindActiveByAppIdAndEnvironmentId(appId, environmentId)
 	if err != nil {
@@ -203,8 +272,11 @@ func (impl CiCdPipelineOrchestratorImpl) findUniqueCiPipelineMaterial(ciPipeline
 	if err != nil {
 		return nil, err
 	}
+	if ciPipelineMaterials == nil {
+		return nil, fmt.Errorf("ciPipelineMaterial not found")
+	}
 	if len(ciPipelineMaterials) != 1 {
-		return nil, fmt.Errorf("unique ciPipelineMaterial was not found, for the given appId and environmentId")
+		return nil, fmt.Errorf(string(bean.CI_PATCH_MULTI_GIT_ERROR))
 	}
 	return ciPipelineMaterials[0], nil
 }
diff --git a/pkg/pipeline/CiService.go b/pkg/pipeline/CiService.go
index 63e2cc5eb..fc9a2643b 100644
--- a/pkg/pipeline/CiService.go
+++ b/pkg/pipeline/CiService.go
@@ -31,6 +31,9 @@ import (
 	"github.com/devtron-labs/devtron/pkg/pipeline/repository"
 	repository2 "github.com/devtron-labs/devtron/pkg/plugin/repository"
 	"github.com/devtron-labs/devtron/pkg/user"
+	"github.com/devtron-labs/devtron/pkg/variables"
+	"github.com/devtron-labs/devtron/pkg/variables/models"
+	repository4 "github.com/devtron-labs/devtron/pkg/variables/repository"
 	"github.com/go-pg/pg"
 	"path/filepath"
 	"strconv"
@@ -68,6 +71,7 @@ type CiServiceImpl struct {
 	appCrudOperationService       app.AppCrudOperationService
 	envRepository                 repository1.EnvironmentRepository
 	appRepository                 appRepository.AppRepository
+	variableSnapshotHistoryService variables.VariableSnapshotHistoryService
 	config                        *CiConfig
 }
 
@@ -78,7 +82,9 @@ func NewCiServiceImpl(Logger *zap.SugaredLogger, workflowService WorkflowService
 	prePostCiScriptHistoryService history.PrePostCiScriptHistoryService,
 	pipelineStageService PipelineStageService,
 	userService user.UserService,
-	ciTemplateService CiTemplateService, appCrudOperationService app.AppCrudOperationService, envRepository repository1.EnvironmentRepository, appRepository appRepository.AppRepository) *CiServiceImpl {
+	ciTemplateService CiTemplateService, appCrudOperationService app.AppCrudOperationService, envRepository repository1.EnvironmentRepository, appRepository appRepository.AppRepository,
+	variableSnapshotHistoryService variables.VariableSnapshotHistoryService,
+) *CiServiceImpl {
 	cis := &CiServiceImpl{
 		Logger:                        Logger,
 		workflowService:               workflowService,
@@ -95,6 +101,7 @@ func NewCiServiceImpl(Logger *zap.SugaredLogger, workflowService WorkflowService
 		appCrudOperationService:       appCrudOperationService,
 		envRepository:                 envRepository,
 		appRepository:                 appRepository,
+		variableSnapshotHistoryService: variableSnapshotHistoryService,
 	}
 	config, err := GetCiConfig()
 	if err != nil {
@@ -141,23 +148,35 @@ func (impl *CiServiceImpl) TriggerCiPipeline(trigger Trigger) (int, error) {
 		impl.Logger.Errorw("could not fetch ci config", "pipeline", trigger.PipelineId)
 		return 0, err
 	}
+
+	scope := models.Scope{
+		AppId: pipeline.App.Id,
+	}
 	env, isJob, err := impl.getEnvironmentForJob(pipeline, trigger)
 	if err != nil {
 		return 0, err
 	}
 	if isJob && env != nil {
 		ciWorkflowConfig.Namespace = env.Namespace
+
+		//This will be populated for jobs running in selected environment
+		scope.EnvId = env.Id
+		scope.ClusterId = env.ClusterId
 	}
 	if ciWorkflowConfig.Namespace == "" {
 		ciWorkflowConfig.Namespace = impl.config.GetDefaultNamespace()
 	}
 
-	preCiSteps, postCiSteps, refPluginsData, err := impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(pipeline.Id, bean2.CiStage)
-
+	//preCiSteps, postCiSteps, refPluginsData, err := impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(pipeline.Id, ciEvent)
+	prePostAndRefPluginResponse, err := impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(pipeline.Id, bean2.CiStage, scope)
 	if err != nil {
 		impl.Logger.Errorw("error in getting pre steps data for wf request", "err", err, "ciPipelineId", pipeline.Id)
 		return 0, err
 	}
+	preCiSteps := prePostAndRefPluginResponse.PreStageSteps
+	postCiSteps := prePostAndRefPluginResponse.PostStageSteps
+	refPluginsData := prePostAndRefPluginResponse.RefPluginData
+	variableSnapshot := prePostAndRefPluginResponse.VariableSnapshot
 
 	if len(preCiSteps) == 0 && isJob {
 		return 0, &util.ApiError{
@@ -207,6 +226,21 @@ func (impl *CiServiceImpl) TriggerCiPipeline(trigger Trigger) (int, error) {
 	}
 	impl.Logger.Debugw("ci triggered", " pipeline ", trigger.PipelineId)
 
+	//Save Scoped VariableSnapshot
+	if len(variableSnapshot) > 0 {
+		variableMapBytes, _ := json.Marshal(variableSnapshot)
+		err := impl.variableSnapshotHistoryService.SaveVariableHistoriesForTrigger([]*repository4.VariableSnapshotHistoryBean{{
+			VariableSnapshot: variableMapBytes,
+			HistoryReference: repository4.HistoryReference{
+				HistoryReferenceId:   savedCiWf.Id,
+				HistoryReferenceType: repository4.HistoryReferenceTypeCIWORKFLOW,
+			},
+		}}, trigger.TriggeredBy)
+		if err != nil {
+			impl.Logger.Errorf("Not able to save variable snapshot for CI trigger %s", err)
+		}
+	}
+
 	middleware.CiTriggerCounter.WithLabelValues(pipeline.App.AppName, pipeline.Name).Inc()
 	go impl.WriteCITriggerEvent(trigger, pipeline, workflowRequest)
 	return savedCiWf.Id, err
@@ -444,22 +478,15 @@ func (impl *CiServiceImpl) buildWfRequestForCiPipeline(pipeline *pipelineConfig.
 			afterDockerBuildScripts = append(afterDockerBuildScripts, ciTask)
 		}
 	}
-	var err error
+
 	if !(len(beforeDockerBuildScripts) == 0 && len(afterDockerBuildScripts) == 0) {
 		//found beforeDockerBuildScripts/afterDockerBuildScripts
 		//building preCiSteps & postCiSteps from them, refPluginsData not needed
 		preCiSteps = buildCiStepsDataFromDockerBuildScripts(beforeDockerBuildScripts)
 		postCiSteps = buildCiStepsDataFromDockerBuildScripts(afterDockerBuildScripts)
 		refPluginsData = []*bean2.RefPluginObject{}
-	} else {
-		//beforeDockerBuildScripts & afterDockerBuildScripts not found
-		//getting preCiStepsData, postCiStepsData & refPluginsData
-		preCiSteps, postCiSteps, refPluginsData, err = impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(pipeline.Id, bean2.CiStage)
-		if err != nil {
-			impl.Logger.Errorw("error in getting pre, post & refPlugin steps data for wf request", "err", err, "ciPipelineId", pipeline.Id)
-			return nil, err
-		}
 	}
+
 	dockerImageTag := impl.buildImageTag(commitHashes, pipeline.Id, savedWf.Id)
 	if ciWorkflowConfig.CiCacheBucket == "" {
 		ciWorkflowConfig.CiCacheBucket = impl.config.DefaultCacheBucket
diff --git a/pkg/pipeline/PipelineBuilder.go b/pkg/pipeline/PipelineBuilder.go
index 5082ce356..40a09fa99 100644
--- a/pkg/pipeline/PipelineBuilder.go
+++ b/pkg/pipeline/PipelineBuilder.go
@@ -119,6 +119,7 @@ type PipelineBuilder interface {
 	UpdateCiTemplate(updateRequest *bean.CiConfigRequest) (*bean.CiConfigRequest, error)
 	PatchCiPipeline(request *bean.CiPatchRequest) (ciConfig *bean.CiConfigRequest, err error)
 	PatchCiMaterialSource(ciPipeline *bean.CiMaterialPatchRequest, userId int32) (*bean.CiMaterialPatchRequest, error)
+	BulkPatchCiMaterialSource(ciPipelines *bean.CiMaterialBulkPatchRequest, userId int32, token string, checkAppSpecificAccess func(token, action string, appId int) (bool, error)) (*bean.CiMaterialBulkPatchResponse, error)
 	CreateCdPipelines(cdPipelines *bean.CdPipelines, ctx context.Context) (*bean.CdPipelines, error)
 	GetApp(appId int) (application *bean.CreateAppDTO, err error)
 	PatchCdPipelines(cdPipelines *bean.CDPatchRequest, ctx context.Context) (*bean.CdPipelines, error)
@@ -135,7 +136,7 @@ type PipelineBuilder interface {
 	/*	CreateCdPipelines(cdPipelines bean.CdPipelines) (*bean.CdPipelines, error)*/
 	RetrieveArtifactsByCDPipeline(pipeline *pipelineConfig.Pipeline, stage bean2.WorkflowType) (*bean.CiArtifactResponse, error)
 	RetrieveParentDetails(pipelineId int) (parentId int, parentType bean2.WorkflowType, err error)
-	FetchArtifactForRollback(cdPipelineId, offset, limit int) (bean.CiArtifactResponse, error)
+	FetchArtifactForRollback(cdPipelineId, appId, offset, limit int) (bean.CiArtifactResponse, error)
 	FindAppsByTeamId(teamId int) ([]*AppBean, error)
 	FindAppsByTeamName(teamName string) ([]AppBean, error)
 	FindPipelineById(cdPipelineId int) (*pipelineConfig.Pipeline, error)
@@ -449,13 +450,43 @@ func (impl *PipelineBuilderImpl) DeleteMaterial(request *bean.UpdateMaterialDTO)
 	existingMaterial.UpdatedBy = request.UserId
 
 	err = impl.materialRepo.MarkMaterialDeleted(existingMaterial)
-
 	if err != nil {
 		impl.logger.Errorw("error in deleting git material", "gitMaterial", existingMaterial)
 		return err
 	}
+
 	err = impl.gitMaterialHistoryService.MarkMaterialDeletedAndCreateHistory(existingMaterial)
 
+	dbConnection := impl.pipelineRepository.GetConnection()
+	tx, err := dbConnection.Begin()
+	if err != nil {
+		return err
+	}
+	// Rollback tx on error.
+	defer tx.Rollback()
+	var materials []*pipelineConfig.CiPipelineMaterial
+	for _, pipeline := range pipelines {
+		materialDbObject, err := impl.ciPipelineMaterialRepository.GetByPipelineIdAndGitMaterialId(pipeline.Id, request.Material.Id)
+		if err != nil {
+			return err
+		}
+		if len(materialDbObject) == 0 {
+			continue
+		}
+		materialDbObject[0].Active = false
+		materials = append(materials, materialDbObject[0])
+	}
+
+	if len(materials) == 0 {
+		return nil
+	}
+
+	err = impl.ciPipelineMaterialRepository.Update(tx, materials...)
+	err = tx.Commit()
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
 
@@ -1646,6 +1677,52 @@ func (impl *PipelineBuilderImpl) PatchCiMaterialSource(ciPipeline *bean.CiMateri
 	return impl.ciCdPipelineOrchestrator.PatchCiMaterialSource(ciPipeline, userId)
 }
 
+func (impl *PipelineBuilderImpl) BulkPatchCiMaterialSource(ciPipelines *bean.CiMaterialBulkPatchRequest, userId int32, token string, checkAppSpecificAccess func(token, action string, appId int) (bool, error)) (*bean.CiMaterialBulkPatchResponse, error) {
+	response := &bean.CiMaterialBulkPatchResponse{}
+	var ciPipelineMaterials []*pipelineConfig.CiPipelineMaterial
+	for _, appId := range ciPipelines.AppIds {
+		ciPipeline := &bean.CiMaterialValuePatchRequest{
+			AppId:         appId,
+			EnvironmentId: ciPipelines.EnvironmentId,
+		}
+		ciPipelineMaterial, err := impl.ciCdPipelineOrchestrator.PatchCiMaterialSourceValue(ciPipeline, userId, ciPipelines.Value, token, checkAppSpecificAccess)
+
+		if err == nil {
+			ciPipelineMaterial.Type = pipelineConfig.SOURCE_TYPE_BRANCH_FIXED
+			ciPipelineMaterials = append(ciPipelineMaterials, ciPipelineMaterial)
+		}
+		response.Apps = append(response.Apps, bean.CiMaterialPatchResponse{
+			AppId:   appId,
+			Status:  getPatchStatus(err),
+			Message: getPatchMessage(err),
+		})
+	}
+	if len(ciPipelineMaterials) == 0 {
+		return response, nil
+	}
+	if err := impl.ciCdPipelineOrchestrator.UpdateCiPipelineMaterials(ciPipelineMaterials); err != nil {
+		return nil, err
+	}
+	return response, nil
+}
+
+func getPatchStatus(err error) bean.CiPatchStatus {
+	if err != nil {
+		if err.Error() == string(bean.CI_PATCH_NOT_AUTHORIZED_MESSAGE) {
+			return bean.CI_PATCH_NOT_AUTHORIZED
+		}
+		return bean.CI_PATCH_FAILED
+	}
+	return bean.CI_PATCH_SUCCESS
+}
+
+func getPatchMessage(err error) bean.CiPatchMessage {
+	if err != nil {
+		return bean.CiPatchMessage(err.Error())
+	}
+	return ""
+}
+
 func (impl *PipelineBuilderImpl) patchCiPipelineUpdateSource(baseCiConfig *bean.CiConfigRequest, modifiedCiPipeline *bean.CiPipeline) (ciConfig *bean.CiConfigRequest, err error) {
 
 	pipeline, err := impl.ciPipelineRepository.FindById(modifiedCiPipeline.Id)
@@ -3132,7 +3209,7 @@ func (impl *PipelineBuilderImpl) createCdPipeline(ctx context.Context, app *app2
 		return 0, err
 	}
 	//VARIABLE_MAPPING_UPDATE
-	err = impl.extractAndMapVariables(envOverride.EnvOverrideValues, envOverride.Id, repository6.EntityTypeDeploymentTemplateEnvLevel, envOverride.UpdatedBy)
+	err = impl.extractAndMapVariables(envOverride.EnvOverrideValues, envOverride.Id, repository6.EntityTypeDeploymentTemplateEnvLevel, envOverride.UpdatedBy, tx)
 	if err != nil {
 		return 0, err
 	}
@@ -3177,7 +3254,7 @@ func (impl *PipelineBuilderImpl) createCdPipeline(ctx context.Context, app *app2
 	return pipelineId, nil
 }
 
-func (impl PipelineBuilderImpl) extractAndMapVariables(template string, entityId int, entityType repository6.EntityType, userId int32) error {
+func (impl PipelineBuilderImpl) extractAndMapVariables(template string, entityId int, entityType repository6.EntityType, userId int32, tx *pg.Tx) error {
 	usedVariables, err := impl.variableTemplateParser.ExtractVariables(template)
 	if err != nil {
 		return err
@@ -3185,7 +3262,7 @@ func (impl PipelineBuilderImpl) extractAndMapVariables(template string, entityId
 	err = impl.variableEntityMappingService.UpdateVariablesForEntity(usedVariables, repository6.Entity{
 		EntityType: entityType,
 		EntityId:   entityId,
-	}, userId)
+	}, userId, tx)
 	if err != nil {
 		return err
 	}
@@ -3765,7 +3842,7 @@ func (impl *PipelineBuilderImpl) BuildArtifactsForCIParent(cdPipelineId int, par
 	return ciArtifacts, nil
 }
 
-func (impl *PipelineBuilderImpl) FetchArtifactForRollback(cdPipelineId, offset, limit int) (bean.CiArtifactResponse, error) {
+func (impl *PipelineBuilderImpl) FetchArtifactForRollback(cdPipelineId, appId, offset, limit int) (bean.CiArtifactResponse, error) {
 	var deployedCiArtifacts []bean.CiArtifactBean
 	var deployedCiArtifactsResponse bean.CiArtifactResponse
 
@@ -3786,6 +3863,14 @@ func (impl *PipelineBuilderImpl) FetchArtifactForRollback(cdPipelineId, offset,
 	for _, item := range users {
 		userEmails[item.Id] = item.EmailId
 	}
+
+	imageTagsDataMap, err := impl.imageTaggingService.GetTagsDataMapByAppId(appId)
+	if err != nil {
+		impl.logger.Errorw("error in getting image tagging data with appId", "err", err, "appId", appId)
+		return deployedCiArtifactsResponse, err
+	}
+	artifactIds := make([]int, 0)
+
 	for _, cdWfr := range cdWfrs {
 		ciArtifact := &repository.CiArtifact{}
 		if cdWfr.CdWorkflow != nil && cdWfr.CdWorkflow.CiArtifact != nil {
@@ -3808,6 +3893,21 @@ func (impl *PipelineBuilderImpl) FetchArtifactForRollback(cdPipelineId, offset,
 			WfrId:        cdWfr.Id,
 			DeployedBy:   userEmail,
 		})
+		artifactIds = append(artifactIds, ciArtifact.Id)
+	}
+	imageCommentsDataMap, err := impl.imageTaggingService.GetImageCommentsDataMapByArtifactIds(artifactIds)
+	if err != nil {
+		impl.logger.Errorw("error in getting GetImageCommentsDataMapByArtifactIds", "err", err, "appId", appId, "artifactIds", artifactIds)
+		return deployedCiArtifactsResponse, err
+	}
+
+	for i, _ := range deployedCiArtifacts {
+		if imageTaggingResp := imageTagsDataMap[deployedCiArtifacts[i].Id]; imageTaggingResp != nil {
+			deployedCiArtifacts[i].ImageReleaseTags = imageTaggingResp
+		}
+		if imageCommentResp := imageCommentsDataMap[deployedCiArtifacts[i].Id]; imageCommentResp != nil {
+			deployedCiArtifacts[i].ImageComment = imageCommentResp
+		}
 	}
 
 	deployedCiArtifactsResponse.CdPipelineId = cdPipelineId
diff --git a/pkg/pipeline/PipelineStageService.go b/pkg/pipeline/PipelineStageService.go
index b2a90237a..00266b1f0 100644
--- a/pkg/pipeline/PipelineStageService.go
+++ b/pkg/pipeline/PipelineStageService.go
@@ -1,12 +1,19 @@
 package pipeline
 
 import (
+	"encoding/json"
 	"errors"
+	mapset "github.com/deckarep/golang-set"
 	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
 	"github.com/devtron-labs/devtron/pkg/pipeline/bean"
 	"github.com/devtron-labs/devtron/pkg/pipeline/repository"
 	repository2 "github.com/devtron-labs/devtron/pkg/plugin/repository"
 	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/devtron-labs/devtron/pkg/variables"
+	"github.com/devtron-labs/devtron/pkg/variables/models"
+	"github.com/devtron-labs/devtron/pkg/variables/parsers"
+	repository3 "github.com/devtron-labs/devtron/pkg/variables/repository"
+	"github.com/devtron-labs/devtron/pkg/variables/utils"
 	"github.com/go-pg/pg"
 	"go.uber.org/zap"
 	"time"
@@ -17,11 +24,11 @@ type PipelineStageService interface {
 	CreatePipelineStage(stageReq *bean.PipelineStageDto, stageType repository.PipelineStageType, pipelineId int, userId int32) error
 	UpdatePipelineStage(stageReq *bean.PipelineStageDto, stageType repository.PipelineStageType, pipelineId int, userId int32) error
 	DeletePipelineStage(stageReq *bean.PipelineStageDto, userId int32, tx *pg.Tx) error
-	BuildPrePostAndRefPluginStepsDataForWfRequest(pipelineId int, stageType string) ([]*bean.StepObject, []*bean.StepObject, []*bean.RefPluginObject, error)
+	BuildPrePostAndRefPluginStepsDataForWfRequest(pipelineId int, stageType string, scope models.Scope) (*bean.PrePostAndRefPluginStepsResponse, error)
 	GetCiPipelineStageDataDeepCopy(ciPipelineId int) (preCiStage *bean.PipelineStageDto, postCiStage *bean.PipelineStageDto, err error)
 	GetCdPipelineStageDataDeepCopy(cdPipelineId int) (*bean.PipelineStageDto, *bean.PipelineStageDto, error)
 	GetCdPipelineStageDataDeepCopyForPipelineIds(cdPipelineIds []int) (map[int][]*bean.PipelineStageDto, error)
-
+	GetCdStageByCdPipelineIdAndStageType(cdPipelineId int, stageType repository.PipelineStageType) (*repository.PipelineStage, error)
 	// DeletePipelineStageIfReq function is used to delete corrupted pipelineStage data
 	// , there was a bug(https://github.com/devtron-labs/devtron/issues/3826) where we were not deleting pipeline stage entry even after deleting all the pipelineStageSteps
 	// , this will delete those pipelineStage entry
@@ -31,20 +38,30 @@ type PipelineStageService interface {
 func NewPipelineStageService(logger *zap.SugaredLogger,
 	pipelineStageRepository repository.PipelineStageRepository,
 	globalPluginRepository repository2.GlobalPluginRepository,
-	pipelineRepository pipelineConfig.PipelineRepository) *PipelineStageServiceImpl {
+	pipelineRepository pipelineConfig.PipelineRepository,
+	scopedVariableService variables.ScopedVariableService,
+	variableEntityMappingService variables.VariableEntityMappingService,
+	variableTemplateParser parsers.VariableTemplateParser,
+) *PipelineStageServiceImpl {
 	return &PipelineStageServiceImpl{
-		logger:                  logger,
-		pipelineStageRepository: pipelineStageRepository,
-		globalPluginRepository:  globalPluginRepository,
-		pipelineRepository:      pipelineRepository,
+		logger:                       logger,
+		pipelineStageRepository:      pipelineStageRepository,
+		globalPluginRepository:       globalPluginRepository,
+		pipelineRepository:           pipelineRepository,
+		scopedVariableService:        scopedVariableService,
+		variableEntityMappingService: variableEntityMappingService,
+		variableTemplateParser:       variableTemplateParser,
 	}
 }
 
 type PipelineStageServiceImpl struct {
-	logger                  *zap.SugaredLogger
-	pipelineStageRepository repository.PipelineStageRepository
-	globalPluginRepository  repository2.GlobalPluginRepository
-	pipelineRepository      pipelineConfig.PipelineRepository
+	logger                       *zap.SugaredLogger
+	pipelineStageRepository      repository.PipelineStageRepository
+	globalPluginRepository       repository2.GlobalPluginRepository
+	pipelineRepository           pipelineConfig.PipelineRepository
+	scopedVariableService        variables.ScopedVariableService
+	variableEntityMappingService variables.VariableEntityMappingService
+	variableTemplateParser       parsers.VariableTemplateParser
 }
 
 func (impl *PipelineStageServiceImpl) GetCiPipelineStageDataDeepCopy(ciPipelineId int) (*bean.PipelineStageDto, *bean.PipelineStageDto, error) {
@@ -77,6 +94,10 @@ func (impl *PipelineStageServiceImpl) GetCiPipelineStageDataDeepCopy(ciPipelineI
 	return preCiStage, postCiStage, nil
 }
 
+func (impl *PipelineStageServiceImpl) GetCdStageByCdPipelineIdAndStageType(cdPipelineId int, stageType repository.PipelineStageType) (*repository.PipelineStage, error) {
+	return impl.pipelineStageRepository.GetCdStageByCdPipelineIdAndStageType(cdPipelineId, stageType)
+}
+
 func (impl *PipelineStageServiceImpl) GetCdPipelineStageDataDeepCopy(cdPipelineId int) (*bean.PipelineStageDto, *bean.PipelineStageDto, error) {
 	//getting all stages by cd pipeline id
 	cdStages, err := impl.pipelineStageRepository.GetAllCdStagesByCdPipelineId(cdPipelineId)
@@ -607,6 +628,12 @@ func (impl *PipelineStageServiceImpl) CreatePipelineStage(stageReq *bean.Pipelin
 		impl.logger.Errorw("error in creating stage steps for ci stage", "err", err, "stageId", stage.Id)
 		return err
 	}
+
+	err = impl.extractAndMapScopedVariables(stageReq, userId, tx)
+	if err != nil {
+		return err
+	}
+
 	err = tx.Commit()
 	if err != nil {
 		impl.logger.Errorw("error in tx commit", "err", err)
@@ -961,6 +988,11 @@ func (impl *PipelineStageServiceImpl) UpdatePipelineStage(stageReq *bean.Pipelin
 			impl.logger.Errorw("error in filtering and performing actions on steps in pipelineStage update request", "err", err, "stageReq", stageReq)
 			return err
 		}
+
+		err := impl.extractAndMapScopedVariables(stageReq, userId, nil)
+		if err != nil {
+			return err
+		}
 	}
 	return nil
 }
@@ -981,6 +1013,7 @@ func (impl *PipelineStageServiceImpl) DeletePipelineStageIfReq(stageReq *bean.Pi
 			impl.logger.Errorw("error in deleting the corrupted pipeline stage", "err", err, "pipelineStageId", stageReq.Id)
 			return err, false
 		}
+
 	}
 
 	return nil, len(steps) == 0
@@ -1574,25 +1607,37 @@ func (impl *PipelineStageServiceImpl) DeletePipelineStage(stageReq *bean.Pipelin
 			return err
 		}
 	}
+
+	err = impl.variableEntityMappingService.DeleteMappingsForEntities([]repository3.Entity{{
+		EntityType: repository3.EntityTypePipelineStage,
+		EntityId:   stageReq.Id,
+	}}, userId, tx)
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
 
 //DeleteCiStage and related methods starts
 
 // BuildPrePostAndRefPluginStepsDataForWfRequest and related methods starts
-func (impl *PipelineStageServiceImpl) BuildPrePostAndRefPluginStepsDataForWfRequest(pipelineId int, stageType string) ([]*bean.StepObject, []*bean.StepObject, []*bean.RefPluginObject, error) {
+func (impl *PipelineStageServiceImpl) BuildPrePostAndRefPluginStepsDataForWfRequest(pipelineId int, stageType string, scope models.Scope) (*bean.PrePostAndRefPluginStepsResponse, error) {
 	//get all stages By pipelineId (it can be ciPipelineId or cdPipelineId)
 	var pipelineStages []*repository.PipelineStage
 	var err error
 	if stageType == bean.CiStage {
 		pipelineStages, err = impl.pipelineStageRepository.GetAllCiStagesByCiPipelineId(pipelineId)
-	} else {
+	} else if stageType == preCdStage || stageType == postCdStage {
 		//cdEvent
-		pipelineStages, err = impl.pipelineStageRepository.GetAllCdStagesByCdPipelineId(pipelineId)
+		//pipelineStages, err = impl.pipelineStageRepository.GetAllCdStagesByCdPipelineId(pipelineId)
+		var pipelineStage *repository.PipelineStage
+		pipelineStage, err = impl.pipelineStageRepository.GetCdStageByCdPipelineIdAndStageType(pipelineId, getPipelineStageFromStageType(stageType))
+		pipelineStages = append(pipelineStages, pipelineStage)
 	}
 	if err != nil && err != pg.ErrNoRows {
 		impl.logger.Errorw("error in getting all ci stages by pipelineId", "err", err, "pipelineId", pipelineId, "stageType", stageType)
-		return nil, nil, nil, err
+		return nil, err
 	}
 	var preCiSteps []*bean.StepObject
 	var postCiSteps []*bean.StepObject
@@ -1600,6 +1645,7 @@ func (impl *PipelineStageServiceImpl) BuildPrePostAndRefPluginStepsDataForWfRequ
 	var postCdSteps []*bean.StepObject
 	var refPluginsData []*bean.RefPluginObject
 	var refPluginIds []int
+	var pipelineStageIds []int
 	for _, pipelineStage := range pipelineStages {
 		var refIds []int
 		steps, refIds, err := impl.BuildPipelineStageDataForWfRequest(pipelineStage)
@@ -1608,41 +1654,63 @@ func (impl *PipelineStageServiceImpl) BuildPrePostAndRefPluginStepsDataForWfRequ
 			preCiSteps = steps
 			if err != nil {
 				impl.logger.Errorw("error in getting pre ci steps data for wf request", "err", err, "ciStage", pipelineStage)
-				return nil, nil, nil, err
+				return nil, err
 			}
 		case repository.PIPELINE_STAGE_TYPE_POST_CI:
 			postCiSteps = steps
 			if err != nil {
 				impl.logger.Errorw("error in getting post ci steps data for wf request", "err", err, "ciStage", pipelineStage)
-				return nil, nil, nil, err
+				return nil, err
 			}
 		case repository.PIPELINE_STAGE_TYPE_PRE_CD:
 			preCdSteps = steps
 			if err != nil {
 				impl.logger.Errorw("error in getting post cd steps data for wf request", "err", err, "cdStage", pipelineStage)
-				return nil, nil, nil, err
+				return nil, err
 			}
 		case repository.PIPELINE_STAGE_TYPE_POST_CD:
 			postCdSteps = steps
 			if err != nil {
 				impl.logger.Errorw("error in getting post cd steps data for wf request", "err", err, "cdStage", pipelineStage)
-				return nil, nil, nil, err
+				return nil, err
 			}
 		}
 		refPluginIds = append(refPluginIds, refIds...)
+		pipelineStageIds = append(pipelineStageIds, pipelineStage.Id)
 	}
 	if len(refPluginIds) > 0 {
 		refPluginsData, err = impl.BuildRefPluginStepDataForWfRequest(refPluginIds)
 		if err != nil {
 			impl.logger.Errorw("error in building ref plugin step data", "err", err, "refPluginIds", refPluginIds)
-			return nil, nil, nil, err
+			return nil, err
 		}
 	}
+	unresolvedResponse := &bean.PrePostAndRefPluginStepsResponse{RefPluginData: refPluginsData}
+
 	if stageType == bean.CiStage {
-		return preCiSteps, postCiSteps, refPluginsData, nil
+		unresolvedResponse.PreStageSteps = preCiSteps
+		unresolvedResponse.PostStageSteps = postCiSteps
 	} else {
-		return preCdSteps, postCdSteps, refPluginsData, nil
+		unresolvedResponse.PreStageSteps = preCdSteps
+		unresolvedResponse.PostStageSteps = postCdSteps
 	}
+
+	resolvedResponse, err := impl.fetchScopedVariablesAndResolveTemplate(unresolvedResponse, pipelineStageIds, scope)
+	if err != nil {
+		impl.logger.Errorw("error in resolving stage request", "err", err, "pipelineStageIds", pipelineStageIds)
+		return resolvedResponse, err
+	}
+	return resolvedResponse, nil
+}
+
+func getPipelineStageFromStageType(stageType string) repository.PipelineStageType {
+	var pipelineStageType repository.PipelineStageType
+	if stageType == preCdStage {
+		pipelineStageType = repository.PIPELINE_STAGE_TYPE_PRE_CD
+	} else if stageType == postCdStage {
+		pipelineStageType = repository.PIPELINE_STAGE_TYPE_POST_CD
+	}
+	return pipelineStageType
 }
 
 func (impl *PipelineStageServiceImpl) BuildPipelineStageDataForWfRequest(pipelineStage *repository.PipelineStage) ([]*bean.StepObject, []int, error) {
@@ -2025,3 +2093,96 @@ func (impl *PipelineStageServiceImpl) BuildPluginVariableAndConditionDataForWfRe
 }
 
 //BuildPrePostAndRefPluginStepsDataForWfRequest and related methods ends
+
+func (impl *PipelineStageServiceImpl) fetchScopedVariablesAndResolveTemplate(unresolvedResponse *bean.PrePostAndRefPluginStepsResponse, pipelineStageIds []int, scope models.Scope) (*bean.PrePostAndRefPluginStepsResponse, error) {
+
+	entities := make([]repository3.Entity, 0)
+	for _, stageId := range pipelineStageIds {
+		entities = append(entities, repository3.Entity{
+			EntityType: repository3.EntityTypePipelineStage,
+			EntityId:   stageId,
+		})
+	}
+	mappingsForEntities, err := impl.variableEntityMappingService.GetAllMappingsForEntities(entities)
+	if err != nil {
+		impl.logger.Errorw("Error in fetching mapped variables in stage request", "error", err)
+		return nil, err
+	}
+
+	//early exit if no variables found
+	if len(mappingsForEntities) == 0 {
+		return unresolvedResponse, nil
+	}
+
+	// collecting all unique variable names in a stage
+	varNamesSet := mapset.NewSet()
+	for _, variableNames := range mappingsForEntities {
+		for _, variableName := range variableNames {
+			varNamesSet.Add(variableName)
+		}
+	}
+	varNames := utils.ToStringArray(varNamesSet.ToSlice())
+
+	scopedVariables, err := impl.scopedVariableService.GetScopedVariables(scope, varNames, true)
+	if err != nil {
+		return nil, err
+	}
+
+	variableSnapshot := make(map[string]string)
+	for _, variable := range scopedVariables {
+		variableSnapshot[variable.VariableName] = variable.VariableValue.StringValue()
+	}
+
+	responseJson, err := json.Marshal(unresolvedResponse)
+	if err != nil {
+		impl.logger.Errorw("Error in marshaling stage", "error", err, "unresolvedResponse", unresolvedResponse)
+		return nil, err
+	}
+	parserResponse := impl.variableTemplateParser.ParseTemplate(parsers.VariableParserRequest{
+		TemplateType:           parsers.JsonVariableTemplate,
+		Template:               string(responseJson),
+		Variables:              scopedVariables,
+		IgnoreUnknownVariables: true,
+	})
+	err = parserResponse.Error
+	if err != nil {
+		impl.logger.Errorw("Error in parsing stage", "error", err, "template", responseJson, "vars", scopedVariables)
+		return nil, err
+	}
+	resolvedResponse := &bean.PrePostAndRefPluginStepsResponse{}
+	err = json.Unmarshal([]byte(parserResponse.ResolvedTemplate), resolvedResponse)
+	if err != nil {
+		impl.logger.Errorw("Error in unmarshalling stage", "error", err)
+
+		return nil, err
+	}
+	resolvedResponse.VariableSnapshot = variableSnapshot
+	return resolvedResponse, nil
+}
+
+func (impl *PipelineStageServiceImpl) extractAndMapScopedVariables(stageReq *bean.PipelineStageDto, userId int32, tx *pg.Tx) error {
+	requestJson, err := json.Marshal(stageReq)
+	if err != nil {
+		impl.logger.Errorw("Error in marshalling stage request", "error", err)
+		return err
+	}
+	scopedVariables, err := impl.variableTemplateParser.ExtractVariables(string(requestJson))
+	if err != nil {
+		impl.logger.Errorw("Error in parsing variable in stage request", "error", err)
+		return err
+	}
+
+	if len(scopedVariables) == 0 {
+		return nil
+	}
+
+	err = impl.variableEntityMappingService.UpdateVariablesForEntity(scopedVariables, repository3.Entity{
+		EntityType: repository3.EntityTypePipelineStage,
+		EntityId:   stageReq.Id,
+	}, userId, tx)
+	if err != nil {
+		impl.logger.Errorw("Error in updating variables for stage request", "error", err)
+		return err
+	}
+	return nil
+}
diff --git a/pkg/pipeline/PropertiesConfig.go b/pkg/pipeline/PropertiesConfig.go
index 2388a5505..a71fa04a0 100644
--- a/pkg/pipeline/PropertiesConfig.go
+++ b/pkg/pipeline/PropertiesConfig.go
@@ -388,7 +388,7 @@ func (impl PropertiesConfigServiceImpl) UpdateEnvironmentProperties(appId int, p
 		return nil, err
 	}
 	//VARIABLE_MAPPING_UPDATE
-	err = impl.extractAndMapVariables(override.EnvOverrideValues, override.Id, repository5.EntityTypeDeploymentTemplateEnvLevel, override.CreatedBy)
+	err = impl.extractAndMapVariables(override.EnvOverrideValues, override.Id, repository5.EntityTypeDeploymentTemplateEnvLevel, override.CreatedBy, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -486,7 +486,7 @@ func (impl PropertiesConfigServiceImpl) CreateIfRequired(chart *chartRepoReposit
 
 		//VARIABLE_MAPPING_UPDATE
 		if envOverride.EnvOverrideValues != "{}" {
-			err = impl.extractAndMapVariables(envOverride.EnvOverrideValues, envOverride.Id, repository5.EntityTypeDeploymentTemplateEnvLevel, envOverride.CreatedBy)
+			err = impl.extractAndMapVariables(envOverride.EnvOverrideValues, envOverride.Id, repository5.EntityTypeDeploymentTemplateEnvLevel, envOverride.CreatedBy, tx)
 			if err != nil {
 				return nil, err
 			}
@@ -752,7 +752,7 @@ func (impl PropertiesConfigServiceImpl) EnvMetricsEnableDisable(appMetricRequest
 	return appMetricRequest, err
 }
 
-func (impl PropertiesConfigServiceImpl) extractAndMapVariables(template string, entityId int, entityType repository5.EntityType, userId int32) error {
+func (impl PropertiesConfigServiceImpl) extractAndMapVariables(template string, entityId int, entityType repository5.EntityType, userId int32, tx *pg.Tx) error {
 	usedVariables, err := impl.variableTemplateParser.ExtractVariables(template)
 	if err != nil {
 		return err
@@ -760,7 +760,7 @@ func (impl PropertiesConfigServiceImpl) extractAndMapVariables(template string,
 	err = impl.variableEntityMappingService.UpdateVariablesForEntity(usedVariables, repository5.Entity{
 		EntityType: entityType,
 		EntityId:   entityId,
-	}, userId)
+	}, userId, tx)
 	if err != nil {
 		return err
 	}
@@ -772,7 +772,7 @@ func (impl PropertiesConfigServiceImpl) removeMappedVariables(entityId int, enti
 	err := impl.variableEntityMappingService.DeleteMappingsForEntities([]repository5.Entity{{
 		EntityType: entityType,
 		EntityId:   entityId,
-	}}, userId)
+	}}, userId, nil)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/pipeline/WorkflowDagExecutor.go b/pkg/pipeline/WorkflowDagExecutor.go
index 7c9a775d3..8602375f7 100644
--- a/pkg/pipeline/WorkflowDagExecutor.go
+++ b/pkg/pipeline/WorkflowDagExecutor.go
@@ -28,6 +28,9 @@ import (
 	"github.com/devtron-labs/devtron/pkg/k8s"
 	bean3 "github.com/devtron-labs/devtron/pkg/pipeline/bean"
 	repository4 "github.com/devtron-labs/devtron/pkg/pipeline/repository"
+	"github.com/devtron-labs/devtron/pkg/variables"
+	models2 "github.com/devtron-labs/devtron/pkg/variables/models"
+	repository5 "github.com/devtron-labs/devtron/pkg/variables/repository"
 	util4 "github.com/devtron-labs/devtron/util"
 	"github.com/devtron-labs/devtron/util/argo"
 	util5 "github.com/devtron-labs/devtron/util/k8s"
@@ -113,6 +116,8 @@ type WorkflowDagExecutorImpl struct {
 	pipelineStageRepository       repository4.PipelineStageRepository
 	pipelineStageService          PipelineStageService
 	config                        *CdConfig
+
+	variableSnapshotHistoryService variables.VariableSnapshotHistoryService
 }
 
 const (
@@ -204,41 +209,42 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi
 	CiTemplateRepository pipelineConfig.CiTemplateRepository,
 	ciWorkflowRepository pipelineConfig.CiWorkflowRepository,
 	appLabelRepository pipelineConfig.AppLabelRepository, gitSensorGrpcClient gitSensorClient.Client,
-	pipelineStageRepository repository4.PipelineStageRepository,
-	pipelineStageService PipelineStageService, k8sCommonService k8s.K8sCommonService) *WorkflowDagExecutorImpl {
+	pipelineStageService PipelineStageService, k8sCommonService k8s.K8sCommonService,
+	variableSnapshotHistoryService variables.VariableSnapshotHistoryService,
+) *WorkflowDagExecutorImpl {
 	wde := &WorkflowDagExecutorImpl{logger: Logger,
-		pipelineRepository:            pipelineRepository,
-		cdWorkflowRepository:          cdWorkflowRepository,
-		pubsubClient:                  pubsubClient,
-		appService:                    appService,
-		cdWorkflowService:             cdWorkflowService,
-		ciPipelineRepository:          ciPipelineRepository,
-		ciArtifactRepository:          ciArtifactRepository,
-		materialRepository:            materialRepository,
-		pipelineOverrideRepository:    pipelineOverrideRepository,
-		user:                          user,
-		enforcer:                      enforcer,
-		enforcerUtil:                  enforcerUtil,
-		groupRepository:               groupRepository,
-		tokenCache:                    tokenCache,
-		acdAuthConfig:                 acdAuthConfig,
-		envRepository:                 envRepository,
-		eventFactory:                  eventFactory,
-		eventClient:                   eventClient,
-		cvePolicyRepository:           cvePolicyRepository,
-		scanResultRepository:          scanResultRepository,
-		appWorkflowRepository:         appWorkflowRepository,
-		prePostCdScriptHistoryService: prePostCdScriptHistoryService,
-		argoUserService:               argoUserService,
-		cdPipelineStatusTimelineRepo:  cdPipelineStatusTimelineRepo,
-		pipelineStatusTimelineService: pipelineStatusTimelineService,
-		CiTemplateRepository:          CiTemplateRepository,
-		ciWorkflowRepository:          ciWorkflowRepository,
-		appLabelRepository:            appLabelRepository,
-		gitSensorGrpcClient:           gitSensorGrpcClient,
-		k8sCommonService:              k8sCommonService,
-		pipelineStageRepository:       pipelineStageRepository,
-		pipelineStageService:          pipelineStageService,
+		pipelineRepository:             pipelineRepository,
+		cdWorkflowRepository:           cdWorkflowRepository,
+		pubsubClient:                   pubsubClient,
+		appService:                     appService,
+		cdWorkflowService:              cdWorkflowService,
+		ciPipelineRepository:           ciPipelineRepository,
+		ciArtifactRepository:           ciArtifactRepository,
+		materialRepository:             materialRepository,
+		pipelineOverrideRepository:     pipelineOverrideRepository,
+		user:                           user,
+		enforcer:                       enforcer,
+		enforcerUtil:                   enforcerUtil,
+		groupRepository:                groupRepository,
+		tokenCache:                     tokenCache,
+		acdAuthConfig:                  acdAuthConfig,
+		envRepository:                  envRepository,
+		eventFactory:                   eventFactory,
+		eventClient:                    eventClient,
+		cvePolicyRepository:            cvePolicyRepository,
+		scanResultRepository:           scanResultRepository,
+		appWorkflowRepository:          appWorkflowRepository,
+		prePostCdScriptHistoryService:  prePostCdScriptHistoryService,
+		argoUserService:                argoUserService,
+		cdPipelineStatusTimelineRepo:   cdPipelineStatusTimelineRepo,
+		pipelineStatusTimelineService:  pipelineStatusTimelineService,
+		CiTemplateRepository:           CiTemplateRepository,
+		ciWorkflowRepository:           ciWorkflowRepository,
+		appLabelRepository:             appLabelRepository,
+		gitSensorGrpcClient:            gitSensorGrpcClient,
+		k8sCommonService:               k8sCommonService,
+		pipelineStageService:           pipelineStageService,
+		variableSnapshotHistoryService: variableSnapshotHistoryService,
 	}
 	config, err := GetCdConfig()
 	if err != nil {
@@ -382,10 +388,9 @@ func (impl *WorkflowDagExecutorImpl) deleteCorruptedPipelineStage(pipelineStage
 }
 
 func (impl *WorkflowDagExecutorImpl) triggerStage(cdWf *pipelineConfig.CdWorkflow, pipeline *pipelineConfig.Pipeline, artifact *repository.CiArtifact, applyAuth bool, triggeredBy int32) error {
-	var err error
-	preStage, err := impl.pipelineStageRepository.GetCdStageByCdPipelineIdAndStageType(pipeline.Id, repository4.PIPELINE_STAGE_TYPE_PRE_CD)
-	if err != nil && err != pg.ErrNoRows {
-		impl.logger.Errorw("error in fetching preStageStepType in GetCdStageByCdPipelineIdAndStageType ", "cdPipelineId", pipeline.Id, "err", err)
+
+	preStage, err := impl.getPipelineStage(pipeline.Id, repository4.PIPELINE_STAGE_TYPE_PRE_CD)
+	if err != nil {
 		return err
 	}
 
@@ -412,11 +417,19 @@ func (impl *WorkflowDagExecutorImpl) triggerStage(cdWf *pipelineConfig.CdWorkflo
 	return nil
 }
 
-func (impl *WorkflowDagExecutorImpl) triggerStageForBulk(cdWf *pipelineConfig.CdWorkflow, pipeline *pipelineConfig.Pipeline, artifact *repository.CiArtifact, applyAuth bool, async bool, triggeredBy int32) error {
-	var err error
-	preStage, err := impl.pipelineStageRepository.GetCdStageByCdPipelineIdAndStageType(pipeline.Id, repository4.PIPELINE_STAGE_TYPE_PRE_CD)
+func (impl *WorkflowDagExecutorImpl) getPipelineStage(pipelineId int, stageType repository4.PipelineStageType) (*repository4.PipelineStage, error) {
+	stage, err := impl.pipelineStageService.GetCdStageByCdPipelineIdAndStageType(pipelineId, stageType)
 	if err != nil && err != pg.ErrNoRows {
-		impl.logger.Errorw("error in fetching preStageStepType in GetCdStageByCdPipelineIdAndStageType ", "cdPipelineId", pipeline.Id, "err", err)
+		impl.logger.Errorw("error in fetching CD pipeline stage", "cdPipelineId", pipelineId, "stage ", stage, "err", err)
+		return nil, err
+	}
+	return stage, nil
+}
+
+func (impl *WorkflowDagExecutorImpl) triggerStageForBulk(cdWf *pipelineConfig.CdWorkflow, pipeline *pipelineConfig.Pipeline, artifact *repository.CiArtifact, applyAuth bool, async bool, triggeredBy int32) error {
+
+	preStage, err := impl.getPipelineStage(pipeline.Id, repository4.PIPELINE_STAGE_TYPE_PRE_CD)
+	if err != nil {
 		return err
 	}
 
@@ -537,6 +550,27 @@ func (impl *WorkflowDagExecutorImpl) TriggerPreStage(ctx context.Context, cdWf *
 		return err
 	}
 
+	//checking vulnerability for the selected image
+	isVulnerable, err := impl.GetArtifactVulnerabilityStatus(artifact, pipeline, ctx)
+	if err != nil {
+		impl.logger.Errorw("error in getting Artifact vulnerability status, TriggerPreStage", "err", err)
+		return err
+	}
+	if isVulnerable {
+		// if image vulnerable, update timeline status and return
+		runner.Status = pipelineConfig.WorkflowFailed
+		runner.Message = "Found vulnerability on image"
+		runner.FinishedOn = time.Now()
+		runner.UpdatedOn = time.Now()
+		runner.UpdatedBy = triggeredBy
+		err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner)
+		if err != nil {
+			impl.logger.Errorw("error in updating wfr status due to vulnerable image", "err", err)
+			return err
+		}
+		return fmt.Errorf("found vulnerability for image digest %s", artifact.ImageDigest)
+	}
+
 	_, span = otel.Tracer("orchestrator").Start(ctx, "buildWFRequest")
 	cdStageWorkflowRequest, err := impl.buildWFRequest(runner, cdWf, pipeline, triggeredBy)
 	span.End()
@@ -625,6 +659,35 @@ func (impl *WorkflowDagExecutorImpl) TriggerPostStage(cdWf *pipelineConfig.CdWor
 	if err != nil {
 		return err
 	}
+
+	if cdWf.CiArtifact == nil || cdWf.CiArtifact.Id == 0 {
+		cdWf.CiArtifact, err = impl.ciArtifactRepository.Get(cdWf.CiArtifactId)
+		if err != nil {
+			impl.logger.Errorw("error fetching artifact data", "err", err)
+			return err
+		}
+	}
+	//checking vulnerability for the selected image
+	isVulnerable, err := impl.GetArtifactVulnerabilityStatus(cdWf.CiArtifact, pipeline, context.Background())
+	if err != nil {
+		impl.logger.Errorw("error in getting Artifact vulnerability status, TriggerPostStage", "err", err)
+		return err
+	}
+	if isVulnerable {
+		// if image vulnerable, update timeline status and return
+		runner.Status = pipelineConfig.WorkflowFailed
+		runner.Message = "Found vulnerability on image"
+		runner.FinishedOn = time.Now()
+		runner.UpdatedOn = time.Now()
+		runner.UpdatedBy = triggeredBy
+		err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner)
+		if err != nil {
+			impl.logger.Errorw("error in updating wfr status due to vulnerable image", "err", err)
+			return err
+		}
+		return fmt.Errorf("found vulnerability for image digest %s", cdWf.CiArtifact.ImageDigest)
+	}
+
 	cdStageWorkflowRequest, err := impl.buildWFRequest(runner, cdWf, pipeline, triggeredBy)
 	if err != nil {
 		impl.logger.Errorw("error in building wfRequest", "err", err, "runner", runner, "cdWf", cdWf, "pipeline", pipeline)
@@ -823,24 +886,44 @@ func (impl *WorkflowDagExecutorImpl) buildWFRequest(runner *pipelineConfig.CdWor
 	var refPluginsData []*bean3.RefPluginObject
 	//if pipeline_stage_steps present for pre-CD or post-CD then no need to add stageYaml to cdWorkflowRequest in that
 	//case add PreDeploySteps and PostDeploySteps to cdWorkflowRequest, this is done for backward compatibility
-	pipelineStage, err := impl.pipelineStageRepository.GetAllCdStagesByCdPipelineId(cdPipeline.Id)
+	pipelineStage, err := impl.getPipelineStage(cdPipeline.Id, runner.WorkflowType.WorkflowTypeToStageType())
 	if err != nil {
-		impl.logger.Errorw("error in getting pipelineStages by cdPipelineId", "err", err, "cdPipelineId", cdPipeline.Id)
 		return nil, err
 	}
-	if len(pipelineStage) > 0 {
+	env, err := impl.envRepository.FindById(cdPipeline.EnvironmentId)
+	if err != nil {
+		impl.logger.Errorw("error in getting environment by id", "err", err)
+		return nil, err
+	}
+	if pipelineStage != nil {
+		//Scope will pick the environment of CD pipeline irrespective of in-cluster mode,
+		//since user sees the environment of the CD pipeline
+		scope := models2.Scope{
+			AppId:     cdPipeline.App.Id,
+			EnvId:     env.Id,
+			ClusterId: env.ClusterId,
+		}
+		var variableSnapshot map[string]string
 		if runner.WorkflowType == bean.CD_WORKFLOW_TYPE_PRE {
-			preDeploySteps, _, refPluginsData, err = impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(cdPipeline.Id, bean3.CdStage)
+			//preDeploySteps, _, refPluginsData, err = impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(cdPipeline.Id, cdStage)
+			prePostAndRefPluginResponse, err := impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(cdPipeline.Id, preCdStage, scope)
 			if err != nil {
 				impl.logger.Errorw("error in getting pre, post & refPlugin steps data for wf request", "err", err, "cdPipelineId", cdPipeline.Id)
 				return nil, err
 			}
+			preDeploySteps = prePostAndRefPluginResponse.PreStageSteps
+			refPluginsData = prePostAndRefPluginResponse.RefPluginData
+			variableSnapshot = prePostAndRefPluginResponse.VariableSnapshot
 		} else if runner.WorkflowType == bean.CD_WORKFLOW_TYPE_POST {
-			_, postDeploySteps, refPluginsData, err = impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(cdPipeline.Id, bean3.CdStage)
+			//_, postDeploySteps, refPluginsData, err = impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(cdPipeline.Id, cdStage)
+			prePostAndRefPluginResponse, err := impl.pipelineStageService.BuildPrePostAndRefPluginStepsDataForWfRequest(cdPipeline.Id, postCdStage, scope)
 			if err != nil {
 				impl.logger.Errorw("error in getting pre, post & refPlugin steps data for wf request", "err", err, "cdPipelineId", cdPipeline.Id)
 				return nil, err
 			}
+			postDeploySteps = prePostAndRefPluginResponse.PostStageSteps
+			refPluginsData = prePostAndRefPluginResponse.RefPluginData
+			variableSnapshot = prePostAndRefPluginResponse.VariableSnapshot
 			deployStageWfr, deployStageTriggeredByUser, pipelineReleaseCounter, err = impl.getDeployStageDetails(cdPipeline.Id)
 			if err != nil {
 				impl.logger.Errorw("error in getting deployStageWfr, deployStageTriggeredByUser and pipelineReleaseCounter wf request", "err", err, "cdPipelineId", cdPipeline.Id)
@@ -850,6 +933,20 @@ func (impl *WorkflowDagExecutorImpl) buildWFRequest(runner *pipelineConfig.CdWor
 			return nil, fmt.Errorf("unsupported workflow triggerd")
 		}
 
+		//Save Scoped VariableSnapshot
+		if len(variableSnapshot) > 0 {
+			variableMapBytes, _ := json.Marshal(variableSnapshot)
+			err := impl.variableSnapshotHistoryService.SaveVariableHistoriesForTrigger([]*repository5.VariableSnapshotHistoryBean{{
+				VariableSnapshot: variableMapBytes,
+				HistoryReference: repository5.HistoryReference{
+					HistoryReferenceId:   runner.Id,
+					HistoryReferenceType: repository5.HistoryReferenceTypeCDWORKFLOWRUNNER,
+				},
+			}}, runner.TriggeredBy)
+			if err != nil {
+				impl.logger.Errorf("Not able to save variable snapshot for CD trigger %s %d %s", err, runner.Id, variableSnapshot)
+			}
+		}
 	} else {
 		//in this case no plugin script is not present for this cdPipeline hence going with attaching preStage or postStage config
 		if runner.WorkflowType == bean.CD_WORKFLOW_TYPE_PRE {
@@ -898,11 +995,6 @@ func (impl *WorkflowDagExecutorImpl) buildWFRequest(runner *pipelineConfig.CdWor
 	}
 
 	extraEnvVariables := make(map[string]string)
-	env, err := impl.envRepository.FindById(cdPipeline.EnvironmentId)
-	if err != nil {
-		impl.logger.Errorw("error in getting environment by id", "err", err)
-		return nil, err
-	}
 	if env != nil {
 		extraEnvVariables[CD_PIPELINE_ENV_NAME_KEY] = env.Name
 		if env.Cluster != nil {
@@ -1156,9 +1248,8 @@ func (impl *WorkflowDagExecutorImpl) HandleDeploymentSuccessEvent(gitHash string
 		return err
 	}
 
-	postStage, err := impl.pipelineStageRepository.GetCdStageByCdPipelineIdAndStageType(pipelineOverride.Pipeline.Id, repository4.PIPELINE_STAGE_TYPE_POST_CD)
-	if err != nil && err != pg.ErrNoRows {
-		impl.logger.Errorw("error in fetching preStageStepType in GetCdStageByCdPipelineIdAndStageType ", "cdPipelineId", pipelineOverride.Pipeline, "err", err)
+	postStage, err := impl.getPipelineStage(pipelineOverride.PipelineId, repository4.PIPELINE_STAGE_TYPE_POST_CD)
+	if err != nil {
 		return err
 	}
 
@@ -1601,6 +1692,14 @@ func (impl *WorkflowDagExecutorImpl) GetArtifactVulnerabilityStatus(artifact *re
 			cveStores = append(cveStores, &item.CveStore)
 		}
 		_, span = otel.Tracer("orchestrator").Start(ctx, "cvePolicyRepository.GetBlockedCVEList")
+		if cdPipeline.Environment.ClusterId == 0 {
+			envDetails, err := impl.envRepository.FindById(cdPipeline.EnvironmentId)
+			if err != nil {
+				impl.logger.Errorw("error fetching cluster details by env, GetArtifactVulnerabilityStatus", "envId", cdPipeline.EnvironmentId, "err", err)
+				return false, err
+			}
+			cdPipeline.Environment = *envDetails
+		}
 		blockCveList, err := impl.cvePolicyRepository.GetBlockedCVEList(cveStores, cdPipeline.Environment.ClusterId, cdPipeline.EnvironmentId, cdPipeline.AppId, false)
 		span.End()
 		if err != nil {
@@ -1710,10 +1809,21 @@ func (impl *WorkflowDagExecutorImpl) ManualCdTrigger(overrideRequest *bean.Value
 		}
 		isVulnerable, err := impl.GetArtifactVulnerabilityStatus(artifact, cdPipeline, ctx)
 		if err != nil {
+			impl.logger.Errorw("error in getting Artifact vulnerability status, ManualCdTrigger", "err", err)
 			return 0, err
 		}
 		if isVulnerable == true {
 			// if image vulnerable, update timeline status and return
+			runner.Status = pipelineConfig.WorkflowFailed
+			runner.Message = "Found vulnerability on image"
+			runner.FinishedOn = time.Now()
+			runner.UpdatedOn = time.Now()
+			runner.UpdatedBy = overrideRequest.UserId
+			err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner)
+			if err != nil {
+				impl.logger.Errorw("error in updating wfr status due to vulnerable image", "err", err)
+				return 0, err
+			}
 			runner.CdWorkflow = &pipelineConfig.CdWorkflow{
 				Pipeline: cdPipeline,
 			}
@@ -1734,6 +1844,12 @@ func (impl *WorkflowDagExecutorImpl) ManualCdTrigger(overrideRequest *bean.Value
 			if err != nil {
 				impl.logger.Errorw("error in creating timeline status for deployment fail - cve policy violation", "err", err, "timeline", timeline)
 			}
+			_, span = otel.Tracer("orchestrator").Start(ctx, "updatePreviousDeploymentStatus")
+			err1 := impl.updatePreviousDeploymentStatus(runner, cdPipeline.Id, err, triggeredAt, overrideRequest.UserId)
+			span.End()
+			if err1 != nil {
+				impl.logger.Errorw("error while update previous cd workflow runners", "err", err, "runner", runner, "pipelineId", cdPipeline.Id)
+			}
 			return 0, fmt.Errorf("found vulnerability for image digest %s", artifact.ImageDigest)
 		}
 		_, span = otel.Tracer("orchestrator").Start(ctx, "appService.TriggerRelease")
@@ -1798,6 +1914,10 @@ func (impl *WorkflowDagExecutorImpl) ManualCdTrigger(overrideRequest *bean.Value
 		_, span = otel.Tracer("orchestrator").Start(ctx, "TriggerPostStage")
 		err = impl.TriggerPostStage(cdWf, cdPipeline, overrideRequest.UserId)
 		span.End()
+		if err != nil {
+			impl.logger.Errorw("err", "err", err)
+			return 0, err
+		}
 	}
 	return releaseId, err
 }
diff --git a/pkg/pipeline/WorkflowService.go b/pkg/pipeline/WorkflowService.go
index 9e23516df..0039355bd 100644
--- a/pkg/pipeline/WorkflowService.go
+++ b/pkg/pipeline/WorkflowService.go
@@ -97,6 +97,8 @@ const (
 	CI_NODE_PVC_PIPELINE_PREFIX    = "devtron.ai/ci-pvc"
 	PRE                            = "PRE"
 	POST                           = "POST"
+ preCdStage = "preCD"
+ postCdStage = "postCD"
 )
 
 func (impl *WorkflowServiceImpl) SubmitWorkflow(workflowRequest *WorkflowRequest) (*unstructured.UnstructuredList, error) {
diff --git a/pkg/pipeline/WorkflowUtils.go b/pkg/pipeline/WorkflowUtils.go
index 1e0573c5c..78f932832 100644
--- a/pkg/pipeline/WorkflowUtils.go
+++ b/pkg/pipeline/WorkflowUtils.go
@@ -673,8 +673,8 @@ func (workflowRequest *WorkflowRequest) GetLimitReqCpuMem(config *CiCdConfig) v1
 			v12.ResourceMemory: resource.MustParse(limitReqCpuMem.LimitMem),
 		},
 		Requests: v12.ResourceList{
-			v12.ResourceCPU:    resource.MustParse(limitReqCpuMem.LimitCpu),
-			v12.ResourceMemory: resource.MustParse(limitReqCpuMem.LimitMem),
+			v12.ResourceCPU:    resource.MustParse(limitReqCpuMem.ReqCpu),
+			v12.ResourceMemory: resource.MustParse(limitReqCpuMem.ReqMem),
 		},
 	}
 }
diff --git a/pkg/pipeline/bean/workFlowRequestBean.go b/pkg/pipeline/bean/workFlowRequestBean.go
index aa8cb03af..c7ae2c3ae 100644
--- a/pkg/pipeline/bean/workFlowRequestBean.go
+++ b/pkg/pipeline/bean/workFlowRequestBean.go
@@ -28,6 +28,13 @@ type RefPluginObject struct {
 	Steps []*StepObject `json:"steps"`
 }
 
+type PrePostAndRefPluginStepsResponse struct {
+	PreStageSteps    []*StepObject
+	PostStageSteps   []*StepObject
+	RefPluginData    []*RefPluginObject
+	VariableSnapshot map[string]string
+}
+
 type StepObject struct {
 	Name                     string             `json:"name"`
 	Index                    int                `json:"index"`
diff --git a/pkg/security/ImageScanService.go b/pkg/security/ImageScanService.go
index a2d3203b0..f8120e592 100644
--- a/pkg/security/ImageScanService.go
+++ b/pkg/security/ImageScanService.go
@@ -455,6 +455,10 @@ func (impl ImageScanServiceImpl) FetchExecutionDetailResult(request *ImageScanRe
 				updatedVulnerabilities = make([]*Vulnerabilities, 0)
 			}
 			imageScanResponse.Vulnerabilities = updatedVulnerabilities
+		} else {
+			for _, vulnerability := range imageScanResponse.Vulnerabilities {
+				vulnerability.Permission = "WHITELISTED"
+			}
 		}
 	}
 	return imageScanResponse, nil
diff --git a/pkg/variables/VariableEntityMappingService.go b/pkg/variables/VariableEntityMappingService.go
index 208624830..0aafc7456 100644
--- a/pkg/variables/VariableEntityMappingService.go
+++ b/pkg/variables/VariableEntityMappingService.go
@@ -5,14 +5,15 @@ import (
 	"github.com/devtron-labs/devtron/pkg/sql"
 	"github.com/devtron-labs/devtron/pkg/variables/repository"
 	"github.com/devtron-labs/devtron/pkg/variables/utils"
+	"github.com/go-pg/pg"
 	"go.uber.org/zap"
 	"time"
 )
 
 type VariableEntityMappingService interface {
-	UpdateVariablesForEntity(variableNames []string, entity repository.Entity, userId int32) error
+	UpdateVariablesForEntity(variableNames []string, entity repository.Entity, userId int32, tx *pg.Tx) error
 	GetAllMappingsForEntities(entities []repository.Entity) (map[repository.Entity][]string, error)
-	DeleteMappingsForEntities(entities []repository.Entity, userId int32) error
+	DeleteMappingsForEntities(entities []repository.Entity, userId int32, tx *pg.Tx) error
 }
 
 type VariableEntityMappingServiceImpl struct {
@@ -27,7 +28,7 @@ func NewVariableEntityMappingServiceImpl(variableEntityMappingRepository reposit
 	}
 }
 
-func (impl VariableEntityMappingServiceImpl) UpdateVariablesForEntity(variableNames []string, entity repository.Entity, userId int32) error {
+func (impl VariableEntityMappingServiceImpl) UpdateVariablesForEntity(variableNames []string, entity repository.Entity, userId int32, passedTx *pg.Tx) error {
 
 	variableMappings, err := impl.variableEntityMappingRepository.GetVariablesForEntities([]repository.Entity{entity})
 
@@ -58,17 +59,23 @@ func (impl VariableEntityMappingServiceImpl) UpdateVariablesForEntity(variableNa
 		})
 	}
 
-	tx, err := impl.variableEntityMappingRepository.StartTx()
-	defer func() {
-		err = impl.variableEntityMappingRepository.RollbackTx(tx)
-		if err != nil {
-			impl.logger.Infow("error in rolling back transaction", "err", err)
-		}
-	}()
+	var tx *pg.Tx
+	if passedTx == nil {
+		tx, err = impl.variableEntityMappingRepository.StartTx()
+		defer func() {
+			err = impl.variableEntityMappingRepository.RollbackTx(tx)
+			if err != nil {
+				impl.logger.Infow("error in rolling back transaction", "err", err)
+			}
+		}()
+	} else {
+		tx = passedTx
+	}
 
 	if len(variablesToDelete) > 0 {
 		err = impl.variableEntityMappingRepository.DeleteVariablesForEntity(tx, utils.ToStringArray(variablesToDelete), entity, userId)
 		if err != nil {
+			impl.logger.Errorw("error in deleting variables for entity", "err", err)
 			return err
 		}
 	}
@@ -76,23 +83,34 @@ func (impl VariableEntityMappingServiceImpl) UpdateVariablesForEntity(variableNa
 	if len(newVariableMappings) > 0 {
 		err = impl.variableEntityMappingRepository.SaveVariableEntityMappings(tx, newVariableMappings)
 		if err != nil {
+			impl.logger.Errorw("error in saving variables for entity", "err", err)
 			return err
 		}
 	}
 
-	err = impl.variableEntityMappingRepository.CommitTx(tx)
-	if err != nil {
-		return err
+	if passedTx == nil {
+		err = impl.variableEntityMappingRepository.CommitTx(tx)
+		if err != nil {
+			impl.logger.Errorw("error in committing transaction for UpdateVariablesForEntity", "err", err)
+			return err
+		}
 	}
 	return nil
 }
 
 func (impl VariableEntityMappingServiceImpl) GetAllMappingsForEntities(entities []repository.Entity) (map[repository.Entity][]string, error) {
+
+	entityIdToVariableNames := make(map[repository.Entity][]string)
+	if len(entities) == 0 {
+		return entityIdToVariableNames, nil
+	}
+
 	variableEntityMappings, err := impl.variableEntityMappingRepository.GetVariablesForEntities(entities)
 	if err != nil {
+		impl.logger.Errorw("error in fetching mappings for entities", "err", err)
 		return nil, err
 	}
-	entityIdToVariableNames := make(map[repository.Entity][]string)
+
 	for _, mapping := range variableEntityMappings {
 		vars := entityIdToVariableNames[mapping.Entity]
 		vars = append(vars, mapping.VariableName)
@@ -101,9 +119,10 @@ func (impl VariableEntityMappingServiceImpl) GetAllMappingsForEntities(entities
 	return entityIdToVariableNames, nil
 }
 
-func (impl VariableEntityMappingServiceImpl) DeleteMappingsForEntities(entities []repository.Entity, userId int32) error {
-	err := impl.variableEntityMappingRepository.DeleteAllVariablesForEntities(entities, userId)
+func (impl VariableEntityMappingServiceImpl) DeleteMappingsForEntities(entities []repository.Entity, userId int32, tx *pg.Tx) error {
+	err := impl.variableEntityMappingRepository.DeleteAllVariablesForEntities(tx, entities, userId)
 	if err != nil {
+		impl.logger.Errorw("error in deleting mappings for entities", "err", err)
 		return err
 	}
 	return nil
diff --git a/pkg/variables/repository/ScopedVariableRepository.go b/pkg/variables/repository/ScopedVariableRepository.go
index 37c2adb7c..a8d553093 100644
--- a/pkg/variables/repository/ScopedVariableRepository.go
+++ b/pkg/variables/repository/ScopedVariableRepository.go
@@ -77,7 +77,7 @@ func (impl *ScopedVariableRepositoryImpl) GetAllVariableMetadata() ([]*VariableD
 	variableDefinition := make([]*VariableDefinition, 0)
 	err := impl.
 		dbConnection.Model(&variableDefinition).
-		Column("id", "name", "data_type", "var_type,short_description").
+		Column("id", "name", "data_type", "var_type", "short_description").
 		Where("active = ?", true).
 		Select()
 	if err == pg.ErrNoRows {
diff --git a/pkg/variables/repository/VariableEntityDTO.go b/pkg/variables/repository/VariableEntityDTO.go
index a0b4fd26e..9ba46c063 100644
--- a/pkg/variables/repository/VariableEntityDTO.go
+++ b/pkg/variables/repository/VariableEntityDTO.go
@@ -21,4 +21,5 @@ type EntityType int
 const (
 	EntityTypeDeploymentTemplateAppLevel EntityType = 1
 	EntityTypeDeploymentTemplateEnvLevel EntityType = 2
+	EntityTypePipelineStage              EntityType = 3
 )
diff --git a/pkg/variables/repository/VariableEntityMappingRepository.go b/pkg/variables/repository/VariableEntityMappingRepository.go
index 3647c0c5c..eeda18d3f 100644
--- a/pkg/variables/repository/VariableEntityMappingRepository.go
+++ b/pkg/variables/repository/VariableEntityMappingRepository.go
@@ -12,7 +12,7 @@ type VariableEntityMappingRepository interface {
 	sql.TransactionWrapper
 	GetVariablesForEntities(entities []Entity) ([]*VariableEntityMapping, error)
 	SaveVariableEntityMappings(tx *pg.Tx, mappings []*VariableEntityMapping) error
-	DeleteAllVariablesForEntities(entities []Entity, userId int32) error
+	DeleteAllVariablesForEntities(tx *pg.Tx, entities []Entity, userId int32) error
 	DeleteVariablesForEntity(tx *pg.Tx, variableIDs []string, entity Entity, userId int32) error
 }
 
@@ -74,8 +74,15 @@ func (impl *VariableEntityMappingRepositoryImpl) DeleteVariablesForEntity(tx *pg
 	return nil
 }
 
-func (impl *VariableEntityMappingRepositoryImpl) DeleteAllVariablesForEntities(entities []Entity, userId int32) error {
-	_, err := impl.dbConnection.Model((*VariableEntityMapping)(nil)).
+func (impl *VariableEntityMappingRepositoryImpl) DeleteAllVariablesForEntities(tx *pg.Tx, entities []Entity, userId int32) error {
+
+	var connection orm.DB
+	connection = tx
+	if tx == nil {
+		connection = impl.dbConnection
+	}
+
+	_, err := connection.Model((*VariableEntityMapping)(nil)).
 		Set("is_deleted = ?", true).
 		Set("updated_by = ?", userId).
 		Set("updated_on = ?", time.Now()).
diff --git a/pkg/variables/repository/VariableSnapshotHistoryDTO.go b/pkg/variables/repository/VariableSnapshotHistoryDTO.go
index 7bc86831a..84c8d7193 100644
--- a/pkg/variables/repository/VariableSnapshotHistoryDTO.go
+++ b/pkg/variables/repository/VariableSnapshotHistoryDTO.go
@@ -26,4 +26,6 @@ type HistoryReferenceType int
 
 const (
 	HistoryReferenceTypeDeploymentTemplate HistoryReferenceType = 1
+	HistoryReferenceTypeCIWORKFLOW         HistoryReferenceType = 2
+	HistoryReferenceTypeCDWORKFLOWRUNNER   HistoryReferenceType = 3
 )
diff --git a/wire_gen.go b/wire_gen.go
index b4153ebe7..85ab2af75 100644
--- a/wire_gen.go
+++ b/wire_gen.go
@@ -423,8 +423,8 @@ func InitializeApp() (*App, error) {
 	}
 	pipelineStageRepositoryImpl := repository10.NewPipelineStageRepository(sugaredLogger, db)
 	globalPluginRepositoryImpl := repository11.NewGlobalPluginRepository(sugaredLogger, db)
-	pipelineStageServiceImpl := pipeline.NewPipelineStageService(sugaredLogger, pipelineStageRepositoryImpl, globalPluginRepositoryImpl, pipelineRepositoryImpl)
-	workflowDagExecutorImpl := pipeline.NewWorkflowDagExecutorImpl(sugaredLogger, pipelineRepositoryImpl, cdWorkflowRepositoryImpl, pubSubClientServiceImpl, appServiceImpl, workflowServiceImpl, ciArtifactRepositoryImpl, ciPipelineRepositoryImpl, materialRepositoryImpl, pipelineOverrideRepositoryImpl, userServiceImpl, deploymentGroupRepositoryImpl, environmentRepositoryImpl, enforcerImpl, enforcerUtilImpl, tokenCache, acdAuthConfig, eventSimpleFactoryImpl, eventRESTClientImpl, cvePolicyRepositoryImpl, imageScanResultRepositoryImpl, appWorkflowRepositoryImpl, prePostCdScriptHistoryServiceImpl, argoUserServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineServiceImpl, ciTemplateRepositoryImpl, ciWorkflowRepositoryImpl, appLabelRepositoryImpl, clientImpl, pipelineStageRepositoryImpl, pipelineStageServiceImpl, k8sCommonServiceImpl)
+	pipelineStageServiceImpl := pipeline.NewPipelineStageService(sugaredLogger, pipelineStageRepositoryImpl, globalPluginRepositoryImpl, pipelineRepositoryImpl, scopedVariableServiceImpl, variableEntityMappingServiceImpl, variableTemplateParserImpl)
+	workflowDagExecutorImpl := pipeline.NewWorkflowDagExecutorImpl(sugaredLogger, pipelineRepositoryImpl, cdWorkflowRepositoryImpl, pubSubClientServiceImpl, appServiceImpl, workflowServiceImpl, ciArtifactRepositoryImpl, ciPipelineRepositoryImpl, materialRepositoryImpl, pipelineOverrideRepositoryImpl, userServiceImpl, deploymentGroupRepositoryImpl, environmentRepositoryImpl, enforcerImpl, enforcerUtilImpl, tokenCache, acdAuthConfig, eventSimpleFactoryImpl, eventRESTClientImpl, cvePolicyRepositoryImpl, imageScanResultRepositoryImpl, appWorkflowRepositoryImpl, prePostCdScriptHistoryServiceImpl, argoUserServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineServiceImpl, ciTemplateRepositoryImpl, ciWorkflowRepositoryImpl, appLabelRepositoryImpl, clientImpl, pipelineStageServiceImpl, k8sCommonServiceImpl, variableSnapshotHistoryServiceImpl)
 	deploymentGroupAppRepositoryImpl := repository.NewDeploymentGroupAppRepositoryImpl(sugaredLogger, db)
 	deploymentGroupServiceImpl := deploymentGroup.NewDeploymentGroupServiceImpl(appRepositoryImpl, sugaredLogger, pipelineRepositoryImpl, ciPipelineRepositoryImpl, deploymentGroupRepositoryImpl, environmentRepositoryImpl, deploymentGroupAppRepositoryImpl, ciArtifactRepositoryImpl, appWorkflowRepositoryImpl, workflowDagExecutorImpl)
 	deploymentConfigServiceImpl := pipeline.NewDeploymentConfigServiceImpl(sugaredLogger, envConfigOverrideRepositoryImpl, chartRepositoryImpl, pipelineRepositoryImpl, envLevelAppMetricsRepositoryImpl, appLevelMetricsRepositoryImpl, pipelineConfigRepositoryImpl, configMapRepositoryImpl, configMapHistoryServiceImpl, chartRefRepositoryImpl, variableEntityMappingServiceImpl, scopedVariableServiceImpl)
@@ -464,7 +464,7 @@ func InitializeApp() (*App, error) {
 	imageTaggingServiceImpl := pipeline.NewImageTaggingServiceImpl(imageTaggingRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, sugaredLogger)
 	pipelineBuilderImpl := pipeline.NewPipelineBuilderImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, materialRepositoryImpl, appRepositoryImpl, pipelineRepositoryImpl, propertiesConfigServiceImpl, ciTemplateRepositoryImpl, ciPipelineRepositoryImpl, applicationServiceClientImpl, chartRepositoryImpl, ciArtifactRepositoryImpl, ecrConfig, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, clusterRepositoryImpl, pipelineConfigRepositoryImpl, utilMergeUtil, appWorkflowRepositoryImpl, ciCdConfig, cdWorkflowRepositoryImpl, appServiceImpl, imageScanResultRepositoryImpl, argoK8sClientImpl, gitFactory, attributesServiceImpl, acdAuthConfig, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, appLevelMetricsRepositoryImpl, pipelineStageServiceImpl, chartRefRepositoryImpl, chartTemplateServiceImpl, chartServiceImpl, helmAppServiceImpl, deploymentGroupRepositoryImpl, ciPipelineMaterialRepositoryImpl, userServiceImpl, ciTemplateServiceImpl, ciTemplateOverrideRepositoryImpl, gitMaterialHistoryServiceImpl, ciTemplateHistoryServiceImpl, ciPipelineHistoryServiceImpl, globalStrategyMetadataRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, pipelineDeploymentServiceTypeConfig, appStatusRepositoryImpl, workflowDagExecutorImpl, enforcerUtilImpl, argoUserServiceImpl, ciWorkflowRepositoryImpl, appGroupServiceImpl, chartDeploymentServiceImpl, k8sUtil, attributesRepositoryImpl, imageTaggingServiceImpl, variableEntityMappingServiceImpl, variableTemplateParserImpl)
 	dbMigrationServiceImpl := pipeline.NewDbMogrationService(sugaredLogger, dbMigrationConfigRepositoryImpl)
-	ciServiceImpl := pipeline.NewCiServiceImpl(sugaredLogger, workflowServiceImpl, ciPipelineMaterialRepositoryImpl, ciWorkflowRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, mergeUtil, ciPipelineRepositoryImpl, prePostCiScriptHistoryServiceImpl, pipelineStageServiceImpl, userServiceImpl, ciTemplateServiceImpl, appCrudOperationServiceImpl, environmentRepositoryImpl, appRepositoryImpl)
+	ciServiceImpl := pipeline.NewCiServiceImpl(sugaredLogger, workflowServiceImpl, ciPipelineMaterialRepositoryImpl, ciWorkflowRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, mergeUtil, ciPipelineRepositoryImpl, prePostCiScriptHistoryServiceImpl, pipelineStageServiceImpl, userServiceImpl, ciTemplateServiceImpl, appCrudOperationServiceImpl, environmentRepositoryImpl, appRepositoryImpl, variableSnapshotHistoryServiceImpl)
 	ciLogServiceImpl, err := pipeline.NewCiLogServiceImpl(sugaredLogger, ciServiceImpl, k8sUtil)
 	if err != nil {
 		return nil, err


Test patch:
diff --git a/pkg/pipeline/CiCdPipelineOrchestrator_test.go b/pkg/pipeline/CiCdPipelineOrchestrator_test.go
index fa7460aac..146f7a3c2 100644
--- a/pkg/pipeline/CiCdPipelineOrchestrator_test.go
+++ b/pkg/pipeline/CiCdPipelineOrchestrator_test.go
@@ -145,7 +145,7 @@ func InitClusterNoteService() {
 	userAuthService := user.NewUserAuthServiceImpl(nil, nil, nil, nil, nil, nil, nil)
 	prePostCdScriptHistoryService := history.NewPrePostCdScriptHistoryServiceImpl(logger, nil, nil, nil)
 	prePostCiScriptHistoryService := history.NewPrePostCiScriptHistoryServiceImpl(logger, nil)
-	pipelineStageService := NewPipelineStageService(logger, nil, nil, nil)
+	pipelineStageService := NewPipelineStageService(logger, nil, nil, nil, nil, nil, nil)
 	ciTemplateOverrideRepository := pipelineConfig.NewCiTemplateOverrideRepositoryImpl(conn, logger)
 	ciTemplateService := *NewCiTemplateServiceImpl(logger, nil, nil, nil)
 	gitMaterialHistoryService := history.NewGitMaterialHistoryServiceImpl(nil, logger)
diff --git a/pkg/pipeline/ConfigMapService_test.go b/pkg/pipeline/ConfigMapService_test.go
index 1043742d2..e46a22520 100644
--- a/pkg/pipeline/ConfigMapService_test.go
+++ b/pkg/pipeline/ConfigMapService_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/devtron-labs/devtron/pkg/cluster/repository"
 	mocks6 "github.com/devtron-labs/devtron/pkg/cluster/repository/mocks"
 	mocks3 "github.com/devtron-labs/devtron/pkg/commonService/mocks"
+	"github.com/devtron-labs/devtron/pkg/pipeline/bean"
 	mocks5 "github.com/devtron-labs/devtron/pkg/pipeline/history/mocks"
 	"github.com/go-pg/pg"
 	"github.com/stretchr/testify/assert"
@@ -45,7 +46,7 @@ func TestConfigMapServiceImpl_ConfigSecretEnvironmentCreate(t *testing.T) {
 		Deleted:       true,
 	}
 	type args struct {
-		createJobEnvOverrideRequest *CreateJobEnvOverridePayload
+		createJobEnvOverrideRequest *bean.CreateJobEnvOverridePayload
 		getByAppError               error
 		getByAppResponse            *chartConfig.ConfigMapEnvModel
 	}
@@ -58,7 +59,7 @@ func TestConfigMapServiceImpl_ConfigSecretEnvironmentCreate(t *testing.T) {
 		{
 			name: "create environment override",
 			args: args{
-				createJobEnvOverrideRequest: &CreateJobEnvOverridePayload{
+				createJobEnvOverrideRequest: &bean.CreateJobEnvOverridePayload{
 					AppId: 22,
 					EnvId: 5,
 				},
@@ -71,7 +72,7 @@ func TestConfigMapServiceImpl_ConfigSecretEnvironmentCreate(t *testing.T) {
 		{
 			name: "create deleted override",
 			args: args{
-				createJobEnvOverrideRequest: &CreateJobEnvOverridePayload{
+				createJobEnvOverrideRequest: &bean.CreateJobEnvOverridePayload{
 					AppId: 22,
 					EnvId: 5,
 				},
@@ -129,7 +130,7 @@ func TestConfigMapServiceImpl_ConfigSecretEnvironmentDelete(t *testing.T) {
 	envRepository := mocks6.NewEnvironmentRepository(t)
 
 	type args struct {
-		createJobEnvOverrideRequest *CreateJobEnvOverridePayload
+		createJobEnvOverrideRequest *bean.CreateJobEnvOverridePayload
 	}
 	configMap := &chartConfig.ConfigMapEnvModel{
 		AppId:         1,
@@ -144,7 +145,7 @@ func TestConfigMapServiceImpl_ConfigSecretEnvironmentDelete(t *testing.T) {
 		{
 			name: "Delete configMap",
 			args: args{
-				createJobEnvOverrideRequest: &CreateJobEnvOverridePayload{
+				createJobEnvOverrideRequest: &bean.CreateJobEnvOverridePayload{
 					AppId: 1,
 					EnvId: 1,
 				},
diff --git a/pkg/pipeline/GitopsOrHelmOption_test.go b/pkg/pipeline/GitopsOrHelmOption_test.go
index 1b3f34738..cccbd64e9 100644
--- a/pkg/pipeline/GitopsOrHelmOption_test.go
+++ b/pkg/pipeline/GitopsOrHelmOption_test.go
@@ -24,7 +24,7 @@ func TestGitopsOrHelmOption(t *testing.T) {
 			nil, nil, nil,
 			nil, nil, nil, nil,
 			nil, nil, nil, nil,
-			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
 
 		pipelineCreateRequest := &bean.CdPipelines{
 			Pipelines: []*bean.CDPipelineConfigObject{
@@ -79,7 +79,7 @@ func TestGitopsOrHelmOption(t *testing.T) {
 			nil, nil, nil,
 			nil, nil, nil, nil,
 			nil, nil, nil, nil,
-			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
 
 		pipelineCreateRequest := &bean.CdPipelines{
 			Pipelines: []*bean.CDPipelineConfigObject{
@@ -135,7 +135,7 @@ func TestGitopsOrHelmOption(t *testing.T) {
 			nil, nil, nil,
 			nil, nil, nil, nil,
 			nil, nil, nil, nil,
-			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
 
 		pipelineCreateRequest := &bean.CdPipelines{
 			Pipelines: []*bean.CDPipelineConfigObject{
@@ -190,7 +190,7 @@ func TestGitopsOrHelmOption(t *testing.T) {
 			nil, nil, nil,
 			nil, nil, nil, nil,
 			nil, nil, nil, nil,
-			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: true}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: true}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
 
 		pipelineCreateRequestHelm := &bean.CdPipelines{
 			Pipelines: []*bean.CDPipelineConfigObject{
@@ -284,7 +284,7 @@ func TestGitopsOrHelmOption(t *testing.T) {
 			nil, nil, nil,
 			nil, nil, nil, nil,
 			nil, nil, nil, nil,
-			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: false}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
 
 		pipelineCreateRequest := &bean.CdPipelines{
 			Pipelines: []*bean.CDPipelineConfigObject{
@@ -341,7 +341,7 @@ func TestGitopsOrHelmOption(t *testing.T) {
 			nil, nil, nil,
 			nil, nil, nil, nil,
 			nil, nil, nil, nil,
-			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: true}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+			nil, nil, nil, nil, nil, nil, nil, nil, &DeploymentServiceTypeConfig{IsInternalUse: true}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
 
 		pipelineCreateRequest := &bean.CdPipelines{
 			Pipelines: []*bean.CDPipelineConfigObject{
diff --git a/pkg/pipeline/PipelineStageServiceIT_test.go b/pkg/pipeline/PipelineStageServiceIT_test.go
index f9be26ebc..f6e8d803c 100644
--- a/pkg/pipeline/PipelineStageServiceIT_test.go
+++ b/pkg/pipeline/PipelineStageServiceIT_test.go
@@ -12,6 +12,10 @@ import (
 	"github.com/devtron-labs/devtron/pkg/pipeline/repository"
 	repository2 "github.com/devtron-labs/devtron/pkg/plugin/repository"
 	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/devtron-labs/devtron/pkg/variables"
+	"github.com/devtron-labs/devtron/pkg/variables/models"
+	"github.com/devtron-labs/devtron/pkg/variables/parsers"
+	repository4 "github.com/devtron-labs/devtron/pkg/variables/repository"
 	"github.com/go-pg/pg"
 	"github.com/stretchr/testify/assert"
 	"go.uber.org/zap"
@@ -22,9 +26,10 @@ import (
 	"time"
 )
 
-const CiPipelineStageCreateReqJson = `{"appId":1,"appWorkflowId":0,"action":0,"ciPipelineRequest":{"active":true,"ciMaterial":[{"gitMaterialId":1,"id":0,"source":{"type":"SOURCE_TYPE_BRANCH_FIXED","value":"main","regex":""}}],"dockerArgs":{},"externalCiConfig":{},"id":0,"isExternal":false,"isManual":false,"name":"ci-1-xyze","linkedCount":0,"scanEnabled":false,"preBuildStage":{"id":0,"steps":[{"id":1,"index":1,"name":"Task 1","description":"chbsdkhbc","stepType":"INLINE","directoryPath":"","inlineStepDetail":{"scriptType":"CONTAINER_IMAGE","script":"echo \"ifudsbvnv\"","conditionDetails":[],"inputVariables":[{"id":1,"name":"Hello","value":"","format":"STRING","description":"jnsdvbdvbsd","defaultValue":"","variableType":"GLOBAL","refVariableStepIndex":0,"refVariableName":"WORKING_DIRECTORY","refVariableStage":""}],"outputVariables":null,"commandArgsMap":[{"command":"echo","args":["\"HOSTNAME\"","\"PORT\""]}],"portMap":[{"portOnLocal":8080,"portOnContainer":9090}],"mountCodeToContainer":true,"mountDirectoryFromHost":true,"mountCodeToContainerPath":"/sourcecode","mountPathMap":[{"filePathOnDisk":"./test","filePathOnContainer":"./test_container"}],"containerImagePath":"python:latest","isMountCustomScript":true,"storeScriptAt":"./directory/script"},"outputDirectoryPath":["./test1"]},{"id":2,"index":2,"name":"K6 Load testing","description":"K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.","stepType":"REF_PLUGIN","directoryPath":"","pluginRefStepDetail":{"id":0,"pluginId":1,"conditionDetails":[{"id":0,"conditionOnVariable":"RelativePathToScript","conditionOperator":"==","conditionType":"TRIGGER","conditionalValue":"svfsv"},{"id":0,"conditionOnVariable":"PrometheusApiKey","conditionOperator":"==","conditionType":"TRIGGER","conditionalValue":"dfbeavafsv"}],"inputVariables":[{"id":1,"name":"RelativePathToScript","format":"STRING","description":"checkout path + script path along with script name","isExposed":true,"allowEmptyValue":false,"defaultValue":"/./script.js","variableType":"NEW","variableStepIndexInPlugin":1,"value":"dethdt","refVariableName":"","refVariableStage":""},{"id":2,"name":"PrometheusUsername","format":"STRING","description":"username of prometheus account","isExposed":true,"allowEmptyValue":true,"defaultValue":"","variableType":"NEW","variableStepIndexInPlugin":1,"value":"ghmfnbd","refVariableName":"","refVariableStage":""},{"id":3,"name":"PrometheusApiKey","format":"STRING","description":"api key of prometheus account","isExposed":true,"allowEmptyValue":true,"defaultValue":"","variableType":"NEW","variableStepIndexInPlugin":1,"value":"afegs","refVariableName":"","refVariableStage":""},{"id":4,"name":"PrometheusRemoteWriteEndpoint","format":"STRING","description":"remote write endpoint of prometheus account","isExposed":true,"allowEmptyValue":true,"defaultValue":"","variableType":"NEW","variableStepIndexInPlugin":1,"value":"aef","refVariableName":"","refVariableStage":""},{"id":5,"name":"OutputType","format":"STRING","description":"output type - LOG or PROMETHEUS","isExposed":true,"allowEmptyValue":false,"defaultValue":"LOG","variableType":"NEW","variableStepIndexInPlugin":1,"value":"fdgn","refVariableName":"","refVariableStage":""}]}},{"id":3,"index":3,"name":"Task 3","description":"sfdbvf","stepType":"INLINE","directoryPath":"","inlineStepDetail":{"scriptType":"SHELL","script":"#!/bin/sh \nset -eo pipefail \n#set -v  ## uncomment this to debug the script \n","conditionDetails":[{"id":0,"conditionOnVariable":"Hello","conditionOperator":"==","conditionType":"PASS","conditionalValue":"aedfrwgwr"},{"id":0,"conditionOnVariable":"Hello","conditionOperator":"!=","conditionType":"PASS","conditionalValue":"tegegr"}],"inputVariables":[],"outputVariables":[{"id":1,"name":"Hello","value":"","format":"STRING","description":"dsuihvsuvhbdv","defaultValue":"","variableType":"NEW","refVariableStepIndex":0,"refVariableName":""}],"commandArgsMap":[{"command":"","args":[]}],"portMap":[],"mountCodeToContainer":false,"mountDirectoryFromHost":false},"outputDirectoryPath":["./test2"]}]},"postBuildStage":{},"dockerConfigOverride":{}}}`
-const CiPipelineStageUpdateReqJson = `{"appId":1,"appWorkflowId":3,"action":1,"ciPipelineRequest":{"isManual":false,"dockerArgs":{},"isExternal":false,"parentCiPipeline":0,"parentAppId":0,"appId":1,"externalCiConfig":{"id":0,"webhookUrl":"","payload":"","accessKey":"","payloadOption":null,"schema":null,"responses":null,"projectId":0,"projectName":"","environmentId":"","environmentName":"","environmentIdentifier":"","appId":0,"appName":"","role":""},"ciMaterial":[{"gitMaterialId":1,"id":3,"source":{"type":"SOURCE_TYPE_BRANCH_FIXED","value":"main","regex":""}}],"name":"ci-1-unov","id":3,"active":true,"linkedCount":0,"scanEnabled":false,"appWorkflowId":3,"preBuildStage":{"id":5,"type":"PRE_CI","steps":[{"id":9,"name":"K6 Load testing","description":"K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.","index":1,"stepType":"REF_PLUGIN","outputDirectoryPath":null,"inlineStepDetail":null,"pluginRefStepDetail":{"pluginId":1,"inputVariables":[{"id":44,"name":"RelativePathToScript","format":"STRING","description":"checkout path + script path along with script name","isExposed":true,"defaultValue":"/./script.js","value":"sfds","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":45,"name":"PrometheusUsername","format":"STRING","description":"username of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"sdf","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":46,"name":"PrometheusApiKey","format":"STRING","description":"api key of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"hter","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":47,"name":"PrometheusRemoteWriteEndpoint","format":"STRING","description":"remote write endpoint of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"ewq","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":48,"name":"OutputType","format":"STRING","description":"output type - LOG or PROMETHEUS","isExposed":true,"defaultValue":"LOG","value":"erg","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""}],"outputVariables":null,"conditionDetails":null},"triggerIfParentStageFail":false},{"id":10,"name":"Task 3","description":"","index":3,"stepType":"INLINE","outputDirectoryPath":["./asap"],"inlineStepDetail":{"scriptType":"CONTAINER_IMAGE","script":null,"storeScriptAt":null,"mountDirectoryFromHost":false,"containerImagePath":"alpine:latest","commandArgsMap":[{"command":"echo","args":["HOSTNAME"]}],"inputVariables":null,"outputVariables":null,"conditionDetails":null,"portMap":[],"mountCodeToContainerPath":null,"mountPathMap":null},"pluginRefStepDetail":null,"triggerIfParentStageFail":false},{"id":8,"name":"Task 1","description":"","index":2,"stepType":"INLINE","outputDirectoryPath":["./test"],"inlineStepDetail":{"scriptType":"SHELL","script":"#!/bin/sh \nset -eo pipefail \necho \"Hello from inside pre-build stage\"\n#set -v  ## uncomment this to debug the script \n","storeScriptAt":"","mountDirectoryFromHost":false,"commandArgsMap":[{"command":"","args":null}],"inputVariables":null,"outputVariables":null,"conditionDetails":null},"pluginRefStepDetail":null,"triggerIfParentStageFail":false}]},"postBuildStage":{},"isDockerConfigOverridden":false,"dockerConfigOverride":{}}}`
-const CiPipelineStageDeleteReqJson = `{"appId":1,"appWorkflowId":8,"action":2,"ciPipelineRequest":{"isManual":false,"dockerArgs":{},"isExternal":false,"parentCiPipeline":0,"parentAppId":0,"appId":1,"externalCiConfig":{"id":0,"webhookUrl":"","payload":"","accessKey":"","payloadOption":null,"schema":null,"responses":null,"projectId":0,"projectName":"","environmentId":"","environmentName":"","environmentIdentifier":"","appId":0,"appName":"","role":""},"ciMaterial":[{"gitMaterialId":1,"id":8,"source":{"type":"SOURCE_TYPE_BRANCH_FIXED","value":"main","regex":""}}],"name":"ci-1-unjn","id":8,"active":true,"linkedCount":0,"scanEnabled":false,"appWorkflowId":8,"preBuildStage":{"id":7,"type":"PRE_CI","steps":[{"id":11,"name":"Task 1","description":"","index":1,"stepType":"INLINE","outputDirectoryPath":["./test"],"inlineStepDetail":{"scriptType":"SHELL","script":"#!/bin/sh \nset -eo pipefail \necho \"Prakash\"\n#set -v  ## uncomment this to debug the script \n","storeScriptAt":"","mountDirectoryFromHost":false,"commandArgsMap":[{"command":"","args":null}],"inputVariables":null,"outputVariables":null,"conditionDetails":null},"pluginRefStepDetail":null,"triggerIfParentStageFail":false},{"id":12,"name":"K6 Load testing","description":"K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.","index":2,"stepType":"REF_PLUGIN","outputDirectoryPath":null,"inlineStepDetail":null,"pluginRefStepDetail":{"pluginId":1,"inputVariables":[{"id":49,"name":"RelativePathToScript","format":"STRING","description":"checkout path + script path along with script name","isExposed":true,"defaultValue":"/./script.js","value":"sfds","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":50,"name":"PrometheusUsername","format":"STRING","description":"username of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"sdf","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":51,"name":"PrometheusApiKey","format":"STRING","description":"api key of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"hter","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":52,"name":"PrometheusRemoteWriteEndpoint","format":"STRING","description":"remote write endpoint of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"ewq","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":53,"name":"OutputType","format":"STRING","description":"output type - LOG or PROMETHEUS","isExposed":true,"defaultValue":"LOG","value":"erg","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""}],"outputVariables":null,"conditionDetails":null},"triggerIfParentStageFail":false},{"id":13,"name":"Task 3","description":"","index":3,"stepType":"INLINE","outputDirectoryPath":["./asap"],"inlineStepDetail":{"scriptType":"CONTAINER_IMAGE","script":"","storeScriptAt":"","mountDirectoryFromHost":false,"containerImagePath":"alpine:latest","commandArgsMap":[{"command":"echo","args":["HOSTNAME"]}],"inputVariables":null,"outputVariables":null,"conditionDetails":null,"portMap":[]},"pluginRefStepDetail":null,"triggerIfParentStageFail":false}]},"isDockerConfigOverridden":false,"dockerConfigOverride":{},"postBuildStage":{}}}`
+const CiPipelineStageCreateReqJson = `{"appId":1,"appWorkflowId":0,"action":0,"ciPipeline":{"active":true,"ciMaterial":[{"gitMaterialId":1,"id":0,"source":{"type":"SOURCE_TYPE_BRANCH_FIXED","value":"main","regex":""}}],"dockerArgs":{},"externalCiConfig":{},"id":0,"isExternal":false,"isManual":false,"name":"ci-1-xyze","linkedCount":0,"scanEnabled":false,"preBuildStage":{"id":0,"steps":[{"id":1,"index":1,"name":"Task 1","description":"chbsdkhbc","stepType":"INLINE","directoryPath":"","inlineStepDetail":{"scriptType":"CONTAINER_IMAGE","script":"echo \"ifudsbvnv\"","conditionDetails":[],"inputVariables":[{"id":1,"name":"Hello","value":"","format":"STRING","description":"jnsdvbdvbsd","defaultValue":"","variableType":"GLOBAL","refVariableStepIndex":0,"refVariableName":"WORKING_DIRECTORY","refVariableStage":""}],"outputVariables":null,"commandArgsMap":[{"command":"echo","args":["\"HOSTNAME\"","\"PORT\""]}],"portMap":[{"portOnLocal":8080,"portOnContainer":9090}],"mountCodeToContainer":true,"mountDirectoryFromHost":true,"mountCodeToContainerPath":"/sourcecode","mountPathMap":[{"filePathOnDisk":"./test","filePathOnContainer":"./test_container"}],"containerImagePath":"python:latest","isMountCustomScript":true,"storeScriptAt":"./directory/script"},"outputDirectoryPath":["./test1"]},{"id":2,"index":2,"name":"K6 Load testing","description":"K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.","stepType":"REF_PLUGIN","directoryPath":"","pluginRefStepDetail":{"id":0,"pluginId":1,"conditionDetails":[{"id":0,"conditionOnVariable":"RelativePathToScript","conditionOperator":"==","conditionType":"TRIGGER","conditionalValue":"svfsv"},{"id":0,"conditionOnVariable":"PrometheusApiKey","conditionOperator":"==","conditionType":"TRIGGER","conditionalValue":"dfbeavafsv"}],"inputVariables":[{"id":1,"name":"RelativePathToScript","format":"STRING","description":"checkout path + script path along with script name","isExposed":true,"allowEmptyValue":false,"defaultValue":"/./script.js","variableType":"NEW","variableStepIndexInPlugin":1,"value":"dethdt","refVariableName":"","refVariableStage":""},{"id":2,"name":"PrometheusUsername","format":"STRING","description":"username of prometheus account","isExposed":true,"allowEmptyValue":true,"defaultValue":"","variableType":"NEW","variableStepIndexInPlugin":1,"value":"ghmfnbd","refVariableName":"","refVariableStage":""},{"id":3,"name":"PrometheusApiKey","format":"STRING","description":"api key of prometheus account","isExposed":true,"allowEmptyValue":true,"defaultValue":"","variableType":"NEW","variableStepIndexInPlugin":1,"value":"afegs","refVariableName":"","refVariableStage":""},{"id":4,"name":"PrometheusRemoteWriteEndpoint","format":"STRING","description":"remote write endpoint of prometheus account","isExposed":true,"allowEmptyValue":true,"defaultValue":"","variableType":"NEW","variableStepIndexInPlugin":1,"value":"aef","refVariableName":"","refVariableStage":""},{"id":5,"name":"OutputType","format":"STRING","description":"output type - LOG or PROMETHEUS","isExposed":true,"allowEmptyValue":false,"defaultValue":"LOG","variableType":"NEW","variableStepIndexInPlugin":1,"value":"fdgn","refVariableName":"","refVariableStage":""}]}},{"id":3,"index":3,"name":"Task 3","description":"sfdbvf","stepType":"INLINE","directoryPath":"","inlineStepDetail":{"scriptType":"SHELL","script":"#!/bin/sh \nset -eo pipefail \n#set -v  ## uncomment this to debug the script \n","conditionDetails":[{"id":0,"conditionOnVariable":"Hello","conditionOperator":"==","conditionType":"PASS","conditionalValue":"aedfrwgwr"},{"id":0,"conditionOnVariable":"Hello","conditionOperator":"!=","conditionType":"PASS","conditionalValue":"tegegr"}],"inputVariables":[],"outputVariables":[{"id":1,"name":"Hello","value":"","format":"STRING","description":"dsuihvsuvhbdv","defaultValue":"","variableType":"NEW","refVariableStepIndex":0,"refVariableName":""}],"commandArgsMap":[{"command":"","args":[]}],"portMap":[],"mountCodeToContainer":false,"mountDirectoryFromHost":false},"outputDirectoryPath":["./test2"]}]},"postBuildStage":{},"dockerConfigOverride":{}}}`
+const CiPipelineStageUpdateReqJson = `{"appId":1,"appWorkflowId":3,"action":1,"ciPipeline":{"isManual":false,"dockerArgs":{},"isExternal":false,"parentCiPipeline":0,"parentAppId":0,"appId":1,"externalCiConfig":{"id":0,"webhookUrl":"","payload":"","accessKey":"","payloadOption":null,"schema":null,"responses":null,"projectId":0,"projectName":"","environmentId":"","environmentName":"","environmentIdentifier":"","appId":0,"appName":"","role":""},"ciMaterial":[{"gitMaterialId":1,"id":3,"source":{"type":"SOURCE_TYPE_BRANCH_FIXED","value":"main","regex":""}}],"name":"ci-1-unov","id":3,"active":true,"linkedCount":0,"scanEnabled":false,"appWorkflowId":3,"preBuildStage":{"id":5,"type":"PRE_CI","steps":[{"id":9,"name":"K6 Load testing","description":"K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.","index":1,"stepType":"REF_PLUGIN","outputDirectoryPath":null,"inlineStepDetail":null,"pluginRefStepDetail":{"pluginId":1,"inputVariables":[{"id":44,"name":"RelativePathToScript","format":"STRING","description":"checkout path + script path along with script name","isExposed":true,"defaultValue":"/./script.js","value":"sfds","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":45,"name":"PrometheusUsername","format":"STRING","description":"username of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"sdf","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":46,"name":"PrometheusApiKey","format":"STRING","description":"api key of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"hter","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":47,"name":"PrometheusRemoteWriteEndpoint","format":"STRING","description":"remote write endpoint of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"ewq","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":48,"name":"OutputType","format":"STRING","description":"output type - LOG or PROMETHEUS","isExposed":true,"defaultValue":"LOG","value":"erg","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""}],"outputVariables":null,"conditionDetails":null},"triggerIfParentStageFail":false},{"id":10,"name":"Task 3","description":"","index":3,"stepType":"INLINE","outputDirectoryPath":["./asap"],"inlineStepDetail":{"scriptType":"CONTAINER_IMAGE","script":null,"storeScriptAt":null,"mountDirectoryFromHost":false,"containerImagePath":"alpine:latest","commandArgsMap":[{"command":"echo","args":["HOSTNAME"]}],"inputVariables":null,"outputVariables":null,"conditionDetails":null,"portMap":[],"mountCodeToContainerPath":null,"mountPathMap":null},"pluginRefStepDetail":null,"triggerIfParentStageFail":false},{"id":8,"name":"Task 1","description":"","index":2,"stepType":"INLINE","outputDirectoryPath":["./test"],"inlineStepDetail":{"scriptType":"SHELL","script":"#!/bin/sh \nset -eo pipefail \necho \"Hello from inside pre-build stage\"\n#set -v  ## uncomment this to debug the script \n","storeScriptAt":"","mountDirectoryFromHost":false,"commandArgsMap":[{"command":"","args":null}],"inputVariables":null,"outputVariables":null,"conditionDetails":null},"pluginRefStepDetail":null,"triggerIfParentStageFail":false}]},"postBuildStage":{},"isDockerConfigOverridden":false,"dockerConfigOverride":{}}}`
+const CiPipelineStageDeleteReqJson = `{"appId":1,"appWorkflowId":8,"action":2,"ciPipeline":{"isManual":false,"dockerArgs":{},"isExternal":false,"parentCiPipeline":0,"parentAppId":0,"appId":1,"externalCiConfig":{"id":0,"webhookUrl":"","payload":"","accessKey":"","payloadOption":null,"schema":null,"responses":null,"projectId":0,"projectName":"","environmentId":"","environmentName":"","environmentIdentifier":"","appId":0,"appName":"","role":""},"ciMaterial":[{"gitMaterialId":1,"id":8,"source":{"type":"SOURCE_TYPE_BRANCH_FIXED","value":"main","regex":""}}],"name":"ci-1-unjn","id":8,"active":true,"linkedCount":0,"scanEnabled":false,"appWorkflowId":8,"preBuildStage":{"id":7,"type":"PRE_CI","steps":[{"id":11,"name":"Task 1","description":"","index":1,"stepType":"INLINE","outputDirectoryPath":["./test"],"inlineStepDetail":{"scriptType":"SHELL","script":"#!/bin/sh \nset -eo pipefail \necho \"Prakash\"\n#set -v  ## uncomment this to debug the script \n","storeScriptAt":"","mountDirectoryFromHost":false,"commandArgsMap":[{"command":"","args":null}],"inputVariables":null,"outputVariables":null,"conditionDetails":null},"pluginRefStepDetail":null,"triggerIfParentStageFail":false},{"id":12,"name":"K6 Load testing","description":"K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.","index":2,"stepType":"REF_PLUGIN","outputDirectoryPath":null,"inlineStepDetail":null,"pluginRefStepDetail":{"pluginId":1,"inputVariables":[{"id":49,"name":"RelativePathToScript","format":"STRING","description":"checkout path + script path along with script name","isExposed":true,"defaultValue":"/./script.js","value":"sfds","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":50,"name":"PrometheusUsername","format":"STRING","description":"username of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"sdf","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":51,"name":"PrometheusApiKey","format":"STRING","description":"api key of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"hter","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":52,"name":"PrometheusRemoteWriteEndpoint","format":"STRING","description":"remote write endpoint of prometheus account","isExposed":true,"allowEmptyValue":true,"value":"ewq","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""},{"id":53,"name":"OutputType","format":"STRING","description":"output type - LOG or PROMETHEUS","isExposed":true,"defaultValue":"LOG","value":"erg","variableType":"NEW","variableStepIndexInPlugin":1,"refVariableStage":""}],"outputVariables":null,"conditionDetails":null},"triggerIfParentStageFail":false},{"id":13,"name":"Task 3","description":"","index":3,"stepType":"INLINE","outputDirectoryPath":["./asap"],"inlineStepDetail":{"scriptType":"CONTAINER_IMAGE","script":"","storeScriptAt":"","mountDirectoryFromHost":false,"containerImagePath":"alpine:latest","commandArgsMap":[{"command":"echo","args":["HOSTNAME"]}],"inputVariables":null,"outputVariables":null,"conditionDetails":null,"portMap":[]},"pluginRefStepDetail":null,"triggerIfParentStageFail":false}]},"isDockerConfigOverridden":false,"dockerConfigOverride":{},"postBuildStage":{}}}`
+const ScopedVariablePayload = `{"variables":[{"definition":{"varName":"KAFKA","dataType":"primitive","varType":"public","description":"Enter any notes for additional details","shortDescription":"Some description for variables"},"attributeValue":[{"variableValue":{"value":"Global"},"attributeType":"Global","attributeParams":null}]},{"definition":{"varName":"NewVariable","dataType":"primitive","varType":"private","description":"New Notes","shortDescription":"New Descriotion"},"attributeValue":[{"variableValue":{"value":"gg"},"attributeType":"Global","attributeParams":null}]},{"definition":{"varName":"test-var-1","dataType":"primitive","varType":"public","description":"","shortDescription":""},"attributeValue":[{"variableValue":{"value":"test1"},"attributeType":"Global","attributeParams":null}]},{"definition":{"varName":"test-var-2","dataType":"primitive","varType":"public","description":"","shortDescription":""},"attributeValue":[{"variableValue":{"value":"test2"},"attributeType":"Global","attributeParams":null}]}]}`
 
 var ciPipelineId int
 var cdPipelineId int
@@ -61,7 +66,7 @@ var pipelineStageReq = &bean.PipelineStageDto{
 					},
 				},
 				ScriptType: repository2.SCRIPT_TYPE_SHELL,
-				Script:     "#!/bin/sh \nset -eo pipefail \necho \"Prakash\"\n#set -v  ## uncomment this to debug the script \n",
+				Script:     "#!/bin/sh \nset -eo pipefail \necho \"@{{test-var}}\"\n#set -v  ## uncomment this to debug the script \n",
 			},
 		},
 		{
@@ -209,6 +214,367 @@ var pipelineStageReq = &bean.PipelineStageDto{
 	},
 	TriggerType: pipelineConfig.TRIGGER_TYPE_AUTOMATIC,
 }
+var pipelineStageReqUnresolved = &bean.PipelineStageDto{
+	Id:          0,
+	Name:        "",
+	Description: "",
+	Type:        repository.PIPELINE_STAGE_TYPE_PRE_CI,
+	Steps: []*bean.PipelineStageStepDto{
+		{
+			Id:                  1,
+			Name:                "Task-1",
+			Description:         "@{{test-var-1}}",
+			Index:               1,
+			StepType:            repository.PIPELINE_STEP_TYPE_INLINE,
+			OutputDirectoryPath: []string{"./@{{test-var-1}}"},
+			InlineStepDetail: &bean.InlineStepDetailDto{
+				OutputVariables: []*bean.StepVariableDto{
+					{
+						Id:                        1,
+						Name:                      "Hello",
+						Format:                    "STRING",
+						Description:               "dsuihvsuvhbdv",
+						IsExposed:                 false,
+						AllowEmptyValue:           false,
+						DefaultValue:              "",
+						Value:                     "",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 0,
+						ReferenceVariableStage:    "",
+					},
+				},
+				ScriptType: repository2.SCRIPT_TYPE_SHELL,
+				Script:     "#!/bin/sh \nset -eo pipefail \necho \"@{{test-var-1}}\"\n#set -v  ## uncomment this to debug the script \n",
+			},
+		},
+		{
+			Id:          2,
+			Name:        "K6-LoadTesting",
+			Description: "K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.",
+			Index:       2,
+			StepType:    repository.PIPELINE_STEP_TYPE_REF_PLUGIN,
+			RefPluginStepDetail: &bean.RefPluginStepDetailDto{
+				PluginId: 1,
+				ConditionDetails: []*bean.ConditionDetailDto{
+					{
+						Id:                  0,
+						ConditionOnVariable: "RelativePathToScript",
+						ConditionType:       "TRIGGER",
+						ConditionalOperator: "==",
+						ConditionalValue:    "@{{test-var-1}}",
+					},
+					{
+						Id:                  0,
+						ConditionOnVariable: "PrometheusApiKey",
+						ConditionType:       "TRIGGER",
+						ConditionalOperator: "!=",
+						ConditionalValue:    "dfbeavafsv",
+					},
+				},
+				InputVariables: []*bean.StepVariableDto{
+					{
+						Id:                        1,
+						Name:                      "RelativePathToScript",
+						Format:                    "STRING",
+						Description:               "checkout path + script path along with script name",
+						IsExposed:                 true,
+						AllowEmptyValue:           false,
+						DefaultValue:              "/./script.js",
+						Value:                     "sfds",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        2,
+						Name:                      "PrometheusUsername",
+						Format:                    "STRING",
+						Description:               "username of prometheus accoun",
+						IsExposed:                 true,
+						AllowEmptyValue:           true,
+						DefaultValue:              "",
+						Value:                     "sdf",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        3,
+						Name:                      "PrometheusApiKey",
+						Format:                    "STRING",
+						Description:               "api key of prometheus account",
+						IsExposed:                 true,
+						AllowEmptyValue:           true,
+						DefaultValue:              "",
+						Value:                     "gwrsd",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        4,
+						Name:                      "PrometheusRemoteWriteEndpoint",
+						Format:                    "STRING",
+						Description:               "remote write endpoint of prometheus account",
+						IsExposed:                 true,
+						AllowEmptyValue:           true,
+						DefaultValue:              "",
+						Value:                     "ewq",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        5,
+						Name:                      "OutputType",
+						Format:                    "STRING",
+						Description:               "output type - LOG or PROMETHEUS",
+						IsExposed:                 true,
+						AllowEmptyValue:           false,
+						DefaultValue:              "LOG",
+						Value:                     "Log",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+				},
+			},
+		},
+		{
+			Id:                  3,
+			Name:                "Task 3",
+			Description:         "",
+			Index:               3,
+			StepType:            repository.PIPELINE_STEP_TYPE_INLINE,
+			OutputDirectoryPath: []string{"./@{{test-var-2}}"},
+			InlineStepDetail: &bean.InlineStepDetailDto{
+				ScriptType:               repository2.SCRIPT_TYPE_CONTAINER_IMAGE,
+				Script:                   "#!/bin/sh \nset -eo pipefail \necho \"@{{test-var-2}}\"\n#set -v  ## uncomment this to debug the script \n",
+				MountCodeToContainer:     true,
+				MountCodeToContainerPath: "/sourcecode",
+				MountDirectoryFromHost:   true,
+				ContainerImagePath:       "alpine:latest",
+				CommandArgsMap: []*bean.CommandArgsMap{
+					{
+						Command: "echo",
+						Args:    []string{"HOSTNAME", "PORT"},
+					},
+				},
+				InputVariables: []*bean.StepVariableDto{
+					{
+						Id:                        1,
+						Name:                      "Hello",
+						Format:                    "STRING",
+						Description:               "jnsdvbdvbsd",
+						IsExposed:                 false,
+						AllowEmptyValue:           false,
+						DefaultValue:              "",
+						Value:                     "",
+						ValueType:                 "GLOBAL",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "WORKING_DIRECTORY",
+						VariableStepIndexInPlugin: 0,
+						ReferenceVariableStage:    "",
+					},
+				},
+			},
+		},
+	},
+	TriggerType: pipelineConfig.TRIGGER_TYPE_AUTOMATIC,
+}
+
+var pipelineStageReqResolved = &bean.PipelineStageDto{
+	Id:          0,
+	Name:        "",
+	Description: "",
+	Type:        repository.PIPELINE_STAGE_TYPE_PRE_CI,
+	Steps: []*bean.PipelineStageStepDto{
+		{
+			Id:                  1,
+			Name:                "Task-1",
+			Description:         "test1",
+			Index:               1,
+			StepType:            repository.PIPELINE_STEP_TYPE_INLINE,
+			OutputDirectoryPath: []string{"./test1"},
+			InlineStepDetail: &bean.InlineStepDetailDto{
+				OutputVariables: []*bean.StepVariableDto{
+					{
+						Id:                        1,
+						Name:                      "Hello",
+						Format:                    "STRING",
+						Description:               "dsuihvsuvhbdv",
+						IsExposed:                 false,
+						AllowEmptyValue:           false,
+						DefaultValue:              "",
+						Value:                     "",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 0,
+						ReferenceVariableStage:    "",
+					},
+				},
+				ScriptType: repository2.SCRIPT_TYPE_SHELL,
+				Script:     "#!/bin/sh \nset -eo pipefail \necho \"test1\"\n#set -v  ## uncomment this to debug the script \n",
+			},
+		},
+		{
+			Id:          2,
+			Name:        "K6-LoadTesting",
+			Description: "K6 is an open-source tool and cloud service that makes load testing easy for developers and QA engineers.",
+			Index:       2,
+			StepType:    repository.PIPELINE_STEP_TYPE_REF_PLUGIN,
+			RefPluginStepDetail: &bean.RefPluginStepDetailDto{
+				PluginId: 1,
+				ConditionDetails: []*bean.ConditionDetailDto{
+					{
+						Id:                  0,
+						ConditionOnVariable: "RelativePathToScript",
+						ConditionType:       "TRIGGER",
+						ConditionalOperator: "==",
+						ConditionalValue:    "test1",
+					},
+					{
+						Id:                  0,
+						ConditionOnVariable: "PrometheusApiKey",
+						ConditionType:       "TRIGGER",
+						ConditionalOperator: "!=",
+						ConditionalValue:    "dfbeavafsv",
+					},
+				},
+				InputVariables: []*bean.StepVariableDto{
+					{
+						Id:                        1,
+						Name:                      "RelativePathToScript",
+						Format:                    "STRING",
+						Description:               "checkout path + script path along with script name",
+						IsExposed:                 true,
+						AllowEmptyValue:           false,
+						DefaultValue:              "/./script.js",
+						Value:                     "sfds",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        2,
+						Name:                      "PrometheusUsername",
+						Format:                    "STRING",
+						Description:               "username of prometheus accoun",
+						IsExposed:                 true,
+						AllowEmptyValue:           true,
+						DefaultValue:              "",
+						Value:                     "sdf",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        3,
+						Name:                      "PrometheusApiKey",
+						Format:                    "STRING",
+						Description:               "api key of prometheus account",
+						IsExposed:                 true,
+						AllowEmptyValue:           true,
+						DefaultValue:              "",
+						Value:                     "gwrsd",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        4,
+						Name:                      "PrometheusRemoteWriteEndpoint",
+						Format:                    "STRING",
+						Description:               "remote write endpoint of prometheus account",
+						IsExposed:                 true,
+						AllowEmptyValue:           true,
+						DefaultValue:              "",
+						Value:                     "ewq",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+					{
+						Id:                        5,
+						Name:                      "OutputType",
+						Format:                    "STRING",
+						Description:               "output type - LOG or PROMETHEUS",
+						IsExposed:                 true,
+						AllowEmptyValue:           false,
+						DefaultValue:              "LOG",
+						Value:                     "Log",
+						ValueType:                 "NEW",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "",
+						VariableStepIndexInPlugin: 1,
+						ReferenceVariableStage:    "",
+					},
+				},
+			},
+		},
+		{
+			Id:                  3,
+			Name:                "Task 3",
+			Description:         "",
+			Index:               3,
+			StepType:            repository.PIPELINE_STEP_TYPE_INLINE,
+			OutputDirectoryPath: []string{"./test2"},
+			InlineStepDetail: &bean.InlineStepDetailDto{
+				ScriptType:               repository2.SCRIPT_TYPE_CONTAINER_IMAGE,
+				Script:                   "#!/bin/sh \nset -eo pipefail \necho \"test2\"\n#set -v  ## uncomment this to debug the script \n",
+				MountCodeToContainer:     true,
+				MountCodeToContainerPath: "/sourcecode",
+				MountDirectoryFromHost:   true,
+				ContainerImagePath:       "alpine:latest",
+				CommandArgsMap: []*bean.CommandArgsMap{
+					{
+						Command: "echo",
+						Args:    []string{"HOSTNAME", "PORT"},
+					},
+				},
+				InputVariables: []*bean.StepVariableDto{
+					{
+						Id:                        1,
+						Name:                      "Hello",
+						Format:                    "STRING",
+						Description:               "jnsdvbdvbsd",
+						IsExposed:                 false,
+						AllowEmptyValue:           false,
+						DefaultValue:              "",
+						Value:                     "",
+						ValueType:                 "GLOBAL",
+						PreviousStepIndex:         0,
+						ReferenceVariableName:     "WORKING_DIRECTORY",
+						VariableStepIndexInPlugin: 0,
+						ReferenceVariableStage:    "",
+					},
+				},
+			},
+		},
+	},
+	TriggerType: pipelineConfig.TRIGGER_TYPE_AUTOMATIC,
+}
 
 func getDbConnAndLoggerService(t *testing.T) (*zap.SugaredLogger, *pg.DB) {
 	cfg, _ := sql.GetConfig()
@@ -225,8 +591,11 @@ func getPipelineStageServiceImpl(t *testing.T) *PipelineStageServiceImpl {
 
 	pipelineStageRepoImpl := repository.NewPipelineStageRepository(logger, dbConnection)
 	pipelineRepoImpl := pipelineConfig.NewPipelineRepositoryImpl(dbConnection, logger)
-
-	pipelineStageServiceImpl := NewPipelineStageService(logger, pipelineStageRepoImpl, nil, pipelineRepoImpl)
+	scopedVarServiceImpl, _ := variables.NewScopedVariableServiceImpl(logger, repository4.NewScopedVariableRepository(dbConnection, logger))
+	entityMappingServiceImpl := variables.NewVariableEntityMappingServiceImpl(repository4.NewVariableEntityMappingRepository(logger, dbConnection), logger)
+	templateParserImpl := parsers.NewVariableTemplateParserImpl(logger)
+	pluginRepository := repository2.NewGlobalPluginRepository(logger, dbConnection)
+	pipelineStageServiceImpl := NewPipelineStageService(logger, pipelineStageRepoImpl, pluginRepository, pipelineRepoImpl, scopedVarServiceImpl, entityMappingServiceImpl, templateParserImpl)
 	return pipelineStageServiceImpl
 }
 
@@ -556,6 +925,33 @@ func TestPipelineStageService_DeletePipelineStage(t *testing.T) {
 
 }
 
+func TestPipelineStageService_BuildPrePostAndRefPluginStepsDataForWfRequest_WithScopedVariables(t *testing.T) {
+	t.Setenv("VARIABLE_CACHE_ENABLED", "false")
+	pipelineStageServiceImpl := getPipelineStageServiceImpl(t)
+	logger, dbConnection := getDbConnAndLoggerService(t)
+	scopedVarServiceImpl, _ := variables.NewScopedVariableServiceImpl(logger, repository4.NewScopedVariableRepository(dbConnection, logger))
+	templateParserImpl := parsers.NewVariableTemplateParserImpl(logger)
+	payload := models.Payload{}
+	json.Unmarshal([]byte(ScopedVariablePayload), &payload)
+
+	err := scopedVarServiceImpl.CreateVariables(payload)
+	assert.Nil(t, err)
+
+	err = pipelineStageServiceImpl.UpdatePipelineStage(pipelineStageReqUnresolved, repository.PIPELINE_STAGE_TYPE_PRE_CI, ciPipelineId, 1)
+	assert.Nil(t, err)
+
+	resolvedRequest, err := pipelineStageServiceImpl.BuildPrePostAndRefPluginStepsDataForWfRequest(ciPipelineId, ciEvent, models.Scope{
+		AppId:     1,
+		EnvId:     1,
+		ClusterId: 1,
+	})
+	assert.Nil(t, err)
+	requestJson, _ := json.Marshal(resolvedRequest)
+	extractVariables, err := templateParserImpl.ExtractVariables(string(requestJson))
+	assert.Nil(t, err)
+	assert.Len(t, extractVariables, 0)
+}
+
 //func TestMain(m *testing.M) {
 //	var t *testing.T
 //	tearDownSuite := setupSuite(t)
diff --git a/pkg/pipeline/WorkflowService_test.go b/pkg/pipeline/WorkflowService_test.go
index 2495a13f6..31306dab9 100644
--- a/pkg/pipeline/WorkflowService_test.go
+++ b/pkg/pipeline/WorkflowService_test.go
@@ -400,7 +400,7 @@ func Test_getCiTemplateWithConfigMapsAndSecrets(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := getCiTemplateWithConfigMapsAndSecrets(tt.args.configMaps, tt.args.secrets, tt.args.ciTemplate, tt.args.existingConfigMap, tt.args.existingSecrets)
+			got, err := getCiTemplateWithConfigMapsAndSecrets(tt.args.configMaps, tt.args.secrets, tt.args.ciTemplate)
 			if !tt.wantErr(t, err, fmt.Sprintf("getCiTemplateWithConfigMapsAndSecrets(%v, %v, %v, %v, %v)", tt.args.configMaps, tt.args.secrets, tt.args.ciTemplate, tt.args.existingConfigMap, tt.args.existingSecrets)) {
 				return
 			}
@@ -468,7 +468,7 @@ func Test_processConfigMapsAndSecrets(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			tt.wantErr(t, processConfigMapsAndSecrets(tt.args.impl, tt.args.configMaps, tt.args.secrets, tt.args.entryPoint, tt.args.steps, tt.args.volumes, tt.args.templates), fmt.Sprintf("processConfigMapsAndSecrets(%v, %v, %v, %v, %v, %v, %v)", tt.args.impl, tt.args.configMaps, tt.args.secrets, tt.args.entryPoint, tt.args.steps, tt.args.volumes, tt.args.templates))
+			tt.wantErr(t, processConfigMapsAndSecrets(tt.args.impl, tt.args.configMaps, tt.args.secrets, tt.args.entryPoint, tt.args.steps, tt.args.templates), fmt.Sprintf("processConfigMapsAndSecrets(%v, %v, %v, %v, %v, %v, %v)", tt.args.impl, tt.args.configMaps, tt.args.secrets, tt.args.entryPoint, tt.args.steps, tt.args.volumes, tt.args.templates))
 		})
 	}
 }
@@ -540,7 +540,7 @@ func Test_processConfigMapsAndSecrets1(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			err := processConfigMapsAndSecrets(tt.args.impl, tt.args.configMaps, tt.args.secrets, tt.args.entryPoint, tt.args.steps, tt.args.volumes, tt.args.templates)
+			err := processConfigMapsAndSecrets(tt.args.impl, tt.args.configMaps, tt.args.secrets, tt.args.entryPoint, tt.args.steps, tt.args.templates)
 
 			if tt.wantErr {
 				if err == nil {