Repository: devtron-labs/devtron
Pull request #3473 (2023-06-04 10:00:25)

docs: updated doc for incluster
<!--
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:

- docs - Execute in application environment option for pre/post stage

Example Title: 
docs: Webhook CI documentation changes
-->

# Description
<!--
Updated documentation for 'Execute in application environment' option for pre/post stage

-->


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=3473)

[![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=3473&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=3473&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3473&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=3473&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=3473&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3473&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=3473&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=3473&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=devtron-labs_devtron&pullRequest=3473&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=3473&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=3473&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=devtron-labs_devtron&pullRequest=3473&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=3473) 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=3473&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/Wire.go b/Wire.go
index acde90a89..0467650a5 100644
--- a/Wire.go
+++ b/Wire.go
@@ -585,6 +585,8 @@ func InitializeApp() (*App, error) {
 		wire.Bind(new(security2.CveStoreRepository), new(*security2.CveStoreRepositoryImpl)),
 		security2.NewImageScanDeployInfoRepositoryImpl,
 		wire.Bind(new(security2.ImageScanDeployInfoRepository), new(*security2.ImageScanDeployInfoRepositoryImpl)),
+		security2.NewScanToolMetadataRepositoryImpl,
+		wire.Bind(new(security2.ScanToolMetadataRepository), new(*security2.ScanToolMetadataRepositoryImpl)),
 		router.NewPolicyRouterImpl,
 		wire.Bind(new(router.PolicyRouter), new(*router.PolicyRouterImpl)),
 		restHandler.NewPolicyRestHandlerImpl,
@@ -593,6 +595,8 @@ func InitializeApp() (*App, error) {
 		wire.Bind(new(security.PolicyService), new(*security.PolicyServiceImpl)),
 		security2.NewPolicyRepositoryImpl,
 		wire.Bind(new(security2.CvePolicyRepository), new(*security2.CvePolicyRepositoryImpl)),
+		security2.NewScanToolExecutionHistoryMappingRepositoryImpl,
+		wire.Bind(new(security2.ScanToolExecutionHistoryMappingRepository), new(*security2.ScanToolExecutionHistoryMappingRepositoryImpl)),
 
 		argocdServer.NewArgoK8sClientImpl,
 		wire.Bind(new(argocdServer.ArgoK8sClient), new(*argocdServer.ArgoK8sClientImpl)),
diff --git a/api/module/ModuleRestHandler.go b/api/module/ModuleRestHandler.go
index b30d266c9..8ed04848a 100644
--- a/api/module/ModuleRestHandler.go
+++ b/api/module/ModuleRestHandler.go
@@ -34,6 +34,7 @@ type ModuleRestHandler interface {
 	GetModuleInfo(w http.ResponseWriter, r *http.Request)
 	GetModuleConfig(w http.ResponseWriter, r *http.Request)
 	HandleModuleAction(w http.ResponseWriter, r *http.Request)
+	EnableModule(w http.ResponseWriter, r *http.Request)
 }
 
 type ModuleRestHandlerImpl struct {
@@ -164,3 +165,46 @@ func (impl ModuleRestHandlerImpl) HandleModuleAction(w http.ResponseWriter, r *h
 	}
 	common.WriteJsonResp(w, err, res, http.StatusOK)
 }
+
+func (impl ModuleRestHandlerImpl) EnableModule(w http.ResponseWriter, r *http.Request) {
+	// check if user is logged in or not
+	userId, err := impl.userService.GetLoggedInUser(r)
+	if userId == 0 || err != nil {
+		common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
+		return
+	}
+
+	// check query param
+	params := mux.Vars(r)
+	moduleName := params["name"]
+	if len(moduleName) == 0 {
+		impl.logger.Error("module name is not supplied")
+		common.WriteJsonResp(w, errors.New("module name is not supplied"), nil, http.StatusBadRequest)
+		return
+	}
+	// decode request
+	decoder := json.NewDecoder(r.Body)
+	var moduleEnableRequestDto module.ModuleEnableRequestDto
+	err = decoder.Decode(&moduleEnableRequestDto)
+	if err != nil {
+		impl.logger.Errorw("error in decoding request in ModuleEnableRequestDto", "err", err)
+		common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
+		return
+	}
+
+	// handle super-admin RBAC
+	token := r.Header.Get("token")
+	if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionUpdate, "*"); !ok {
+		common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
+		return
+	}
+
+	// service call
+	res, err := impl.moduleService.EnableModule(moduleName, moduleEnableRequestDto.Version)
+	if err != nil {
+		impl.logger.Errorw("service err, Enabling Module", "err", err, "moduleName", moduleName, "toolVersion", moduleEnableRequestDto.Version)
+		common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
+		return
+	}
+	common.WriteJsonResp(w, err, res, http.StatusOK)
+}
diff --git a/api/module/ModuleRouter.go b/api/module/ModuleRouter.go
index 02ba66208..db71f00b4 100644
--- a/api/module/ModuleRouter.go
+++ b/api/module/ModuleRouter.go
@@ -21,4 +21,5 @@ func (impl ModuleRouterImpl) Init(configRouter *mux.Router) {
 	configRouter.Path("").HandlerFunc(impl.moduleRestHandler.GetModuleInfo).Methods("GET")
 	configRouter.Path("/config").HandlerFunc(impl.moduleRestHandler.GetModuleConfig).Queries("name", "{name}").Methods("GET")
 	configRouter.Path("").HandlerFunc(impl.moduleRestHandler.HandleModuleAction).Queries("name", "{name}").Methods("POST")
+	configRouter.Path("/enable").HandlerFunc(impl.moduleRestHandler.EnableModule).Queries("name", "{name}").Methods("POST")
 }
diff --git a/cmd/external-app/wire.go b/cmd/external-app/wire.go
index c3fcbd002..49bf691f0 100644
--- a/cmd/external-app/wire.go
+++ b/cmd/external-app/wire.go
@@ -31,6 +31,7 @@ import (
 	app2 "github.com/devtron-labs/devtron/internal/sql/repository/app"
 	"github.com/devtron-labs/devtron/internal/sql/repository/appStatus"
 	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	security2 "github.com/devtron-labs/devtron/internal/sql/repository/security"
 	"github.com/devtron-labs/devtron/internal/util"
 	"github.com/devtron-labs/devtron/pkg/app"
 	appStoreBean "github.com/devtron-labs/devtron/pkg/appStore/bean"
@@ -174,6 +175,9 @@ func InitializeApp() (*App, error) {
 		wire.Value(appStoreBean.RefChartProxyDir("scripts/devtron-reference-helm-charts")),
 		util.NewGitFactory,
 		util.NewGitCliUtil,
+
+		security2.NewScanToolMetadataRepositoryImpl,
+		wire.Bind(new(security2.ScanToolMetadataRepository), new(*security2.ScanToolMetadataRepositoryImpl)),
 	)
 	return &App{}, nil
 }
diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go
index 54c0013e0..1b0c8cb1e 100644
--- a/cmd/external-app/wire_gen.go
+++ b/cmd/external-app/wire_gen.go
@@ -37,6 +37,7 @@ import (
 	"github.com/devtron-labs/devtron/internal/sql/repository/app"
 	"github.com/devtron-labs/devtron/internal/sql/repository/appStatus"
 	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	"github.com/devtron-labs/devtron/internal/sql/repository/security"
 	"github.com/devtron-labs/devtron/internal/util"
 	"github.com/devtron-labs/devtron/pkg/apiToken"
 	app2 "github.com/devtron-labs/devtron/pkg/app"
@@ -295,7 +296,8 @@ func InitializeApp() (*App, error) {
 	if err != nil {
 		return nil, err
 	}
-	moduleServiceImpl := module.NewModuleServiceImpl(sugaredLogger, serverEnvConfigServerEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepositoryImpl, helmAppServiceImpl, serverDataStoreServerDataStore, serverCacheServiceImpl, moduleCacheServiceImpl, moduleCronServiceImpl, moduleServiceHelperImpl, moduleResourceStatusRepositoryImpl)
+	scanToolMetadataRepositoryImpl := security.NewScanToolMetadataRepositoryImpl(db, sugaredLogger)
+	moduleServiceImpl := module.NewModuleServiceImpl(sugaredLogger, serverEnvConfigServerEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepositoryImpl, helmAppServiceImpl, serverDataStoreServerDataStore, serverCacheServiceImpl, moduleCacheServiceImpl, moduleCronServiceImpl, moduleServiceHelperImpl, moduleResourceStatusRepositoryImpl, scanToolMetadataRepositoryImpl)
 	moduleRestHandlerImpl := module2.NewModuleRestHandlerImpl(sugaredLogger, moduleServiceImpl, userServiceImpl, enforcerImpl, validate)
 	moduleRouterImpl := module2.NewModuleRouterImpl(moduleRestHandlerImpl)
 	serverActionAuditLogRepositoryImpl := server.NewServerActionAuditLogRepositoryImpl(db)
diff --git a/docs/user-guide/creating-application/workflow/cd-pipeline.md b/docs/user-guide/creating-application/workflow/cd-pipeline.md
index 56fa31f0b..73baf61b3 100644
--- a/docs/user-guide/creating-application/workflow/cd-pipeline.md
+++ b/docs/user-guide/creating-application/workflow/cd-pipeline.md
@@ -120,6 +120,53 @@ You can use Config Map and Secrets in post deployments as well, as defined in th
 Once you have configured the CD pipeline, click on `Create Pipeline` to save it. You can see your newly created CD Pipeline on the Workflow tab attached to the corresponding CI Pipeline.
 
 
+### 6. Execute in Application Environment
+
+When deploying an application, we often need to perform additional tasks before or after the deployments. These tasks require extra permissions for the node where Devtron is installed. However, if the node already has the necessary permissions for deploying applications, there is no need to assign them again. Instead, you can enable the "Execute in application environment" option for the pre-CD and post-CD steps. By default, this option is disabled, and some configurations are required to enable it.
+
+To enable the "Execute in application environment" option, follow these steps:
+
+1. Go to the chart store and search for the devtron-in-clustercd chart.
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/creating-application/workflow-cd-pipeline/devtron-incluster-chart.jpg)
+2. Configure the chart according to your requirements and deploy it in the target cluster.
+3. After the deployment, edit the devtron-cm configmap and add the following key-value pair:
+
+```bash
+ORCH_HOST: <host_url>/orchestrator/webhook/msg/nats
+
+Example:
+
+ORCH_HOST: http://xyz.devtron.com/orchestrator/webhook/msg/nats
+
+```
+`ORCH_HOST` value should be same as of `CD_EXTERNAL_LISTENER_URL` value which is passed in values.yaml.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/creating-application/workflow-cd-pipeline/incluster-configuration.jpg)
+
+
+
+4. Delete the Devtron pod using the following command:
+
+```bash
+kubectl delete pod -l app=devtron -n devtroncd
+```
+
+5. Again navigate to the chart store and search for the "migration-incluster-cd" chart.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/creating-application/workflow-cd-pipeline/migration-incluster-chart.jpg)
+
+6. Edit the `cluster-name` and `secret name` values within the chart. The `cluster name` refers to the name used when adding the cluster in the global configuration and for which you are going to enable `Execute in application environment` option.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/creating-application/workflow-cd-pipeline/migration-incluster.jpg)
+
+7. Deploy the chart in any environment within the Devtron cluster. 
+
+Now you should be able to enable `Execute in application environmet` option for an environment of target cluster.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/creating-application/workflow-cd-pipeline/enabled-incluster.jpg)
+
+
+
 ## Update CD Pipeline
 
 You can update the deployment stages and the deployment strategy of the CD Pipeline whenever you require it. But, you cannot change the name of a CD Pipeline or its Deployment Environment. If you need to change such configurations, you need to make another CD Pipeline from scratch.
