Add scanner info and report_id to sbom_overview on listing artifact (#20358)

Add scan_status and report_id when scan has a failed task

Signed-off-by: stonezdj <stone.zhang@broadcom.com>
This commit is contained in:
stonezdj(Daojun Zhang) 2024-04-25 17:00:35 +08:00 committed by GitHub
parent 2af02f3b25
commit ec8d692fe6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 68 additions and 23 deletions

View File

@ -6816,6 +6816,8 @@ definitions:
format: int64
description: 'Time in seconds required to create the report'
example: 300
scanner:
$ref: '#/definitions/Scanner'
NativeReportSummary:
type: object
description: 'The summary for the native report'

View File

@ -751,6 +751,11 @@ func (bc *basicController) GetSBOMSummary(ctx context.Context, art *ar.Artifact,
reportContent := reports[0].Report
result := map[string]interface{}{}
if len(reportContent) == 0 {
status := bc.retrieveStatusFromTask(ctx, reports[0].UUID)
if len(status) > 0 {
result[sbomModel.ReportID] = reports[0].UUID
result[sbomModel.ScanStatus] = status
}
log.Debug("no content for current report")
return result, nil
}
@ -758,6 +763,22 @@ func (bc *basicController) GetSBOMSummary(ctx context.Context, art *ar.Artifact,
return result, err
}
// retrieve the status from task
func (bc *basicController) retrieveStatusFromTask(ctx context.Context, reportID string) string {
if len(reportID) == 0 {
return ""
}
tasks, err := bc.taskMgr.ListScanTasksByReportUUID(ctx, reportID)
if err != nil {
log.Warningf("can not find the task with report UUID %v, error %v", reportID, err)
return ""
}
if len(tasks) > 0 {
return tasks[0].Status
}
return ""
}
// GetScanLog ...
func (bc *basicController) GetScanLog(ctx context.Context, artifact *ar.Artifact, uuid string) ([]byte, error) {
if len(uuid) == 0 {

View File

@ -70,9 +70,10 @@ type ControllerTestSuite struct {
tagCtl *tagtesting.FakeController
registration *scanner.Registration
artifact *artifact.Artifact
rawReport string
registration *scanner.Registration
artifact *artifact.Artifact
wrongArtifact *artifact.Artifact
rawReport string
execMgr *tasktesting.ExecutionManager
taskMgr *tasktesting.Manager
@ -101,6 +102,9 @@ func (suite *ControllerTestSuite) SetupSuite() {
suite.artifact.Digest = "digest-code"
suite.artifact.ManifestMediaType = v1.MimeTypeDockerArtifact
suite.wrongArtifact = &artifact.Artifact{Artifact: art.Artifact{ID: 2, ProjectID: 1}}
suite.wrongArtifact.Digest = "digest-wrong"
m := &v1.ScannerAdapterMetadata{
Scanner: &v1.Scanner{
Name: "Trivy",
@ -202,8 +206,11 @@ func (suite *ControllerTestSuite) SetupSuite() {
Report: `{"sbom_digest": "sha256:1234567890", "scan_status": "Success", "duration": 3, "start_time": "2021-09-01T00:00:00Z", "end_time": "2021-09-01T00:00:03Z"}`,
},
}
emptySBOMReport := []*scan.Report{{Report: ``, UUID: "rp-uuid-004"}}
mgr.On("GetBy", mock.Anything, suite.artifact.Digest, suite.registration.UUID, []string{v1.MimeTypeNativeReport}).Return(reports, nil)
mgr.On("GetBy", mock.Anything, suite.artifact.Digest, suite.registration.UUID, []string{v1.MimeTypeSBOMReport}).Return(sbomReport, nil)
mgr.On("GetBy", mock.Anything, suite.wrongArtifact.Digest, suite.registration.UUID, []string{v1.MimeTypeSBOMReport}).Return(emptySBOMReport, nil)
mgr.On("Get", mock.Anything, "rp-uuid-001").Return(reports[0], nil)
mgr.On("UpdateReportData", "rp-uuid-001", suite.rawReport, (int64)(10000)).Return(nil)
mgr.On("UpdateStatus", "the-uuid-123", "Success", (int64)(10000)).Return(nil)
@ -654,6 +661,12 @@ func (suite *ControllerTestSuite) TestGenerateSBOMSummary() {
suite.NotNil(dgst)
suite.Equal("Success", status)
suite.Equal("sha256:1234567890", dgst)
tasks := []*task.Task{{Status: "Error"}}
suite.taskMgr.On("ListScanTasksByReportUUID", mock.Anything, "rp-uuid-004").Return(tasks, nil).Once()
sum2, err := suite.c.GetSummary(context.TODO(), suite.wrongArtifact, []string{v1.MimeTypeSBOMReport})
suite.Nil(err)
suite.NotNil(sum2)
}
func TestIsSBOMMimeTypes(t *testing.T) {
@ -683,5 +696,11 @@ func (suite *ControllerTestSuite) TestDeleteArtifactAccessories() {
}
ctx := orm.NewContext(nil, &ormtesting.FakeOrmer{})
suite.NoError(suite.c.deleteArtifactAccessories(ctx, reports))
}
func (suite *ControllerTestSuite) TestRetrieveStatusFromTask() {
tasks := []*task.Task{{Status: "Error"}}
suite.taskMgr.On("ListScanTasksByReportUUID", mock.Anything, "rp-uuid-004").Return(tasks, nil).Once()
status := suite.c.retrieveStatusFromTask(nil, "rp-uuid-004")
suite.Equal("Error", status)
}

View File

@ -27,6 +27,10 @@ const (
Duration = "duration"
// ScanStatus ...
ScanStatus = "scan_status"
// ReportID ...
ReportID = "report_id"
// Scanner ...
Scanner = "scanner"
)
// Summary includes the sbom summary information

View File

@ -87,7 +87,7 @@ func (v *scanHandler) RequiredPermissions() []*types.Policy {
// PostScan defines task specific operations after the scan is complete
func (v *scanHandler) PostScan(ctx job.Context, sr *v1.ScanRequest, _ *scanModel.Report, rawReport string, startTime time.Time, robot *model.Robot) (string, error) {
sbomContent, err := retrieveSBOMContent(rawReport)
sbomContent, s, err := retrieveSBOMContent(rawReport)
if err != nil {
return "", err
}
@ -107,7 +107,7 @@ func (v *scanHandler) PostScan(ctx job.Context, sr *v1.ScanRequest, _ *scanModel
myLogger.Errorf("error when create accessory from image %v", err)
return "", err
}
return v.generateReport(startTime, sr.Artifact.Repository, dgst, "Success")
return v.generateReport(startTime, sr.Artifact.Repository, dgst, "Success", s)
}
// annotations defines the annotations for the accessory artifact
@ -121,7 +121,7 @@ func (v *scanHandler) annotations() map[string]string {
}
}
func (v *scanHandler) generateReport(startTime time.Time, repository, digest, status string) (string, error) {
func (v *scanHandler) generateReport(startTime time.Time, repository, digest, status string, scanner *v1.Scanner) (string, error) {
summary := sbom.Summary{}
endTime := time.Now()
summary[sbom.StartTime] = startTime
@ -130,6 +130,7 @@ func (v *scanHandler) generateReport(startTime time.Time, repository, digest, st
summary[sbom.SBOMRepository] = repository
summary[sbom.SBOMDigest] = digest
summary[sbom.ScanStatus] = status
summary[sbom.Scanner] = scanner
rep, err := json.Marshal(summary)
if err != nil {
return "", err
@ -150,15 +151,15 @@ func registryFQDN(ctx context.Context) string {
}
// retrieveSBOMContent retrieves the "sbom" field from the raw report
func retrieveSBOMContent(rawReport string) ([]byte, error) {
func retrieveSBOMContent(rawReport string) ([]byte, *v1.Scanner, error) {
rpt := vuln.Report{}
err := json.Unmarshal([]byte(rawReport), &rpt)
if err != nil {
return nil, err
return nil, nil, err
}
sbomContent, err := json.Marshal(rpt.SBOM)
if err != nil {
return nil, err
return nil, nil, err
}
return sbomContent, nil
return sbomContent, rpt.Scanner, nil
}

View File

@ -21,16 +21,12 @@ import (
"github.com/goharbor/harbor/src/lib"
"github.com/goharbor/harbor/src/lib/log"
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/server/v2.0/handler/model"
)
const (
vulnerabilitiesAddition = "vulnerabilities"
startTime = "start_time"
endTime = "end_time"
scanStatus = "scan_status"
sbomDigest = "sbom_digest"
duration = "duration"
)
// NewScanReportAssembler returns vul assembler
@ -92,17 +88,19 @@ func (assembler *ScanReportAssembler) Assemble(ctx context.Context) error {
overview, err := assembler.scanCtl.GetSummary(ctx, &artifact.Artifact, []string{v1.MimeTypeSBOMReport})
if err != nil {
log.Warningf("get scan summary of artifact %s@%s for %s failed, error:%v", artifact.RepositoryName, artifact.Digest, v1.MimeTypeSBOMReport, err)
} else if len(overview) > 0 {
}
if len(overview) > 0 {
artifact.SBOMOverView = map[string]interface{}{
startTime: overview[startTime],
endTime: overview[endTime],
scanStatus: overview[scanStatus],
sbomDigest: overview[sbomDigest],
duration: overview[duration],
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],
}
}
}
}
return nil
}