mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
Fix scan log mismatch issue (#17085)
Add checks in label Signed-off-by: stonezdj <stonezdj@gmail.com>
This commit is contained in:
parent
889407ab38
commit
aa63569de2
@ -80,6 +80,7 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionUpdate},
|
||||
@ -180,6 +181,7 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
|
||||
|
||||
@ -238,6 +240,7 @@ var (
|
||||
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionCreate},
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionDelete},
|
||||
{Resource: rbac.ResourceHelmChartVersionLabel, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
|
||||
|
||||
|
@ -633,11 +633,23 @@ func (bc *basicController) GetSummary(ctx context.Context, artifact *ar.Artifact
|
||||
}
|
||||
|
||||
// GetScanLog ...
|
||||
func (bc *basicController) GetScanLog(ctx context.Context, uuid string) ([]byte, error) {
|
||||
func (bc *basicController) GetScanLog(ctx context.Context, artifact *ar.Artifact, uuid string) ([]byte, error) {
|
||||
if len(uuid) == 0 {
|
||||
return nil, errors.New("empty uuid to get scan log")
|
||||
}
|
||||
r, err := bc.sc.GetRegistrationByProject(ctx, artifact.ProjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
artifacts, _, err := bc.collectScanningArtifacts(ctx, r, artifact)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
artifactMap := map[int64]interface{}{}
|
||||
for _, a := range artifacts {
|
||||
artifactMap[a.ID] = struct{}{}
|
||||
}
|
||||
reportUUIDs := vuln.ParseReportIDs(uuid)
|
||||
tasks, err := bc.listScanTasks(ctx, reportUUIDs)
|
||||
if err != nil {
|
||||
@ -649,9 +661,12 @@ func (bc *basicController) GetScanLog(ctx context.Context, uuid string) ([]byte,
|
||||
}
|
||||
|
||||
reportUUIDToTasks := map[string]*task.Task{}
|
||||
for _, task := range tasks {
|
||||
for _, reportUUID := range getReportUUIDs(task.ExtraAttrs) {
|
||||
reportUUIDToTasks[reportUUID] = task
|
||||
for _, t := range tasks {
|
||||
if !scanTaskForArtifacts(t, artifactMap) {
|
||||
return nil, errors.NotFoundError(nil).WithMessage("scan log with uuid: %s not found", uuid)
|
||||
}
|
||||
for _, reportUUID := range getReportUUIDs(t.ExtraAttrs) {
|
||||
reportUUIDToTasks[reportUUID] = t
|
||||
}
|
||||
}
|
||||
|
||||
@ -719,6 +734,18 @@ func (bc *basicController) GetScanLog(ctx context.Context, uuid string) ([]byte,
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func scanTaskForArtifacts(task *task.Task, artifactMap map[int64]interface{}) bool {
|
||||
if task == nil {
|
||||
return false
|
||||
}
|
||||
artifactID := int64(task.GetNumFromExtraAttrs(artifactIDKey))
|
||||
if artifactID == 0 {
|
||||
return false
|
||||
}
|
||||
_, exist := artifactMap[artifactID]
|
||||
return exist
|
||||
}
|
||||
|
||||
// DeleteReports ...
|
||||
func (bc *basicController) DeleteReports(ctx context.Context, digests ...string) error {
|
||||
if err := bc.manager.DeleteByDigests(ctx, digests...); err != nil {
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
art "github.com/goharbor/harbor/src/pkg/artifact"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/db"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
@ -88,7 +89,7 @@ func (suite *ControllerTestSuite) SetupSuite() {
|
||||
suite.artifactCtl = &artifacttesting.Controller{}
|
||||
artifact.Ctl = suite.artifactCtl
|
||||
|
||||
suite.artifact = &artifact.Artifact{}
|
||||
suite.artifact = &artifact.Artifact{Artifact: art.Artifact{ID: 1}}
|
||||
suite.artifact.Type = "IMAGE"
|
||||
suite.artifact.ProjectID = 1
|
||||
suite.artifact.RepositoryName = "library/photon"
|
||||
@ -320,7 +321,7 @@ func (suite *ControllerTestSuite) TestScanControllerScan() {
|
||||
}).Once()
|
||||
|
||||
mock.OnAnything(suite.taskMgr, "List").Return([]*task.Task{
|
||||
{ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001"), Status: "Success"},
|
||||
{ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001"), Status: "Success"},
|
||||
}, nil).Once()
|
||||
|
||||
mock.OnAnything(suite.reportMgr, "Delete").Return(nil).Once()
|
||||
@ -342,7 +343,7 @@ func (suite *ControllerTestSuite) TestScanControllerScan() {
|
||||
}).Once()
|
||||
|
||||
mock.OnAnything(suite.taskMgr, "List").Return([]*task.Task{
|
||||
{ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001"), Status: "Success"},
|
||||
{ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001"), Status: "Success"},
|
||||
}, nil).Once()
|
||||
|
||||
mock.OnAnything(suite.reportMgr, "Delete").Return(fmt.Errorf("delete failed")).Once()
|
||||
@ -359,7 +360,7 @@ func (suite *ControllerTestSuite) TestScanControllerScan() {
|
||||
}).Once()
|
||||
|
||||
mock.OnAnything(suite.taskMgr, "List").Return([]*task.Task{
|
||||
{ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001"), Status: "Running"},
|
||||
{ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001"), Status: "Running"},
|
||||
}, nil).Once()
|
||||
|
||||
suite.Require().Error(suite.c.Scan(context.TODO(), suite.artifact))
|
||||
@ -376,7 +377,7 @@ func (suite *ControllerTestSuite) TestScanControllerStop() {
|
||||
{
|
||||
// success
|
||||
mock.OnAnything(suite.execMgr, "List").Return([]*task.Execution{
|
||||
{ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001"), Status: "Running"},
|
||||
{ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001"), Status: "Running"},
|
||||
}, nil).Once()
|
||||
mock.OnAnything(suite.execMgr, "Stop").Return(nil).Once()
|
||||
|
||||
@ -413,9 +414,9 @@ func (suite *ControllerTestSuite) TestScanControllerGetReport() {
|
||||
}).Once()
|
||||
|
||||
mock.OnAnything(suite.taskMgr, "List").Return([]*task.Task{
|
||||
{ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001")},
|
||||
{ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001")},
|
||||
}, nil).Once()
|
||||
|
||||
mock.OnAnything(suite.accessoryMgr, "List").Return(nil, nil)
|
||||
rep, err := suite.c.GetReport(context.TODO(), suite.artifact, []string{v1.MimeTypeNativeReport})
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), 1, len(rep))
|
||||
@ -440,13 +441,13 @@ func (suite *ControllerTestSuite) TestScanControllerGetScanLog() {
|
||||
mock.OnAnything(suite.taskMgr, "List").Return([]*task.Task{
|
||||
{
|
||||
ID: 1,
|
||||
ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001"),
|
||||
ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001"),
|
||||
},
|
||||
}, nil).Once()
|
||||
|
||||
mock.OnAnything(suite.taskMgr, "GetLog").Return([]byte("log"), nil).Once()
|
||||
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), "rp-uuid-001")
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), &artifact.Artifact{Artifact: art.Artifact{ID: 1, ProjectID: 1}}, "rp-uuid-001")
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Condition(suite.T(), func() (success bool) {
|
||||
success = len(bytes) > 0
|
||||
@ -459,23 +460,26 @@ func (suite *ControllerTestSuite) TestScanControllerGetMultiScanLog() {
|
||||
suite.taskMgr.On("List", context.TODO(), q.New(kw1)).Return([]*task.Task{
|
||||
{
|
||||
ID: 1,
|
||||
ExtraAttrs: suite.makeExtraAttrs("rp-uuid-001"),
|
||||
ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001"),
|
||||
},
|
||||
}, nil).Times(4)
|
||||
|
||||
mock.OnAnything(suite.ar, "Walk").Return(nil).Run(func(args mock.Arguments) {
|
||||
walkFn := args.Get(2).(func(*artifact.Artifact) error)
|
||||
walkFn(suite.artifact)
|
||||
})
|
||||
mock.OnAnything(suite.accessoryMgr, "List").Return(nil, nil)
|
||||
kw2 := q.KeyWords{"extra_attrs.report:rp-uuid-002": "1"}
|
||||
suite.taskMgr.On("List", context.TODO(), q.New(kw2)).Return([]*task.Task{
|
||||
{
|
||||
ID: 2,
|
||||
ExtraAttrs: suite.makeExtraAttrs("rp-uuid-002"),
|
||||
ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-002"),
|
||||
},
|
||||
}, nil).Times(4)
|
||||
|
||||
{
|
||||
// Both success
|
||||
mock.OnAnything(suite.taskMgr, "GetLog").Return([]byte("log"), nil).Twice()
|
||||
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), &artifact.Artifact{Artifact: art.Artifact{ID: 1, ProjectID: 1}}, base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
suite.Nil(err)
|
||||
suite.NotEmpty(bytes)
|
||||
suite.Contains(string(bytes), "Logs of report rp-uuid-001")
|
||||
@ -487,7 +491,7 @@ func (suite *ControllerTestSuite) TestScanControllerGetMultiScanLog() {
|
||||
suite.taskMgr.On("GetLog", context.TODO(), int64(1)).Return([]byte("log"), nil).Once()
|
||||
suite.taskMgr.On("GetLog", context.TODO(), int64(2)).Return(nil, fmt.Errorf("failed")).Once()
|
||||
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), &artifact.Artifact{Artifact: art.Artifact{ID: 1, ProjectID: 1}}, base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
suite.Nil(err)
|
||||
suite.NotEmpty(bytes)
|
||||
suite.NotContains(string(bytes), "Logs of report rp-uuid-001")
|
||||
@ -497,7 +501,7 @@ func (suite *ControllerTestSuite) TestScanControllerGetMultiScanLog() {
|
||||
// Both failed
|
||||
mock.OnAnything(suite.taskMgr, "GetLog").Return(nil, fmt.Errorf("failed")).Twice()
|
||||
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), &artifact.Artifact{Artifact: art.Artifact{ID: 1, ProjectID: 1}}, base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
suite.Error(err)
|
||||
suite.Empty(bytes)
|
||||
}
|
||||
@ -506,7 +510,7 @@ func (suite *ControllerTestSuite) TestScanControllerGetMultiScanLog() {
|
||||
// Both empty
|
||||
mock.OnAnything(suite.taskMgr, "GetLog").Return(nil, nil).Twice()
|
||||
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
bytes, err := suite.c.GetScanLog(context.TODO(), &artifact.Artifact{Artifact: art.Artifact{ID: 1, ProjectID: 1}}, base64.StdEncoding.EncodeToString([]byte("rp-uuid-001|rp-uuid-002")))
|
||||
suite.Nil(err)
|
||||
suite.Empty(bytes)
|
||||
}
|
||||
@ -578,11 +582,12 @@ func (suite *ControllerTestSuite) TestDeleteReports() {
|
||||
suite.Error(suite.c.DeleteReports(context.TODO(), "digest"))
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) makeExtraAttrs(reportUUIDs ...string) map[string]interface{} {
|
||||
func (suite *ControllerTestSuite) makeExtraAttrs(artifactID int64, reportUUIDs ...string) map[string]interface{} {
|
||||
b, _ := json.Marshal(map[string]interface{}{reportUUIDsKey: reportUUIDs})
|
||||
|
||||
extraAttrs := map[string]interface{}{}
|
||||
json.Unmarshal(b, &extraAttrs)
|
||||
extraAttrs[artifactIDKey] = float64(artifactID)
|
||||
|
||||
return extraAttrs
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ type Controller interface {
|
||||
// Returns:
|
||||
// []byte : the log text stream
|
||||
// error : non nil error if any errors occurred
|
||||
GetScanLog(ctx context.Context, uuid string) ([]byte, error)
|
||||
GetScanLog(ctx context.Context, art *artifact.Artifact, uuid string) ([]byte, error)
|
||||
|
||||
// Delete the reports related with the specified digests
|
||||
//
|
||||
|
@ -107,5 +107,8 @@ func (cla *ChartLabelAPI) RemoveLabel() {
|
||||
|
||||
// GetLabels gets labels for the specified chart version.
|
||||
func (cla *ChartLabelAPI) GetLabels() {
|
||||
if !cla.requireAccess(rbac.ActionList) {
|
||||
return
|
||||
}
|
||||
cla.getLabelsOfResource(common.ResourceTypeChart, cla.chartFullName)
|
||||
}
|
||||
|
@ -18,11 +18,14 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/label"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
@ -49,23 +52,25 @@ import (
|
||||
|
||||
func newArtifactAPI() *artifactAPI {
|
||||
return &artifactAPI{
|
||||
accMgr: accessory.Mgr,
|
||||
artCtl: artifact.Ctl,
|
||||
proCtl: project.Ctl,
|
||||
repoCtl: repository.Ctl,
|
||||
scanCtl: scan.DefaultController,
|
||||
tagCtl: tag.Ctl,
|
||||
accMgr: accessory.Mgr,
|
||||
artCtl: artifact.Ctl,
|
||||
proCtl: project.Ctl,
|
||||
repoCtl: repository.Ctl,
|
||||
scanCtl: scan.DefaultController,
|
||||
tagCtl: tag.Ctl,
|
||||
labelMgr: label.Mgr,
|
||||
}
|
||||
}
|
||||
|
||||
type artifactAPI struct {
|
||||
BaseAPI
|
||||
accMgr accessory.Manager
|
||||
artCtl artifact.Controller
|
||||
proCtl project.Controller
|
||||
repoCtl repository.Controller
|
||||
scanCtl scan.Controller
|
||||
tagCtl tag.Controller
|
||||
accMgr accessory.Manager
|
||||
artCtl artifact.Controller
|
||||
proCtl project.Controller
|
||||
repoCtl repository.Controller
|
||||
scanCtl scan.Controller
|
||||
tagCtl tag.Controller
|
||||
labelMgr label.Manager
|
||||
}
|
||||
|
||||
func (a *artifactAPI) Prepare(ctx context.Context, operation string, params interface{}) middleware.Responder {
|
||||
@ -453,7 +458,14 @@ func (a *artifactAPI) GetAddition(ctx context.Context, params operation.GetAddit
|
||||
}
|
||||
|
||||
func (a *artifactAPI) AddLabel(ctx context.Context, params operation.AddLabelParams) middleware.Responder {
|
||||
if err := a.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionCreate, rbac.ResourceArtifactLabel); err != nil {
|
||||
projectID, err := getProjectID(ctx, params.ProjectName)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
if err := a.RequireProjectAccess(ctx, projectID, rbac.ActionCreate, rbac.ResourceArtifactLabel); err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
if err := a.RequireLabelInProject(ctx, projectID, params.Label.ID); err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
art, err := a.artCtl.GetByReference(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName), params.Reference, nil)
|
||||
@ -480,6 +492,17 @@ func (a *artifactAPI) RemoveLabel(ctx context.Context, params operation.RemoveLa
|
||||
return operation.NewRemoveLabelOK()
|
||||
}
|
||||
|
||||
func (a *artifactAPI) RequireLabelInProject(ctx context.Context, projectID, labelID int64) error {
|
||||
l, err := a.labelMgr.Get(ctx, labelID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if l.Scope == common.LabelScopeProject && l.ProjectID != projectID {
|
||||
return errors.NotFoundError(nil).WithMessage("project id %d, label %d not found", projectID, labelID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func option(withTag, withImmutableStatus, withLabel, withSignature, withAccessory *bool) *artifact.Option {
|
||||
option := &artifact.Option{
|
||||
WithTag: true, // return the tag by default
|
||||
|
@ -92,14 +92,13 @@ func (s *scanAPI) GetReportLog(ctx context.Context, params operation.GetReportLo
|
||||
if err := s.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionRead, rbac.ResourceScan); err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
|
||||
repository := fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName)
|
||||
_, err := s.artCtl.GetByReference(ctx, repository, params.Reference, nil)
|
||||
a, err := s.artCtl.GetByReference(ctx, repository, params.Reference, nil)
|
||||
if err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
|
||||
bytes, err := s.scanCtl.GetScanLog(ctx, params.ReportID)
|
||||
bytes, err := s.scanCtl.GetScanLog(ctx, a, params.ReportID)
|
||||
if err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
|
@ -65,13 +65,13 @@ func (_m *Controller) GetReport(ctx context.Context, _a1 *artifact.Artifact, mim
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetScanLog provides a mock function with given fields: ctx, uuid
|
||||
func (_m *Controller) GetScanLog(ctx context.Context, uuid string) ([]byte, error) {
|
||||
ret := _m.Called(ctx, uuid)
|
||||
// GetScanLog provides a mock function with given fields: ctx, art, uuid
|
||||
func (_m *Controller) GetScanLog(ctx context.Context, art *artifact.Artifact, uuid string) ([]byte, error) {
|
||||
ret := _m.Called(ctx, art, uuid)
|
||||
|
||||
var r0 []byte
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []byte); ok {
|
||||
r0 = rf(ctx, uuid)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact, string) []byte); ok {
|
||||
r0 = rf(ctx, art, uuid)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
@ -79,8 +79,8 @@ func (_m *Controller) GetScanLog(ctx context.Context, uuid string) ([]byte, erro
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, uuid)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *artifact.Artifact, string) error); ok {
|
||||
r1 = rf(ctx, art, uuid)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user