mirror of
https://github.com/goharbor/harbor
synced 2025-04-15 21:43:40 +00:00
feat(addition-link): only set vuls addition link when artifact scanable (#10892)
1. Add Checker to check the scannable status of the artifact. 2. Only set vulnerabilities addition link when the artifact scanable in the project. Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
parent
0d45308fbc
commit
69119b6410
|
@ -17,6 +17,7 @@ package artifact
|
|||
import (
|
||||
"container/list"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -54,6 +55,11 @@ var (
|
|||
Ctl = NewController()
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrBreak error to break walk
|
||||
ErrBreak = errors.New("break")
|
||||
)
|
||||
|
||||
// Controller defines the operations related with artifacts and tags
|
||||
type Controller interface {
|
||||
// Ensure the artifact specified by the digest exists under the repository,
|
||||
|
@ -453,6 +459,10 @@ func (c *controller) Walk(ctx context.Context, root *Artifact, walkFn func(*Arti
|
|||
|
||||
artifact := elem.Value.(*Artifact)
|
||||
if err := walkFn(artifact); err != nil {
|
||||
if err == ErrBreak {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
artifacttesting "github.com/goharbor/harbor/src/testing/api/artifact"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/project"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/repository"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -30,13 +31,13 @@ type controllerTestSuite struct {
|
|||
ctl *controller
|
||||
proMgr *project.FakeManager
|
||||
repoMgr *repository.FakeManager
|
||||
artCtl *artifacttesting.FakeController
|
||||
artCtl *artifacttesting.Controller
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) SetupTest() {
|
||||
c.proMgr = &project.FakeManager{}
|
||||
c.repoMgr = &repository.FakeManager{}
|
||||
c.artCtl = &artifacttesting.FakeController{}
|
||||
c.artCtl = &artifacttesting.Controller{}
|
||||
c.ctl = &controller{
|
||||
proMgr: c.proMgr,
|
||||
repoMgr: c.repoMgr,
|
||||
|
@ -118,8 +119,8 @@ func (c *controllerTestSuite) TestGetByName() {
|
|||
func (c *controllerTestSuite) TestDelete() {
|
||||
art := &artifact.Artifact{}
|
||||
art.ID = 1
|
||||
c.artCtl.On("List").Return([]*artifact.Artifact{art}, nil)
|
||||
c.artCtl.On("Delete").Return(nil)
|
||||
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{art}, nil)
|
||||
mock.OnAnything(c.artCtl, "Delete").Return(nil)
|
||||
c.repoMgr.On("Delete").Return(nil)
|
||||
err := c.ctl.Delete(nil, 1)
|
||||
c.Require().Nil(err)
|
||||
|
|
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/vuln"
|
||||
scannertesting "github.com/goharbor/harbor/src/testing/api/scanner"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -94,7 +95,7 @@ func (suite *ControllerTestSuite) SetupSuite() {
|
|||
},
|
||||
}
|
||||
|
||||
sc := &MockScannerController{}
|
||||
sc := &scannertesting.Controller{}
|
||||
sc.On("GetRegistrationByProject", suite.artifact.NamespaceID).Return(suite.registration, nil)
|
||||
sc.On("Ping", suite.registration).Return(m, nil)
|
||||
|
||||
|
@ -364,119 +365,6 @@ func (mrm *MockReportManager) GetStats(requester string) (*all.Stats, error) {
|
|||
return args.Get(0).(*all.Stats), args.Error(1)
|
||||
}
|
||||
|
||||
// MockScannerController ...
|
||||
type MockScannerController struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// ListRegistrations ...
|
||||
func (msc *MockScannerController) ListRegistrations(query *q.Query) ([]*scanner.Registration, error) {
|
||||
args := msc.Called(query)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).([]*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// CreateRegistration ...
|
||||
func (msc *MockScannerController) CreateRegistration(registration *scanner.Registration) (string, error) {
|
||||
args := msc.Called(registration)
|
||||
|
||||
return args.String(0), args.Error(1)
|
||||
}
|
||||
|
||||
// GetRegistration ...
|
||||
func (msc *MockScannerController) GetRegistration(registrationUUID string) (*scanner.Registration, error) {
|
||||
args := msc.Called(registrationUUID)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).(*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// RegistrationExists ...
|
||||
func (msc *MockScannerController) RegistrationExists(registrationUUID string) bool {
|
||||
args := msc.Called(registrationUUID)
|
||||
|
||||
return args.Bool(0)
|
||||
}
|
||||
|
||||
// UpdateRegistration ...
|
||||
func (msc *MockScannerController) UpdateRegistration(registration *scanner.Registration) error {
|
||||
args := msc.Called(registration)
|
||||
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// DeleteRegistration ...
|
||||
func (msc *MockScannerController) DeleteRegistration(registrationUUID string) (*scanner.Registration, error) {
|
||||
args := msc.Called(registrationUUID)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).(*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// SetDefaultRegistration ...
|
||||
func (msc *MockScannerController) SetDefaultRegistration(registrationUUID string) error {
|
||||
args := msc.Called(registrationUUID)
|
||||
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// SetRegistrationByProject ...
|
||||
func (msc *MockScannerController) SetRegistrationByProject(projectID int64, scannerID string) error {
|
||||
args := msc.Called(projectID, scannerID)
|
||||
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// GetRegistrationByProject ...
|
||||
func (msc *MockScannerController) GetRegistrationByProject(projectID int64) (*scanner.Registration, error) {
|
||||
args := msc.Called(projectID)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).(*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// Ping ...
|
||||
func (msc *MockScannerController) Ping(registration *scanner.Registration) (*v1.ScannerAdapterMetadata, error) {
|
||||
args := msc.Called(registration)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).(*v1.ScannerAdapterMetadata), args.Error(1)
|
||||
}
|
||||
|
||||
// GetMetadata ...
|
||||
func (msc *MockScannerController) GetMetadata(registrationUUID string) (*v1.ScannerAdapterMetadata, error) {
|
||||
args := msc.Called(registrationUUID)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).(*v1.ScannerAdapterMetadata), args.Error(1)
|
||||
}
|
||||
|
||||
// IsScannerAvailable ...
|
||||
func (msc *MockScannerController) IsScannerAvailable(projectID int64) (bool, error) {
|
||||
args := msc.Called(projectID)
|
||||
|
||||
return args.Bool(0), args.Error(1)
|
||||
}
|
||||
|
||||
// MockJobServiceClient ...
|
||||
type MockJobServiceClient struct {
|
||||
mock.Mock
|
||||
|
|
85
src/api/scan/checker.go
Normal file
85
src/api/scan/checker.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/api/scanner"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
)
|
||||
|
||||
// Checker checker which can check that the artifact is scannable
|
||||
type Checker interface {
|
||||
// IsScannable returns true when the artifact is scannable
|
||||
IsScannable(ctx context.Context, artifact *artifact.Artifact) (bool, error)
|
||||
}
|
||||
|
||||
// NewChecker returns checker
|
||||
func NewChecker() Checker {
|
||||
return &checker{
|
||||
artifactCtl: artifact.Ctl,
|
||||
scannerCtl: scanner.DefaultController,
|
||||
scannerMetadatas: map[int64]*v1.ScannerAdapterMetadata{},
|
||||
}
|
||||
}
|
||||
|
||||
type checker struct {
|
||||
artifactCtl artifact.Controller
|
||||
scannerCtl scanner.Controller
|
||||
scannerMetadatas map[int64]*v1.ScannerAdapterMetadata
|
||||
}
|
||||
|
||||
func (c *checker) IsScannable(ctx context.Context, art *artifact.Artifact) (bool, error) {
|
||||
projectID := art.ProjectID
|
||||
|
||||
metadata, ok := c.scannerMetadatas[projectID]
|
||||
if !ok {
|
||||
registration, err := c.scannerCtl.GetRegistrationByProject(projectID, scanner.WithPing(false))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if registration == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
md, err := c.scannerCtl.Ping(registration)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
metadata = md
|
||||
c.scannerMetadatas[projectID] = md
|
||||
}
|
||||
|
||||
var scannable bool
|
||||
|
||||
walkFn := func(a *artifact.Artifact) error {
|
||||
scannable = metadata.HasCapability(a.ManifestMediaType)
|
||||
if scannable {
|
||||
return artifact.ErrBreak
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.artifactCtl.Walk(ctx, art, walkFn, nil); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return scannable, nil
|
||||
}
|
99
src/api/scan/checker_test.go
Normal file
99
src/api/scan/checker_test.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
artifacttesting "github.com/goharbor/harbor/src/testing/api/artifact"
|
||||
scannertesting "github.com/goharbor/harbor/src/testing/api/scanner"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type CheckerTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *CheckerTestSuite) new() *checker {
|
||||
artifactCtl := &artifacttesting.Controller{}
|
||||
scannerCtl := &scannertesting.Controller{}
|
||||
|
||||
return &checker{
|
||||
artifactCtl: artifactCtl,
|
||||
scannerCtl: scannerCtl,
|
||||
scannerMetadatas: map[int64]*v1.ScannerAdapterMetadata{},
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *CheckerTestSuite) TestScannerNotFound() {
|
||||
c := suite.new()
|
||||
|
||||
{
|
||||
mock.OnAnything(c.scannerCtl, "GetRegistrationByProject").Return(nil, nil)
|
||||
|
||||
isScannable, err := c.IsScannable(context.TODO(), &artifact.Artifact{})
|
||||
suite.Nil(err)
|
||||
suite.False(isScannable)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *CheckerTestSuite) TestIsScannable() {
|
||||
c := suite.new()
|
||||
|
||||
supportMimeType := "support mime type"
|
||||
|
||||
mock.OnAnything(c.scannerCtl, "GetRegistrationByProject").Return(&scanner.Registration{}, nil)
|
||||
mock.OnAnything(c.scannerCtl, "Ping").Return(&v1.ScannerAdapterMetadata{
|
||||
Capabilities: []*v1.ScannerCapability{
|
||||
{ConsumesMimeTypes: []string{supportMimeType}},
|
||||
},
|
||||
}, nil)
|
||||
|
||||
{
|
||||
art := &artifact.Artifact{}
|
||||
|
||||
mock.OnAnything(c.artifactCtl, "Walk").Return(nil).Once().Run(func(args mock.Arguments) {
|
||||
walkFn := args.Get(2).(func(*artifact.Artifact) error)
|
||||
walkFn(art)
|
||||
})
|
||||
|
||||
isScannable, err := c.IsScannable(context.TODO(), art)
|
||||
suite.Nil(err)
|
||||
suite.False(isScannable)
|
||||
}
|
||||
|
||||
{
|
||||
art := &artifact.Artifact{}
|
||||
art.ManifestMediaType = supportMimeType
|
||||
|
||||
mock.OnAnything(c.artifactCtl, "Walk").Return(nil).Once().Run(func(args mock.Arguments) {
|
||||
walkFn := args.Get(2).(func(*artifact.Artifact) error)
|
||||
walkFn(art)
|
||||
})
|
||||
|
||||
isScannable, err := c.IsScannable(context.TODO(), art)
|
||||
suite.Nil(err)
|
||||
suite.True(isScannable)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckerTestSuite(t *testing.T) {
|
||||
suite.Run(t, &CheckerTestSuite{})
|
||||
}
|
|
@ -180,7 +180,7 @@ func (bc *basicController) SetRegistrationByProject(projectID int64, registratio
|
|||
}
|
||||
|
||||
// GetRegistrationByProject ...
|
||||
func (bc *basicController) GetRegistrationByProject(projectID int64) (*scanner.Registration, error) {
|
||||
func (bc *basicController) GetRegistrationByProject(projectID int64, options ...Option) (*scanner.Registration, error) {
|
||||
if projectID == 0 {
|
||||
return nil, errors.New("invalid project ID")
|
||||
}
|
||||
|
@ -222,18 +222,22 @@ func (bc *basicController) GetRegistrationByProject(projectID int64) (*scanner.R
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Get metadata of the configured registration
|
||||
meta, err := bc.Ping(registration)
|
||||
if err != nil {
|
||||
// Not blocked, just logged it
|
||||
log.Error(errors.Wrap(err, "api controller: get project scanner"))
|
||||
registration.Health = statusUnhealthy
|
||||
} else {
|
||||
registration.Health = statusHealthy
|
||||
// Fill in some metadata
|
||||
registration.Adapter = meta.Scanner.Name
|
||||
registration.Vendor = meta.Scanner.Vendor
|
||||
registration.Version = meta.Scanner.Version
|
||||
opts := newOptions(options...)
|
||||
|
||||
if opts.Ping {
|
||||
// Get metadata of the configured registration
|
||||
meta, err := bc.Ping(registration)
|
||||
if err != nil {
|
||||
// Not blocked, just logged it
|
||||
log.Error(errors.Wrap(err, "api controller: get project scanner"))
|
||||
registration.Health = statusUnhealthy
|
||||
} else {
|
||||
registration.Health = statusHealthy
|
||||
// Fill in some metadata
|
||||
registration.Adapter = meta.Scanner.Name
|
||||
registration.Vendor = meta.Scanner.Vendor
|
||||
registration.Version = meta.Scanner.Version
|
||||
}
|
||||
}
|
||||
|
||||
return registration, err
|
||||
|
|
|
@ -112,7 +112,7 @@ type Controller interface {
|
|||
// Returns:
|
||||
// *scanner.Registration : the default scanner registration
|
||||
// error : non nil error if any errors occurred
|
||||
GetRegistrationByProject(projectID int64) (*scanner.Registration, error)
|
||||
GetRegistrationByProject(projectID int64, options ...Option) (*scanner.Registration, error)
|
||||
|
||||
// Ping pings Scanner Adapter to test EndpointURL and Authorization settings.
|
||||
// The implementation is supposed to call the GetMetadata method on scanner.Client.
|
||||
|
|
48
src/api/scanner/options.go
Normal file
48
src/api/scanner/options.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package scanner
|
||||
|
||||
// Options keep the settings/configurations for scanner.
|
||||
type Options struct {
|
||||
// Mark the scan triggered by who.
|
||||
// Identified by the UUID.
|
||||
Ping bool
|
||||
}
|
||||
|
||||
// Option represents an option item by func template.
|
||||
// The validation result of the options are marked by nil/non-nil error.
|
||||
// e.g:
|
||||
// If the option is required and the input arg is empty,
|
||||
// then a non nil error should be returned at then.
|
||||
type Option func(options *Options) error
|
||||
|
||||
// WithPing sets the requester option.
|
||||
func WithPing(ping bool) Option {
|
||||
return func(options *Options) error {
|
||||
options.Ping = ping
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func newOptions(options ...Option) *Options {
|
||||
opts := &Options{Ping: true}
|
||||
|
||||
for _, o := range options {
|
||||
o(opts)
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
|
@ -19,12 +19,12 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
sc "github.com/goharbor/harbor/src/api/scanner"
|
||||
"github.com/goharbor/harbor/src/pkg/q"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
scannertesting "github.com/goharbor/harbor/src/testing/api/scanner"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
sc "github.com/goharbor/harbor/src/api/scanner"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
|
@ -33,7 +33,7 @@ type ProScannerAPITestSuite struct {
|
|||
suite.Suite
|
||||
|
||||
originC sc.Controller
|
||||
mockC *MockScannerAPIController
|
||||
mockC *scannertesting.Controller
|
||||
}
|
||||
|
||||
// TestProScannerAPI is the entry of ProScannerAPITestSuite
|
||||
|
@ -44,7 +44,7 @@ func TestProScannerAPI(t *testing.T) {
|
|||
// SetupSuite prepares testing env
|
||||
func (suite *ProScannerAPITestSuite) SetupTest() {
|
||||
suite.originC = sc.DefaultController
|
||||
m := &MockScannerAPIController{}
|
||||
m := &scannertesting.Controller{}
|
||||
sc.DefaultController = m
|
||||
|
||||
suite.mockC = m
|
||||
|
|
|
@ -19,13 +19,11 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
|
||||
sc "github.com/goharbor/harbor/src/api/scanner"
|
||||
"github.com/goharbor/harbor/src/pkg/q"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
scannertesting "github.com/goharbor/harbor/src/testing/api/scanner"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
@ -39,7 +37,7 @@ type ScannerAPITestSuite struct {
|
|||
suite.Suite
|
||||
|
||||
originC sc.Controller
|
||||
mockC *MockScannerAPIController
|
||||
mockC *scannertesting.Controller
|
||||
}
|
||||
|
||||
// TestScannerAPI is the entry of ScannerAPITestSuite
|
||||
|
@ -50,7 +48,7 @@ func TestScannerAPI(t *testing.T) {
|
|||
// SetupSuite prepares testing env
|
||||
func (suite *ScannerAPITestSuite) SetupTest() {
|
||||
suite.originC = sc.DefaultController
|
||||
m := &MockScannerAPIController{}
|
||||
m := &scannertesting.Controller{}
|
||||
sc.DefaultController = m
|
||||
|
||||
suite.mockC = m
|
||||
|
@ -275,99 +273,3 @@ func (suite *ScannerAPITestSuite) mockQuery(r *scanner.Registration) {
|
|||
}
|
||||
suite.mockC.On("ListRegistrations", query2).Return(emptyL, nil)
|
||||
}
|
||||
|
||||
// MockScannerAPIController is mock of scanner API controller
|
||||
type MockScannerAPIController struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// ListRegistrations ...
|
||||
func (m *MockScannerAPIController) ListRegistrations(query *q.Query) ([]*scanner.Registration, error) {
|
||||
args := m.Called(query)
|
||||
return args.Get(0).([]*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// CreateRegistration ...
|
||||
func (m *MockScannerAPIController) CreateRegistration(registration *scanner.Registration) (string, error) {
|
||||
args := m.Called(registration)
|
||||
return args.String(0), args.Error(1)
|
||||
}
|
||||
|
||||
// GetRegistration ...
|
||||
func (m *MockScannerAPIController) GetRegistration(registrationUUID string) (*scanner.Registration, error) {
|
||||
args := m.Called(registrationUUID)
|
||||
s := args.Get(0)
|
||||
if s == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return s.(*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// RegistrationExists ...
|
||||
func (m *MockScannerAPIController) RegistrationExists(registrationUUID string) bool {
|
||||
args := m.Called(registrationUUID)
|
||||
return args.Bool(0)
|
||||
}
|
||||
|
||||
// UpdateRegistration ...
|
||||
func (m *MockScannerAPIController) UpdateRegistration(registration *scanner.Registration) error {
|
||||
args := m.Called(registration)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// DeleteRegistration ...
|
||||
func (m *MockScannerAPIController) DeleteRegistration(registrationUUID string) (*scanner.Registration, error) {
|
||||
args := m.Called(registrationUUID)
|
||||
s := args.Get(0)
|
||||
if s == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return s.(*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// SetDefaultRegistration ...
|
||||
func (m *MockScannerAPIController) SetDefaultRegistration(registrationUUID string) error {
|
||||
args := m.Called(registrationUUID)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// SetRegistrationByProject ...
|
||||
func (m *MockScannerAPIController) SetRegistrationByProject(projectID int64, scannerID string) error {
|
||||
args := m.Called(projectID, scannerID)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// GetRegistrationByProject ...
|
||||
func (m *MockScannerAPIController) GetRegistrationByProject(projectID int64) (*scanner.Registration, error) {
|
||||
args := m.Called(projectID)
|
||||
s := args.Get(0)
|
||||
if s == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return s.(*scanner.Registration), args.Error(1)
|
||||
}
|
||||
|
||||
// Ping ...
|
||||
func (m *MockScannerAPIController) Ping(registration *scanner.Registration) (*v1.ScannerAdapterMetadata, error) {
|
||||
args := m.Called(registration)
|
||||
sam := args.Get(0)
|
||||
if sam == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return sam.(*v1.ScannerAdapterMetadata), nil
|
||||
}
|
||||
|
||||
// GetMetadata ...
|
||||
func (m *MockScannerAPIController) GetMetadata(registrationUUID string) (*v1.ScannerAdapterMetadata, error) {
|
||||
args := m.Called(registrationUUID)
|
||||
sam := args.Get(0)
|
||||
if sam == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return sam.(*v1.ScannerAdapterMetadata), nil
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/scan/rest/auth"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
|
@ -65,6 +65,19 @@ type ScannerAdapterMetadata struct {
|
|||
Properties ScannerProperties `json:"properties"`
|
||||
}
|
||||
|
||||
// HasCapability returns true when mine type of the artifact support by the scanner
|
||||
func (md *ScannerAdapterMetadata) HasCapability(mimeType string) bool {
|
||||
for _, capability := range md.Capabilities {
|
||||
for _, mt := range capability.ConsumesMimeTypes {
|
||||
if mt == mimeType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Artifact represents an artifact stored in Registry.
|
||||
type Artifact struct {
|
||||
// ID of the namespace (project). It will not be sent to scanner adapter.
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/api/repository"
|
||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||
arttesting "github.com/goharbor/harbor/src/testing/api/artifact"
|
||||
repotesting "github.com/goharbor/harbor/src/testing/api/repository"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type manifestTestSuite struct {
|
||||
|
@ -32,7 +34,7 @@ type manifestTestSuite struct {
|
|||
originalArtCtl artifact.Controller
|
||||
originalProxy http.Handler
|
||||
repoCtl *repotesting.FakeController
|
||||
artCtl *arttesting.FakeController
|
||||
artCtl *arttesting.Controller
|
||||
}
|
||||
|
||||
func (m *manifestTestSuite) SetupSuite() {
|
||||
|
@ -43,7 +45,7 @@ func (m *manifestTestSuite) SetupSuite() {
|
|||
|
||||
func (m *manifestTestSuite) SetupTest() {
|
||||
m.repoCtl = &repotesting.FakeController{}
|
||||
m.artCtl = &arttesting.FakeController{}
|
||||
m.artCtl = &arttesting.Controller{}
|
||||
repository.Ctl = m.repoCtl
|
||||
artifact.Ctl = m.artCtl
|
||||
}
|
||||
|
@ -63,7 +65,7 @@ func (m *manifestTestSuite) TestGetManifest() {
|
|||
req := httptest.NewRequest(http.MethodGet, "/v2/library/hello-world/manifests/latest", nil)
|
||||
w := &httptest.ResponseRecorder{}
|
||||
|
||||
m.artCtl.On("GetByReference").Return(nil, ierror.New(nil).WithCode(ierror.NotFoundCode))
|
||||
mock.OnAnything(m.artCtl, "GetByReference").Return(nil, ierror.New(nil).WithCode(ierror.NotFoundCode))
|
||||
getManifest(w, req)
|
||||
m.Equal(http.StatusNotFound, w.Code)
|
||||
|
||||
|
@ -85,7 +87,7 @@ func (m *manifestTestSuite) TestGetManifest() {
|
|||
|
||||
art := &artifact.Artifact{}
|
||||
art.Digest = "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180"
|
||||
m.artCtl.On("GetByReference").Return(art, nil)
|
||||
mock.OnAnything(m.artCtl, "GetByReference").Return(art, nil)
|
||||
getManifest(w, req)
|
||||
m.Equal(http.StatusOK, w.Code)
|
||||
}
|
||||
|
@ -95,7 +97,7 @@ func (m *manifestTestSuite) TestDeleteManifest() {
|
|||
req := httptest.NewRequest(http.MethodDelete, "/v2/library/hello-world/manifests/latest", nil)
|
||||
w := &httptest.ResponseRecorder{}
|
||||
|
||||
m.artCtl.On("GetByReference").Return(nil, ierror.New(nil).WithCode(ierror.NotFoundCode))
|
||||
mock.OnAnything(m.artCtl, "GetByReference").Return(nil, ierror.New(nil).WithCode(ierror.NotFoundCode))
|
||||
deleteManifest(w, req)
|
||||
m.Equal(http.StatusNotFound, w.Code)
|
||||
|
||||
|
@ -116,8 +118,8 @@ func (m *manifestTestSuite) TestDeleteManifest() {
|
|||
})
|
||||
req = httptest.NewRequest(http.MethodDelete, "/v2/library/hello-world/manifests/latest", nil)
|
||||
w = &httptest.ResponseRecorder{}
|
||||
m.artCtl.On("GetByReference").Return(&artifact.Artifact{}, nil)
|
||||
m.artCtl.On("Delete").Return(nil)
|
||||
mock.OnAnything(m.artCtl, "GetByReference").Return(&artifact.Artifact{}, nil)
|
||||
mock.OnAnything(m.artCtl, "Delete").Return(nil)
|
||||
deleteManifest(w, req)
|
||||
m.Equal(http.StatusAccepted, w.Code)
|
||||
}
|
||||
|
@ -152,7 +154,7 @@ func (m *manifestTestSuite) TestPutManifest() {
|
|||
req = httptest.NewRequest(http.MethodPut, "/v2/library/hello-world/manifests/latest", nil)
|
||||
w = &httptest.ResponseRecorder{}
|
||||
m.repoCtl.On("Ensure").Return(false, 1, nil)
|
||||
m.artCtl.On("Ensure").Return(true, 1, nil)
|
||||
mock.OnAnything(m.artCtl, "Ensure").Return(true, int64(1), nil)
|
||||
putManifest(w, req)
|
||||
m.Equal(http.StatusCreated, w.Code)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/api/scan"
|
||||
"github.com/goharbor/harbor/src/api/scanner"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/internal"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
|
@ -32,40 +31,22 @@ const (
|
|||
// NewVulAssembler returns vul assembler
|
||||
func NewVulAssembler(withScanOverview bool) *VulAssembler {
|
||||
return &VulAssembler{
|
||||
scanChecker: scan.NewChecker(),
|
||||
scanCtl: scan.DefaultController,
|
||||
|
||||
withScanOverview: withScanOverview,
|
||||
scanCtl: scan.DefaultController,
|
||||
scannerCtl: scanner.DefaultController,
|
||||
scanners: map[int64]bool{},
|
||||
}
|
||||
}
|
||||
|
||||
// VulAssembler vul assembler
|
||||
type VulAssembler struct {
|
||||
artifacts []*model.Artifact
|
||||
|
||||
scanCtl scan.Controller
|
||||
scannerCtl scanner.Controller
|
||||
scanners map[int64]bool
|
||||
scanChecker scan.Checker
|
||||
scanCtl scan.Controller
|
||||
|
||||
artifacts []*model.Artifact
|
||||
withScanOverview bool
|
||||
}
|
||||
|
||||
func (assembler *VulAssembler) hasScanner(ctx context.Context, projectID int64) bool {
|
||||
value, ok := assembler.scanners[projectID]
|
||||
if !ok {
|
||||
scanner, err := assembler.scannerCtl.GetRegistrationByProject(projectID)
|
||||
if err != nil {
|
||||
log.Warningf("get scanner for project %d failed, error: %v", projectID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
value = scanner != nil
|
||||
assembler.scanners[projectID] = value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// WithArtifacts set artifacts for the assembler
|
||||
func (assembler *VulAssembler) WithArtifacts(artifacts ...*model.Artifact) *VulAssembler {
|
||||
assembler.artifacts = artifacts
|
||||
|
@ -78,9 +59,13 @@ func (assembler *VulAssembler) Assemble(ctx context.Context) error {
|
|||
version := internal.GetAPIVersion(ctx)
|
||||
|
||||
for _, artifact := range assembler.artifacts {
|
||||
hasScanner := assembler.hasScanner(ctx, artifact.ProjectID)
|
||||
isScannable, err := assembler.scanChecker.IsScannable(ctx, &artifact.Artifact)
|
||||
if err != nil {
|
||||
log.Errorf("check the scannable status of %s@%s failed, error: %v", artifact.RepositoryName, artifact.Digest, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !hasScanner {
|
||||
if !isScannable {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -16,14 +16,11 @@ package assembler
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
models "github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||
"github.com/goharbor/harbor/src/testing/api/scan"
|
||||
"github.com/goharbor/harbor/src/testing/api/scanner"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
|
@ -31,75 +28,48 @@ type VulAssemblerTestSuite struct {
|
|||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *VulAssemblerTestSuite) newVulAssembler(withScanOverview bool) (*VulAssembler, *scan.Controller, *scanner.Controller) {
|
||||
vulAssembler := NewVulAssembler(withScanOverview)
|
||||
|
||||
func (suite *VulAssemblerTestSuite) TestScannable() {
|
||||
checker := &scan.Checker{}
|
||||
scanCtl := &scan.Controller{}
|
||||
scannerCtl := &scanner.Controller{}
|
||||
|
||||
vulAssembler.scanCtl = scanCtl
|
||||
vulAssembler.scannerCtl = scannerCtl
|
||||
assembler := VulAssembler{
|
||||
scanChecker: checker,
|
||||
scanCtl: scanCtl,
|
||||
withScanOverview: true,
|
||||
}
|
||||
|
||||
return vulAssembler, scanCtl, scannerCtl
|
||||
mock.OnAnything(checker, "IsScannable").Return(true, nil)
|
||||
|
||||
summary := map[string]interface{}{"key": "value"}
|
||||
mock.OnAnything(scanCtl, "GetSummary").Return(summary, nil)
|
||||
|
||||
var artifact model.Artifact
|
||||
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 1)
|
||||
suite.Equal(artifact.ScanOverview, summary)
|
||||
}
|
||||
|
||||
func (suite *VulAssemblerTestSuite) TestNotHasScanner() {
|
||||
{
|
||||
assembler, _, scannerCtl := suite.newVulAssembler(true)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(nil, nil)
|
||||
func (suite *VulAssemblerTestSuite) TestNotScannable() {
|
||||
checker := &scan.Checker{}
|
||||
scanCtl := &scan.Controller{}
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 0)
|
||||
assembler := VulAssembler{
|
||||
scanChecker: checker,
|
||||
scanCtl: scanCtl,
|
||||
withScanOverview: true,
|
||||
}
|
||||
|
||||
{
|
||||
assembler, _, scannerCtl := suite.newVulAssembler(true)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(nil, fmt.Errorf("error"))
|
||||
mock.OnAnything(checker, "IsScannable").Return(false, nil)
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 0)
|
||||
}
|
||||
}
|
||||
summary := map[string]interface{}{"key": "value"}
|
||||
mock.OnAnything(scanCtl, "GetSummary").Return(summary, nil)
|
||||
|
||||
func (suite *VulAssemblerTestSuite) TestHasScanner() {
|
||||
{
|
||||
assembler, scanCtl, scannerCtl := suite.newVulAssembler(true)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(&models.Registration{}, nil)
|
||||
var art model.Artifact
|
||||
|
||||
summary := map[string]interface{}{"key": "value"}
|
||||
scanCtl.On("GetSummary", mock.AnythingOfType("*v1.Artifact"), mock.AnythingOfType("[]string")).Return(summary, nil)
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 1)
|
||||
suite.Equal(artifact.ScanOverview, summary)
|
||||
}
|
||||
|
||||
{
|
||||
assembler, scanCtl, scannerCtl := suite.newVulAssembler(false)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(&models.Registration{}, nil)
|
||||
summary := map[string]interface{}{"key": "value"}
|
||||
scanCtl.On("GetSummary", mock.AnythingOfType("*v1.Artifact"), mock.AnythingOfType("[]string")).Return(summary, nil)
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 1)
|
||||
suite.Nil(artifact.ScanOverview)
|
||||
}
|
||||
|
||||
{
|
||||
assembler, scanCtl, scannerCtl := suite.newVulAssembler(true)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(&models.Registration{}, nil)
|
||||
|
||||
scanCtl.On("GetSummary", mock.AnythingOfType("*v1.Artifact"), mock.AnythingOfType("[]string")).Return(nil, fmt.Errorf("error"))
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 1)
|
||||
suite.Nil(artifact.ScanOverview)
|
||||
}
|
||||
suite.Nil(assembler.WithArtifacts(&art).Assemble(context.TODO()))
|
||||
suite.Len(art.AdditionLinks, 0)
|
||||
scanCtl.AssertNotCalled(suite.T(), "GetSummary")
|
||||
}
|
||||
|
||||
func TestVulAssemblerTestSuite(t *testing.T) {
|
||||
|
|
|
@ -14,5 +14,7 @@
|
|||
|
||||
package api
|
||||
|
||||
//go:generate mockery -case snake -dir ../../api/artifact -name Controller -output ./artifact -outpkg artifact
|
||||
//go:generate mockery -case snake -dir ../../api/scan -name Controller -output ./scan -outpkg scan
|
||||
//go:generate mockery -case snake -dir ../../api/scan -name Checker -output ./scan -outpkg scan
|
||||
//go:generate mockery -case snake -dir ../../api/scanner -name Controller -output ./scanner -outpkg scanner
|
||||
|
|
|
@ -1,118 +1,261 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
context "context"
|
||||
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||
"github.com/goharbor/harbor/src/pkg/q"
|
||||
"github.com/stretchr/testify/mock"
|
||||
artifact "github.com/goharbor/harbor/src/api/artifact"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
q "github.com/goharbor/harbor/src/pkg/q"
|
||||
|
||||
resolver "github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||
|
||||
time "time"
|
||||
)
|
||||
|
||||
// FakeController is a fake artifact controller that implement src/api/artifact.Controller interface
|
||||
type FakeController struct {
|
||||
// Controller is an autogenerated mock type for the Controller type
|
||||
type Controller struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Ensure ...
|
||||
func (f *FakeController) Ensure(ctx context.Context, repository, digest string, tags ...string) (bool, int64, error) {
|
||||
args := f.Called()
|
||||
return args.Bool(0), int64(args.Int(1)), args.Error(2)
|
||||
}
|
||||
// AddLabel provides a mock function with given fields: ctx, artifactID, labelID
|
||||
func (_m *Controller) AddLabel(ctx context.Context, artifactID int64, labelID int64) error {
|
||||
ret := _m.Called(ctx, artifactID, labelID)
|
||||
|
||||
// Count ...
|
||||
func (f *FakeController) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
args := f.Called()
|
||||
return int64(args.Int(0)), args.Error(1)
|
||||
}
|
||||
|
||||
// List ...
|
||||
func (f *FakeController) List(ctx context.Context, query *q.Query, option *artifact.Option) ([]*artifact.Artifact, error) {
|
||||
args := f.Called()
|
||||
var artifacts []*artifact.Artifact
|
||||
if args.Get(0) != nil {
|
||||
artifacts = args.Get(0).([]*artifact.Artifact)
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) error); ok {
|
||||
r0 = rf(ctx, artifactID, labelID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
return artifacts, args.Error(1)
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (f *FakeController) Get(ctx context.Context, id int64, option *artifact.Option) (*artifact.Artifact, error) {
|
||||
args := f.Called()
|
||||
var art *artifact.Artifact
|
||||
if args.Get(0) != nil {
|
||||
art = args.Get(0).(*artifact.Artifact)
|
||||
// Copy provides a mock function with given fields: ctx, srcRepo, reference, dstRepo
|
||||
func (_m *Controller) Copy(ctx context.Context, srcRepo string, reference string, dstRepo string) (int64, error) {
|
||||
ret := _m.Called(ctx, srcRepo, reference, dstRepo)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) int64); ok {
|
||||
r0 = rf(ctx, srcRepo, reference, dstRepo)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
return art, args.Error(1)
|
||||
}
|
||||
|
||||
// GetByReference ...
|
||||
func (f *FakeController) GetByReference(ctx context.Context, repository, reference string, option *artifact.Option) (*artifact.Artifact, error) {
|
||||
args := f.Called()
|
||||
var art *artifact.Artifact
|
||||
if args.Get(0) != nil {
|
||||
art = args.Get(0).(*artifact.Artifact)
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {
|
||||
r1 = rf(ctx, srcRepo, reference, dstRepo)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return art, args.Error(1)
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (f *FakeController) Delete(ctx context.Context, id int64) (err error) {
|
||||
args := f.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
// Count provides a mock function with given fields: ctx, query
|
||||
func (_m *Controller) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
// Copy ...
|
||||
func (f *FakeController) Copy(ctx context.Context, srcRepo, ref, dstRepo string) (int64, error) {
|
||||
args := f.Called()
|
||||
return int64(args.Int(0)), args.Error(1)
|
||||
}
|
||||
|
||||
// UpdatePullTime ...
|
||||
func (f *FakeController) UpdatePullTime(ctx context.Context, artifactID int64, tagID int64, time time.Time) error {
|
||||
args := f.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// GetAddition ...
|
||||
func (f *FakeController) GetAddition(ctx context.Context, artifactID int64, addition string) (*resolver.Addition, error) {
|
||||
args := f.Called()
|
||||
var res *resolver.Addition
|
||||
if args.Get(0) != nil {
|
||||
res = args.Get(0).(*resolver.Addition)
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
return res, args.Error(1)
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddLabel ...
|
||||
func (f *FakeController) AddLabel(ctx context.Context, artifactID int64, labelID int64) error {
|
||||
args := f.Called()
|
||||
return args.Error(0)
|
||||
// Delete provides a mock function with given fields: ctx, id
|
||||
func (_m *Controller) Delete(ctx context.Context, id int64) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// RemoveLabel ...
|
||||
func (f *FakeController) RemoveLabel(ctx context.Context, artifactID int64, labelID int64) error {
|
||||
args := f.Called()
|
||||
return args.Error(0)
|
||||
// Ensure provides a mock function with given fields: ctx, repository, digest, tags
|
||||
func (_m *Controller) Ensure(ctx context.Context, repository string, digest string, tags ...string) (bool, int64, error) {
|
||||
_va := make([]interface{}, len(tags))
|
||||
for _i := range tags {
|
||||
_va[_i] = tags[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, repository, digest)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, ...string) bool); ok {
|
||||
r0 = rf(ctx, repository, digest, tags...)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 int64
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, ...string) int64); ok {
|
||||
r1 = rf(ctx, repository, digest, tags...)
|
||||
} else {
|
||||
r1 = ret.Get(1).(int64)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, string, string, ...string) error); ok {
|
||||
r2 = rf(ctx, repository, digest, tags...)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// Walk ...
|
||||
func (f *FakeController) Walk(ctx context.Context, root *artifact.Artifact, workFn func(*artifact.Artifact) error, option *artifact.Option) error {
|
||||
args := f.Called()
|
||||
return args.Error(0)
|
||||
// Get provides a mock function with given fields: ctx, id, option
|
||||
func (_m *Controller) Get(ctx context.Context, id int64, option *artifact.Option) (*artifact.Artifact, error) {
|
||||
ret := _m.Called(ctx, id, option)
|
||||
|
||||
var r0 *artifact.Artifact
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, *artifact.Option) *artifact.Artifact); ok {
|
||||
r0 = rf(ctx, id, option)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*artifact.Artifact)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, *artifact.Option) error); ok {
|
||||
r1 = rf(ctx, id, option)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetAddition provides a mock function with given fields: ctx, artifactID, additionType
|
||||
func (_m *Controller) GetAddition(ctx context.Context, artifactID int64, additionType string) (*resolver.Addition, error) {
|
||||
ret := _m.Called(ctx, artifactID, additionType)
|
||||
|
||||
var r0 *resolver.Addition
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *resolver.Addition); ok {
|
||||
r0 = rf(ctx, artifactID, additionType)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*resolver.Addition)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
|
||||
r1 = rf(ctx, artifactID, additionType)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetByReference provides a mock function with given fields: ctx, repository, reference, option
|
||||
func (_m *Controller) GetByReference(ctx context.Context, repository string, reference string, option *artifact.Option) (*artifact.Artifact, error) {
|
||||
ret := _m.Called(ctx, repository, reference, option)
|
||||
|
||||
var r0 *artifact.Artifact
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, *artifact.Option) *artifact.Artifact); ok {
|
||||
r0 = rf(ctx, repository, reference, option)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*artifact.Artifact)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, *artifact.Option) error); ok {
|
||||
r1 = rf(ctx, repository, reference, option)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// List provides a mock function with given fields: ctx, query, option
|
||||
func (_m *Controller) List(ctx context.Context, query *q.Query, option *artifact.Option) ([]*artifact.Artifact, error) {
|
||||
ret := _m.Called(ctx, query, option)
|
||||
|
||||
var r0 []*artifact.Artifact
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query, *artifact.Option) []*artifact.Artifact); ok {
|
||||
r0 = rf(ctx, query, option)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*artifact.Artifact)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query, *artifact.Option) error); ok {
|
||||
r1 = rf(ctx, query, option)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RemoveLabel provides a mock function with given fields: ctx, artifactID, labelID
|
||||
func (_m *Controller) RemoveLabel(ctx context.Context, artifactID int64, labelID int64) error {
|
||||
ret := _m.Called(ctx, artifactID, labelID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) error); ok {
|
||||
r0 = rf(ctx, artifactID, labelID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdatePullTime provides a mock function with given fields: ctx, artifactID, tagID, _a3
|
||||
func (_m *Controller) UpdatePullTime(ctx context.Context, artifactID int64, tagID int64, _a3 time.Time) error {
|
||||
ret := _m.Called(ctx, artifactID, tagID, _a3)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64, time.Time) error); ok {
|
||||
r0 = rf(ctx, artifactID, tagID, _a3)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Walk provides a mock function with given fields: ctx, root, walkFn, option
|
||||
func (_m *Controller) Walk(ctx context.Context, root *artifact.Artifact, walkFn func(*artifact.Artifact) error, option *artifact.Option) error {
|
||||
ret := _m.Called(ctx, root, walkFn, option)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact, func(*artifact.Artifact) error, *artifact.Option) error); ok {
|
||||
r0 = rf(ctx, root, walkFn, option)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
|
37
src/testing/api/scan/checker.go
Normal file
37
src/testing/api/scan/checker.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package scan
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
artifact "github.com/goharbor/harbor/src/api/artifact"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// Checker is an autogenerated mock type for the Checker type
|
||||
type Checker struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// IsScannable provides a mock function with given fields: ctx, _a1
|
||||
func (_m *Checker) IsScannable(ctx context.Context, _a1 *artifact.Artifact) (bool, error) {
|
||||
ret := _m.Called(ctx, _a1)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact) bool); ok {
|
||||
r0 = rf(ctx, _a1)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *artifact.Artifact) error); ok {
|
||||
r1 = rf(ctx, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
|
@ -3,9 +3,11 @@
|
|||
package scanner
|
||||
|
||||
import (
|
||||
q "github.com/goharbor/harbor/src/pkg/q"
|
||||
apiscanner "github.com/goharbor/harbor/src/api/scanner"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
q "github.com/goharbor/harbor/src/pkg/q"
|
||||
|
||||
scanner "github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
|
@ -106,13 +108,20 @@ func (_m *Controller) GetRegistration(registrationUUID string) (*scanner.Registr
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetRegistrationByProject provides a mock function with given fields: projectID
|
||||
func (_m *Controller) GetRegistrationByProject(projectID int64) (*scanner.Registration, error) {
|
||||
ret := _m.Called(projectID)
|
||||
// GetRegistrationByProject provides a mock function with given fields: projectID, options
|
||||
func (_m *Controller) GetRegistrationByProject(projectID int64, options ...apiscanner.Option) (*scanner.Registration, error) {
|
||||
_va := make([]interface{}, len(options))
|
||||
for _i := range options {
|
||||
_va[_i] = options[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, projectID)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *scanner.Registration
|
||||
if rf, ok := ret.Get(0).(func(int64) *scanner.Registration); ok {
|
||||
r0 = rf(projectID)
|
||||
if rf, ok := ret.Get(0).(func(int64, ...apiscanner.Option) *scanner.Registration); ok {
|
||||
r0 = rf(projectID, options...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*scanner.Registration)
|
||||
|
@ -120,8 +129,8 @@ func (_m *Controller) GetRegistrationByProject(projectID int64) (*scanner.Regist
|
|||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
||||
r1 = rf(projectID)
|
||||
if rf, ok := ret.Get(1).(func(int64, ...apiscanner.Option) error); ok {
|
||||
r1 = rf(projectID, options...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
61
src/testing/mock/mock.go
Normal file
61
src/testing/mock/mock.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
// Anything anything alias of mock.Anything
|
||||
Anything = mock.Anything
|
||||
)
|
||||
|
||||
var (
|
||||
// AnythingOfType func alias of mock.AnythingOfType
|
||||
AnythingOfType = mock.AnythingOfType
|
||||
)
|
||||
|
||||
// Arguments type alias of mock.Arguments
|
||||
type Arguments = mock.Arguments
|
||||
|
||||
type mockable interface {
|
||||
On(methodName string, arguments ...interface{}) *mock.Call
|
||||
}
|
||||
|
||||
// OnAnything mock method on obj which match any args
|
||||
func OnAnything(obj interface{}, methodName string) *mock.Call {
|
||||
m, ok := obj.(mockable)
|
||||
if !ok {
|
||||
panic("obj not mockable")
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(obj).MethodByName(methodName)
|
||||
fnType := v.Type()
|
||||
|
||||
if fnType.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("assert: arguments: %s is not a func", v))
|
||||
}
|
||||
|
||||
args := []interface{}{}
|
||||
for i := 0; i < fnType.NumIn(); i++ {
|
||||
args = append(args, mock.Anything)
|
||||
}
|
||||
|
||||
return m.On(methodName, args...)
|
||||
}
|
Loading…
Reference in New Issue
Block a user