Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0af4e63
Add cluster overview module with caching, insights, and enhanced cons…
prakash100198 Dec 1, 2025
173b7ee
Add methods for querying environments and teams by time range
prakash100198 Dec 2, 2025
4b94d56
Add `ci_pipeline_type` filter to active CI pipeline count query
prakash100198 Dec 3, 2025
8f7d114
feat: kubecon 2025 feature release (#6884)
Ash-exp Dec 8, 2025
c3df496
chore: rename SQL migration files for consistency
Ash-exp Dec 8, 2025
4d3de85
Merge pull request #6885 from devtron-labs/chore/develop-sync-8-dec
Ash-exp Dec 8, 2025
57cb63d
Merge remote-tracking branch 'origin/main' into chore/develop-sync-8-dec
Ash-exp Dec 8, 2025
2db58b0
chore: update common-lib dependency to latest version
Ash-exp Dec 8, 2025
951084b
Merge pull request #6886 from devtron-labs/chore/develop-sync-8-dec
Ash-exp Dec 8, 2025
656f27c
fix: enhance validation and error handling in cluster update process
Ash-exp Dec 8, 2025
2bfa764
fix: improve error logging in cluster service for better traceability
Ash-exp Dec 8, 2025
4072b9a
fix: update secret creation to handle additional parameters in cluste…
Ash-exp Dec 8, 2025
26ecc4e
fix: rename SQL migration files for consistency in cluster service
Ash-exp Dec 8, 2025
b6d0530
Merge pull request #6887 from devtron-labs/fix/cluster-update-validation
Ash-exp Dec 8, 2025
502ebf2
Add `VulnerabilitySummary` and `VulnerabilityListing` APIs to ImageSc…
prakash100198 Dec 12, 2025
1a86ef0
Add migrations and code updates for cost module, Velero integration, …
prakash100198 Dec 12, 2025
f010451
Update module references for authenticator and common-lib dependencies
prakash100198 Dec 12, 2025
f1b31ba
Merge pull request #6891 from devtron-labs/overview-oss-develop-sync
prakash100198 Dec 12, 2025
e47f6b5
cluster overview code
iamayushm Dec 16, 2025
7bc59db
Merge pull request #6895 from devtron-labs/feat-infra-overview-router
iamayushm Dec 16, 2025
880110d
Merge remote-tracking branch 'origin/main' into chore/main-sync-17-dec
Ash-exp Dec 17, 2025
a7bd0b6
fix: rename SQL migration files for consistency
Ash-exp Dec 17, 2025
d92a857
fix: update dependencies for authenticator and common-lib to latest v…
Ash-exp Dec 17, 2025
4b8eb26
Merge pull request #6897 from devtron-labs/chore/main-sync-17-dec
Ash-exp Dec 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ import (
"github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs"
repository7 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository"
"github.com/devtron-labs/devtron/pkg/notifier"
"github.com/devtron-labs/devtron/pkg/overview"
"github.com/devtron-labs/devtron/pkg/pipeline"
"github.com/devtron-labs/devtron/pkg/pipeline/draftAwareConfigService"
"github.com/devtron-labs/devtron/pkg/pipeline/executors"
Expand Down Expand Up @@ -984,6 +985,20 @@ func InitializeApp() (*App, error) {

acdConfig.NewArgoCDConfigGetter,
wire.Bind(new(acdConfig.ArgoCDConfigGetter), new(*acdConfig.ArgoCDConfigGetterImpl)),

// overview starts
overview.OverviewWireSet,
restHandler.NewOverviewRestHandlerImpl,
wire.Bind(new(restHandler.OverviewRestHandler), new(*restHandler.OverviewRestHandlerImpl)),

router.NewOverviewRouterImpl,
wire.Bind(new(router.OverviewRouter), new(*router.OverviewRouterImpl)),

restHandler.NewInfraOverviewRestHandlerImpl,
wire.Bind(new(restHandler.InfraOverviewRestHandler), new(*restHandler.InfraOverviewRestHandlerImpl)),

router.NewInfraOverviewRouterImpl,
wire.Bind(new(router.InfraOverviewRouter), new(*router.InfraOverviewRouterImpl)),
)
return &App{}, nil
}
235 changes: 233 additions & 2 deletions api/restHandler/ImageScanRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ package restHandler
import (
"encoding/json"
"fmt"
"net/http"
"strconv"

"github.com/devtron-labs/devtron/pkg/cluster/environment"
"github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning"
securityBean "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/bean"
security2 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository"
"github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository/bean"
"github.com/devtron-labs/devtron/util/sliceUtil"
"net/http"
"strconv"
"go.opentelemetry.io/otel"

"github.com/devtron-labs/devtron/api/restHandler/common"
"github.com/devtron-labs/devtron/internal/util"
Expand All @@ -46,6 +49,8 @@ type ImageScanRestHandler interface {
FetchExecutionDetail(w http.ResponseWriter, r *http.Request)
FetchMinScanResultByAppIdAndEnvId(w http.ResponseWriter, r *http.Request)
VulnerabilityExposure(w http.ResponseWriter, r *http.Request)
VulnerabilitySummary(w http.ResponseWriter, r *http.Request)
VulnerabilityListing(w http.ResponseWriter, r *http.Request)
}

type ImageScanRestHandlerImpl struct {
Expand Down Expand Up @@ -402,3 +407,229 @@ func (impl ImageScanRestHandlerImpl) VulnerabilityExposure(w http.ResponseWriter
results.VulnerabilityExposure = vulnerabilityExposure
common.WriteJsonResp(w, err, results, http.StatusOK)
}

func (impl ImageScanRestHandlerImpl) VulnerabilitySummary(w http.ResponseWriter, r *http.Request) {
ctx, span := otel.Tracer("imageScanRestHandler").Start(r.Context(), "VulnerabilitySummary")
defer span.End()

userId, err := impl.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.HandleUnauthorized(w, r)
return
}

// Parse request body with filters
decoder := json.NewDecoder(r.Body)
var summaryRequest *securityBean.VulnerabilitySummaryRequest
err = decoder.Decode(&summaryRequest)
if err != nil {
impl.logger.Errorw("request err, VulnerabilitySummary", "err", err, "payload", r.Body)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}

// Create ImageScanRequest with filters for fetching deploy info
request := &securityBean.ImageScanRequest{
ImageScanFilter: bean.ImageScanFilter{
EnvironmentIds: summaryRequest.EnvironmentIds,
ClusterIds: summaryRequest.ClusterIds,
},
}

deployInfoList, err := impl.imageScanService.FetchAllDeployInfo(request)
if err != nil {
impl.logger.Errorw("service err, VulnerabilitySummary", "err", err)
if util.IsErrNoRows(err) {
emptySummary := &securityBean.VulnerabilitySummary{
TotalVulnerabilities: 0,
SeverityCount: &securityBean.SeverityCount{
Critical: 0,
High: 0,
Medium: 0,
Low: 0,
Unknown: 0,
},
FixableVulnerabilities: 0,
NotFixableVulnerabilities: 0,
}
common.WriteJsonResp(w, nil, emptySummary, http.StatusOK)
} else {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
}
return
}

filteredDeployInfoList, err := impl.imageScanService.FilterDeployInfoByScannedArtifactsDeployedInEnv(deployInfoList)
if err != nil {
impl.logger.Errorw("request err, FilterDeployInfoListForScannedArtifacts", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}

_, rbacSpan := otel.Tracer("imageScanRestHandler").Start(ctx, "RBACProcessing")
token := r.Header.Get("token")
isSuperAdmin := false
if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
isSuperAdmin = true
}
var ids []int
if isSuperAdmin {
ids = sliceUtil.NewSliceFromFuncExec(filteredDeployInfoList, func(item *security2.ImageScanDeployInfo) int {
return item.Id
})
} else {
ids, err = impl.getAuthorisedImageScanDeployInfoIds(token, filteredDeployInfoList)
if err != nil {
impl.logger.Errorw("error in getting authorised image scan deploy info ids", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
rbacSpan.End()

if len(ids) == 0 {
emptySummary := &securityBean.VulnerabilitySummary{
TotalVulnerabilities: 0,
SeverityCount: &securityBean.SeverityCount{
Critical: 0,
High: 0,
Medium: 0,
Low: 0,
Unknown: 0,
},
FixableVulnerabilities: 0,
NotFixableVulnerabilities: 0,
}
common.WriteJsonResp(w, nil, emptySummary, http.StatusOK)
return
}

summary, err := impl.imageScanService.FetchVulnerabilitySummary(ctx, summaryRequest, ids)
if err != nil {
impl.logger.Errorw("service err, VulnerabilitySummary", "err", err)
if util.IsErrNoRows(err) {
emptySummary := &securityBean.VulnerabilitySummary{
TotalVulnerabilities: 0,
SeverityCount: &securityBean.SeverityCount{
Critical: 0,
High: 0,
Medium: 0,
Low: 0,
Unknown: 0,
},
FixableVulnerabilities: 0,
NotFixableVulnerabilities: 0,
}
common.WriteJsonResp(w, nil, emptySummary, http.StatusOK)
} else {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
}
return
}
common.WriteJsonResp(w, err, summary, http.StatusOK)
}

func (impl ImageScanRestHandlerImpl) VulnerabilityListing(w http.ResponseWriter, r *http.Request) {
ctx, span := otel.Tracer("imageScanRestHandler").Start(r.Context(), "VulnerabilityListing")
defer span.End()

userId, err := impl.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.HandleUnauthorized(w, r)
return
}

// Parse request body
decoder := json.NewDecoder(r.Body)
var request *securityBean.VulnerabilityListingRequest
err = decoder.Decode(&request)
if err != nil {
impl.logger.Errorw("request err, VulnerabilityListing", "err", err, "payload", r.Body)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}

// Fetch all deploy info to apply RBAC
deployInfoRequest := &securityBean.ImageScanRequest{
ImageScanFilter: bean.ImageScanFilter{
EnvironmentIds: request.EnvironmentIds,
ClusterIds: request.ClusterIds,
},
}

deployInfoList, err := impl.imageScanService.FetchAllDeployInfo(deployInfoRequest)
if err != nil {
impl.logger.Errorw("service err, VulnerabilityListing", "err", err)
if util.IsErrNoRows(err) {
emptyResponse := &securityBean.VulnerabilityListingResponse{
Offset: request.Offset,
Size: request.Size,
Total: 0,
Vulnerabilities: []*securityBean.VulnerabilityDetail{},
}
common.WriteJsonResp(w, nil, emptyResponse, http.StatusOK)
} else {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
}
return
}

filteredDeployInfoList, err := impl.imageScanService.FilterDeployInfoByScannedArtifactsDeployedInEnv(deployInfoList)
if err != nil {
impl.logger.Errorw("request err, FilterDeployInfoListForScannedArtifacts", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}

// Apply RBAC
_, rbacSpan := otel.Tracer("imageScanRestHandler").Start(ctx, "RBACProcessing")
token := r.Header.Get("token")
isSuperAdmin := false
if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
isSuperAdmin = true
}
var ids []int
if isSuperAdmin {
ids = sliceUtil.NewSliceFromFuncExec(filteredDeployInfoList, func(item *security2.ImageScanDeployInfo) int {
return item.Id
})
} else {
ids, err = impl.getAuthorisedImageScanDeployInfoIds(token, filteredDeployInfoList)
if err != nil {
impl.logger.Errorw("error in getting authorised image scan deploy info ids", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
rbacSpan.End()

if len(ids) == 0 {
emptyResponse := &securityBean.VulnerabilityListingResponse{
Offset: request.Offset,
Size: request.Size,
Total: 0,
Vulnerabilities: []*securityBean.VulnerabilityDetail{},
}
common.WriteJsonResp(w, nil, emptyResponse, http.StatusOK)
return
}

// Fetch vulnerability listing
listing, err := impl.imageScanService.FetchVulnerabilityListing(ctx, request, ids)
if err != nil {
impl.logger.Errorw("service err, VulnerabilityListing", "err", err)
if util.IsErrNoRows(err) {
emptyResponse := &securityBean.VulnerabilityListingResponse{
Offset: request.Offset,
Size: request.Size,
Total: 0,
Vulnerabilities: []*securityBean.VulnerabilityDetail{},
}
common.WriteJsonResp(w, nil, emptyResponse, http.StatusOK)
} else {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
}
return
}
common.WriteJsonResp(w, err, listing, http.StatusOK)
}
Loading
Loading