From 5425815e5ef201891f24b4b4fe853aa43420491e Mon Sep 17 00:00:00 2001 From: AJ Heflin Date: Thu, 28 Aug 2025 11:26:27 -0400 Subject: [PATCH] Update image views --- central/views/imagecve/db_response.go | 4 ++++ central/views/imagecve/view_impl.go | 14 ++++++++++++++ central/views/imagecveflat/view_impl.go | 9 ++++++++- central/views/images/db_response.go | 7 ++++++- central/views/images/singleton.go | 7 +++++++ central/views/images/view_impl.go | 13 ++++++++++--- 6 files changed, 49 insertions(+), 5 deletions(-) diff --git a/central/views/imagecve/db_response.go b/central/views/imagecve/db_response.go index 8a42bb94accb0..336d23b766737 100644 --- a/central/views/imagecve/db_response.go +++ b/central/views/imagecve/db_response.go @@ -83,6 +83,10 @@ type imageResponse struct { ImageID string `db:"image_sha"` } +type imageV2Response struct { + ImageID string `db:"id"` +} + type deploymentResponse struct { DeploymentID string `db:"deployment_id"` } diff --git a/central/views/imagecve/view_impl.go b/central/views/imagecve/view_impl.go index 3d94348ea0c01..b4048f1ab3ba1 100644 --- a/central/views/imagecve/view_impl.go +++ b/central/views/imagecve/view_impl.go @@ -10,6 +10,7 @@ import ( v1 "github.com/stackrox/rox/generated/api/v1" "github.com/stackrox/rox/pkg/contextutil" "github.com/stackrox/rox/pkg/env" + "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/postgres" "github.com/stackrox/rox/pkg/postgres/walker" "github.com/stackrox/rox/pkg/sac/resources" @@ -191,6 +192,19 @@ func (v *imageCVECoreViewImpl) GetImageIDs(ctx context.Context, q *v1.Query) ([] queryCtx, cancel := contextutil.ContextWithTimeoutIfNotExists(ctx, queryTimeout) defer cancel() + if features.FlattenImageData.Enabled() { + var results []*imageV2Response + results, err = pgSearch.RunSelectRequestForSchema[imageV2Response](queryCtx, v.db, v.schema, q) + if err != nil || len(results) == 0 { + return nil, err + } + + ret := make([]string, 0, len(results)) + for _, r := range results { + ret = append(ret, r.ImageID) + } + return ret, nil + } var results []*imageResponse results, err = pgSearch.RunSelectRequestForSchema[imageResponse](queryCtx, v.db, v.schema, q) if err != nil || len(results) == 0 { diff --git a/central/views/imagecveflat/view_impl.go b/central/views/imagecveflat/view_impl.go index 20aba441b230a..941375968f671 100644 --- a/central/views/imagecveflat/view_impl.go +++ b/central/views/imagecveflat/view_impl.go @@ -10,6 +10,7 @@ import ( v1 "github.com/stackrox/rox/generated/api/v1" "github.com/stackrox/rox/pkg/contextutil" "github.com/stackrox/rox/pkg/env" + "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/postgres" "github.com/stackrox/rox/pkg/postgres/walker" "github.com/stackrox/rox/pkg/sac/resources" @@ -169,8 +170,14 @@ func withSelectCVEFlatResponseQuery(q *v1.Query, cveIDsToFilter []string, option if !options.SkipGetTopCVSS { cloned.Selects = append(cloned.Selects, search.NewQuerySelect(search.CVSS).AggrFunc(aggregatefunc.Max).Proto()) } + var searchField search.FieldLabel + if features.FlattenImageData.Enabled() { + searchField = search.ImageID + } else { + searchField = search.ImageSHA + } if !options.SkipGetAffectedImages { - cloned.Selects = append(cloned.Selects, search.NewQuerySelect(search.ImageSHA).AggrFunc(aggregatefunc.Count).Distinct().Proto()) + cloned.Selects = append(cloned.Selects, search.NewQuerySelect(searchField).AggrFunc(aggregatefunc.Count).Distinct().Proto()) } if !options.SkipGetFirstDiscoveredInSystem { cloned.Selects = append(cloned.Selects, search.NewQuerySelect(search.CVECreatedTime).AggrFunc(aggregatefunc.Min).Proto()) diff --git a/central/views/images/db_response.go b/central/views/images/db_response.go index 208f3b95ca934..1f9bad3b406f7 100644 --- a/central/views/images/db_response.go +++ b/central/views/images/db_response.go @@ -2,14 +2,19 @@ package images import ( "github.com/stackrox/rox/central/views/common" + "github.com/stackrox/rox/pkg/features" ) type imageResponse struct { common.ResourceCountByImageCVESeverity - ImageID string `db:"image_sha"` + ImageID string `db:"image_sha"` + ImageV2ID string `db:"id"` } func (i *imageResponse) GetImageID() string { + if features.FlattenImageData.Enabled() { + return i.ImageV2ID + } return i.ImageID } diff --git a/central/views/images/singleton.go b/central/views/images/singleton.go index 34f06e8fadc4c..be79d774f747e 100644 --- a/central/views/images/singleton.go +++ b/central/views/images/singleton.go @@ -2,6 +2,7 @@ package images import ( "github.com/stackrox/rox/central/globaldb" + "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/postgres" "github.com/stackrox/rox/pkg/postgres/schema" "github.com/stackrox/rox/pkg/sync" @@ -16,6 +17,12 @@ var ( // NewImageView returns the interface ImageView // that provides methods for searching images stored in the database. func NewImageView(db postgres.DB) ImageView { + if features.FlattenImageData.Enabled() { + return &imageCoreViewImpl{ + db: db, + schema: schema.ImagesV2Schema, + } + } return &imageCoreViewImpl{ db: db, schema: schema.ImagesSchema, diff --git a/central/views/images/view_impl.go b/central/views/images/view_impl.go index 47d9df2207b21..9abff78923871 100644 --- a/central/views/images/view_impl.go +++ b/central/views/images/view_impl.go @@ -7,6 +7,7 @@ import ( v1 "github.com/stackrox/rox/generated/api/v1" "github.com/stackrox/rox/pkg/contextutil" "github.com/stackrox/rox/pkg/env" + "github.com/stackrox/rox/pkg/features" "github.com/stackrox/rox/pkg/postgres" "github.com/stackrox/rox/pkg/postgres/walker" "github.com/stackrox/rox/pkg/sac/resources" @@ -53,20 +54,26 @@ func (v *imageCoreViewImpl) Get(ctx context.Context, query *v1.Query) ([]ImageCo func withSelectQuery(query *v1.Query) *v1.Query { cloned := query.CloneVT() + var searchField search.FieldLabel + if features.FlattenImageData.Enabled() { + searchField = search.ImageID + } else { + searchField = search.ImageSHA + } cloned.Selects = []*v1.QuerySelect{ - search.NewQuerySelect(search.ImageSHA).Proto(), + search.NewQuerySelect(searchField).Proto(), } if common.IsSortBySeverityCounts(cloned) { cloned.GroupBy = &v1.QueryGroupBy{ - Fields: []string{search.ImageSHA.String()}, + Fields: []string{searchField.String()}, } cloned.Selects = append(cloned.Selects, common.WithCountBySeverityAndFixabilityQuery(query, search.CVE).Selects..., ) } cloned.GroupBy = &v1.QueryGroupBy{ - Fields: []string{search.ImageSHA.String()}, + Fields: []string{searchField.String()}, } // This is to minimize UI change and hide an implementation detail that the query groups images by their SHA.