diff --git a/internal/sql/repository/security/ImageScanDeployInfoRepository.go b/internal/sql/repository/security/ImageScanDeployInfoRepository.go
index 1e2438a7d..6d4a6e6c6 100644
--- a/internal/sql/repository/security/ImageScanDeployInfoRepository.go
+++ b/internal/sql/repository/security/ImageScanDeployInfoRepository.go
@@ -28,7 +28,8 @@ import (
 	"go.uber.org/zap"
 )
 
-/**
+/*
+*
 this table contains scanned images registry for deployed object and apps,
 images which are deployed on cluster by anyway and has scanned result
 */
@@ -126,8 +127,8 @@ func (impl ImageScanDeployInfoRepositoryImpl) FindByIds(ids []int) ([]*ImageScan
 	return models, err
 }
 
-func (impl ImageScanDeployInfoRepositoryImpl) Update(team *ImageScanDeployInfo) error {
-	err := impl.dbConnection.Update(team)
+func (impl ImageScanDeployInfoRepositoryImpl) Update(model *ImageScanDeployInfo) error {
+	err := impl.dbConnection.Update(model)
 	return err
 }
 
diff --git a/internal/sql/repository/security/ImageScanResultRepository.go b/internal/sql/repository/security/ImageScanResultRepository.go
index a9f2c1467..24cc26766 100644
--- a/internal/sql/repository/security/ImageScanResultRepository.go
+++ b/internal/sql/repository/security/ImageScanResultRepository.go
@@ -27,6 +27,7 @@ type ImageScanExecutionResult struct {
 	Id                          int      `sql:"id,pk"`
 	CveStoreName                string   `sql:"cve_store_name,notnull"`
 	ImageScanExecutionHistoryId int      `sql:"image_scan_execution_history_id"`
+	ScanToolId                  int      `sql:"scan_tool_id"`
 	CveStore                    CveStore
 	ImageScanExecutionHistory   ImageScanExecutionHistory
 }
@@ -93,7 +94,7 @@ func (impl ImageScanResultRepositoryImpl) FetchByScanExecutionId(scanExecutionId
 	Where("image_scan_execution_result.scan_execution_id = ?", id).Select()
 	*/
 
-	err := impl.dbConnection.Model(&models).Column("image_scan_execution_result.*", "CveStore").
+	err := impl.dbConnection.Model(&models).ColumnExpr("DISTINCT cve_store_name").Column("image_scan_execution_result.*", "CveStore").
 		Where("image_scan_execution_result.image_scan_execution_history_id = ?", scanExecutionId).
 		Select()
 	return models, err
@@ -101,7 +102,7 @@ func (impl ImageScanResultRepositoryImpl) FetchByScanExecutionId(scanExecutionId
 
 func (impl ImageScanResultRepositoryImpl) FetchByScanExecutionIds(ids []int) ([]*ImageScanExecutionResult, error) {
 	var models []*ImageScanExecutionResult
-	err := impl.dbConnection.Model(&models).Column("image_scan_execution_result.*", "ImageScanExecutionHistory", "CveStore").
+	err := impl.dbConnection.Model(&models).ColumnExpr("DISTINCT cve_store_name").Column("image_scan_execution_result.*", "ImageScanExecutionHistory", "CveStore").
 		Where("image_scan_execution_result.image_scan_execution_history_id in(?)", pg.In(ids)).
 		Select()
 	return models, err
@@ -109,14 +110,14 @@ func (impl ImageScanResultRepositoryImpl) FetchByScanExecutionIds(ids []int) ([]
 
 func (impl ImageScanResultRepositoryImpl) FindByImageDigest(imageDigest string) ([]*ImageScanExecutionResult, error) {
 	var model []*ImageScanExecutionResult
-	err := impl.dbConnection.Model(&model).Column("image_scan_execution_result.*", "ImageScanExecutionHistory", "CveStore").
+	err := impl.dbConnection.Model(&model).ColumnExpr("DISTINCT cve_store_name").Column("image_scan_execution_result.*", "ImageScanExecutionHistory", "CveStore").
 		Where("image_scan_execution_history.image_hash = ?", imageDigest).Order("image_scan_execution_history.execution_time desc").Select()
 	return model, err
 }
 
 func (impl ImageScanResultRepositoryImpl) FindByImageDigests(digest []string) ([]*ImageScanExecutionResult, error) {
 	var models []*ImageScanExecutionResult
-	err := impl.dbConnection.Model(&models).Column("image_scan_execution_result.*", "ImageScanExecutionHistory", "CveStore").
+	err := impl.dbConnection.Model(&models).ColumnExpr("DISTINCT cve_store_name").Column("image_scan_execution_result.*", "ImageScanExecutionHistory", "CveStore").
 		Where("image_hash in (?)", pg.In(digest)).Order("execution_time desc").Select()
 	return models, err
 }
diff --git a/internal/sql/repository/security/ScanToolExecutionHistoryMapping.go b/internal/sql/repository/security/ScanToolExecutionHistoryMapping.go
new file mode 100644
index 000000000..0562798f6
--- /dev/null
+++ b/internal/sql/repository/security/ScanToolExecutionHistoryMapping.go
@@ -0,0 +1,127 @@
+package security
+
+import (
+	serverBean "github.com/devtron-labs/devtron/pkg/server/bean"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/go-pg/pg"
+	"go.uber.org/zap"
+	"time"
+)
+
+type ScanToolExecutionHistoryMapping struct {
+	tableName                   struct{}                             `sql:"scan_tool_execution_history_mapping" pg:",discard_unknown_columns"`
+	Id                          int                                  `sql:"id,pk"`
+	ImageScanExecutionHistoryId int                                  `sql:"image_scan_execution_history_id"`
+	ScanToolId                  int                                  `sql:"scan_tool_id"`
+	ExecutionStartTime          time.Time                            `sql:"execution_start_time,notnull"`
+	ExecutionFinishTime         time.Time                            `sql:"execution_finish_time,notnull"`
+	State                       serverBean.ScanExecutionProcessState `sql:"state"`
+	TryCount                    int                                  `sql:"try_count"`
+	sql.AuditLog
+}
+
+type ScanToolExecutionHistoryMappingRepository interface {
+	Save(model *ScanToolExecutionHistoryMapping) error
+	SaveInBatch(models []*ScanToolExecutionHistoryMapping) error
+	UpdateStateByToolAndExecutionHistoryId(executionHistoryId, toolId int, state serverBean.ScanExecutionProcessState, executionFinishTime time.Time) error
+	MarkAllRunningStateAsFailedHavingTryCountReachedLimit(tryCount int) error
+	GetAllScanHistoriesByState(state serverBean.ScanExecutionProcessState) ([]*ScanToolExecutionHistoryMapping, error)
+	GetAllScanHistoriesByExecutionHistoryIdAndStates(executionHistoryId int, states []serverBean.ScanExecutionProcessState) ([]*ScanToolExecutionHistoryMapping, error)
+	GetAllScanHistoriesByExecutionHistoryIds(ids []int) ([]*ScanToolExecutionHistoryMapping, error)
+}
+
+type ScanToolExecutionHistoryMappingRepositoryImpl struct {
+	dbConnection *pg.DB
+	logger       *zap.SugaredLogger
+}
+
+func NewScanToolExecutionHistoryMappingRepositoryImpl(dbConnection *pg.DB,
+	logger *zap.SugaredLogger) *ScanToolExecutionHistoryMappingRepositoryImpl {
+	return &ScanToolExecutionHistoryMappingRepositoryImpl{
+		dbConnection: dbConnection,
+		logger:       logger,
+	}
+}
+
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) Save(model *ScanToolExecutionHistoryMapping) error {
+	err := repo.dbConnection.Insert(model)
+	if err != nil {
+		repo.logger.Errorw("error in ScanToolExecutionHistoryMappingRepository, Save", "model", model, "err", err)
+		return err
+	}
+	return nil
+}
+
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) SaveInBatch(models []*ScanToolExecutionHistoryMapping) error {
+	err := repo.dbConnection.Insert(&models)
+	if err != nil {
+		repo.logger.Errorw("error in ScanToolExecutionHistoryMappingRepository, SaveInBatch", "err", err, "models", models)
+		return err
+	}
+	return nil
+}
+
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) UpdateStateByToolAndExecutionHistoryId(executionHistoryId, toolId int,
+	state serverBean.ScanExecutionProcessState, executionFinishTime time.Time) error {
+	model := &ScanToolExecutionHistoryMapping{}
+	_, err := repo.dbConnection.Model(model).Set("state = ?", state).
+		Set("execution_finish_time  = ?", executionFinishTime).
+		Set("updated_on = ?", time.Now()).
+		Set("updated_by =?", time.Now()).
+		Where("image_scan_execution_history_id = ?", executionHistoryId).
+		Where("scan_tool_id = ?", toolId).Update()
+	if err != nil {
+		repo.logger.Errorw("error in ScanToolExecutionHistoryMappingRepository, SaveInBatch", "err", err, "model", model)
+		return err
+	}
+	return nil
+}
+
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) MarkAllRunningStateAsFailedHavingTryCountReachedLimit(tryCount int) error {
+	var models []*ScanToolExecutionHistoryMapping
+	_, err := repo.dbConnection.Model(&models).
+		Set("state = ?", serverBean.ScanExecutionProcessStateFailed).
+		Set("updated_on = ?", time.Now()).
+		Set("updated_by =?", time.Now()).
+		Where("state = ?", serverBean.ScanExecutionProcessStateRunning).
+		Where("try_count > ?", tryCount).Update()
+	if err != nil {
+		repo.logger.Errorw("error in ScanToolExecutionHistoryMappingRepository, MarkAllRunningStateAsFailedHavingTryCountReachedLimit", "err", err)
+		return err
+	}
+	return nil
+}
+
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) GetAllScanHistoriesByState(state serverBean.ScanExecutionProcessState) ([]*ScanToolExecutionHistoryMapping, error) {
+	var models []*ScanToolExecutionHistoryMapping
+	err := repo.dbConnection.Model(&models).Column("scan_tool_execution_history_mapping.*").
+		Where("state = ?", state).Select()
+	if err != nil {
+		repo.logger.Errorw("error in ScanToolExecutionHistoryMappingRepository, GetAllScanHistoriesByState", "err", err)
+		return nil, err
+	}
+	return models, nil
+}
+
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) GetAllScanHistoriesByExecutionHistoryIdAndStates(executionHistoryId int, states []serverBean.ScanExecutionProcessState) ([]*ScanToolExecutionHistoryMapping, error) {
+	var models []*ScanToolExecutionHistoryMapping
+	err := repo.dbConnection.Model(&models).Column("scan_tool_execution_history_mapping.*").
+		Where("image_scan_execution_history_id = ?", executionHistoryId).
+		Where("state in (?)", pg.In(states)).Select()
+	if err != nil {
+		repo.logger.Errorw("error in ScanToolExecutionHistoryMappingRepository, GetAllScanHistoriesByState", "err", err)
+		return nil, err
+	}
+	return models, nil
+}
+func (repo *ScanToolExecutionHistoryMappingRepositoryImpl) GetAllScanHistoriesByExecutionHistoryIds(ids []int) ([]*ScanToolExecutionHistoryMapping, error) {
+	var models []*ScanToolExecutionHistoryMapping
+	err := repo.dbConnection.Model(&models).Column("scan_tool_execution_history_mapping.*").
+		Where("image_scan_execution_history_id in (?)", pg.In(ids)).
+		Select()
+	if err != nil {
+		repo.logger.Errorw("error in getting ScanToolExecutionHistoryMappingRepository, GetAllScanHistoriesByState", "err", err)
+		return nil, err
+	}
+	return models, nil
+}
diff --git a/internal/sql/repository/security/ScanToolMetaDataRepository.go b/internal/sql/repository/security/ScanToolMetaDataRepository.go
new file mode 100644
index 000000000..3c7bc461e
--- /dev/null
+++ b/internal/sql/repository/security/ScanToolMetaDataRepository.go
@@ -0,0 +1,156 @@
+package security
+
+import (
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/go-pg/pg"
+	"go.uber.org/zap"
+)
+
+type ScanTargetType string
+
+type ScanToolMetadata struct {
+	tableName                struct{}       `sql:"scan_tool_metadata" pg:",discard_unknown_columns"`
+	Id                       int            `sql:"id,pk"`
+	Name                     string         `sql:"name"`
+	Version                  string         `sql:"version"`
+	ServerBaseUrl            string         `sql:"server_base_url"`
+	ResultDescriptorTemplate string         `sql:"result_descriptor_template"`
+	ScanTarget               ScanTargetType `sql:"scan_target"`
+	Active                   bool           `sql:"active,notnull"`
+	Deleted                  bool           `sql:"deleted,notnull"`
+	ToolMetaData             string         `sql:"tool_metadata"`
+	sql.AuditLog
+}
+
+type ScanToolMetadataRepository interface {
+	FindActiveToolByScanTarget(scanTarget ScanTargetType) (*ScanToolMetadata, error)
+	FindByNameAndVersion(name, version string) (*ScanToolMetadata, error)
+	FindActiveById(id int) (*ScanToolMetadata, error)
+	Save(model *ScanToolMetadata) (*ScanToolMetadata, error)
+	Update(model *ScanToolMetadata) (*ScanToolMetadata, error)
+	MarkToolDeletedById(id int) error
+	FindAllActiveTools() ([]*ScanToolMetadata, error)
+	MarkToolAsActive(toolName, version string, tx *pg.Tx) error
+	MarkOtherToolsInActive(toolName string, tx *pg.Tx, version string) error
+	FindActiveTool() (*ScanToolMetadata, error)
+}
+
+type ScanToolMetadataRepositoryImpl struct {
+	dbConnection *pg.DB
+	logger       *zap.SugaredLogger
+}
+
+func NewScanToolMetadataRepositoryImpl(dbConnection *pg.DB,
+	logger *zap.SugaredLogger) *ScanToolMetadataRepositoryImpl {
+	return &ScanToolMetadataRepositoryImpl{
+		dbConnection: dbConnection,
+		logger:       logger,
+	}
+}
+
+func (repo *ScanToolMetadataRepositoryImpl) FindActiveToolByScanTarget(scanTargetType ScanTargetType) (*ScanToolMetadata, error) {
+	var model ScanToolMetadata
+	err := repo.dbConnection.Model(&model).Where("active = ?", true).
+		Where("scan_target = ?", scanTargetType).
+		Where("deleted = ?", false).Limit(1).Select()
+	if err != nil {
+		repo.logger.Errorw("error in getting active tool for scan target", "err", err, "scanTargetType", scanTargetType)
+		return nil, err
+	}
+	return &model, nil
+}
+
+func (repo *ScanToolMetadataRepositoryImpl) FindByNameAndVersion(name, version string) (*ScanToolMetadata, error) {
+	model := &ScanToolMetadata{}
+	err := repo.dbConnection.Model(&model).Where("active = ?", true).
+		Where("name = ?", name).Where("version = ?", version).
+		Where("deleted = ?", false).Select()
+	if err != nil {
+		repo.logger.Errorw("error in getting tool by name and version", "err", err, "name", name, "version", version)
+		return nil, err
+	}
+	return model, nil
+}
+
+func (repo *ScanToolMetadataRepositoryImpl) FindActiveById(id int) (*ScanToolMetadata, error) {
+	model := &ScanToolMetadata{}
+	err := repo.dbConnection.Model(model).Where("id = ?", id).
+		Where("active = ?", true).
+		Where("deleted = ?", false).Select()
+	if err != nil {
+		repo.logger.Errorw("error in getting active by id", "err", err, "id", id)
+		return nil, err
+	}
+	return model, nil
+}
+
+func (repo *ScanToolMetadataRepositoryImpl) Save(model *ScanToolMetadata) (*ScanToolMetadata, error) {
+	err := repo.dbConnection.Insert(model)
+	if err != nil {
+		repo.logger.Errorw("error in saving scan tool metadata", "err", err, "model", model)
+		return nil, err
+	}
+	return model, nil
+}
+
+func (repo *ScanToolMetadataRepositoryImpl) Update(model *ScanToolMetadata) (*ScanToolMetadata, error) {
+	err := repo.dbConnection.Update(model)
+	if err != nil {
+		repo.logger.Errorw("error in updating scan tool metadata", "err", err, "model", model)
+		return nil, err
+	}
+	return model, nil
+}
+
+func (repo *ScanToolMetadataRepositoryImpl) MarkToolDeletedById(id int) error {
+	model := &ScanToolMetadata{}
+	_, err := repo.dbConnection.Model(model).Set("deleted = ?", true).
+		Where("id = ?", id).Update()
+	if err != nil {
+		repo.logger.Errorw("error in marking tool entry deleted by id", "err", err, "id", id)
+		return err
+	}
+	return nil
+}
+func (repo *ScanToolMetadataRepositoryImpl) FindAllActiveTools() ([]*ScanToolMetadata, error) {
+	var models []*ScanToolMetadata
+	err := repo.dbConnection.Model(&models).Where("active = ?", true).
+		Where("deleted = ?", false).Select()
+	if err != nil {
+		repo.logger.Errorw("error in getting active tool for scan target", "err", err)
+		return nil, err
+	}
+	return models, nil
+
+}
+func (repo *ScanToolMetadataRepositoryImpl) MarkToolAsActive(toolName, version string, tx *pg.Tx) error {
+	model := &ScanToolMetadata{}
+	_, err := tx.Model(model).Set("active = ?", true).Where("name = ?", toolName).Where("version = ?", version).Update()
+
+	if err != nil {
+		repo.logger.Errorw("error in marking tool active for scan target", "err", err)
+		return err
+	}
+	return nil
+}
+func (repo *ScanToolMetadataRepositoryImpl) MarkOtherToolsInActive(toolName string, tx *pg.Tx, version string) error {
+	model := &ScanToolMetadata{}
+	_, err := tx.Model(model).Set("active = ?", false).Where("name != ?", toolName).Where("version != ?", version).Update()
+
+	if err != nil {
+		repo.logger.Errorw("error in marking tool active for scan target", "err", err)
+		return err
+	}
+	return nil
+}
+func (repo *ScanToolMetadataRepositoryImpl) FindActiveTool() (*ScanToolMetadata, error) {
+	var model *ScanToolMetadata
+	err := repo.dbConnection.Model(&model).Where("active = ?", true).
+		Where("deleted = ?", false).Select()
+	if err != nil {
+		repo.logger.Errorw("error in getting active tool for scan target", "err", err)
+		return nil, err
+	}
+	return model, nil
+
+}
diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go
index e177a93b6..e194ed9a9 100644
--- a/pkg/app/AppService.go
+++ b/pkg/app/AppService.go
@@ -2450,7 +2450,12 @@ func (impl *AppServiceImpl) MarkImageScanDeployed(appId int, envId int, imageDig
 			impl.logger.Errorw("error in creating deploy info", "err", err)
 		}
 	} else {
-		impl.logger.Debugw("pt", "ot", ot)
+		// Updating Execution history for Latest Deployment to fetch out security Vulnerabilities for latest deployed info
+		ot.ImageScanExecutionHistoryId = ids
+		err = impl.imageScanDeployInfoRepository.Update(ot)
+		if err != nil {
+			impl.logger.Errorw("error in updating deploy info for latest deployed image", "err", err)
+		}
 	}
 	return err
 }
