diff --git a/Dockerfile b/Dockerfile index af93dae97c..e64bb95137 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.0 AS build-env +FROM golang:1.24.6 AS build-env RUN echo $GOPATH && \ apt update && \ diff --git a/DockerfileEA b/DockerfileEA index f5d8d34b0b..45beccbf64 100644 --- a/DockerfileEA +++ b/DockerfileEA @@ -1,4 +1,4 @@ -FROM golang:1.24.0 AS build-env +FROM golang:1.24.6 AS build-env RUN echo $GOPATH && \ apt update && \ diff --git a/go.mod b/go.mod index 16ae70f449..f634dfeb3c 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/devtron-labs/devtron -go 1.24.0 +go 1.24.6 -toolchain go1.24.2 +toolchain go1.24.7 require ( github.com/Masterminds/semver v1.5.0 github.com/Pallinder/go-randomdata v1.2.0 - github.com/argoproj/argo-cd/v2 v2.14.13 + github.com/argoproj/argo-cd/v2 v2.14.17 github.com/argoproj/argo-workflows/v3 v3.5.13 github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1 github.com/aws/aws-sdk-go v1.55.7 diff --git a/go.sum b/go.sum index 6d9933c0ee..54d657e660 100644 --- a/go.sum +++ b/go.sum @@ -118,6 +118,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/argoproj/argo-cd/v2 v2.14.13 h1:oSLPHV9Gon6mEqVkyBOuLJ7T16ShZv6xSjkCiquzEDM= github.com/argoproj/argo-cd/v2 v2.14.13/go.mod h1:P72XxcRigWQpQsuAgaXyHPFYkSPE4sdACA5g/s3Si1I= +github.com/argoproj/argo-cd/v2 v2.14.17 h1:r/CkYKzHoPjGgJ/4/fdubUVpG+LBj6AtOigbitNHgy4= +github.com/argoproj/argo-cd/v2 v2.14.17/go.mod h1:CF9GX0CjKiszpAnvYNCLV5tLSVqgfOgn/tcOt2VHTQo= github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1 h1:Ze4U6kV49vSzlUBhH10HkO52bYKAIXS4tHr/MlNDfdU= github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1/go.mod h1:WsnykM8idYRUnneeT31cM/Fq/ZsjkefCbjiD8ioCJkU= github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e h1:kuLQvJqwwRMQTheT4MFyKVM8Txncu21CHT4yBWUl1Mk= diff --git a/internal/sql/repository/AppListingRepository.go b/internal/sql/repository/AppListingRepository.go index 4b780c16a4..7c72caac99 100644 --- a/internal/sql/repository/AppListingRepository.go +++ b/internal/sql/repository/AppListingRepository.go @@ -197,9 +197,9 @@ func (impl *AppListingRepositoryImpl) FetchJobsLastSucceededOn(CiPipelineIDs []i if len(CiPipelineIDs) == 0 { return lastSucceededTimeArray, nil } - jobsLastFinishedOnQuery := impl.appListingRepositoryQueryBuilder.JobsLastSucceededOnTimeQuery(CiPipelineIDs) + jobsLastFinishedOnQuery, queryParams := impl.appListingRepositoryQueryBuilder.JobsLastSucceededOnTimeQuery(CiPipelineIDs) impl.Logger.Debugw("basic app detail query: ", jobsLastFinishedOnQuery) - _, appsErr := impl.dbConnection.Query(&lastSucceededTimeArray, jobsLastFinishedOnQuery) + _, appsErr := impl.dbConnection.Query(&lastSucceededTimeArray, jobsLastFinishedOnQuery, queryParams...) if appsErr != nil { impl.Logger.Errorw("error in fetching lastSucceededTimeArray", "error", appsErr, jobsLastFinishedOnQuery) return lastSucceededTimeArray, appsErr diff --git a/internal/sql/repository/CiArtifactRepository.go b/internal/sql/repository/CiArtifactRepository.go index 4f765c8eee..d74883509f 100644 --- a/internal/sql/repository/CiArtifactRepository.go +++ b/internal/sql/repository/CiArtifactRepository.go @@ -19,7 +19,6 @@ package repository import ( "encoding/json" "fmt" - "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/sql" "github.com/devtron-labs/devtron/util" "golang.org/x/exp/slices" @@ -419,9 +418,9 @@ func (impl CiArtifactRepositoryImpl) GetLatestArtifactTimeByCiPipelineIds(ciPipe "(SELECT pipeline_id, MAX(created_on) created_on " + "FROM ci_artifact " + "GROUP BY pipeline_id) cws " + - "where cws.pipeline_id IN (" + helper.GetCommaSepratedString(ciPipelineIds) + "); " + "where cws.pipeline_id IN (?); " - _, err := impl.dbConnection.Query(&artifacts, query) + _, err := impl.dbConnection.Query(&artifacts, query, pg.In(ciPipelineIds)) if err != nil { return nil, err } @@ -779,8 +778,8 @@ func (impl CiArtifactRepositoryImpl) FindArtifactByListFilter(listingFilterOptio var ciArtifactsResp []CiArtifactWithExtraData ciArtifacts := make([]*CiArtifact, 0) totalCount := 0 - finalQuery := BuildQueryForArtifactsForCdStage(*listingFilterOptions) - _, err := impl.dbConnection.Query(&ciArtifactsResp, finalQuery) + finalQuery, queryParams := BuildQueryForArtifactsForCdStage(*listingFilterOptions) + _, err := impl.dbConnection.Query(&ciArtifactsResp, finalQuery, queryParams...) if err == pg.ErrNoRows || len(ciArtifactsResp) == 0 { return ciArtifacts, totalCount, nil } @@ -821,8 +820,8 @@ func (impl CiArtifactRepositoryImpl) FindArtifactByListFilter(listingFilterOptio func (impl CiArtifactRepositoryImpl) FetchArtifactsByCdPipelineIdV2(listingFilterOptions bean.ArtifactsListFilterOptions) ([]CiArtifactWithExtraData, int, error) { var wfrList []CiArtifactWithExtraData totalCount := 0 - finalQuery := BuildQueryForArtifactsForRollback(listingFilterOptions) - _, err := impl.dbConnection.Query(&wfrList, finalQuery) + finalQuery, queryParams := BuildQueryForArtifactsForRollback(listingFilterOptions) + _, err := impl.dbConnection.Query(&wfrList, finalQuery, queryParams...) if err != nil && err != pg.ErrNoRows { impl.logger.Errorw("error in getting Wfrs and ci artifacts by pipelineId", "err", err, "pipelineId", listingFilterOptions.PipelineId) return nil, totalCount, err diff --git a/internal/sql/repository/CiArtifactsListingQueryBuilder.go b/internal/sql/repository/CiArtifactsListingQueryBuilder.go index e13ea4632d..42a135f476 100644 --- a/internal/sql/repository/CiArtifactsListingQueryBuilder.go +++ b/internal/sql/repository/CiArtifactsListingQueryBuilder.go @@ -19,7 +19,6 @@ package repository import ( "fmt" "github.com/devtron-labs/devtron/api/bean" - "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/go-pg/pg" ) @@ -28,7 +27,7 @@ const EmptyLikeRegex = "%%" func BuildQueryForParentTypeCIOrWebhook(listingFilterOpts bean.ArtifactsListFilterOptions) (string, []interface{}) { commonPaginatedQueryPart, commonPaginatedQueryParams := " cia.image LIKE ?", []interface{}{listingFilterOpts.SearchString} orderByClause := " ORDER BY cia.id DESC" - limitOffsetQueryPart, limitOffsetQueryParams := fmt.Sprintf(" LIMIT ? OFFSET ?"), []interface{}{listingFilterOpts.Limit, listingFilterOpts.Offset} + limitOffsetQueryPart, limitOffsetQueryParams := " LIMIT ? OFFSET ?", []interface{}{listingFilterOpts.Limit, listingFilterOpts.Offset} finalQuery := "" var finalQueryParams []interface{} var remainingQueryParams []interface{} @@ -71,7 +70,7 @@ func BuildQueryForParentTypeCIOrWebhook(listingFilterOpts bean.ArtifactsListFilt return finalQuery, finalQueryParams } -func BuildQueryForArtifactsForCdStage(listingFilterOptions bean.ArtifactsListFilterOptions) string { +func BuildQueryForArtifactsForCdStage(listingFilterOptions bean.ArtifactsListFilterOptions) (string, []interface{}) { // expected result -> will fetch all successfully deployed artifacts ar parent stage plus its own stage. Along with this it will // also fetch all artifacts generated by plugin at pre_cd or post_cd process (will use data_source in ci artifact table for this) @@ -79,74 +78,115 @@ func BuildQueryForArtifactsForCdStage(listingFilterOptions bean.ArtifactsListFil return buildQueryForArtifactsForCdStageV2(listingFilterOptions) } + var queryParams []interface{} + commonQuery := " from ci_artifact LEFT JOIN cd_workflow ON ci_artifact.id = cd_workflow.ci_artifact_id" + " LEFT JOIN cd_workflow_runner ON cd_workflow_runner.cd_workflow_id=cd_workflow.id " + " Where (((cd_workflow_runner.id in (select MAX(cd_workflow_runner.id) OVER (PARTITION BY cd_workflow.ci_artifact_id) FROM cd_workflow_runner inner join cd_workflow on cd_workflow.id=cd_workflow_runner.cd_workflow_id))" + - " AND ((cd_workflow.pipeline_id= %v and cd_workflow_runner.workflow_type = '%v' ) OR (cd_workflow.pipeline_id = %v AND cd_workflow_runner.workflow_type = '%v' AND cd_workflow_runner.status IN ('Healthy','Succeeded') )))" + - " OR (ci_artifact.component_id = %v and ci_artifact.data_source= '%v' ))" + - " AND (ci_artifact.image LIKE '%v' )" + " AND ((cd_workflow.pipeline_id = ? and cd_workflow_runner.workflow_type = ?) OR (cd_workflow.pipeline_id = ? AND cd_workflow_runner.workflow_type = ? AND cd_workflow_runner.status IN ('Healthy','Succeeded') )))" + + " OR (ci_artifact.component_id = ? and ci_artifact.data_source = ?))" + + " AND (ci_artifact.image LIKE ?)" + + queryParams = append(queryParams, + listingFilterOptions.PipelineId, + listingFilterOptions.StageType, + listingFilterOptions.ParentId, + listingFilterOptions.ParentStageType, + listingFilterOptions.ParentId, + listingFilterOptions.PluginStage, + listingFilterOptions.SearchString) - commonQuery = fmt.Sprintf(commonQuery, listingFilterOptions.PipelineId, listingFilterOptions.StageType, listingFilterOptions.ParentId, listingFilterOptions.ParentStageType, listingFilterOptions.ParentId, listingFilterOptions.PluginStage, listingFilterOptions.SearchString) if len(listingFilterOptions.ExcludeArtifactIds) > 0 { - commonQuery = commonQuery + fmt.Sprintf(" AND ( ci_artifact.id NOT IN (%v))", helper.GetCommaSepratedString(listingFilterOptions.ExcludeArtifactIds)) + commonQuery += " AND ci_artifact.id NOT IN (?)" + queryParams = append(queryParams, pg.In(listingFilterOptions.ExcludeArtifactIds)) } totalCountQuery := "SELECT COUNT(DISTINCT ci_artifact.id) as total_count " + commonQuery - selectQuery := fmt.Sprintf("SELECT DISTINCT(ci_artifact.id) , (%v) ", totalCountQuery) - //GroupByQuery := " GROUP BY cia.id " - limitOffSetQuery := fmt.Sprintf(" order by ci_artifact.id desc LIMIT %v OFFSET %v", listingFilterOptions.Limit, listingFilterOptions.Offset) + selectQuery := "SELECT DISTINCT(ci_artifact.id), (" + totalCountQuery + ") " + limitOffSetQuery := " order by ci_artifact.id desc LIMIT ? OFFSET ?" + + // Duplicate queryParams for the subquery + finalQueryParams := append(queryParams, queryParams...) + finalQueryParams = append(finalQueryParams, listingFilterOptions.Limit, listingFilterOptions.Offset) - //finalQuery := selectQuery + commonQuery + GroupByQuery + limitOffSetQuery finalQuery := selectQuery + commonQuery + limitOffSetQuery - return finalQuery + return finalQuery, finalQueryParams } -func buildQueryForArtifactsForCdStageV2(listingFilterOptions bean.ArtifactsListFilterOptions) string { - whereCondition := fmt.Sprintf(" WHERE (id IN ("+ - " SELECT DISTINCT(cd_workflow.ci_artifact_id) as ci_artifact_id "+ - " FROM cd_workflow_runner"+ - " INNER JOIN cd_workflow ON cd_workflow.id = cd_workflow_runner.cd_workflow_id "+ - " AND (cd_workflow.pipeline_id = %d OR cd_workflow.pipeline_id = %d)"+ - " WHERE ("+ - " (cd_workflow.pipeline_id = %d AND cd_workflow_runner.workflow_type = '%s')"+ - " OR"+ - " (cd_workflow.pipeline_id = %d"+ - " AND cd_workflow_runner.workflow_type = '%s'"+ - " AND cd_workflow_runner.status IN ('Healthy','Succeeded')"+ - " )"+ - " ) ) ", listingFilterOptions.PipelineId, listingFilterOptions.ParentId, listingFilterOptions.PipelineId, listingFilterOptions.StageType, listingFilterOptions.ParentId, listingFilterOptions.ParentStageType) - - whereCondition = fmt.Sprintf(" %s OR (ci_artifact.component_id = %d AND ci_artifact.data_source= '%s' ))", whereCondition, listingFilterOptions.ParentId, listingFilterOptions.PluginStage) +func buildQueryForArtifactsForCdStageV2(listingFilterOptions bean.ArtifactsListFilterOptions) (string, []interface{}) { + var queryParams []interface{} + + whereCondition := " WHERE (id IN (" + + " SELECT DISTINCT(cd_workflow.ci_artifact_id) as ci_artifact_id " + + " FROM cd_workflow_runner" + + " INNER JOIN cd_workflow ON cd_workflow.id = cd_workflow_runner.cd_workflow_id " + + " AND (cd_workflow.pipeline_id = ? OR cd_workflow.pipeline_id = ?)" + + " WHERE (" + + " (cd_workflow.pipeline_id = ? AND cd_workflow_runner.workflow_type = ?)" + + " OR" + + " (cd_workflow.pipeline_id = ?" + + " AND cd_workflow_runner.workflow_type = ?" + + " AND cd_workflow_runner.status IN ('Healthy','Succeeded')" + + " )" + + " ) ) " + + queryParams = append(queryParams, + listingFilterOptions.PipelineId, + listingFilterOptions.ParentId, + listingFilterOptions.PipelineId, + listingFilterOptions.StageType, + listingFilterOptions.ParentId, + listingFilterOptions.ParentStageType) + + whereCondition += " OR (ci_artifact.component_id = ? AND ci_artifact.data_source = ?))" + queryParams = append(queryParams, listingFilterOptions.ParentId, listingFilterOptions.PluginStage) + if listingFilterOptions.SearchString != EmptyLikeRegex { - whereCondition = whereCondition + fmt.Sprintf(" AND ci_artifact.image LIKE '%s' ", listingFilterOptions.SearchString) + whereCondition += " AND ci_artifact.image LIKE ?" + queryParams = append(queryParams, listingFilterOptions.SearchString) } + if len(listingFilterOptions.ExcludeArtifactIds) > 0 { - whereCondition = whereCondition + fmt.Sprintf(" AND ( ci_artifact.id NOT IN (%s))", helper.GetCommaSepratedString(listingFilterOptions.ExcludeArtifactIds)) + whereCondition += " AND ci_artifact.id NOT IN (?)" + queryParams = append(queryParams, pg.In(listingFilterOptions.ExcludeArtifactIds)) } - selectQuery := fmt.Sprintf(" SELECT ci_artifact.* ,COUNT(id) OVER() AS total_count " + - " FROM ci_artifact") - ordeyByAndPaginated := fmt.Sprintf(" ORDER BY id DESC LIMIT %d OFFSET %d ", listingFilterOptions.Limit, listingFilterOptions.Offset) - finalQuery := selectQuery + whereCondition + ordeyByAndPaginated - return finalQuery + selectQuery := " SELECT ci_artifact.*, COUNT(id) OVER() AS total_count FROM ci_artifact" + orderByAndPaginated := " ORDER BY id DESC LIMIT ? OFFSET ?" + queryParams = append(queryParams, listingFilterOptions.Limit, listingFilterOptions.Offset) + + finalQuery := selectQuery + whereCondition + orderByAndPaginated + return finalQuery, queryParams } -func BuildQueryForArtifactsForRollback(listingFilterOptions bean.ArtifactsListFilterOptions) string { +func BuildQueryForArtifactsForRollback(listingFilterOptions bean.ArtifactsListFilterOptions) (string, []interface{}) { + var queryParams []interface{} + commonQuery := " FROM cd_workflow_runner cdwr " + " INNER JOIN cd_workflow cdw ON cdw.id=cdwr.cd_workflow_id " + " INNER JOIN ci_artifact cia ON cia.id=cdw.ci_artifact_id " + - " WHERE cdw.pipeline_id=%v AND cdwr.workflow_type = '%v' " + " WHERE cdw.pipeline_id = ? AND cdwr.workflow_type = ?" + + queryParams = append(queryParams, listingFilterOptions.PipelineId, listingFilterOptions.StageType) - commonQuery = fmt.Sprintf(commonQuery, listingFilterOptions.PipelineId, listingFilterOptions.StageType) if listingFilterOptions.SearchString != EmptyLikeRegex { - commonQuery += fmt.Sprintf(" AND cia.image LIKE '%v' ", listingFilterOptions.SearchString) + commonQuery += " AND cia.image LIKE ?" + queryParams = append(queryParams, listingFilterOptions.SearchString) } + if len(listingFilterOptions.ExcludeWfrIds) > 0 { - commonQuery = fmt.Sprintf(" %s AND cdwr.id NOT IN (%s)", commonQuery, helper.GetCommaSepratedString(listingFilterOptions.ExcludeWfrIds)) + commonQuery += " AND cdwr.id NOT IN (?)" + queryParams = append(queryParams, pg.In(listingFilterOptions.ExcludeWfrIds)) } + totalCountQuery := " SELECT COUNT(cia.id) as total_count " + commonQuery orderByQuery := " ORDER BY cdwr.id DESC " - limitOffsetQuery := fmt.Sprintf("LIMIT %v OFFSET %v", listingFilterOptions.Limit, listingFilterOptions.Offset) - finalQuery := fmt.Sprintf(" SELECT cdwr.id as cd_workflow_runner_id,cdwr.triggered_by,cdwr.started_on,cia.*,(%s) ", totalCountQuery) + commonQuery + orderByQuery + limitOffsetQuery - return finalQuery + limitOffsetQuery := " LIMIT ? OFFSET ?" + + // Duplicate queryParams for the subquery + finalQueryParams := append(queryParams, queryParams...) + finalQueryParams = append(finalQueryParams, listingFilterOptions.Limit, listingFilterOptions.Offset) + + finalQuery := " SELECT cdwr.id as cd_workflow_runner_id,cdwr.triggered_by,cdwr.started_on,cia.*,(" + totalCountQuery + ") " + commonQuery + orderByQuery + limitOffsetQuery + return finalQuery, finalQueryParams } diff --git a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go index 8767773b5c..b6b879a6ad 100644 --- a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go +++ b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go @@ -111,16 +111,16 @@ func (impl AppListingRepositoryQueryBuilder) OverviewCiPipelineQuery() string { } // use this query with atleast 1 cipipeline id -func (impl AppListingRepositoryQueryBuilder) JobsLastSucceededOnTimeQuery(ciPipelineIDs []int) string { +func (impl AppListingRepositoryQueryBuilder) JobsLastSucceededOnTimeQuery(ciPipelineIDs []int) (string, []interface{}) { // use this query with atleast 1 cipipeline id query := "select cw.ci_pipeline_id,cw.finished_on " + "as last_succeeded_on from ci_workflow cw inner join " + "(SELECT ci_pipeline_id, MAX(finished_on) finished_on " + "FROM ci_workflow WHERE ci_workflow.status = 'Succeeded'" + "GROUP BY ci_pipeline_id) cws on cw.ci_pipeline_id = cws.ci_pipeline_id and cw.finished_on = cws.finished_on " + - "where cw.ci_pipeline_id IN (" + GetCommaSepratedString(ciPipelineIDs) + "); " + "where cw.ci_pipeline_id IN (?); " - return query + return query, []interface{}{pg.In(ciPipelineIDs)} } func getAppListingCommonQueryString() string { diff --git a/pkg/auth/user/repository/DefaultAuthPolicyRepository.go b/pkg/auth/user/repository/DefaultAuthPolicyRepository.go index b88fb3a72f..b0feb1fd79 100644 --- a/pkg/auth/user/repository/DefaultAuthPolicyRepository.go +++ b/pkg/auth/user/repository/DefaultAuthPolicyRepository.go @@ -70,15 +70,18 @@ func (impl DefaultAuthPolicyRepositoryImpl) UpdatePolicyByRoleType(policy string func (impl DefaultAuthPolicyRepositoryImpl) GetPolicyByRoleTypeAndEntity(roleType bean.RoleType, accessType string, entity string) (policy string, err error) { var model DefaultAuthPolicy - query := "SELECT * FROM default_auth_policy WHERE role_type = ? " - query += " and entity = '" + entity + "' " + var queryParams []interface{} + query := "SELECT * FROM default_auth_policy WHERE role_type = ? AND entity = ? " + queryParams = append(queryParams, roleType, entity) + if accessType == "" { - query += "and access_type IS NULL ;" + query += "AND access_type IS NULL ;" } else { - query += "and access_type ='" + accessType + "' ;" + query += "AND access_type = ? ;" + queryParams = append(queryParams, accessType) } - _, err = impl.dbConnection.Query(&model, query, roleType) + _, err = impl.dbConnection.Query(&model, query, queryParams...) if err != nil { impl.logger.Error("error in getting policy by roleType", "err", err, "roleType", roleType, "entity", entity) return "", err diff --git a/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go b/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go index f8d559eb19..155307af58 100644 --- a/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go +++ b/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go @@ -18,6 +18,7 @@ package helper import ( "fmt" + bean2 "github.com/devtron-labs/devtron/pkg/auth/user/bean" "github.com/devtron-labs/devtron/util" ) @@ -83,11 +84,27 @@ func GetQueryForGroupListingWithFilters(req *bean2.ListingRequest) (string, []in orderCondition := "" if len(req.SortBy) > 0 && !req.CountCheck { - orderCondition += " order by " + // Validate SortBy to prevent SQL injection - only allow safe column names + var sortColumn string + switch req.SortBy { + case bean2.GroupName: + sortColumn = "name" + case "id": + sortColumn = "id" + case "created_on": + sortColumn = "created_on" + case "updated_on": + sortColumn = "updated_on" + default: + // Default to name if invalid sort field provided + sortColumn = "name" + } + + orderCondition += " order by " + sortColumn if req.SortOrder == bean2.Desc { - orderCondition += fmt.Sprintf(" %s %s ", req.SortBy, bean2.Desc) + orderCondition += " DESC" } else { - orderCondition += fmt.Sprintf(" %s ", req.SortBy) + orderCondition += " ASC" } } if req.Size > 0 && !req.CountCheck && !req.ShowAll { diff --git a/pkg/genericNotes/repository/GenericNoteRepository.go b/pkg/genericNotes/repository/GenericNoteRepository.go index 5d580d3043..30a6ee1763 100644 --- a/pkg/genericNotes/repository/GenericNoteRepository.go +++ b/pkg/genericNotes/repository/GenericNoteRepository.go @@ -17,9 +17,7 @@ package repository import ( - "fmt" repository1 "github.com/devtron-labs/devtron/internal/sql/repository/app" - "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" ) @@ -108,9 +106,8 @@ func (impl GenericNoteRepositoryImpl) GetDescriptionFromAppIds(appIds []int) ([] if len(appIds) == 0 { return nil, nil } - query := fmt.Sprintf("SELECT * "+ - "FROM app WHERE id IN (%s)", helper.GetCommaSepratedString(appIds)) - _, err := impl.dbConnection.Query(&apps, query) + // Use parameterized query to prevent SQL injection + err := impl.dbConnection.Model(&apps).Where("id IN (?)", pg.In(appIds)).Select() if err != nil { return nil, err } diff --git a/pkg/plugin/repository/GlobalPluginRepository.go b/pkg/plugin/repository/GlobalPluginRepository.go index 715b74fcc0..7bd359a053 100644 --- a/pkg/plugin/repository/GlobalPluginRepository.go +++ b/pkg/plugin/repository/GlobalPluginRepository.go @@ -18,7 +18,6 @@ package repository import ( "fmt" - "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" "go.uber.org/zap" @@ -947,19 +946,23 @@ func (impl *GlobalPluginRepositoryImpl) GetAllFilteredPluginParentMetadata(searc var plugins []*PluginParentMetadata query := "select ppm.id, ppm.identifier,ppm.name,ppm.description,ppm.type,ppm.icon,ppm.deleted,ppm.created_by, ppm.created_on,ppm.updated_by,ppm.updated_on from plugin_parent_metadata ppm" + " inner join plugin_metadata pm on pm.plugin_parent_metadata_id=ppm.id" - whereCondition := fmt.Sprintf(" where ppm.deleted=false AND pm.deleted=false AND pm.is_latest=true AND pm.is_deprecated=false AND pm.is_exposed=true AND ppm.is_exposed=true") + var queryParams []interface{} + whereCondition := " where ppm.deleted=false AND pm.deleted=false AND pm.is_latest=true AND pm.is_deprecated=false AND pm.is_exposed=true AND ppm.is_exposed=true" + if len(tags) > 0 { - tagFilterSubQuery := fmt.Sprintf("select ptr.plugin_id from plugin_tag_relation ptr inner join plugin_tag pt on ptr.tag_id =pt.id where pt.deleted =false and pt.name in (%s) group by ptr.plugin_id having count(ptr.plugin_id )=%d", helper.GetCommaSepratedStringWithComma(tags), len(tags)) - whereCondition += fmt.Sprintf(" AND pm.id in (%s)", tagFilterSubQuery) + tagFilterSubQuery := "select ptr.plugin_id from plugin_tag_relation ptr inner join plugin_tag pt on ptr.tag_id =pt.id where pt.deleted =false and pt.name in (?) group by ptr.plugin_id having count(ptr.plugin_id )=?" + whereCondition += " AND pm.id in (" + tagFilterSubQuery + ")" + queryParams = append(queryParams, pg.In(tags), len(tags)) } if len(searchKey) > 0 { + whereCondition += " AND (pm.description ilike ? or pm.name ilike ?)" searchKeyLike := "%" + searchKey + "%" - whereCondition += fmt.Sprintf(" AND (pm.description ilike '%s' or pm.name ilike '%s')", searchKeyLike, searchKeyLike) + queryParams = append(queryParams, searchKeyLike, searchKeyLike) } orderCondition := " ORDER BY ppm.name asc;" query += whereCondition + orderCondition - _, err := impl.dbConnection.Query(&plugins, query) + _, err := impl.dbConnection.Query(&plugins, query, queryParams...) if err != nil { return nil, err } diff --git a/pkg/policyGovernance/security/imageScanning/repository/ImageScanDeployInfoRepository.go b/pkg/policyGovernance/security/imageScanning/repository/ImageScanDeployInfoRepository.go index 0829398cbe..2b27887b01 100644 --- a/pkg/policyGovernance/security/imageScanning/repository/ImageScanDeployInfoRepository.go +++ b/pkg/policyGovernance/security/imageScanning/repository/ImageScanDeployInfoRepository.go @@ -18,10 +18,11 @@ package repository import ( "fmt" + "time" + repoBean "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository/bean" "github.com/devtron-labs/devtron/pkg/sql" "github.com/devtron-labs/devtron/util" - "time" "github.com/go-pg/pg" "go.uber.org/zap" @@ -238,10 +239,11 @@ func (impl ImageScanDeployInfoRepositoryImpl) scanListQueryWithObject(request *r INNER JOIN cve_store cs on cs.name= res.cve_store_name ` } - query = query + ` INNER JOIN environment env on env.id=info.env_id - INNER JOIN cluster c on c.id=env.cluster_id - WHERE info.scan_object_meta_id > 0 and env.active=true and info.image_scan_execution_history_id[1] != -1 - AND a.app_name like '%` + request.AppName + `%' ` + query = query + ` INNER JOIN environment env on env.id=info.env_id + INNER JOIN cluster c on c.id=env.cluster_id + WHERE info.scan_object_meta_id > 0 and env.active=true and info.image_scan_execution_history_id[1] != -1 + AND a.app_name like ? ` + queryParams = append(queryParams, "%"+request.AppName+"%") if len(deployInfoIds) > 0 { query += " AND info.id IN (?) " diff --git a/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/repository_types.go b/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/repository_types.go index 047ae14b1a..33d50b513d 100644 --- a/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/repository_types.go +++ b/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/repository_types.go @@ -290,7 +290,6 @@ func (m *Repository) Sanitized() *Repository { Repo: m.Repo, Type: m.Type, Name: m.Name, - Username: m.Username, Insecure: m.IsInsecure(), EnableLFS: m.EnableLFS, EnableOCI: m.EnableOCI, diff --git a/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/types.go b/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/types.go index 524f574f88..6eedbfd91a 100644 --- a/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/types.go +++ b/vendor/github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/types.go @@ -2099,6 +2099,32 @@ type Cluster struct { Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,13,opt,name=annotations"` } +func (c *Cluster) Sanitized() *Cluster { + return &Cluster{ + ID: c.ID, + Server: c.Server, + Name: c.Name, + Project: c.Project, + Namespaces: c.Namespaces, + Shard: c.Shard, + Labels: c.Labels, + Annotations: c.Annotations, + ClusterResources: c.ClusterResources, + ConnectionState: c.ConnectionState, + ServerVersion: c.ServerVersion, + Info: c.Info, + RefreshRequestedAt: c.RefreshRequestedAt, + Config: ClusterConfig{ + AWSAuthConfig: c.Config.AWSAuthConfig, + ProxyUrl: c.Config.ProxyUrl, + DisableCompression: c.Config.DisableCompression, + TLSClientConfig: TLSClientConfig{ + Insecure: c.Config.Insecure, + }, + }, + } +} + // Equals returns true if two cluster objects are considered to be equal func (c *Cluster) Equals(other *Cluster) bool { if c.Server != other.Server { diff --git a/vendor/github.com/argoproj/argo-cd/v2/util/tls/tls.go b/vendor/github.com/argoproj/argo-cd/v2/util/tls/tls.go index 819a8761af..24c659d274 100644 --- a/vendor/github.com/argoproj/argo-cd/v2/util/tls/tls.go +++ b/vendor/github.com/argoproj/argo-cd/v2/util/tls/tls.go @@ -193,6 +193,11 @@ func publicKey(priv interface{}) interface{} { func pemBlockForKey(priv interface{}) *pem.Block { switch k := priv.(type) { case *rsa.PrivateKey: + // In Go 1.24+, MarshalPKCS1PrivateKey calls Precompute() which can panic + // if the key is invalid. Validate the key first. + if k == nil || k.Validate() != nil { + return nil + } return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} case *ecdsa.PrivateKey: b, err := x509.MarshalECPrivateKey(k) @@ -298,7 +303,11 @@ func generatePEM(opts CertOptions) ([]byte, []byte, error) { return nil, nil, err } certpem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) - keypem := pem.EncodeToMemory(pemBlockForKey(privateKey)) + keyBlock := pemBlockForKey(privateKey) + if keyBlock == nil { + return nil, nil, errors.New("failed to encode private key") + } + keypem := pem.EncodeToMemory(keyBlock) return certpem, keypem, nil } @@ -321,7 +330,11 @@ func EncodeX509KeyPair(cert tls.Certificate) ([]byte, []byte) { for _, certtmp := range cert.Certificate { certpem = append(certpem, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certtmp})...) } - keypem := pem.EncodeToMemory(pemBlockForKey(cert.PrivateKey)) + keyBlock := pemBlockForKey(cert.PrivateKey) + if keyBlock == nil { + return certpem, []byte{} + } + keypem := pem.EncodeToMemory(keyBlock) return certpem, keypem } diff --git a/vendor/modules.txt b/vendor/modules.txt index 407762cd6d..b351b2ca4c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -149,8 +149,8 @@ github.com/apparentlymart/go-textseg/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 ## explicit; go 1.16 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/argoproj/argo-cd/v2 v2.14.13 -## explicit; go 1.23.0 +# github.com/argoproj/argo-cd/v2 v2.14.17 +## explicit; go 1.24.6 github.com/argoproj/argo-cd/v2/assets github.com/argoproj/argo-cd/v2/common github.com/argoproj/argo-cd/v2/pkg/apiclient/account