mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-23 07:11:36 +01:00
Add security hub summary API (#18872)
include WithCVE, WithArtifact option Signed-off-by: stonezdj <daojunz@vmware.com>
This commit is contained in:
parent
90259f3c80
commit
93e428d0d2
@ -6052,7 +6052,40 @@ paths:
|
||||
$ref: '#/responses/404'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
|
||||
/security/summary:
|
||||
get:
|
||||
summary: Get vulnerability system summary
|
||||
description: Retrieve the vulnerability summary of the system
|
||||
tags:
|
||||
- securityhub
|
||||
operationId: getSecuritySummary
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- name: with_dangerous_cve
|
||||
in: query
|
||||
description: Specify whether the dangerous CVE is include in the security summary
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_dangerous_artifact
|
||||
in: query
|
||||
description: Specify whether the dangerous artifacts is include in the security summary
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
schema:
|
||||
$ref: '#/definitions/SecuritySummary'
|
||||
'401':
|
||||
$ref: '#/responses/401'
|
||||
'403':
|
||||
$ref: '#/responses/403'
|
||||
'404':
|
||||
$ref: '#/responses/404'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
parameters:
|
||||
query:
|
||||
name: q
|
||||
@ -9614,3 +9647,116 @@ definitions:
|
||||
type: boolean
|
||||
description: if the scheduler is paused
|
||||
x-omitempty: false
|
||||
SecuritySummary:
|
||||
type: object
|
||||
description: the security summary
|
||||
properties:
|
||||
critical_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of critical vulnerabilities
|
||||
high_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
description: the count of high vulnerabilities
|
||||
medium_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of medium vulnerabilities
|
||||
low_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of low vulnerabilities
|
||||
none_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
description: the count of none vulnerabilities
|
||||
unknown_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
description: the count of unknown vulnerabilities
|
||||
total_vuls:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of total vulnerabilities
|
||||
scanned_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of scanned artifacts
|
||||
total_artifact:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the total count of artifacts
|
||||
fixable_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of fixable vulnerabilities
|
||||
dangerous_cves:
|
||||
type: array
|
||||
x-omitempty: true
|
||||
description: the list of dangerous CVEs
|
||||
items:
|
||||
$ref: '#/definitions/DangerousCVE'
|
||||
dangerous_artifacts:
|
||||
type: array
|
||||
x-omitempty: true
|
||||
description: the list of dangerous artifacts
|
||||
items:
|
||||
$ref: '#/definitions/DangerousArtifact'
|
||||
DangerousCVE:
|
||||
type: object
|
||||
description: the dangerous CVE information
|
||||
properties:
|
||||
cve_id:
|
||||
type: string
|
||||
description: the cve id
|
||||
severity:
|
||||
type: string
|
||||
description: the severity of the CVE
|
||||
cvss_score_v3:
|
||||
type: number
|
||||
format: float64
|
||||
description: the cvss score v3
|
||||
desc:
|
||||
type: string
|
||||
description: the description of the CVE
|
||||
package:
|
||||
type: string
|
||||
description: the package of the CVE
|
||||
version:
|
||||
type: string
|
||||
description: the version of the package
|
||||
DangerousArtifact:
|
||||
type: object
|
||||
description: the dangerous artifact information
|
||||
properties:
|
||||
project_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: the project id of the artifact
|
||||
repository_name:
|
||||
type: string
|
||||
description: the repository name of the artifact
|
||||
digest:
|
||||
type: string
|
||||
description: the digest of the artifact
|
||||
critical_cnt:
|
||||
type: integer
|
||||
x-omitempty: false
|
||||
description: the count of critical vulnerabilities
|
||||
high_cnt:
|
||||
type: integer
|
||||
format: int64
|
||||
x-omitempty: false
|
||||
description: the count of high vulnerabilities
|
||||
medium_cnt:
|
||||
type: integer
|
||||
x-omitempty: false
|
||||
description: the count of medium vulnerabilities
|
||||
|
@ -75,4 +75,5 @@ const (
|
||||
ResourcePurgeAuditLog = Resource("purge-audit")
|
||||
ResourceExportCVE = Resource("export-cve")
|
||||
ResourceJobServiceMonitor = Resource("jobservice-monitor")
|
||||
ResourceSecurityHub = Resource("security-hub")
|
||||
)
|
||||
|
@ -84,5 +84,7 @@ var (
|
||||
{Resource: rbac.ResourceJobServiceMonitor, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceJobServiceMonitor, Action: rbac.ActionList},
|
||||
{Resource: rbac.ResourceJobServiceMonitor, Action: rbac.ActionStop},
|
||||
|
||||
{Resource: rbac.ResourceSecurityHub, Action: rbac.ActionRead},
|
||||
}
|
||||
)
|
||||
|
138
src/controller/securityhub/controller.go
Normal file
138
src/controller/securityhub/controller.go
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 securityhub
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/scanner"
|
||||
"github.com/goharbor/harbor/src/pkg/securityhub"
|
||||
secHubModel "github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
)
|
||||
|
||||
// Ctl is the global controller for security hub
|
||||
var Ctl = NewController()
|
||||
|
||||
// Options define the option to query summary info
|
||||
type Options struct {
|
||||
WithCVE bool
|
||||
WithArtifact bool
|
||||
}
|
||||
|
||||
// Option define the func to build options
|
||||
type Option func(*Options)
|
||||
|
||||
func newOptions(options ...Option) *Options {
|
||||
opts := &Options{}
|
||||
for _, f := range options {
|
||||
f(opts)
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
// WithCVE enable CVE info in summary
|
||||
func WithCVE(enable bool) Option {
|
||||
return func(o *Options) {
|
||||
o.WithCVE = enable
|
||||
}
|
||||
}
|
||||
|
||||
// WithArtifact enable artifact info in summary
|
||||
func WithArtifact(enable bool) Option {
|
||||
return func(o *Options) {
|
||||
o.WithArtifact = enable
|
||||
}
|
||||
}
|
||||
|
||||
// Controller controller of security hub
|
||||
type Controller interface {
|
||||
// SecuritySummary returns the security summary of the specified project.
|
||||
SecuritySummary(ctx context.Context, projectID int64, options ...Option) (*secHubModel.Summary, error)
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
artifactMgr artifact.Manager
|
||||
scannerMgr scanner.Manager
|
||||
secHubMgr securityhub.Manager
|
||||
}
|
||||
|
||||
// NewController ...
|
||||
func NewController() Controller {
|
||||
return &controller{
|
||||
artifactMgr: pkg.ArtifactMgr,
|
||||
scannerMgr: scanner.New(),
|
||||
secHubMgr: securityhub.Mgr,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controller) SecuritySummary(ctx context.Context, projectID int64, options ...Option) (*secHubModel.Summary, error) {
|
||||
opts := newOptions(options...)
|
||||
scannerUUID, err := c.defaultScannerUUID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sum, err := c.secHubMgr.Summary(ctx, scannerUUID, projectID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sum.TotalArtifactCnt, err = c.totalArtifactCount(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sum.ScannedCnt, err = c.secHubMgr.ScannedArtifactsCount(ctx, scannerUUID, projectID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if opts.WithCVE {
|
||||
sum.DangerousCVEs, err = c.secHubMgr.DangerousCVEs(ctx, scannerUUID, projectID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if opts.WithArtifact {
|
||||
sum.DangerousArtifacts, err = c.secHubMgr.DangerousArtifacts(ctx, scannerUUID, projectID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return sum, nil
|
||||
}
|
||||
|
||||
func (c *controller) scannedArtifactCount(ctx context.Context, projectID int64) (int64, error) {
|
||||
scannerUUID, err := c.defaultScannerUUID(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return c.secHubMgr.ScannedArtifactsCount(ctx, scannerUUID, projectID, nil)
|
||||
}
|
||||
|
||||
func (c *controller) totalArtifactCount(ctx context.Context, projectID int64) (int64, error) {
|
||||
if projectID == 0 {
|
||||
return c.artifactMgr.Count(ctx, nil)
|
||||
}
|
||||
return c.artifactMgr.Count(ctx, q.New(q.KeyWords{"project_id": projectID}))
|
||||
}
|
||||
|
||||
// defaultScannerUUID returns the default scanner uuid.
|
||||
func (c *controller) defaultScannerUUID(ctx context.Context) (string, error) {
|
||||
reg, err := c.scannerMgr.GetDefault(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return reg.UUID, nil
|
||||
}
|
157
src/controller/securityhub/controller_test.go
Normal file
157
src/controller/securityhub/controller_test.go
Normal file
@ -0,0 +1,157 @@
|
||||
// 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 securityhub
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
"github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
artifactMock "github.com/goharbor/harbor/src/testing/pkg/artifact"
|
||||
scannerMock "github.com/goharbor/harbor/src/testing/pkg/scan/scanner"
|
||||
securityMock "github.com/goharbor/harbor/src/testing/pkg/securityhub"
|
||||
)
|
||||
|
||||
var sum = &model.Summary{
|
||||
CriticalCnt: 50,
|
||||
HighCnt: 40,
|
||||
MediumCnt: 30,
|
||||
LowCnt: 20,
|
||||
NoneCnt: 10,
|
||||
FixableCnt: 90,
|
||||
}
|
||||
|
||||
type ControllerTestSuite struct {
|
||||
htesting.Suite
|
||||
c *controller
|
||||
artifactMgr *artifactMock.Manager
|
||||
scannerMgr *scannerMock.Manager
|
||||
secHubMgr *securityMock.Manager
|
||||
}
|
||||
|
||||
// TestController is the entry of controller test suite
|
||||
func TestController(t *testing.T) {
|
||||
suite.Run(t, new(ControllerTestSuite))
|
||||
}
|
||||
|
||||
// SetupTest prepares env for the controller test suite
|
||||
func (suite *ControllerTestSuite) SetupTest() {
|
||||
suite.artifactMgr = &artifactMock.Manager{}
|
||||
suite.secHubMgr = &securityMock.Manager{}
|
||||
suite.scannerMgr = &scannerMock.Manager{}
|
||||
suite.c = &controller{
|
||||
artifactMgr: suite.artifactMgr,
|
||||
secHubMgr: suite.secHubMgr,
|
||||
scannerMgr: suite.scannerMgr,
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TearDownTest() {
|
||||
}
|
||||
|
||||
// TestSecuritySummary tests the security summary
|
||||
func (suite *ControllerTestSuite) TestSecuritySummary() {
|
||||
ctx := suite.Context()
|
||||
|
||||
mock.OnAnything(suite.artifactMgr, "Count").Return(int64(1234), nil)
|
||||
mock.OnAnything(suite.secHubMgr, "ScannedArtifactsCount").Return(int64(1000), nil)
|
||||
mock.OnAnything(suite.secHubMgr, "Summary").Return(sum, nil).Twice()
|
||||
mock.OnAnything(suite.scannerMgr, "GetDefault").Return(&scanner.Registration{UUID: "ruuid"}, nil)
|
||||
summary, err := suite.c.SecuritySummary(ctx, 0, WithArtifact(false), WithCVE(false))
|
||||
suite.NoError(err)
|
||||
suite.NotNil(summary)
|
||||
suite.Equal(int64(1234), summary.TotalArtifactCnt)
|
||||
suite.Equal(int64(1000), summary.ScannedCnt)
|
||||
suite.Equal(int64(50), summary.CriticalCnt)
|
||||
suite.Equal(int64(40), summary.HighCnt)
|
||||
suite.Equal(int64(30), summary.MediumCnt)
|
||||
suite.Equal(int64(20), summary.LowCnt)
|
||||
suite.Equal(int64(10), summary.NoneCnt)
|
||||
suite.Equal(int64(90), summary.FixableCnt)
|
||||
sum.DangerousCVEs = []*scan.VulnerabilityRecord{
|
||||
{CVEID: "CVE-2020-1234", Severity: "CRITICAL"},
|
||||
{CVEID: "CVE-2020-1235", Severity: "HIGH"},
|
||||
{CVEID: "CVE-2020-1236", Severity: "MEDIUM"},
|
||||
{CVEID: "CVE-2020-1237", Severity: "LOW"},
|
||||
{CVEID: "CVE-2020-1238", Severity: "NONE"},
|
||||
}
|
||||
sum.DangerousArtifacts = []*model.DangerousArtifact{
|
||||
{Project: 1, Repository: "library/busybox"},
|
||||
{Project: 1, Repository: "library/nginx"},
|
||||
{Project: 1, Repository: "library/hello-world"},
|
||||
{Project: 1, Repository: "library/harbor-jobservice"},
|
||||
{Project: 1, Repository: "library/harbor-core"},
|
||||
}
|
||||
mock.OnAnything(suite.secHubMgr, "Summary").Return(sum, nil).Once()
|
||||
mock.OnAnything(suite.secHubMgr, "DangerousCVEs").Return(sum.DangerousCVEs, nil).Once()
|
||||
mock.OnAnything(suite.secHubMgr, "DangerousArtifacts").Return(sum.DangerousArtifacts, nil).Once()
|
||||
sum2, err := suite.c.SecuritySummary(ctx, 0, WithCVE(false), WithArtifact(false))
|
||||
suite.NoError(err)
|
||||
suite.NotNil(sum2)
|
||||
suite.NotNil(sum2.DangerousCVEs)
|
||||
suite.NotNil(sum2.DangerousArtifacts)
|
||||
|
||||
sum3, err := suite.c.SecuritySummary(ctx, 0, WithCVE(true), WithArtifact(true))
|
||||
suite.NoError(err)
|
||||
suite.NotNil(sum3)
|
||||
suite.True(len(sum3.DangerousCVEs) > 0)
|
||||
suite.True(len(sum3.DangerousArtifacts) > 0)
|
||||
}
|
||||
|
||||
// TestSecuritySummaryError tests the security summary with error
|
||||
func (suite *ControllerTestSuite) TestSecuritySummaryError() {
|
||||
ctx := suite.Context()
|
||||
mock.OnAnything(suite.scannerMgr, "GetDefault").Return(&scanner.Registration{UUID: "ruuid"}, nil)
|
||||
mock.OnAnything(suite.secHubMgr, "ScannedArtifactsCount").Return(int64(1000), nil)
|
||||
mock.OnAnything(suite.secHubMgr, "Summary").Return(nil, errors.New("invalid project")).Once()
|
||||
summary, err := suite.c.SecuritySummary(ctx, 0, WithCVE(false), WithArtifact(false))
|
||||
suite.Error(err)
|
||||
suite.Nil(summary)
|
||||
mock.OnAnything(suite.artifactMgr, "Count").Return(int64(0), errors.New("failed to connect db")).Once()
|
||||
mock.OnAnything(suite.secHubMgr, "Summary").Return(sum, nil).Once()
|
||||
summary, err = suite.c.SecuritySummary(ctx, 0, WithCVE(false), WithArtifact(false))
|
||||
suite.Error(err)
|
||||
suite.Nil(summary)
|
||||
|
||||
}
|
||||
|
||||
// TestGetDefaultScanner tests the get default scanner
|
||||
func (suite *ControllerTestSuite) TestGetDefaultScanner() {
|
||||
ctx := suite.Context()
|
||||
mock.OnAnything(suite.scannerMgr, "GetDefault").Return(&scanner.Registration{UUID: ""}, nil).Once()
|
||||
scanner, err := suite.c.defaultScannerUUID(ctx)
|
||||
suite.NoError(err)
|
||||
suite.Equal("", scanner)
|
||||
|
||||
mock.OnAnything(suite.scannerMgr, "GetDefault").Return(nil, errors.New("failed to get scanner")).Once()
|
||||
scanner, err = suite.c.defaultScannerUUID(ctx)
|
||||
suite.Error(err)
|
||||
suite.Equal("", scanner)
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestScannedArtifact() {
|
||||
ctx := suite.Context()
|
||||
mock.OnAnything(suite.scannerMgr, "GetDefault").Return(&scanner.Registration{UUID: "ruuid"}, nil)
|
||||
mock.OnAnything(suite.secHubMgr, "ScannedArtifactsCount").Return(int64(1000), nil)
|
||||
scanned, err := suite.c.scannedArtifactCount(ctx, 0)
|
||||
suite.NoError(err)
|
||||
suite.Equal(int64(1000), scanned)
|
||||
}
|
@ -71,6 +71,10 @@ func (c *nativeToRelationalSchemaConverter) ToRelationalSchema(ctx context.Conte
|
||||
return "", "", errors.Wrap(err, "Error when converting vulnerability report")
|
||||
}
|
||||
|
||||
if err := c.updateReport(ctx, rawReport.Vulnerabilities, reportUUID); err != nil {
|
||||
return "", "", errors.Wrap(err, "Error when updating report")
|
||||
}
|
||||
|
||||
rawReport.Vulnerabilities = nil
|
||||
data, err := json.Marshal(rawReport)
|
||||
if err != nil {
|
||||
|
133
src/pkg/securityhub/dao/security.go
Normal file
133
src/pkg/securityhub/dao/security.go
Normal file
@ -0,0 +1,133 @@
|
||||
// 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 dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
"github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
)
|
||||
|
||||
const (
|
||||
summarySQL = `select sum(s.critical_cnt) critical_cnt,
|
||||
sum(s.high_cnt) high_cnt,
|
||||
sum(s.medium_cnt) medium_cnt,
|
||||
sum(s.low_cnt) low_cnt,
|
||||
sum(s.none_cnt) none_cnt,
|
||||
sum(s.unknown_cnt) unknown_cnt,
|
||||
sum(s.fixable_cnt) fixable_cnt
|
||||
from artifact a
|
||||
left join scan_report s on a.digest = s.digest
|
||||
where s.registration_uuid = ?`
|
||||
|
||||
dangerousArtifactSQL = `select a.project_id project, a.repository_name repository, a.digest, s.critical_cnt, s.high_cnt, s.medium_cnt, s.low_cnt
|
||||
from artifact a,
|
||||
scan_report s
|
||||
where a.digest = s.digest
|
||||
and s.registration_uuid = ?
|
||||
order by s.critical_cnt desc, s.high_cnt desc, s.medium_cnt desc, s.low_cnt desc
|
||||
limit 5`
|
||||
|
||||
scannedArtifactCountSQL = `select count(1)
|
||||
from artifact a
|
||||
left join scan_report s on a.digest = s.digest
|
||||
where s.registration_uuid= ? and s.uuid is not null`
|
||||
|
||||
dangerousCVESQL = `select vr.*
|
||||
from vulnerability_record vr
|
||||
where vr.cvss_score_v3 is not null
|
||||
and vr.registration_uuid = ?
|
||||
order by vr.cvss_score_v3 desc
|
||||
limit 5`
|
||||
)
|
||||
|
||||
// SecurityHubDao defines the interface to access security hub data.
|
||||
type SecurityHubDao interface {
|
||||
// Summary returns the summary of the scan cve reports.
|
||||
Summary(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (*model.Summary, error)
|
||||
// DangerousCVEs get the top 5 most dangerous CVEs, return top 5 result
|
||||
DangerousCVEs(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*scan.VulnerabilityRecord, error)
|
||||
// DangerousArtifacts returns top 5 dangerous artifact for the given scanner. return top 5 result
|
||||
DangerousArtifacts(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*model.DangerousArtifact, error)
|
||||
// ScannedArtifactsCount return the count of scanned artifacts.
|
||||
ScannedArtifactsCount(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (int64, error)
|
||||
}
|
||||
|
||||
// New creates a new SecurityHubDao instance.
|
||||
func New() SecurityHubDao {
|
||||
return &dao{}
|
||||
}
|
||||
|
||||
type dao struct {
|
||||
}
|
||||
|
||||
func (d *dao) Summary(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (*model.Summary, error) {
|
||||
if len(scannerUUID) == 0 || projectID != 0 {
|
||||
return nil, nil
|
||||
}
|
||||
o, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var sum model.Summary
|
||||
err = o.Raw(summarySQL, scannerUUID).QueryRow(&sum.CriticalCnt,
|
||||
&sum.HighCnt,
|
||||
&sum.MediumCnt,
|
||||
&sum.LowCnt,
|
||||
&sum.NoneCnt,
|
||||
&sum.UnknownCnt,
|
||||
&sum.FixableCnt)
|
||||
return &sum, err
|
||||
}
|
||||
func (d *dao) DangerousArtifacts(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*model.DangerousArtifact, error) {
|
||||
if len(scannerUUID) == 0 || projectID != 0 {
|
||||
return nil, nil
|
||||
}
|
||||
o, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var artifacts []*model.DangerousArtifact
|
||||
_, err = o.Raw(dangerousArtifactSQL, scannerUUID).QueryRows(&artifacts)
|
||||
return artifacts, err
|
||||
}
|
||||
|
||||
func (d *dao) ScannedArtifactsCount(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (int64, error) {
|
||||
if len(scannerUUID) == 0 || projectID != 0 {
|
||||
return 0, nil
|
||||
}
|
||||
var cnt int64
|
||||
o, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return cnt, err
|
||||
}
|
||||
err = o.Raw(scannedArtifactCountSQL, scannerUUID).QueryRow(&cnt)
|
||||
return cnt, err
|
||||
}
|
||||
func (d *dao) DangerousCVEs(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*scan.VulnerabilityRecord, error) {
|
||||
if len(scannerUUID) == 0 || projectID != 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cves := make([]*scan.VulnerabilityRecord, 0)
|
||||
o, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = o.Raw(dangerousCVESQL, scannerUUID).QueryRows(&cves)
|
||||
return cves, err
|
||||
}
|
104
src/pkg/securityhub/dao/security_test.go
Normal file
104
src/pkg/securityhub/dao/security_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
// 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 dao
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
testDao "github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
)
|
||||
|
||||
func TestDao(t *testing.T) {
|
||||
suite.Run(t, &SecurityDaoTestSuite{})
|
||||
}
|
||||
|
||||
type SecurityDaoTestSuite struct {
|
||||
htesting.Suite
|
||||
dao SecurityHubDao
|
||||
}
|
||||
|
||||
// SetupSuite prepares env for test suite.
|
||||
func (suite *SecurityDaoTestSuite) SetupSuite() {
|
||||
suite.Suite.SetupSuite()
|
||||
suite.dao = New()
|
||||
}
|
||||
|
||||
// SetupTest prepares env for test case.
|
||||
func (suite *SecurityDaoTestSuite) SetupTest() {
|
||||
testDao.ExecuteBatchSQL([]string{
|
||||
`insert into scan_report(uuid, digest, registration_uuid, mime_type, critical_cnt, high_cnt, medium_cnt, low_cnt, unknown_cnt, fixable_cnt) values('uuid', 'digest1001', 'ruuid', 'application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0', 50, 50, 50, 0, 0, 20)`,
|
||||
`insert into artifact (project_id, repository_name, digest, type, pull_time, push_time, repository_id, media_type, manifest_media_type, size, extra_attrs, annotations, icon)
|
||||
values (1, 'library/hello-world', 'digest1001', 'IMAGE', '2023-06-02 09:16:47.838778', '2023-06-02 01:45:55.050785', 1742, 'application/vnd.docker.container.image.v1+json', 'application/vnd.docker.distribution.manifest.v2+json', 4452, '{"architecture":"amd64","author":"","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"]},"created":"2023-05-04T17:37:03.872958712Z","os":"linux"}', null, '');`,
|
||||
`insert into scanner_registration (name, url, uuid, auth) values('trivy', 'https://www.vmware.com', 'ruuid', 'empty')`,
|
||||
`insert into vulnerability_record (id, cve_id, registration_uuid, cvss_score_v3) values (1, '2023-4567-12345', 'ruuid', 9.8)`,
|
||||
`insert into report_vulnerability_record (report_uuid, vuln_record_id) VALUES ('uuid', 1)`,
|
||||
})
|
||||
|
||||
testDao.ExecuteBatchSQL([]string{
|
||||
`INSERT INTO scanner_registration (name, url, uuid, auth) values('trivy2', 'https://www.trivy.com', 'uuid2', 'empty')`,
|
||||
`INSERT INTO vulnerability_record(cve_id, registration_uuid, cvss_score_v3, package) VALUES ('CVE-2021-44228', 'uuid2', 10, 'org.apache.logging.log4j:log4j-core');
|
||||
INSERT INTO vulnerability_record(cve_id, registration_uuid, cvss_score_v3, package) VALUES ('CVE-2021-21345', 'uuid2', 9.9, 'com.thoughtworks.xstream:xstream');
|
||||
INSERT INTO vulnerability_record(cve_id, registration_uuid, cvss_score_v3, package) VALUES ('CVE-2016-1585', 'uuid2', 9.8, 'libapparmor1');
|
||||
INSERT INTO vulnerability_record(cve_id, registration_uuid, cvss_score_v3, package) VALUES ('CVE-2023-0950', 'uuid2', 9.8, 'ure');
|
||||
INSERT INTO vulnerability_record(cve_id, registration_uuid, cvss_score_v3, package) VALUES ('CVE-2022-47629', 'uuid2', 9.8, 'libksba8');
|
||||
`,
|
||||
})
|
||||
}
|
||||
|
||||
// TearDownTest clears enf for test case.
|
||||
func (suite *SecurityDaoTestSuite) TearDownTest() {
|
||||
testDao.ExecuteBatchSQL([]string{
|
||||
`delete from scan_report where uuid = 'uuid'`,
|
||||
`delete from artifact where digest = 'digest1001'`,
|
||||
`delete from scanner_registration where uuid='ruuid'`,
|
||||
`delete from vulnerability_record where cve_id='2023-4567-12345'`,
|
||||
`delete from report_vulnerability_record where report_uuid='ruuid'`,
|
||||
`delete from vulnerability_record where registration_uuid ='uuid2'`,
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *SecurityDaoTestSuite) TestGetSummary() {
|
||||
s, err := suite.dao.Summary(suite.Context(), "ruuid", 0, nil)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(int64(50), s.CriticalCnt)
|
||||
suite.Equal(int64(50), s.HighCnt)
|
||||
suite.Equal(int64(50), s.MediumCnt)
|
||||
suite.Equal(int64(20), s.FixableCnt)
|
||||
}
|
||||
func (suite *SecurityDaoTestSuite) TestGetMostDangerousArtifact() {
|
||||
aList, err := suite.dao.DangerousArtifacts(orm.Context(), "ruuid", 0, nil)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(1, len(aList))
|
||||
suite.Equal(int64(50), aList[0].CriticalCnt)
|
||||
suite.Equal(int64(50), aList[0].HighCnt)
|
||||
suite.Equal(int64(50), aList[0].MediumCnt)
|
||||
suite.Equal(int64(0), aList[0].LowCnt)
|
||||
}
|
||||
|
||||
func (suite *SecurityDaoTestSuite) TestGetScannedArtifactCount() {
|
||||
count, err := suite.dao.ScannedArtifactsCount(orm.Context(), "ruuid", 0, nil)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(int64(1), count)
|
||||
}
|
||||
|
||||
func (suite *SecurityDaoTestSuite) TestGetDangerousCVEs() {
|
||||
records, err := suite.dao.DangerousCVEs(suite.Context(), `uuid2`, 0, nil)
|
||||
suite.NoError(err, "Error when fetching most dangerous artifact")
|
||||
suite.Equal(5, len(records))
|
||||
}
|
69
src/pkg/securityhub/manager.go
Normal file
69
src/pkg/securityhub/manager.go
Normal file
@ -0,0 +1,69 @@
|
||||
// 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 securityhub
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
"github.com/goharbor/harbor/src/pkg/securityhub/dao"
|
||||
"github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
)
|
||||
|
||||
var (
|
||||
// Mgr is the global security manager
|
||||
Mgr = NewManager()
|
||||
)
|
||||
|
||||
// Manager is used to manage the security manager.
|
||||
type Manager interface {
|
||||
// Summary returns the summary of the scan cve reports.
|
||||
Summary(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (*model.Summary, error)
|
||||
// DangerousArtifacts returns the most dangerous artifact for the given scanner.
|
||||
DangerousArtifacts(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*model.DangerousArtifact, error)
|
||||
// ScannedArtifactsCount return the count of scanned artifacts.
|
||||
ScannedArtifactsCount(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (int64, error)
|
||||
// DangerousCVEs returns the most dangerous CVEs for the given scanner.
|
||||
DangerousCVEs(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*scan.VulnerabilityRecord, error)
|
||||
}
|
||||
|
||||
// NewManager news security manager.
|
||||
func NewManager() Manager {
|
||||
return &securityManager{
|
||||
dao: dao.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// securityManager is a default implementation of security manager.
|
||||
type securityManager struct {
|
||||
dao dao.SecurityHubDao
|
||||
}
|
||||
|
||||
func (s *securityManager) Summary(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (*model.Summary, error) {
|
||||
return s.dao.Summary(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
|
||||
func (s *securityManager) DangerousArtifacts(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*model.DangerousArtifact, error) {
|
||||
return s.dao.DangerousArtifacts(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
|
||||
func (s *securityManager) ScannedArtifactsCount(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (int64, error) {
|
||||
return s.dao.ScannedArtifactsCount(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
|
||||
func (s *securityManager) DangerousCVEs(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*scan.VulnerabilityRecord, error) {
|
||||
return s.dao.DangerousCVEs(ctx, scannerUUID, projectID, query)
|
||||
}
|
44
src/pkg/securityhub/model/model.go
Normal file
44
src/pkg/securityhub/model/model.go
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 model
|
||||
|
||||
import "github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
|
||||
// Summary is the summary of scan result
|
||||
type Summary struct {
|
||||
CriticalCnt int64 `json:"critical_cnt"`
|
||||
HighCnt int64 `json:"high_cnt"`
|
||||
MediumCnt int64 `json:"medium_cnt"`
|
||||
LowCnt int64 `json:"low_cnt"`
|
||||
NoneCnt int64 `json:"none_cnt"`
|
||||
UnknownCnt int64 `json:"unknown_cnt"`
|
||||
FixableCnt int64 `json:"fixable_cnt"`
|
||||
ScannedCnt int64 `json:"scanned_cnt"`
|
||||
NotScanCnt int64 `json:"not_scan_cnt"`
|
||||
TotalArtifactCnt int64 `json:"total_artifact_cnt"`
|
||||
DangerousCVEs []*scan.VulnerabilityRecord `json:"dangerous_cves"`
|
||||
DangerousArtifacts []*DangerousArtifact `json:"dangerous_artifacts"`
|
||||
}
|
||||
|
||||
// DangerousArtifact define the most dangerous artifact
|
||||
type DangerousArtifact struct {
|
||||
Project int64 `json:"project" orm:"column(project)"`
|
||||
Repository string `json:"repository" orm:"column(repository)"`
|
||||
Digest string `json:"digest" orm:"column(digest)"`
|
||||
CriticalCnt int64 `json:"critical_cnt" orm:"column(critical_cnt)"`
|
||||
HighCnt int64 `json:"high_cnt" orm:"column(high_cnt)"`
|
||||
MediumCnt int64 `json:"medium_cnt" orm:"column(medium_cnt)"`
|
||||
LowCnt int64 `json:"low_cnt" orm:"column(low_cnt)"`
|
||||
}
|
@ -69,6 +69,7 @@ func New() http.Handler {
|
||||
ScanDataExportAPI: newScanDataExportAPI(),
|
||||
JobserviceAPI: newJobServiceAPI(),
|
||||
ScheduleAPI: newScheduleAPI(),
|
||||
SecurityhubAPI: newSecurityAPI(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
98
src/server/v2.0/handler/security.go
Normal file
98
src/server/v2.0/handler/security.go
Normal file
@ -0,0 +1,98 @@
|
||||
// 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 handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
securityModel "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/securityhub"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/securityhub"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
secHubModel "github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
)
|
||||
|
||||
func newSecurityAPI() *securityAPI {
|
||||
return &securityAPI{
|
||||
controller: securityhub.Ctl,
|
||||
}
|
||||
}
|
||||
|
||||
type securityAPI struct {
|
||||
BaseAPI
|
||||
controller securityhub.Controller
|
||||
}
|
||||
|
||||
func (s *securityAPI) GetSecuritySummary(ctx context.Context,
|
||||
params securityModel.GetSecuritySummaryParams) middleware.Responder {
|
||||
if err := s.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceSecurityHub); err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
summary, err := s.controller.SecuritySummary(ctx, 0, securityhub.WithCVE(*params.WithDangerousCVE), securityhub.WithArtifact(*params.WithDangerousArtifact))
|
||||
if err != nil {
|
||||
return s.SendError(ctx, err)
|
||||
}
|
||||
sum := toSecuritySummaryModel(summary)
|
||||
return securityModel.NewGetSecuritySummaryOK().WithPayload(sum)
|
||||
}
|
||||
|
||||
func toSecuritySummaryModel(summary *secHubModel.Summary) *models.SecuritySummary {
|
||||
return &models.SecuritySummary{
|
||||
CriticalCnt: summary.CriticalCnt,
|
||||
HighCnt: summary.HighCnt,
|
||||
MediumCnt: summary.MediumCnt,
|
||||
LowCnt: summary.LowCnt,
|
||||
NoneCnt: summary.NoneCnt,
|
||||
UnknownCnt: summary.UnknownCnt,
|
||||
FixableCnt: summary.FixableCnt,
|
||||
TotalVuls: summary.CriticalCnt + summary.HighCnt + summary.MediumCnt + summary.LowCnt + summary.NoneCnt + summary.UnknownCnt,
|
||||
TotalArtifact: summary.TotalArtifactCnt,
|
||||
ScannedCnt: summary.ScannedCnt,
|
||||
DangerousCves: toDangerousCves(summary.DangerousCVEs),
|
||||
DangerousArtifacts: toDangerousArtifacts(summary.DangerousArtifacts),
|
||||
}
|
||||
}
|
||||
func toDangerousArtifacts(artifacts []*secHubModel.DangerousArtifact) []*models.DangerousArtifact {
|
||||
var result []*models.DangerousArtifact
|
||||
for _, artifact := range artifacts {
|
||||
result = append(result, &models.DangerousArtifact{
|
||||
ProjectID: artifact.Project,
|
||||
RepositoryName: artifact.Repository,
|
||||
Digest: artifact.Digest,
|
||||
CriticalCnt: artifact.CriticalCnt,
|
||||
HighCnt: artifact.HighCnt,
|
||||
MediumCnt: artifact.MediumCnt,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toDangerousCves(cves []*scan.VulnerabilityRecord) []*models.DangerousCVE {
|
||||
var result []*models.DangerousCVE
|
||||
for _, vul := range cves {
|
||||
result = append(result, &models.DangerousCVE{
|
||||
CVEID: vul.CVEID,
|
||||
Package: vul.Package,
|
||||
Version: vul.PackageVersion,
|
||||
Severity: vul.Severity,
|
||||
CvssScoreV3: *vul.CVE3Score,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
@ -35,3 +35,4 @@ package controller
|
||||
//go:generate mockery --case snake --dir ../../controller/task --name Controller --output ./task --outpkg task
|
||||
//go:generate mockery --case snake --dir ../../controller/task --name ExecutionController --output ./task --outpkg task
|
||||
//go:generate mockery --case snake --dir ../../controller/webhook --name Controller --output ./webhook --outpkg webhook
|
||||
//go:generate mockery --case snake --dir ../../controller/securityhub --name Controller --output ./securityhub --outpkg securityhub
|
||||
|
65
src/testing/controller/securityhub/controller.go
Normal file
65
src/testing/controller/securityhub/controller.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Code generated by mockery v2.22.1. DO NOT EDIT.
|
||||
|
||||
package securityhub
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
model "github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
securityhub "github.com/goharbor/harbor/src/controller/securityhub"
|
||||
)
|
||||
|
||||
// Controller is an autogenerated mock type for the Controller type
|
||||
type Controller struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// SecuritySummary provides a mock function with given fields: ctx, projectID, options
|
||||
func (_m *Controller) SecuritySummary(ctx context.Context, projectID int64, options ...securityhub.Option) (*model.Summary, error) {
|
||||
_va := make([]interface{}, len(options))
|
||||
for _i := range options {
|
||||
_va[_i] = options[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, projectID)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *model.Summary
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, ...securityhub.Option) (*model.Summary, error)); ok {
|
||||
return rf(ctx, projectID, options...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, ...securityhub.Option) *model.Summary); ok {
|
||||
r0 = rf(ctx, projectID, options...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Summary)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, ...securityhub.Option) error); ok {
|
||||
r1 = rf(ctx, projectID, options...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewController interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewController creates a new instance of Controller. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewController(t mockConstructorTestingTNewController) *Controller {
|
||||
mock := &Controller{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
@ -73,3 +73,4 @@ package pkg
|
||||
//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name QueueManager --output ./jobmonitor --outpkg jobmonitor
|
||||
//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name RedisClient --output ./jobmonitor --outpkg jobmonitor
|
||||
//go:generate mockery --case snake --dir ../../pkg/queuestatus --name Manager --output ./queuestatus --outpkg queuestatus
|
||||
//go:generate mockery --case snake --dir ../../pkg/securityhub --name Manager --output ./securityhub --outpkg securityhub
|
||||
|
136
src/testing/pkg/securityhub/manager.go
Normal file
136
src/testing/pkg/securityhub/manager.go
Normal file
@ -0,0 +1,136 @@
|
||||
// Code generated by mockery v2.22.1. DO NOT EDIT.
|
||||
|
||||
package securityhub
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
model "github.com/goharbor/harbor/src/pkg/securityhub/model"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
q "github.com/goharbor/harbor/src/lib/q"
|
||||
|
||||
scan "github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
)
|
||||
|
||||
// Manager is an autogenerated mock type for the Manager type
|
||||
type Manager struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// DangerousArtifacts provides a mock function with given fields: ctx, scannerUUID, projectID, query
|
||||
func (_m *Manager) DangerousArtifacts(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*model.DangerousArtifact, error) {
|
||||
ret := _m.Called(ctx, scannerUUID, projectID, query)
|
||||
|
||||
var r0 []*model.DangerousArtifact
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) ([]*model.DangerousArtifact, error)); ok {
|
||||
return rf(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) []*model.DangerousArtifact); ok {
|
||||
r0 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.DangerousArtifact)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, int64, *q.Query) error); ok {
|
||||
r1 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DangerousCVEs provides a mock function with given fields: ctx, scannerUUID, projectID, query
|
||||
func (_m *Manager) DangerousCVEs(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) ([]*scan.VulnerabilityRecord, error) {
|
||||
ret := _m.Called(ctx, scannerUUID, projectID, query)
|
||||
|
||||
var r0 []*scan.VulnerabilityRecord
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) ([]*scan.VulnerabilityRecord, error)); ok {
|
||||
return rf(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) []*scan.VulnerabilityRecord); ok {
|
||||
r0 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*scan.VulnerabilityRecord)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, int64, *q.Query) error); ok {
|
||||
r1 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ScannedArtifactsCount provides a mock function with given fields: ctx, scannerUUID, projectID, query
|
||||
func (_m *Manager) ScannedArtifactsCount(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (int64, error) {
|
||||
ret := _m.Called(ctx, scannerUUID, projectID, query)
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) (int64, error)); ok {
|
||||
return rf(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) int64); ok {
|
||||
r0 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, int64, *q.Query) error); ok {
|
||||
r1 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Summary provides a mock function with given fields: ctx, scannerUUID, projectID, query
|
||||
func (_m *Manager) Summary(ctx context.Context, scannerUUID string, projectID int64, query *q.Query) (*model.Summary, error) {
|
||||
ret := _m.Called(ctx, scannerUUID, projectID, query)
|
||||
|
||||
var r0 *model.Summary
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) (*model.Summary, error)); ok {
|
||||
return rf(ctx, scannerUUID, projectID, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64, *q.Query) *model.Summary); ok {
|
||||
r0 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Summary)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, int64, *q.Query) error); ok {
|
||||
r1 = rf(ctx, scannerUUID, projectID, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewManager interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewManager(t mockConstructorTestingTNewManager) *Manager {
|
||||
mock := &Manager{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
Loading…
Reference in New Issue
Block a user