diff --git a/pkg/module/Bean.go b/pkg/module/Bean.go
index f2a33a6c6..6aabe2b2c 100644
--- a/pkg/module/Bean.go
+++ b/pkg/module/Bean.go
@@ -27,6 +27,8 @@ type ModuleInfoDto struct {
 	Name                  string                     `json:"name,notnull"`
 	Status                string                     `json:"status,notnull" validate:"oneof=notInstalled installed installing installFailed timeout"`
 	ModuleResourcesStatus []*ModuleResourceStatusDto `json:"moduleResourcesStatus"`
+	Enabled               bool                       `json:"enabled"`
+	Moduletype            string                     `json:"moduleType,omitempty"`
 }
 
 type ModuleConfigDto struct {
@@ -38,7 +40,11 @@ type BlobStorageConfig struct {
 }
 
 type ModuleActionRequestDto struct {
-	Action  string `json:"action,notnull" validate:"oneof=install"`
+	Action     string `json:"action,notnull" validate:"oneof=install"`
+	Version    string `json:"version,notnull"`
+	ModuleType string `json:"moduleType"`
+}
+type ModuleEnableRequestDto struct {
 	Version string `json:"version,notnull"`
 }
 
@@ -75,6 +81,11 @@ type ModuleName = string
 
 const BlobStorage = "blob-storage"
 const INSTALLER_MODULES_HELM_KEY = "installer.modules"
+const (
+	CLAIR_V4 = "V4"
+	CLAIR_V2 = "V2"
+	TRIVY_V1 = "V1"
+)
 
 const (
 	ModuleStatusNotInstalled  ModuleStatus = "notInstalled"
@@ -90,6 +101,11 @@ const (
 	ModuleNameSecurityClair     ModuleName = "security.clair"
 	ModuleNameNotification      ModuleName = "notifier"
 	ModuleNameMonitoringGrafana ModuleName = "monitoring.grafana"
+	ModuleNameSecurityTrivy     ModuleName = "security.trivy"
+)
+
+const (
+	MODULE_TYPE_SECURITY string = "security"
 )
 
 var SupportedModuleNamesListFirstReleaseExcludingCicd = []string{ModuleNameArgoCd, ModuleNameSecurityClair, ModuleNameNotification, ModuleNameMonitoringGrafana}
diff --git a/pkg/module/ModuleService.go b/pkg/module/ModuleService.go
index f539b2855..fbced4fa2 100644
--- a/pkg/module/ModuleService.go
+++ b/pkg/module/ModuleService.go
@@ -22,6 +22,7 @@ import (
 	"errors"
 	"github.com/caarlos0/env/v6"
 	client "github.com/devtron-labs/devtron/api/helm-app"
+	"github.com/devtron-labs/devtron/internal/sql/repository/security"
 	moduleRepo "github.com/devtron-labs/devtron/pkg/module/repo"
 	moduleUtil "github.com/devtron-labs/devtron/pkg/module/util"
 	"github.com/devtron-labs/devtron/pkg/server"
@@ -33,6 +34,7 @@ import (
 	"github.com/tidwall/gjson"
 	"go.uber.org/zap"
 	"reflect"
+	"strings"
 	"time"
 )
 
@@ -41,6 +43,7 @@ type ModuleService interface {
 	GetModuleConfig(name string) (*ModuleConfigDto, error)
 	HandleModuleAction(userId int32, moduleName string, moduleActionRequest *ModuleActionRequestDto) (*ActionResponse, error)
 	GetAllModuleInfo() ([]ModuleInfoDto, error)
+	EnableModule(moduleName, version string) (*ActionResponse, error)
 }
 
 type ModuleServiceImpl struct {
@@ -57,11 +60,12 @@ type ModuleServiceImpl struct {
 	moduleCronService              ModuleCronService
 	moduleServiceHelper            ModuleServiceHelper
 	moduleResourceStatusRepository moduleRepo.ModuleResourceStatusRepository
+	scanToolMetaDataRepository     security.ScanToolMetadataRepository
 }
 
 func NewModuleServiceImpl(logger *zap.SugaredLogger, serverEnvConfig *serverEnvConfig.ServerEnvConfig, moduleRepository moduleRepo.ModuleRepository,
 	moduleActionAuditLogRepository ModuleActionAuditLogRepository, helmAppService client.HelmAppService, serverDataStore *serverDataStore.ServerDataStore, serverCacheService server.ServerCacheService, moduleCacheService ModuleCacheService, moduleCronService ModuleCronService,
-	moduleServiceHelper ModuleServiceHelper, moduleResourceStatusRepository moduleRepo.ModuleResourceStatusRepository) *ModuleServiceImpl {
+	moduleServiceHelper ModuleServiceHelper, moduleResourceStatusRepository moduleRepo.ModuleResourceStatusRepository, scantoolMetaDataRepository security.ScanToolMetadataRepository) *ModuleServiceImpl {
 	return &ModuleServiceImpl{
 		logger:                         logger,
 		serverEnvConfig:                serverEnvConfig,
@@ -74,6 +78,7 @@ func NewModuleServiceImpl(logger *zap.SugaredLogger, serverEnvConfig *serverEnvC
 		moduleCronService:              moduleCronService,
 		moduleServiceHelper:            moduleServiceHelper,
 		moduleResourceStatusRepository: moduleResourceStatusRepository,
+		scanToolMetaDataRepository:     scantoolMetaDataRepository,
 	}
 }
 
@@ -88,11 +93,12 @@ func (impl ModuleServiceImpl) GetModuleInfo(name string) (*ModuleInfoDto, error)
 	module, err := impl.moduleRepository.FindOne(name)
 	if err != nil {
 		if err == pg.ErrNoRows {
-			status, err := impl.handleModuleNotFoundStatus(name)
+			status, moduleType, err := impl.handleModuleNotFoundStatus(name)
 			if err != nil {
 				impl.logger.Errorw("error in handling module not found status ", "name", name, "err", err)
 			}
 			moduleInfoDto.Status = status
+			moduleInfoDto.Moduletype = moduleType
 			return moduleInfoDto, err
 		}
 		// otherwise some error case
@@ -111,10 +117,21 @@ func (impl ModuleServiceImpl) GetModuleInfo(name string) (*ModuleInfoDto, error)
 			return nil, err
 		}
 	}
-
+	// Handling for previous Modules
+	flagForEnablingState := false
+	if module.ModuleType != MODULE_TYPE_SECURITY && module.Status == ModuleStatusInstalled {
+		flagForEnablingState = true
+		err = impl.moduleRepository.MarkModuleAsEnabled(name)
+		if err != nil {
+			impl.logger.Errorw("error in updating module as active ", "moduleName", name, "err", err)
+			return nil, err
+		}
+	}
 	// send DB status
 	moduleInfoDto.Status = module.Status
-
+	// Enabled State Assignment
+	moduleInfoDto.Enabled = module.Enabled || flagForEnablingState
+	moduleInfoDto.Moduletype = module.ModuleType
 	// handle module resources status data
 	moduleId := module.Id
 	moduleResourcesStatusFromDb, err := impl.moduleResourceStatusRepository.FindAllActiveByModuleId(moduleId)
@@ -150,7 +167,7 @@ func (impl ModuleServiceImpl) GetModuleConfig(name string) (*ModuleConfigDto, er
 	return moduleConfig, nil
 }
 
-func (impl ModuleServiceImpl) handleModuleNotFoundStatus(moduleName string) (ModuleStatus, error) {
+func (impl ModuleServiceImpl) handleModuleNotFoundStatus(moduleName string) (ModuleStatus, string, error) {
 	// if entry is not found in database, then check if that module is legacy or not
 	// if enterprise user -> if legacy -> then mark as installed in db and return as installed, if not legacy -> return as not installed
 	// if non-enterprise user->  fetch helm release enable Key. if true -> then mark as installed in db and return as installed. if false ->
@@ -160,26 +177,42 @@ func (impl ModuleServiceImpl) handleModuleNotFoundStatus(moduleName string) (Mod
 	moduleMetaData, err := impl.moduleServiceHelper.GetModuleMetadata(moduleName)
 	if err != nil {
 		impl.logger.Errorw("Error in getting module metadata", "moduleName", moduleName, "err", err)
-		return ModuleStatusNotInstalled, err
+		return ModuleStatusNotInstalled, "", err
 	}
 	moduleMetaDataStr := string(moduleMetaData)
 	isLegacyModule := gjson.Get(moduleMetaDataStr, "result.isIncludedInLegacyFullPackage").Bool()
 	baseMinVersionSupported := gjson.Get(moduleMetaDataStr, "result.baseMinVersionSupported").String()
+	moduleType := gjson.Get(moduleMetaDataStr, "result.moduleType").String()
+
+	flagForEnablingState := false
+	if moduleType == MODULE_TYPE_SECURITY {
+		err = impl.moduleRepository.FindByModuleTypeAndStatus(moduleType, ModuleStatusInstalled)
+		if err != nil {
+			if err == pg.ErrNoRows {
+				flagForEnablingState = true
+			} else {
+				impl.logger.Errorw("error in getting module by type", "moduleName", moduleName, "err", err)
+				return ModuleStatusNotInstalled, moduleType, err
+			}
+		}
+	} else {
+		flagForEnablingState = true
+	}
 
 	// for enterprise user
 	if impl.serverEnvConfig.DevtronInstallationType == serverBean.DevtronInstallationTypeEnterprise {
 		if isLegacyModule {
-			return impl.saveModuleAsInstalled(moduleName)
+			status, err := impl.saveModuleAsInstalled(moduleName, moduleType, flagForEnablingState)
+			return status, moduleType, err
 		}
-		return ModuleStatusNotInstalled, nil
+		return ModuleStatusNotInstalled, moduleType, nil
 	}
-
 	// for non-enterprise user
 	devtronHelmAppIdentifier := impl.helmAppService.GetDevtronHelmAppIdentifier()
 	releaseInfo, err := impl.helmAppService.GetValuesYaml(context.Background(), devtronHelmAppIdentifier)
 	if err != nil {
 		impl.logger.Errorw("Error in getting values yaml for devtron operator helm release", "moduleName", moduleName, "err", err)
-		return ModuleStatusNotInstalled, err
+		return ModuleStatusNotInstalled, moduleType, err
 	}
 	releaseValues := releaseInfo.MergedValues
 
@@ -187,7 +220,8 @@ func (impl ModuleServiceImpl) handleModuleNotFoundStatus(moduleName string) (Mod
 	if moduleName != ModuleNameCicd {
 		isEnabled := gjson.Get(releaseValues, moduleUtil.BuildModuleEnableKey(moduleName)).Bool()
 		if isEnabled {
-			return impl.saveModuleAsInstalled(moduleName)
+			status, err := impl.saveModuleAsInstalled(moduleName, moduleType, flagForEnablingState)
+			return status, moduleType, err
 		}
 	} else if util2.IsBaseStack() {
 		// check if cicd is in installing state
@@ -199,7 +233,8 @@ func (impl ModuleServiceImpl) handleModuleNotFoundStatus(moduleName string) (Mod
 				installerModules := installerModulesIface.([]interface{})
 				for _, installerModule := range installerModules {
 					if installerModule == moduleName {
-						return impl.saveModule(moduleName, ModuleStatusInstalling)
+						status, err := impl.saveModule(moduleName, ModuleStatusInstalling, moduleType, flagForEnablingState)
+						return status, moduleType, err
 					}
 				}
 			} else {
@@ -215,30 +250,31 @@ func (impl ModuleServiceImpl) handleModuleNotFoundStatus(moduleName string) (Mod
 				cicdModule, err := impl.moduleRepository.FindOne(ModuleNameCicd)
 				if err != nil {
 					if err == pg.ErrNoRows {
-						return ModuleStatusNotInstalled, nil
+						return ModuleStatusNotInstalled, moduleType, nil
 					} else {
 						impl.logger.Errorw("Error in getting cicd module from DB", "err", err)
-						return ModuleStatusNotInstalled, err
+						return ModuleStatusNotInstalled, moduleType, err
 					}
 				}
 				cicdVersion := cicdModule.Version
 				// if cicd was installed and any module/integration comes after that then mark that module installed only if cicd was installed before that module introduction
 				if len(baseMinVersionSupported) > 0 && cicdVersion < baseMinVersionSupported {
-					return impl.saveModuleAsInstalled(moduleName)
+					status, err := impl.saveModuleAsInstalled(moduleName, moduleType, flagForEnablingState)
+					return status, moduleType, err
 				}
 				break
 			}
 		}
 	}
 
-	return ModuleStatusNotInstalled, nil
+	return ModuleStatusNotInstalled, moduleType, nil
 
 }
 
 func (impl ModuleServiceImpl) HandleModuleAction(userId int32, moduleName string, moduleActionRequest *ModuleActionRequestDto) (*ActionResponse, error) {
 	impl.logger.Debugw("handling module action request", "moduleName", moduleName, "userId", userId, "payload", moduleActionRequest)
 
-	// check if can update server
+	//check if can update server
 	if impl.serverEnvConfig.DevtronInstallationType != serverBean.DevtronInstallationTypeOssHelm {
 		return nil, errors.New("module installation is not allowed")
 	}
@@ -291,15 +327,59 @@ func (impl ModuleServiceImpl) HandleModuleAction(userId int32, moduleName string
 	module.Status = ModuleStatusInstalling
 	module.Version = moduleActionRequest.Version
 	module.UpdatedOn = time.Now()
+	tx, err := impl.moduleRepository.GetConnection().Begin()
+	if err != nil {
+		impl.logger.Errorw("error in  opening an transaction", "err", err)
+		return nil, err
+	}
+	defer tx.Rollback()
+	flagForEnablingState := false
+	if moduleActionRequest.ModuleType == MODULE_TYPE_SECURITY {
+		res := strings.Split(moduleName, ".")
+		if len(res) < 2 {
+			impl.logger.Errorw("error in getting toolname from module name as len is less than 2", "err", err, "moduleName", moduleName)
+			return nil, errors.New("error in getting tool name from module name as len is less than 2")
+		}
+		toolName := strings.ToUpper(res[1])
+		// Finding the Module by type and status, if no module exists of current type marking current module as active and enabled by default.
+		err = impl.moduleRepository.FindByModuleTypeAndStatus(moduleActionRequest.ModuleType, ModuleStatusInstalled)
+		if err != nil {
+			if err == pg.ErrNoRows {
+				var toolversion string
+				if moduleName == ModuleNameSecurityClair {
+					// Handled for V4 for CLAIR as we are not using CLAIR V2 anymore.
+					toolversion = CLAIR_V4
+				} else if moduleName == ModuleNameSecurityTrivy {
+					toolversion = TRIVY_V1
+				}
+				err2 := impl.scanToolMetaDataRepository.MarkToolAsActive(toolName, toolversion, tx)
+				if err2 != nil {
+					impl.logger.Errorw("error in marking tool as active ", "err", err2)
+					return nil, err2
+				}
+				flagForEnablingState = true
+			} else {
+				impl.logger.Errorw("error in getting module by type", "moduleName", moduleName, "err", err)
+				return nil, err
+			}
+		}
+	} else {
+		flagForEnablingState = true
+	}
+	module.ModuleType = moduleActionRequest.ModuleType
 	if moduleFound {
-		err = impl.moduleRepository.Update(module)
+		err = impl.moduleRepository.UpdateWithTransaction(module, tx)
 	} else {
-		err = impl.moduleRepository.Save(module)
+		err = impl.moduleRepository.SaveWithTransaction(module, tx)
 	}
 	if err != nil {
 		impl.logger.Errorw("error in saving/updating module ", "moduleName", moduleName, "err", err)
 		return nil, err
 	}
+	err = tx.Commit()
+	if err != nil {
+		return nil, err
+	}
 
 	// HELM_OPERATION Starts
 	devtronHelmAppIdentifier := impl.helmAppService.GetDevtronHelmAppIdentifier()
@@ -343,22 +423,84 @@ func (impl ModuleServiceImpl) HandleModuleAction(userId int32, moduleName string
 		return nil, errors.New("success is false from helm")
 	}
 	// HELM_OPERATION Ends
+	if flagForEnablingState {
+		err = impl.moduleRepository.MarkModuleAsEnabled(moduleName)
+		if err != nil {
+			impl.logger.Errorw("error in updating module as active ", "moduleName", moduleName, "err", err)
+			return nil, err
+		}
+	}
+	return &ActionResponse{
+		Success: true,
+	}, nil
+}
+func (impl ModuleServiceImpl) EnableModule(moduleName, version string) (*ActionResponse, error) {
+	if impl.serverEnvConfig.DevtronInstallationType != serverBean.DevtronInstallationTypeOssHelm {
+		return nil, errors.New("module Enabling is not allowed")
+	}
 
+	// get module by name
+	module, err := impl.moduleRepository.FindOne(moduleName)
+	if err != nil {
+		impl.logger.Errorw("error in getting module ", "moduleName", moduleName, "err", err)
+		return nil, err
+	}
+	dbConnection := impl.moduleRepository.GetConnection()
+	tx, err := dbConnection.Begin()
+	if err != nil {
+		return nil, err
+	}
+	defer tx.Rollback()
+	res := strings.Split(moduleName, ".")
+	// Handling for future tools if integrated
+	if len(res) < 2 {
+		impl.logger.Errorw("error in getting toolName from modulename as module Length is smaller than 2")
+		return nil, errors.New("error in getting tool name from module name as len is less than 2")
+	}
+	// Extracting out toolName for security module for now
+	toolName := strings.ToUpper(res[1])
+	err = impl.moduleRepository.MarkModuleAsEnabledWithTransaction(moduleName, tx)
+	if err != nil {
+		impl.logger.Errorw("error in updating module as active ", "moduleName", moduleName, "err", err, "moduleName", module.Name)
+		return nil, err
+	}
+	err = impl.scanToolMetaDataRepository.MarkToolAsActive(toolName, version, tx)
+	if err != nil {
+		impl.logger.Errorw("error in marking tool as active ", "err", err, "moduleName", module.Name)
+		return nil, err
+	}
+	err = impl.scanToolMetaDataRepository.MarkOtherToolsInActive(toolName, tx, version)
+	if err != nil {
+		impl.logger.Errorw("error in marking other tools inactive ", "err", err, "moduleName", module.Name)
+		return nil, err
+	}
+	// Currently Supporting one tool at a time
+	err = impl.moduleRepository.MarkOtherModulesDisabledOfSameType(moduleName, module.ModuleType, tx)
+	if err != nil {
+		impl.logger.Errorw("error in marking other modules of same module type inactive ", "err", err, "moduleName", module.Name)
+		return nil, err
+	}
+	err = tx.Commit()
+	if err != nil {
+		return nil, err
+	}
 	return &ActionResponse{
 		Success: true,
 	}, nil
 }
 
-func (impl ModuleServiceImpl) saveModuleAsInstalled(moduleName string) (ModuleStatus, error) {
-	return impl.saveModule(moduleName, ModuleStatusInstalled)
+func (impl ModuleServiceImpl) saveModuleAsInstalled(moduleName string, moduleType string, moduleEnabled bool) (ModuleStatus, error) {
+	return impl.saveModule(moduleName, ModuleStatusInstalled, moduleType, moduleEnabled)
 }
 
-func (impl ModuleServiceImpl) saveModule(moduleName string, moduleStatus ModuleStatus) (ModuleStatus, error) {
+func (impl ModuleServiceImpl) saveModule(moduleName string, moduleStatus ModuleStatus, moduleType string, moduleEnabled bool) (ModuleStatus, error) {
 	module := &moduleRepo.Module{
-		Name:      moduleName,
-		Version:   impl.serverDataStore.CurrentVersion,
-		Status:    moduleStatus,
-		UpdatedOn: time.Now(),
+		Name:       moduleName,
+		Version:    impl.serverDataStore.CurrentVersion,
+		Status:     moduleStatus,
+		UpdatedOn:  time.Now(),
+		ModuleType: moduleType,
+		Enabled:    moduleEnabled,
 	}
 	err := impl.moduleRepository.Save(module)
 	if err != nil {
@@ -384,9 +526,21 @@ func (impl ModuleServiceImpl) GetAllModuleInfo() ([]ModuleInfoDto, error) {
 	// now this is the case when data found in DB
 	for _, module := range modules {
 		moduleInfoDto := ModuleInfoDto{
-			Name:   module.Name,
-			Status: module.Status,
+			Name:       module.Name,
+			Status:     module.Status,
+			Moduletype: module.ModuleType,
+			Enabled:    module.Enabled,
+		}
+		enabled := false
+		if module.ModuleType != MODULE_TYPE_SECURITY && module.Status == ModuleStatusInstalled {
+			module.Enabled = true
+			enabled = true
+			err := impl.moduleRepository.Update(&module)
+			if err != nil {
+				impl.logger.Errorw("error in updating installed module to enabled for previous modules", "err", err, "module", module.Name)
+			}
 		}
+		moduleInfoDto.Enabled = enabled || module.Enabled
 		moduleId := module.Id
 		moduleResourcesStatusFromDb, err := impl.moduleResourceStatusRepository.FindAllActiveByModuleId(moduleId)
 		if err != nil && err != pg.ErrNoRows {
diff --git a/pkg/module/repo/ModuleRepository.go b/pkg/module/repo/ModuleRepository.go
index 92972deed..9b18e4f03 100644
--- a/pkg/module/repo/ModuleRepository.go
+++ b/pkg/module/repo/ModuleRepository.go
@@ -23,12 +23,14 @@ import (
 )
 
 type Module struct {
-	tableName struct{}  `sql:"module"`
-	Id        int       `sql:"id,pk"`
-	Name      string    `sql:"name, notnull"`
-	Version   string    `sql:"version, notnull"`
-	Status    string    `sql:"status,notnull"`
-	UpdatedOn time.Time `sql:"updated_on"`
+	tableName  struct{}  `sql:"module"`
+	Id         int       `sql:"id,pk"`
+	Name       string    `sql:"name, notnull"`
+	Version    string    `sql:"version, notnull"`
+	Status     string    `sql:"status,notnull"`
+	UpdatedOn  time.Time `sql:"updated_on"`
+	Enabled    bool      `sql:"enabled"`
+	ModuleType string    `sql:"module_type"`
 }
 
 type ModuleRepository interface {
@@ -38,12 +40,23 @@ type ModuleRepository interface {
 	FindAll() ([]Module, error)
 	ModuleExists() (bool, error)
 	GetInstalledModuleNames() ([]string, error)
+	FindByModuleTypeAndStatus(moduleType string, status string) error
+	MarkModuleAsEnabledWithTransaction(moduleName string, tx *pg.Tx) error
+	GetConnection() (dbConnection *pg.DB)
+	MarkOtherModulesDisabledOfSameType(moduleName, moduleType string, tx *pg.Tx) error
+	UpdateWithTransaction(module *Module, tx *pg.Tx) error
+	SaveWithTransaction(module *Module, tx *pg.Tx) error
+	MarkModuleAsEnabled(moduleName string) error
 }
 
 type ModuleRepositoryImpl struct {
 	dbConnection *pg.DB
 }
 
+func (impl ModuleRepositoryImpl) GetConnection() (dbConnection *pg.DB) {
+	return impl.dbConnection
+}
+
 func NewModuleRepositoryImpl(dbConnection *pg.DB) *ModuleRepositoryImpl {
 	return &ModuleRepositoryImpl{dbConnection: dbConnection}
 }
@@ -52,6 +65,10 @@ func (impl ModuleRepositoryImpl) Save(module *Module) error {
 	return impl.dbConnection.Insert(module)
 }
 
+func (impl ModuleRepositoryImpl) SaveWithTransaction(module *Module, tx *pg.Tx) error {
+	return tx.Insert(module)
+}
+
 func (impl ModuleRepositoryImpl) FindOne(name string) (*Module, error) {
 	module := &Module{}
 	err := impl.dbConnection.Model(module).
@@ -63,6 +80,9 @@ func (impl ModuleRepositoryImpl) Update(module *Module) error {
 	return impl.dbConnection.Update(module)
 }
 
+func (impl ModuleRepositoryImpl) UpdateWithTransaction(module *Module, tx *pg.Tx) error {
+	return tx.Update(module)
+}
 func (impl ModuleRepositoryImpl) FindAllByStatus(status string) ([]Module, error) {
 	var modules []Module
 	err := impl.dbConnection.Model(&modules).
@@ -97,3 +117,29 @@ func (impl ModuleRepositoryImpl) GetInstalledModuleNames() ([]string, error) {
 	}
 	return moduleNames, nil
 }
+
+func (impl ModuleRepositoryImpl) FindByModuleTypeAndStatus(moduleType string, status string) error {
+	module := &Module{}
+	err := impl.dbConnection.Model(module).
+		Where("module_type = ?", moduleType).
+		Where("status = ?", status).
+		Select()
+	return err
+}
+
+func (impl ModuleRepositoryImpl) MarkModuleAsEnabledWithTransaction(moduleName string, tx *pg.Tx) error {
+	module := &Module{}
+	_, err := tx.Model(module).Set("enabled = ?", true).Where("name = ?", moduleName).Update()
+	return err
+}
+func (impl ModuleRepositoryImpl) MarkModuleAsEnabled(moduleName string) error {
+	module := &Module{}
+	_, err := impl.dbConnection.Model(module).Set("enabled = ?", true).Where("name = ?", moduleName).Update()
+	return err
+}
+
+func (impl ModuleRepositoryImpl) MarkOtherModulesDisabledOfSameType(moduleName, moduleType string, tx *pg.Tx) error {
+	module := &Module{}
+	_, err := tx.Model(module).Set("enabled = ?", false).Where("name != ?", moduleName).Where("module_type = ?", moduleType).Update()
+	return err
+}
diff --git a/pkg/security/ImageScanService.go b/pkg/security/ImageScanService.go
index 9a7ed9a5a..47b138666 100644
--- a/pkg/security/ImageScanService.go
+++ b/pkg/security/ImageScanService.go
@@ -41,20 +41,22 @@ type ImageScanService interface {
 }
 
 type ImageScanServiceImpl struct {
-	Logger                        *zap.SugaredLogger
-	scanHistoryRepository         security.ImageScanHistoryRepository
-	scanResultRepository          security.ImageScanResultRepository
-	scanObjectMetaRepository      security.ImageScanObjectMetaRepository
-	cveStoreRepository            security.CveStoreRepository
-	imageScanDeployInfoRepository security.ImageScanDeployInfoRepository
-	userService                   user.UserService
-	teamRepository                repository2.TeamRepository
-	appRepository                 repository1.AppRepository
-	envService                    cluster.EnvironmentService
-	ciArtifactRepository          repository.CiArtifactRepository
-	policyService                 PolicyService
-	pipelineRepository            pipelineConfig.PipelineRepository
-	ciPipelineRepository          pipelineConfig.CiPipelineRepository
+	Logger                                    *zap.SugaredLogger
+	scanHistoryRepository                     security.ImageScanHistoryRepository
+	scanResultRepository                      security.ImageScanResultRepository
+	scanObjectMetaRepository                  security.ImageScanObjectMetaRepository
+	cveStoreRepository                        security.CveStoreRepository
+	imageScanDeployInfoRepository             security.ImageScanDeployInfoRepository
+	userService                               user.UserService
+	teamRepository                            repository2.TeamRepository
+	appRepository                             repository1.AppRepository
+	envService                                cluster.EnvironmentService
+	ciArtifactRepository                      repository.CiArtifactRepository
+	policyService                             PolicyService
+	pipelineRepository                        pipelineConfig.PipelineRepository
+	ciPipelineRepository                      pipelineConfig.CiPipelineRepository
+	scanToolMetaDataRepository                security.ScanToolMetadataRepository
+	scanToolExecutionHistoryMappingRepository security.ScanToolExecutionHistoryMappingRepository
 }
 
 type ImageScanRequest struct {
@@ -103,6 +105,7 @@ type ImageScanExecutionDetail struct {
 	ScanEnabled           bool               `json:"scanEnabled,notnull"`
 	Scanned               bool               `json:"scanned,notnull"`
 	ObjectType            string             `json:"objectType,notnull"`
+	ScanToolId            int                `json:"scanToolId,omitempty""`
 }
 
 type Vulnerabilities struct {
@@ -126,18 +129,20 @@ func NewImageScanServiceImpl(Logger *zap.SugaredLogger, scanHistoryRepository se
 	userService user.UserService, teamRepository repository2.TeamRepository,
 	appRepository repository1.AppRepository,
 	envService cluster.EnvironmentService, ciArtifactRepository repository.CiArtifactRepository, policyService PolicyService,
-	pipelineRepository pipelineConfig.PipelineRepository, ciPipelineRepository pipelineConfig.CiPipelineRepository) *ImageScanServiceImpl {
+	pipelineRepository pipelineConfig.PipelineRepository, ciPipelineRepository pipelineConfig.CiPipelineRepository, scanToolMetaDataRepository security.ScanToolMetadataRepository, scanToolExecutionHistoryMappingRepository security.ScanToolExecutionHistoryMappingRepository) *ImageScanServiceImpl {
 	return &ImageScanServiceImpl{Logger: Logger, scanHistoryRepository: scanHistoryRepository, scanResultRepository: scanResultRepository,
 		scanObjectMetaRepository: scanObjectMetaRepository, cveStoreRepository: cveStoreRepository,
-		imageScanDeployInfoRepository: imageScanDeployInfoRepository,
-		userService:                   userService,
-		teamRepository:                teamRepository,
-		appRepository:                 appRepository,
-		envService:                    envService,
-		ciArtifactRepository:          ciArtifactRepository,
-		policyService:                 policyService,
-		pipelineRepository:            pipelineRepository,
-		ciPipelineRepository:          ciPipelineRepository,
+		imageScanDeployInfoRepository:             imageScanDeployInfoRepository,
+		userService:                               userService,
+		teamRepository:                            teamRepository,
+		appRepository:                             appRepository,
+		envService:                                envService,
+		ciArtifactRepository:                      ciArtifactRepository,
+		policyService:                             policyService,
+		pipelineRepository:                        pipelineRepository,
+		ciPipelineRepository:                      ciPipelineRepository,
+		scanToolMetaDataRepository:                scanToolMetaDataRepository,
+		scanToolExecutionHistoryMappingRepository: scanToolExecutionHistoryMappingRepository,
 	}
 }
 
@@ -373,6 +378,16 @@ func (impl ImageScanServiceImpl) FetchExecutionDetailResult(request *ImageScanRe
 			}
 			executionTime = item.ImageScanExecutionHistory.ExecutionTime
 		}
+		if len(imageScanResult) > 0 {
+			imageScanResponse.ScanToolId = imageScanResult[0].ScanToolId
+		} else {
+			toolIdFromExecutionHistory, err := impl.getScanToolIdFromExecutionHistory(scanExecutionIds)
+			if err != nil || toolIdFromExecutionHistory == -1 {
+				impl.Logger.Errorw("error in getting scan tool id from exection history", "err", err, "")
+				return nil, err
+			}
+			imageScanResponse.ScanToolId = toolIdFromExecutionHistory
+		}
 	}
 	severityCount := &SeverityCount{
 		High:     highCount,
@@ -462,7 +477,7 @@ func (impl ImageScanServiceImpl) FetchMinScanResultByAppIdAndEnvId(request *Imag
 	}
 	scanExecutionIds = append(scanExecutionIds, scanDeployInfo.ImageScanExecutionHistoryId...)
 
-	var highCount, moderateCount, lowCount int
+	var highCount, moderateCount, lowCount, scantoolId int
 	if len(scanExecutionIds) > 0 {
 		imageScanResult, err := impl.scanResultRepository.FetchByScanExecutionIds(scanExecutionIds)
 		if err != nil {
@@ -479,6 +494,16 @@ func (impl ImageScanServiceImpl) FetchMinScanResultByAppIdAndEnvId(request *Imag
 				lowCount = lowCount + 1
 			}
 		}
+		if len(imageScanResult) > 0 {
+			scantoolId = imageScanResult[0].ScanToolId
+		} else {
+			toolIdFromExecutionHistory, err := impl.getScanToolIdFromExecutionHistory(scanExecutionIds)
+			if err != nil || toolIdFromExecutionHistory == -1 {
+				impl.Logger.Errorw("error in getting scan tool id from exection history", "err", err, "")
+				return nil, err
+			}
+			scantoolId = toolIdFromExecutionHistory
+		}
 	}
 	severityCount := &SeverityCount{
 		High:     highCount,
@@ -492,9 +517,25 @@ func (impl ImageScanServiceImpl) FetchMinScanResultByAppIdAndEnvId(request *Imag
 		ObjectType:            scanDeployInfo.ObjectType,
 		ScanEnabled:           true,
 		Scanned:               true,
+		ScanToolId:            scantoolId,
 	}
 	return imageScanResponse, nil
 }
+func (impl ImageScanServiceImpl) getScanToolIdFromExecutionHistory(scanExecutionIds []int) (int, error) {
+	scanToolHistoryMappings, err := impl.scanToolExecutionHistoryMappingRepository.GetAllScanHistoriesByExecutionHistoryIds(scanExecutionIds)
+	if err != nil {
+		if err == pg.ErrNoRows {
+			impl.Logger.Errorw("got no rows for scanToolHistoryMappings", "err", err)
+		} else {
+			impl.Logger.Errorw("error in getting scanToolHistoryMappings", "err", err)
+			return -1, err
+		}
+	}
+	if len(scanToolHistoryMappings) > 0 {
+		return scanToolHistoryMappings[0].ScanToolId, nil
+	}
+	return -1, err
+}
 
 func (impl ImageScanServiceImpl) VulnerabilityExposure(request *security.VulnerabilityRequest) (*security.VulnerabilityExposureListingResponse, error) {
 	vulnerabilityExposureListingResponse := &security.VulnerabilityExposureListingResponse{
diff --git a/pkg/server/bean/Bean.go b/pkg/server/bean/Bean.go
index 7b396ecec..ef548d536 100644
--- a/pkg/server/bean/Bean.go
+++ b/pkg/server/bean/Bean.go
@@ -48,6 +48,14 @@ const (
 	InstallerCrdObjectStatusApplied    InstallerCrdObjectStatus = "Applied"
 )
 
+type ScanExecutionProcessState int
+
+const (
+	ScanExecutionProcessStateFailed    ScanExecutionProcessState = iota - 1 //resolved value = -1
+	ScanExecutionProcessStateRunning                                        //resolved value =  0
+	ScanExecutionProcessStateCompleted                                      //resolved value =  1
+)
+
 type HelmReleaseStatus = string
 
 // Describe the status of a release
diff --git a/scripts/sql/146_helm_package.up.sql b/scripts/sql/146_helm_package.up.sql
index 5e347762c..17018754b 100644
--- a/scripts/sql/146_helm_package.up.sql
+++ b/scripts/sql/146_helm_package.up.sql
@@ -1,2 +1,1 @@
-ALTER TABLE cd_workflow_runner ADD COLUMN helm_reference_chart bytea;
-alter table cluster drop column is_virtual_cluster;
+ALTER TABLE cd_workflow_runner ADD COLUMN helm_reference_chart bytea;
\ No newline at end of file
diff --git a/scripts/sql/147_generic_image_scanning.down.sql b/scripts/sql/147_generic_image_scanning.down.sql
new file mode 100644
index 000000000..158963df3
--- /dev/null
+++ b/scripts/sql/147_generic_image_scanning.down.sql
@@ -0,0 +1,13 @@
+ALTER TABLE public.image_scan_execution_history
+    DROP COLUMN "scan_event_json" ,
+    DROP COLUMN "execution_history_directory_path";
+
+ALTER TABLE public.image_scan_execution_result
+DROP COLUMN "scan_tool_id";
+
+DROP TABLE scan_step_condition_mapping,
+    scan_tool_step,
+    scan_step_condition,
+    scan_tool_execution_history_mapping,
+    scan_tool_metadata,
+    registry_index_mapping;
diff --git a/scripts/sql/147_generic_image_scanning.up.sql b/scripts/sql/147_generic_image_scanning.up.sql
new file mode 100644
index 000000000..c2274dc6d
--- /dev/null
+++ b/scripts/sql/147_generic_image_scanning.up.sql
@@ -0,0 +1,121 @@
+CREATE SEQUENCE IF NOT EXISTS id_seq_scan_tool_metadata;
+
+CREATE TABLE public.scan_tool_metadata
+(
+    "id"                                  integer NOT NULL DEFAULT nextval('id_seq_scan_tool_metadata'::regclass),
+    "name"                                VARCHAR(100),
+    "version"                             VARCHAR(50),
+    "server_base_url"                     VARCHAR(30),
+    "result_descriptor_template"            text,
+    "scan_target"                          VARCHAR(10),
+    "active"                              bool,
+    "deleted"                               bool,
+    "created_on"                          timestamptz,
+    "created_by"                          int4,
+    "updated_on"                          timestamptz,
+    "updated_by"                          int4,
+    "tool_metadata"                         text,
+    PRIMARY KEY ("id")
+);
+
+CREATE SEQUENCE IF NOT EXISTS id_seq_scan_tool_execution_history_mapping;
+
+CREATE TABLE public.scan_tool_execution_history_mapping
+(
+    "id"                             integer NOT NULL DEFAULT nextval('id_seq_scan_tool_execution_history_mapping'::regclass),
+    "image_scan_execution_history_id" integer,
+    "scan_tool_id"             integer,
+    "execution_start_time"           timestamptz,
+    "execution_finish_time"              timestamptz,
+    "state"                            int,
+    "try_count"                         int,
+    "created_on"                     timestamptz,
+    "created_by"                     int4,
+    "updated_on"                     timestamptz,
+    "updated_by"                     int4,
+    PRIMARY KEY ("id"),
+    CONSTRAINT "scan_tool_execution_history_mapping_result_id_fkey" FOREIGN KEY ("image_scan_execution_history_id") REFERENCES "public"."image_scan_execution_history" ("id"),
+    CONSTRAINT "scan_tool_execution_history_mapping_scan_tool_id_fkey" FOREIGN KEY ("scan_tool_id") REFERENCES "public"."scan_tool_metadata" ("id")
+);
+
+CREATE SEQUENCE IF NOT EXISTS id_seq_scan_step_condition;
+
+CREATE TABLE public.scan_step_condition
+(
+    "id"                   integer NOT NULL DEFAULT nextval('id_seq_scan_step_condition'::regclass),
+    "condition_variable_format" VARCHAR(10),
+    "conditional_operator" VARCHAR(5),
+    "conditional_value"    VARCHAR(100),
+    "condition_on"         VARCHAR(20),
+    "deleted"               bool,
+    "created_on"           timestamptz,
+    "created_by"           int4,
+    "updated_on"           timestamptz,
+    "updated_by"           int4,
+    PRIMARY KEY ("id")
+);
+
+CREATE SEQUENCE IF NOT EXISTS id_seq_scan_tool_step;
+
+CREATE TABLE public.scan_tool_step
+(
+    "id"                   integer NOT NULL DEFAULT nextval('id_seq_scan_tool_step'::regclass),
+    "scan_tool_id"   integer,
+    "index"                integer,
+    "step_execution_type"  VARCHAR(10),
+    "step_execution_sync"   bool NOT NULL ,
+    "retry_count"          integer,
+    "execute_step_on_fail" integer,
+    "execute_step_on_pass" integer,
+    "render_input_data_from_step" integer,
+    "http_input_payload"        jsonb,
+    "http_method_type"     VARCHAR(10),
+    "http_req_headers"     jsonb,
+    "http_query_params"    jsonb,
+    "cli_command"            text,
+    "cli_output_type"      VARCHAR(10),
+    "deleted"               bool,
+    "created_on"           timestamptz,
+    "created_by"           int4,
+    "updated_on"           timestamptz,
+    "updated_by"           int4,
+    PRIMARY KEY ("id"),
+    CONSTRAINT "scan_tool_step_scan_tool_id_fkey" FOREIGN KEY ("scan_tool_id") REFERENCES "public"."scan_tool_metadata" ("id")
+
+);
+
+CREATE SEQUENCE IF NOT EXISTS id_seq_scan_step_condition_mapping;
+
+CREATE TABLE public.scan_step_condition_mapping
+(
+    "id"                           integer NOT NULL DEFAULT nextval('id_seq_scan_step_condition_mapping'::regclass),
+    "scan_step_condition_id" integer,
+    "scan_tool_step_id"      integer,
+    "created_on"                   timestamptz,
+    "created_by"                   int4,
+    "updated_on"                   timestamptz,
+    "updated_by"                   int4,
+    PRIMARY KEY ("id"),
+    CONSTRAINT "scan_step_condition_mapping_condition_id_fkey" FOREIGN KEY ("scan_step_condition_id") REFERENCES "public"."scan_step_condition" ("id"),
+    CONSTRAINT "scan_step_condition_mapping_tool_step_id_fkey" FOREIGN KEY ("scan_tool_step_id") REFERENCES "public"."scan_tool_step" ("id")
+
+);
+
+CREATE SEQUENCE IF NOT EXISTS id_registry_index_mapping;
+
+CREATE TABLE public.registry_index_mapping
+(
+    "id"                           integer NOT NULL DEFAULT nextval('id_registry_index_mapping'::regclass),
+    "scan_tool_id"      integer,
+    "registry_type"                   varchar(20),
+    "starting_index"   integer,
+    PRIMARY KEY ("id"),
+    CONSTRAINT "registry_index_mapping_id_fkey" FOREIGN KEY ("scan_tool_id") REFERENCES "public"."scan_tool_metadata" ("id")
+);
+
+ALTER TABLE public.image_scan_execution_history
+    ADD "scan_event_json" text ,
+    ADD "execution_history_directory_path" text;
+
+ALTER TABLE public.image_scan_execution_result
+    ADD "scan_tool_id" int;
\ No newline at end of file
diff --git a/scripts/sql/148_trivy_image_scanning.down.sql b/scripts/sql/148_trivy_image_scanning.down.sql
new file mode 100644
index 000000000..e4b8fb972
--- /dev/null
+++ b/scripts/sql/148_trivy_image_scanning.down.sql
@@ -0,0 +1,7 @@
+ALTER TABLE public.module
+    DROP COLUMN "enabled" ,
+    DROP COLUMN "module_type";
+
+DELETE from public.scan_tool_step CASCADE;
+DELETE from public.registry_index_mapping CASCADE;
+DELETE from public.scan_tool_metadata CASCADE;
\ No newline at end of file
diff --git a/scripts/sql/148_trivy_image_scanning.up.sql b/scripts/sql/148_trivy_image_scanning.up.sql
new file mode 100644
index 000000000..0da5e4854
--- /dev/null
+++ b/scripts/sql/148_trivy_image_scanning.up.sql
@@ -0,0 +1,26 @@
+INSERT INTO public.scan_tool_metadata(name, version, server_base_url, result_descriptor_template, scan_target, active, deleted, created_on, created_by, updated_on, updated_by,tool_metadata) VALUES ('CLAIR','V2',null,null,'IMAGE',false,false,now()::timestamp,'1',now()::timestamp,'1',null),('CLAIR','V4',null,null,'IMAGE',false,false,now()::timestamp,'1',now()::timestamp,'1',null),('TRIVY','V1',null,'[{{$size1:= len .Results}}{{range $i1, $v1 := .Results}}{{ if  $v1.Vulnerabilities}}{{$size2:= len $v1.Vulnerabilities}}{{range $i2, $v2 := $v1.Vulnerabilities}}{{if and (eq $i1 (add $size1 -1)) (eq $i2 (add $size2 -1)) }}
+{
+"package": "{{$v2.PkgName}}",
+"packageVersion": "{{$v2.InstalledVersion}}",
+"fixedInVersion": "{{$v2.FixedVersion}}",
+"severity": "{{$v2.Severity}}",
+"name": "{{$v2.VulnerabilityID}}"
+}{{else}}{
+"package": "{{$v2.PkgName}}",
+"packageVersion": "{{$v2.InstalledVersion}}",
+"fixedInVersion": "{{$v2.FixedVersion}}",
+"severity": "{{$v2.Severity}}",
+"name": "{{$v2.VulnerabilityID}}"
+},{{end}}{{end}}{{end}}{{end}}]' ,'IMAGE',false,false,now()::timestamp,'1',now()::timestamp,'1','{"timeout":"10m"}');
+
+INSERT INTO public.scan_tool_step(scan_tool_id, index, step_execution_type, step_execution_sync, retry_count, execute_step_on_fail, execute_step_on_pass, render_input_data_from_step, http_input_payload, http_method_type, http_req_headers, http_query_params, cli_command, cli_output_type, deleted, created_on, created_by, updated_on, updated_by) VALUES (3,1,'CLI',true,1,-1,-1,-1,null,null,null,null,'trivy image -f json -o {{.OUTPUT_FILE_PATH}} --timeout {{.timeout}} {{.IMAGE_NAME}} --username {{.USERNAME}} --password {{.PASSWORD}}', 'STATIC',false,now()::timestamp,'1',now()::timestamp,'1'),(3,2,'CLI',true,1,-1,-1 ,-1,null,null,null,null,'(export AWS_ACCESS_KEY_ID={{.AWS_ACCESS_KEY_ID}} AWS_SECRET_ACCESS_KEY={{.AWS_SECRET_ACCESS_KEY}} AWS_DEFAULT_REGION={{.AWS_DEFAULT_REGION}}; trivy image -f json -o {{.OUTPUT_FILE_PATH}} --timeout {{.timeout}} {{.IMAGE_NAME}})','STATIC', false,now()::timestamp,'1',now()::timestamp,'1'), (3,3,'CLI',true,1,-1,-1,-1,null,null,null,null,'GOOGLE_APPLICATION_CREDENTIALS="{{.FILE_PATH}}/credentials.json" trivy image -f json -o {{.OUTPUT_FILE_PATH}} --timeout {{.timeout}} {{.IMAGE_NAME}}', 'STATIC',false,now()::timestamp,'1',now()::timestamp,'1'),(3,4,'CLI',true,1,-1,3,-1,null,null,null,null,'echo {{.PASSWORD}} > {{.FILE_PATH}}/credentials.json','STATIC',false,now()::timestamp,'1',now()::timestamp,'1');
+INSERT INTO public.registry_index_mapping(scan_tool_id, registry_type, starting_index) VALUES (3,'ecr',2), (3,'other',1),(3,'artifact-registry',4),( 3,'docker-hub',1), (3,'gcr',4), (3,'acr',1),(3,'quay',1);
+
+ALTER TABLE public.module
+    ADD "module_type" varchar(30),
+    ADD "enabled" bool;
+
+UPDATE public.module SET module_type = 'security',enabled=true where name='security.clair';
+UPDATE public.module SET enabled=true where status='installed';
+UPDATE public.module SET enabled=false where status!='installed';
+UPDATE scan_tool_metadata SET active='true' where id in (SELECT stmd.id FROM module m, scan_tool_metadata stmd where m.name ='security.clair' and m.enabled =true and stmd.name ='CLAIR' and stmd.version='V4');
\ No newline at end of file
diff --git a/wire_gen.go b/wire_gen.go
index e8a1b7106..c9ebcfb6d 100644
--- a/wire_gen.go
+++ b/wire_gen.go
@@ -264,7 +264,8 @@ func InitializeApp() (*App, error) {
 	if err != nil {
 		return nil, err
 	}
-	moduleServiceImpl := module.NewModuleServiceImpl(sugaredLogger, serverEnvConfigServerEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepositoryImpl, helmAppServiceImpl, serverDataStoreServerDataStore, serverCacheServiceImpl, moduleCacheServiceImpl, moduleCronServiceImpl, moduleServiceHelperImpl, moduleResourceStatusRepositoryImpl)
+	scanToolMetadataRepositoryImpl := security.NewScanToolMetadataRepositoryImpl(db, sugaredLogger)
+	moduleServiceImpl := module.NewModuleServiceImpl(sugaredLogger, serverEnvConfigServerEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepositoryImpl, helmAppServiceImpl, serverDataStoreServerDataStore, serverCacheServiceImpl, moduleCacheServiceImpl, moduleCronServiceImpl, moduleServiceHelperImpl, moduleResourceStatusRepositoryImpl, scanToolMetadataRepositoryImpl)
 	eventRESTClientImpl := client.NewEventRESTClientImpl(sugaredLogger, httpClient, eventClientConfig, pubSubClientServiceImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, attributesRepositoryImpl, moduleServiceImpl)
 	cdWorkflowRepositoryImpl := pipelineConfig.NewCdWorkflowRepositoryImpl(db, sugaredLogger)
 	ciWorkflowRepositoryImpl := pipelineConfig.NewCiWorkflowRepositoryImpl(db, sugaredLogger)
@@ -595,7 +596,8 @@ func InitializeApp() (*App, error) {
 	chartGroupRouterImpl := router.NewChartGroupRouterImpl(chartGroupRestHandlerImpl)
 	testSuitRestHandlerImpl := restHandler.NewTestSuitRestHandlerImpl(sugaredLogger, userServiceImpl, validate, enforcerImpl, enforcerUtilImpl, eventClientConfig, httpClient)
 	testSuitRouterImpl := router.NewTestSuitRouterImpl(testSuitRestHandlerImpl)
-	imageScanServiceImpl := security2.NewImageScanServiceImpl(sugaredLogger, imageScanHistoryRepositoryImpl, imageScanResultRepositoryImpl, imageScanObjectMetaRepositoryImpl, cveStoreRepositoryImpl, imageScanDeployInfoRepositoryImpl, userServiceImpl, teamRepositoryImpl, appRepositoryImpl, environmentServiceImpl, ciArtifactRepositoryImpl, policyServiceImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl)
+	scanToolExecutionHistoryMappingRepositoryImpl := security.NewScanToolExecutionHistoryMappingRepositoryImpl(db, sugaredLogger)
+	imageScanServiceImpl := security2.NewImageScanServiceImpl(sugaredLogger, imageScanHistoryRepositoryImpl, imageScanResultRepositoryImpl, imageScanObjectMetaRepositoryImpl, cveStoreRepositoryImpl, imageScanDeployInfoRepositoryImpl, userServiceImpl, teamRepositoryImpl, appRepositoryImpl, environmentServiceImpl, ciArtifactRepositoryImpl, policyServiceImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, scanToolMetadataRepositoryImpl, scanToolExecutionHistoryMappingRepositoryImpl)
 	imageScanRestHandlerImpl := restHandler.NewImageScanRestHandlerImpl(sugaredLogger, imageScanServiceImpl, userServiceImpl, enforcerImpl, enforcerUtilImpl, environmentServiceImpl)
 	imageScanRouterImpl := router.NewImageScanRouterImpl(imageScanRestHandlerImpl)
 	policyRestHandlerImpl := restHandler.NewPolicyRestHandlerImpl(sugaredLogger, policyServiceImpl, userServiceImpl, userAuthServiceImpl, enforcerImpl, enforcerUtilImpl, environmentServiceImpl)


Test patch:
diff --git a/pkg/app/integrationTest/AppService_test.go b/pkg/app/integrationTest/AppService_test.go
index 3f8e9520d..fde479bec 100644
--- a/pkg/app/integrationTest/AppService_test.go
+++ b/pkg/app/integrationTest/AppService_test.go
@@ -135,7 +135,7 @@ func InitAppService() *app2.AppServiceImpl {
 	}
 	helmAppClient := client.NewHelmAppClientImpl(logger, helmClientConfig)
 	helmAppService := client.NewHelmAppServiceImpl(logger, clusterService, helmAppClient, nil, nil, nil, serverEnvConfig, nil, nil, nil, nil, nil, nil, nil, nil)
-	moduleService := module.NewModuleServiceImpl(logger, serverEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepository, helmAppService, nil, nil, nil, nil, nil, nil)
+	moduleService := module.NewModuleServiceImpl(logger, serverEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepository, helmAppService, nil, nil, nil, nil, nil, nil, nil)
 	eventClient := client1.NewEventRESTClientImpl(logger, httpClient, eventClientConfig, pubSubClient, ciPipelineRepositoryImpl,
 		pipelineRepository, attributesRepositoryImpl, moduleService)
 	cdWorkflowRepository := pipelineConfig.NewCdWorkflowRepositoryImpl(dbConnection, logger)