diff --git a/go.mod b/go.mod index 06d6106d44..7dd3707a8c 100644 --- a/go.mod +++ b/go.mod @@ -335,7 +335,7 @@ require ( replace ( github.com/argoproj/argo-workflows/v3 v3.5.13 => github.com/devtron-labs/argo-workflows/v3 v3.5.13 github.com/cyphar/filepath-securejoin v0.4.1 => github.com/cyphar/filepath-securejoin v0.3.6 // indirect - github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250806142853-d5a47198188d - github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250806142853-d5a47198188d + github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250901093002-1be330be4db3 + github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 ) diff --git a/go.sum b/go.sum index d01bdaae31..b30af420d6 100644 --- a/go.sum +++ b/go.sum @@ -237,10 +237,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzq github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/devtron-labs/argo-workflows/v3 v3.5.13 h1:3pINq0gXOSeTw2z/vYe+j80lRpSN5Rp/8mfQORh8SmU= github.com/devtron-labs/argo-workflows/v3 v3.5.13/go.mod h1:/vqxcovDPT4zqr4DjR5v7CF8ggpY1l3TSa2CIG3jmjA= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250806142853-d5a47198188d h1:+g3SnMSqHWPpKkU2fdp1dTkcPvedXuZ6kVR7S4U4IvU= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250806142853-d5a47198188d/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250806142853-d5a47198188d h1:PcwklqogA1ppPtC0M2jn2QiFAkoKKeOY2tbNOCjedeI= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250806142853-d5a47198188d/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250901093002-1be330be4db3 h1:7WTBEjb3nhvfAbbYyKYb8oTRRyLQ89mkVCIhKzN7Iu0= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250901093002-1be330be4db3/go.mod h1:9LCkYfiWaEKIBkmxw9jX1GujvEMyHwmDtVsatffAkeU= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/devtron-labs/go-bitbucket v0.9.60-beta h1:VEx1jvDgdtDPS6A1uUFoaEi0l1/oLhbr+90xOwr6sDU= github.com/devtron-labs/go-bitbucket v0.9.60-beta/go.mod h1:GnuiCesvh8xyHeMCb+twm8lBR/kQzJYSKL28ZfObp1Y= github.com/devtron-labs/protos v0.0.3-0.20250323220609-ecf8a0f7305e h1:U6UdYbW8a7xn5IzFPd8cywjVVPfutGJCudjePAfL/Hs= 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/vendor/modules.txt b/vendor/modules.txt index f17d7b3b5a..34688eb133 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -523,7 +523,7 @@ github.com/davecgh/go-spew/spew # github.com/deckarep/golang-set v1.8.0 ## explicit; go 1.17 github.com/deckarep/golang-set -# github.com/devtron-labs/authenticator v0.4.35-0.20240809073103-6e11da8083f8 => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250806142853-d5a47198188d +# github.com/devtron-labs/authenticator v0.4.35-0.20240809073103-6e11da8083f8 => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250901093002-1be330be4db3 ## explicit; go 1.24.0 github.com/devtron-labs/authenticator/apiToken github.com/devtron-labs/authenticator/client @@ -531,7 +531,7 @@ github.com/devtron-labs/authenticator/jwt github.com/devtron-labs/authenticator/middleware github.com/devtron-labs/authenticator/oidc github.com/devtron-labs/authenticator/password -# github.com/devtron-labs/common-lib v0.18.1-0.20241001061923-eda545dc839e => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250806142853-d5a47198188d +# github.com/devtron-labs/common-lib v0.18.1-0.20241001061923-eda545dc839e => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/async github.com/devtron-labs/common-lib/blob-storage @@ -2654,5 +2654,5 @@ xorm.io/xorm/log xorm.io/xorm/names xorm.io/xorm/schemas xorm.io/xorm/tags -# github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250806142853-d5a47198188d -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250806142853-d5a47198188d +# github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3