mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 02:05:41 +01:00
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:
parent
2af02f3b25
commit
ec8d692fe6
@ -6816,6 +6816,8 @@ definitions:
|
|||||||
format: int64
|
format: int64
|
||||||
description: 'Time in seconds required to create the report'
|
description: 'Time in seconds required to create the report'
|
||||||
example: 300
|
example: 300
|
||||||
|
scanner:
|
||||||
|
$ref: '#/definitions/Scanner'
|
||||||
NativeReportSummary:
|
NativeReportSummary:
|
||||||
type: object
|
type: object
|
||||||
description: 'The summary for the native report'
|
description: 'The summary for the native report'
|
||||||
|
@ -751,6 +751,11 @@ func (bc *basicController) GetSBOMSummary(ctx context.Context, art *ar.Artifact,
|
|||||||
reportContent := reports[0].Report
|
reportContent := reports[0].Report
|
||||||
result := map[string]interface{}{}
|
result := map[string]interface{}{}
|
||||||
if len(reportContent) == 0 {
|
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")
|
log.Debug("no content for current report")
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@ -758,6 +763,22 @@ func (bc *basicController) GetSBOMSummary(ctx context.Context, art *ar.Artifact,
|
|||||||
return result, err
|
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 ...
|
// GetScanLog ...
|
||||||
func (bc *basicController) GetScanLog(ctx context.Context, artifact *ar.Artifact, uuid string) ([]byte, error) {
|
func (bc *basicController) GetScanLog(ctx context.Context, artifact *ar.Artifact, uuid string) ([]byte, error) {
|
||||||
if len(uuid) == 0 {
|
if len(uuid) == 0 {
|
||||||
|
@ -70,9 +70,10 @@ type ControllerTestSuite struct {
|
|||||||
|
|
||||||
tagCtl *tagtesting.FakeController
|
tagCtl *tagtesting.FakeController
|
||||||
|
|
||||||
registration *scanner.Registration
|
registration *scanner.Registration
|
||||||
artifact *artifact.Artifact
|
artifact *artifact.Artifact
|
||||||
rawReport string
|
wrongArtifact *artifact.Artifact
|
||||||
|
rawReport string
|
||||||
|
|
||||||
execMgr *tasktesting.ExecutionManager
|
execMgr *tasktesting.ExecutionManager
|
||||||
taskMgr *tasktesting.Manager
|
taskMgr *tasktesting.Manager
|
||||||
@ -101,6 +102,9 @@ func (suite *ControllerTestSuite) SetupSuite() {
|
|||||||
suite.artifact.Digest = "digest-code"
|
suite.artifact.Digest = "digest-code"
|
||||||
suite.artifact.ManifestMediaType = v1.MimeTypeDockerArtifact
|
suite.artifact.ManifestMediaType = v1.MimeTypeDockerArtifact
|
||||||
|
|
||||||
|
suite.wrongArtifact = &artifact.Artifact{Artifact: art.Artifact{ID: 2, ProjectID: 1}}
|
||||||
|
suite.wrongArtifact.Digest = "digest-wrong"
|
||||||
|
|
||||||
m := &v1.ScannerAdapterMetadata{
|
m := &v1.ScannerAdapterMetadata{
|
||||||
Scanner: &v1.Scanner{
|
Scanner: &v1.Scanner{
|
||||||
Name: "Trivy",
|
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"}`,
|
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.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.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("Get", mock.Anything, "rp-uuid-001").Return(reports[0], nil)
|
||||||
mgr.On("UpdateReportData", "rp-uuid-001", suite.rawReport, (int64)(10000)).Return(nil)
|
mgr.On("UpdateReportData", "rp-uuid-001", suite.rawReport, (int64)(10000)).Return(nil)
|
||||||
mgr.On("UpdateStatus", "the-uuid-123", "Success", (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.NotNil(dgst)
|
||||||
suite.Equal("Success", status)
|
suite.Equal("Success", status)
|
||||||
suite.Equal("sha256:1234567890", dgst)
|
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) {
|
func TestIsSBOMMimeTypes(t *testing.T) {
|
||||||
@ -683,5 +696,11 @@ func (suite *ControllerTestSuite) TestDeleteArtifactAccessories() {
|
|||||||
}
|
}
|
||||||
ctx := orm.NewContext(nil, &ormtesting.FakeOrmer{})
|
ctx := orm.NewContext(nil, &ormtesting.FakeOrmer{})
|
||||||
suite.NoError(suite.c.deleteArtifactAccessories(ctx, reports))
|
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)
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,10 @@ const (
|
|||||||
Duration = "duration"
|
Duration = "duration"
|
||||||
// ScanStatus ...
|
// ScanStatus ...
|
||||||
ScanStatus = "scan_status"
|
ScanStatus = "scan_status"
|
||||||
|
// ReportID ...
|
||||||
|
ReportID = "report_id"
|
||||||
|
// Scanner ...
|
||||||
|
Scanner = "scanner"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Summary includes the sbom summary information
|
// Summary includes the sbom summary information
|
||||||
|
@ -87,7 +87,7 @@ func (v *scanHandler) RequiredPermissions() []*types.Policy {
|
|||||||
|
|
||||||
// PostScan defines task specific operations after the scan is complete
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return "", err
|
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)
|
myLogger.Errorf("error when create accessory from image %v", err)
|
||||||
return "", 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
|
// 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{}
|
summary := sbom.Summary{}
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
summary[sbom.StartTime] = startTime
|
summary[sbom.StartTime] = startTime
|
||||||
@ -130,6 +130,7 @@ func (v *scanHandler) generateReport(startTime time.Time, repository, digest, st
|
|||||||
summary[sbom.SBOMRepository] = repository
|
summary[sbom.SBOMRepository] = repository
|
||||||
summary[sbom.SBOMDigest] = digest
|
summary[sbom.SBOMDigest] = digest
|
||||||
summary[sbom.ScanStatus] = status
|
summary[sbom.ScanStatus] = status
|
||||||
|
summary[sbom.Scanner] = scanner
|
||||||
rep, err := json.Marshal(summary)
|
rep, err := json.Marshal(summary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -150,15 +151,15 @@ func registryFQDN(ctx context.Context) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// retrieveSBOMContent retrieves the "sbom" field from the raw report
|
// 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{}
|
rpt := vuln.Report{}
|
||||||
err := json.Unmarshal([]byte(rawReport), &rpt)
|
err := json.Unmarshal([]byte(rawReport), &rpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
sbomContent, err := json.Marshal(rpt.SBOM)
|
sbomContent, err := json.Marshal(rpt.SBOM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return sbomContent, nil
|
return sbomContent, rpt.Scanner, nil
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,12 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/lib"
|
"github.com/goharbor/harbor/src/lib"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
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"
|
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
vulnerabilitiesAddition = "vulnerabilities"
|
vulnerabilitiesAddition = "vulnerabilities"
|
||||||
startTime = "start_time"
|
|
||||||
endTime = "end_time"
|
|
||||||
scanStatus = "scan_status"
|
|
||||||
sbomDigest = "sbom_digest"
|
|
||||||
duration = "duration"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewScanReportAssembler returns vul assembler
|
// 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})
|
overview, err := assembler.scanCtl.GetSummary(ctx, &artifact.Artifact, []string{v1.MimeTypeSBOMReport})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("get scan summary of artifact %s@%s for %s failed, error:%v", artifact.RepositoryName, artifact.Digest, v1.MimeTypeSBOMReport, err)
|
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{}{
|
artifact.SBOMOverView = map[string]interface{}{
|
||||||
startTime: overview[startTime],
|
sbomModel.StartTime: overview[sbomModel.StartTime],
|
||||||
endTime: overview[endTime],
|
sbomModel.EndTime: overview[sbomModel.EndTime],
|
||||||
scanStatus: overview[scanStatus],
|
sbomModel.ScanStatus: overview[sbomModel.ScanStatus],
|
||||||
sbomDigest: overview[sbomDigest],
|
sbomModel.SBOMDigest: overview[sbomModel.SBOMDigest],
|
||||||
duration: overview[duration],
|
sbomModel.Duration: overview[sbomModel.Duration],
|
||||||
|
sbomModel.ReportID: overview[sbomModel.ReportID],
|
||||||
|
sbomModel.Scanner: overview[sbomModel.Scanner],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user