From 722bb16dc0d77e86b867ec5d2c133ce61510bf7c Mon Sep 17 00:00:00 2001 From: AJ Heflin Date: Wed, 18 Feb 2026 12:31:28 -0500 Subject: [PATCH 1/3] Fix query in GetListImagesView function for ImageV2 --- central/imagev2/datastore/store/postgres/store.go | 6 +++++- central/imagev2/views/list_image_view.go | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/central/imagev2/datastore/store/postgres/store.go b/central/imagev2/datastore/store/postgres/store.go index e5d7b044a9b8f..825ed0934b56a 100644 --- a/central/imagev2/datastore/store/postgres/store.go +++ b/central/imagev2/datastore/store/postgres/store.go @@ -27,6 +27,7 @@ import ( "github.com/stackrox/rox/pkg/search" "github.com/stackrox/rox/pkg/search/paginated" pgSearch "github.com/stackrox/rox/pkg/search/postgres" + "github.com/stackrox/rox/pkg/search/postgres/aggregatefunc" "github.com/stackrox/rox/pkg/search/sortfields" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -985,7 +986,7 @@ func (s *storeImpl) GetListImagesView(ctx context.Context, q *v1.Query) ([]*view selects := []*v1.QuerySelect{ search.NewQuerySelect(search.ImageSHA).Proto(), search.NewQuerySelect(search.ImageName).Proto(), - search.NewQuerySelect(search.ComponentCount).Proto(), + search.NewQuerySelect(search.ComponentID).AggrFunc(aggregatefunc.Count).Proto(), search.NewQuerySelect(search.ImageCVECount).Proto(), search.NewQuerySelect(search.FixableCVECount).Proto(), search.NewQuerySelect(search.ImageCreatedTime).Proto(), @@ -993,6 +994,9 @@ func (s *storeImpl) GetListImagesView(ctx context.Context, q *v1.Query) ([]*view } cloned := q.CloneVT() cloned.Selects = selects + cloned.GroupBy = &v1.QueryGroupBy{ + Fields: []string{search.ImageID.String()}, + } var results []*views.ListImageV2View err := pgSearch.RunSelectRequestForSchemaFn[views.ListImageV2View](ctx, s.db, pkgSchema.ImagesV2Schema, cloned, func(row *views.ListImageV2View) error { diff --git a/central/imagev2/views/list_image_view.go b/central/imagev2/views/list_image_view.go index 82c328fa8bf91..647c739b8dc66 100644 --- a/central/imagev2/views/list_image_view.go +++ b/central/imagev2/views/list_image_view.go @@ -12,7 +12,7 @@ import ( type ListImageV2View struct { Digest string `db:"image_sha"` Name string `db:"image"` - ComponentCount int32 `db:"component_count"` + ComponentCount int32 `db:"component_id_count"` CVECount int32 `db:"image_cve_count"` FixableCVECount int32 `db:"fixable_cve_count"` Created *time.Time `db:"image_created_time"` From 463cee8bd758874531e93fb131f6a58fd5da0454 Mon Sep 17 00:00:00 2001 From: AJ Heflin Date: Wed, 18 Feb 2026 15:58:30 -0500 Subject: [PATCH 2/3] switch to use direct db column instead of doing it with an aggregate query --- central/imagev2/datastore/store/postgres/store.go | 6 +----- central/imagev2/views/list_image_view.go | 2 +- generated/internalapi/central/v1/token_service.pb.go | 4 ++-- generated/storage/image_v2.pb.go | 2 +- pkg/search/options.go | 1 + proto/storage/image_v2.proto | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/central/imagev2/datastore/store/postgres/store.go b/central/imagev2/datastore/store/postgres/store.go index 825ed0934b56a..f40c4155f66de 100644 --- a/central/imagev2/datastore/store/postgres/store.go +++ b/central/imagev2/datastore/store/postgres/store.go @@ -27,7 +27,6 @@ import ( "github.com/stackrox/rox/pkg/search" "github.com/stackrox/rox/pkg/search/paginated" pgSearch "github.com/stackrox/rox/pkg/search/postgres" - "github.com/stackrox/rox/pkg/search/postgres/aggregatefunc" "github.com/stackrox/rox/pkg/search/sortfields" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -986,7 +985,7 @@ func (s *storeImpl) GetListImagesView(ctx context.Context, q *v1.Query) ([]*view selects := []*v1.QuerySelect{ search.NewQuerySelect(search.ImageSHA).Proto(), search.NewQuerySelect(search.ImageName).Proto(), - search.NewQuerySelect(search.ComponentID).AggrFunc(aggregatefunc.Count).Proto(), + search.NewQuerySelect(search.ImageComponentCount).Proto(), search.NewQuerySelect(search.ImageCVECount).Proto(), search.NewQuerySelect(search.FixableCVECount).Proto(), search.NewQuerySelect(search.ImageCreatedTime).Proto(), @@ -994,9 +993,6 @@ func (s *storeImpl) GetListImagesView(ctx context.Context, q *v1.Query) ([]*view } cloned := q.CloneVT() cloned.Selects = selects - cloned.GroupBy = &v1.QueryGroupBy{ - Fields: []string{search.ImageID.String()}, - } var results []*views.ListImageV2View err := pgSearch.RunSelectRequestForSchemaFn[views.ListImageV2View](ctx, s.db, pkgSchema.ImagesV2Schema, cloned, func(row *views.ListImageV2View) error { diff --git a/central/imagev2/views/list_image_view.go b/central/imagev2/views/list_image_view.go index 647c739b8dc66..2be005fd8e474 100644 --- a/central/imagev2/views/list_image_view.go +++ b/central/imagev2/views/list_image_view.go @@ -12,7 +12,7 @@ import ( type ListImageV2View struct { Digest string `db:"image_sha"` Name string `db:"image"` - ComponentCount int32 `db:"component_id_count"` + ComponentCount int32 `db:"image_component_count"` CVECount int32 `db:"image_cve_count"` FixableCVECount int32 `db:"fixable_cve_count"` Created *time.Time `db:"image_created_time"` diff --git a/generated/internalapi/central/v1/token_service.pb.go b/generated/internalapi/central/v1/token_service.pb.go index 355fa7fc46727..d976570f83085 100644 --- a/generated/internalapi/central/v1/token_service.pb.go +++ b/generated/internalapi/central/v1/token_service.pb.go @@ -307,8 +307,8 @@ var file_internalapi_central_v1_token_service_proto_enumTypes = make([]protoimpl var file_internalapi_central_v1_token_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_internalapi_central_v1_token_service_proto_goTypes = []any{ (Access)(0), // 0: central.v1.Access - (*GenerateTokenForPermissionsAndScopeRequest)(nil), // 1: central.v1.GenerateTokenForPermissionsAndScopeRequest - (*ClusterScope)(nil), // 2: central.v1.ClusterScope + (*GenerateTokenForPermissionsAndScopeRequest)(nil), // 1: central.v1.GenerateTokenForPermissionsAndScopeRequest + (*ClusterScope)(nil), // 2: central.v1.ClusterScope (*GenerateTokenForPermissionsAndScopeResponse)(nil), // 3: central.v1.GenerateTokenForPermissionsAndScopeResponse nil, // 4: central.v1.GenerateTokenForPermissionsAndScopeRequest.PermissionsEntry (*durationpb.Duration)(nil), // 5: google.protobuf.Duration diff --git a/generated/storage/image_v2.pb.go b/generated/storage/image_v2.pb.go index 6c304fe896c3f..91c8fec274ec4 100644 --- a/generated/storage/image_v2.pb.go +++ b/generated/storage/image_v2.pb.go @@ -343,7 +343,7 @@ func (x *ListImageV2) GetPriority() int64 { type ImageV2_ScanStats struct { state protoimpl.MessageState `protogen:"open.v1"` // Caching component count to avoid re-calculating it by joining on the component table. - ComponentCount int32 `protobuf:"varint,1,opt,name=component_count,json=componentCount,proto3" json:"component_count,omitempty" search:"Component Count,hidden"` // @gotags: search:"Component Count,hidden" + ComponentCount int32 `protobuf:"varint,1,opt,name=component_count,json=componentCount,proto3" json:"component_count,omitempty" search:"Image Component Count,hidden"` // @gotags: search:"Image Component Count,hidden" // Caching cve count to avoid re-calculating it by joining on the cve table. CveCount int32 `protobuf:"varint,2,opt,name=cve_count,json=cveCount,proto3" json:"cve_count,omitempty" search:"Image CVE Count,hidden"` // @gotags: search:"Image CVE Count,hidden" // Caching fixable cve count to avoid re-calculating it by joining on the cve table. diff --git a/pkg/search/options.go b/pkg/search/options.go index fb4d931804b2c..1c2111f837397 100644 --- a/pkg/search/options.go +++ b/pkg/search/options.go @@ -97,6 +97,7 @@ var ( ImageUser = newFieldLabel("Image User") ImageCommand = newFieldLabel("Image Command") ImageCVECount = newFieldLabel("Image CVE Count") + ImageComponentCount = newFieldLabel("Image Component Count") ImageEntrypoint = newFieldLabel("Image Entrypoint") ImageLabel = newFieldLabel("Image Label") ImageVolumes = newFieldLabel("Image Volumes") diff --git a/proto/storage/image_v2.proto b/proto/storage/image_v2.proto index c3120d96e5185..65f4beca37dfd 100644 --- a/proto/storage/image_v2.proto +++ b/proto/storage/image_v2.proto @@ -22,7 +22,7 @@ message ImageV2 { message ScanStats { // Caching component count to avoid re-calculating it by joining on the component table. - int32 component_count = 1; // @gotags: search:"Component Count,hidden" + int32 component_count = 1; // @gotags: search:"Image Component Count,hidden" // Caching cve count to avoid re-calculating it by joining on the cve table. int32 cve_count = 2; // @gotags: search:"Image CVE Count,hidden" From 4ca14a1f7dad0937d89c11b2d6ec3bc484a4702f Mon Sep 17 00:00:00 2001 From: AJ Heflin Date: Thu, 19 Feb 2026 09:40:44 -0500 Subject: [PATCH 3/3] Revert token_service changes --- generated/internalapi/central/v1/token_service.pb.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generated/internalapi/central/v1/token_service.pb.go b/generated/internalapi/central/v1/token_service.pb.go index d976570f83085..355fa7fc46727 100644 --- a/generated/internalapi/central/v1/token_service.pb.go +++ b/generated/internalapi/central/v1/token_service.pb.go @@ -307,8 +307,8 @@ var file_internalapi_central_v1_token_service_proto_enumTypes = make([]protoimpl var file_internalapi_central_v1_token_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_internalapi_central_v1_token_service_proto_goTypes = []any{ (Access)(0), // 0: central.v1.Access - (*GenerateTokenForPermissionsAndScopeRequest)(nil), // 1: central.v1.GenerateTokenForPermissionsAndScopeRequest - (*ClusterScope)(nil), // 2: central.v1.ClusterScope + (*GenerateTokenForPermissionsAndScopeRequest)(nil), // 1: central.v1.GenerateTokenForPermissionsAndScopeRequest + (*ClusterScope)(nil), // 2: central.v1.ClusterScope (*GenerateTokenForPermissionsAndScopeResponse)(nil), // 3: central.v1.GenerateTokenForPermissionsAndScopeResponse nil, // 4: central.v1.GenerateTokenForPermissionsAndScopeRequest.PermissionsEntry (*durationpb.Duration)(nil), // 5: google.protobuf.Duration