From df5b3618c7ce067364b9134d59adac91a4f7e904 Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Wed, 15 May 2024 19:52:39 +0800 Subject: [PATCH] Display status in sbom_overview for image index (#20425) fixes #20418 Signed-off-by: stonezdj --- src/server/v2.0/handler/assembler/report.go | 47 ++++++++++++++----- .../v2.0/handler/assembler/report_test.go | 36 ++++++++++++++ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/server/v2.0/handler/assembler/report.go b/src/server/v2.0/handler/assembler/report.go index ff11e2b8f..51b0df460 100644 --- a/src/server/v2.0/handler/assembler/report.go +++ b/src/server/v2.0/handler/assembler/report.go @@ -20,8 +20,10 @@ import ( "github.com/goharbor/harbor/src/controller/scan" "github.com/goharbor/harbor/src/lib" "github.com/goharbor/harbor/src/lib/log" + "github.com/goharbor/harbor/src/lib/q" v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1" sbomModel "github.com/goharbor/harbor/src/pkg/scan/sbom/model" + "github.com/goharbor/harbor/src/pkg/task" "github.com/goharbor/harbor/src/server/v2.0/handler/model" ) @@ -36,13 +38,15 @@ func NewScanReportAssembler(option *model.OverviewOptions, mimeTypes []string) * scanChecker: scan.NewChecker(), scanCtl: scan.DefaultController, mimeTypes: mimeTypes, + executionMgr: task.ExecMgr, } } // ScanReportAssembler vul assembler type ScanReportAssembler struct { - scanChecker scan.Checker - scanCtl scan.Controller + scanChecker scan.Checker + scanCtl scan.Controller + executionMgr task.ExecutionManager artifacts []*model.Artifact mimeTypes []string @@ -89,16 +93,37 @@ func (assembler *ScanReportAssembler) Assemble(ctx context.Context) error { if err != nil { log.Warningf("get scan summary of artifact %s@%s for %s failed, error:%v", artifact.RepositoryName, artifact.Digest, v1.MimeTypeSBOMReport, err) } - if len(overview) > 0 { - artifact.SBOMOverView = map[string]interface{}{ - sbomModel.StartTime: overview[sbomModel.StartTime], - sbomModel.EndTime: overview[sbomModel.EndTime], - sbomModel.ScanStatus: overview[sbomModel.ScanStatus], - sbomModel.SBOMDigest: overview[sbomModel.SBOMDigest], - sbomModel.Duration: overview[sbomModel.Duration], - sbomModel.ReportID: overview[sbomModel.ReportID], - sbomModel.Scanner: overview[sbomModel.Scanner], + if len(overview) == 0 { + log.Warningf("overview is empty, retrieve sbom status from execution") + query := q.New(q.KeyWords{"extra_attrs.artifact.digest": artifact.Digest, "extra_attrs.enabled_capabilities.type": "sbom"}) + // sort by ID desc to get the latest execution + query.Sorts = []*q.Sort{q.NewSort("ID", true)} + execs, err := assembler.executionMgr.List(ctx, query) + if err != nil { + log.Warningf("get scan summary of artifact %s@%s for %s failed, error:%v", artifact.RepositoryName, artifact.Digest, v1.MimeTypeSBOMReport, err) + continue } + // if no execs, means this artifact is not scanned, leave the sbom_overview empty + if len(execs) == 0 { + continue + } + artifact.SBOMOverView = map[string]interface{}{ + sbomModel.ScanStatus: execs[0].Status, + sbomModel.StartTime: execs[0].StartTime, + sbomModel.EndTime: execs[0].EndTime, + sbomModel.Duration: int64(execs[0].EndTime.Sub(execs[0].StartTime).Seconds()), + } + continue + } + + artifact.SBOMOverView = map[string]interface{}{ + sbomModel.StartTime: overview[sbomModel.StartTime], + sbomModel.EndTime: overview[sbomModel.EndTime], + sbomModel.ScanStatus: overview[sbomModel.ScanStatus], + sbomModel.SBOMDigest: overview[sbomModel.SBOMDigest], + sbomModel.Duration: overview[sbomModel.Duration], + sbomModel.ReportID: overview[sbomModel.ReportID], + sbomModel.Scanner: overview[sbomModel.Scanner], } } } diff --git a/src/server/v2.0/handler/assembler/report_test.go b/src/server/v2.0/handler/assembler/report_test.go index 6079a1d60..88ff6a3bd 100644 --- a/src/server/v2.0/handler/assembler/report_test.go +++ b/src/server/v2.0/handler/assembler/report_test.go @@ -21,9 +21,11 @@ import ( "github.com/stretchr/testify/suite" v1sq "github.com/goharbor/harbor/src/pkg/scan/rest/v1" + "github.com/goharbor/harbor/src/pkg/task" "github.com/goharbor/harbor/src/server/v2.0/handler/model" "github.com/goharbor/harbor/src/testing/controller/scan" "github.com/goharbor/harbor/src/testing/mock" + mockTask "github.com/goharbor/harbor/src/testing/pkg/task" ) type VulAssemblerTestSuite struct { @@ -101,6 +103,40 @@ func (suite *VulAssemblerTestSuite) TestAssembleSBOMOverview() { } +func (suite *VulAssemblerTestSuite) TestAssembleSBOMOverviewImageIndex() { + checker := &scan.Checker{} + scanCtl := &scan.Controller{} + exeMgr := &mockTask.ExecutionManager{} + + assembler := ScanReportAssembler{ + scanChecker: checker, + scanCtl: scanCtl, + executionMgr: exeMgr, + overviewOption: model.NewOverviewOptions(model.WithSBOM(true)), + mimeTypes: []string{v1sq.MimeTypeSBOMReport}, + } + + mock.OnAnything(checker, "IsScannable").Return(true, nil) + overview := map[string]interface{}{} + mock.OnAnything(scanCtl, "GetSummary").Return(overview, nil) + execs := []*task.Execution{ + {ID: 1, Status: "Error"}, + {ID: 2, Status: "Success"}, + } + mock.OnAnything(exeMgr, "List").Return(execs, nil).Once() + + var artifact model.Artifact + err := assembler.WithArtifacts(&artifact).Assemble(context.TODO()) + suite.Nil(err) + suite.Equal(artifact.SBOMOverView["scan_status"], "Error") + + mock.OnAnything(exeMgr, "List").Return(nil, nil).Once() + var artifact2 model.Artifact + err2 := assembler.WithArtifacts(&artifact2).Assemble(context.TODO()) + suite.Nil(err2) + suite.Nil(artifact2.SBOMOverView, "sbom overview should be nil") +} + func TestVulAssemblerTestSuite(t *testing.T) { suite.Run(t, &VulAssemblerTestSuite{}) }