mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
feat(vulnerability): assemble vulnerabilities info for artifact (#10800)
1. Assemble scan overview to artifact when scanner enabled in the project of the artifact. 2. Set addition link for vulnerabilities to artifact when scanner enabled in the project of the artifact. Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
parent
1765abc985
commit
f36152a560
@ -135,31 +135,31 @@ paths:
|
||||
required: false
|
||||
- name: with_tag
|
||||
in: query
|
||||
description: Specify whether the tags are inclued inside the returning artifacts
|
||||
description: Specify whether the tags are included inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
- name: with_label
|
||||
in: query
|
||||
description: Specify whether the labels are inclued inside the returning artifacts
|
||||
description: Specify whether the labels are included inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_scan_overview
|
||||
in: query
|
||||
description: Specify whether the scan overview is inclued inside the returning artifacts
|
||||
description: Specify whether the scan overview is included inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_signature
|
||||
in: query
|
||||
description: Specify whether the signature is inclued inside the tags of the returning artifacts. Only works when setting "with_tag=true"
|
||||
description: Specify whether the signature is included inside the tags of the returning artifacts. Only works when setting "with_tag=true"
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_immutable_status
|
||||
in: query
|
||||
description: Specify whether the immutable status is inclued inside the tags of the returning artifacts. Only works when setting "with_tag=true"
|
||||
description: Specify whether the immutable status is included inside the tags of the returning artifacts. Only works when setting "with_tag=true"
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
@ -372,7 +372,7 @@ paths:
|
||||
in: path
|
||||
description: The type of addition.
|
||||
type: string
|
||||
enum: [build_history, values.yaml, readme.md, dependencies]
|
||||
enum: [build_history, values.yaml, readme.md, dependencies, vulnerabilities]
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
@ -670,6 +670,9 @@ definitions:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Label'
|
||||
scan_overview:
|
||||
$ref: '#/definitions/ScanOverview'
|
||||
description: The overview of the scan result.
|
||||
Tag:
|
||||
type: object
|
||||
properties:
|
||||
@ -796,4 +799,66 @@ definitions:
|
||||
deleted:
|
||||
type: boolean
|
||||
description: Whether the label is deleted or not
|
||||
|
||||
ScanOverview:
|
||||
type: object
|
||||
description: 'The scan overview attached in the metadata of tag'
|
||||
additionalProperties:
|
||||
$ref: '#/definitions/NativeReportSummary'
|
||||
NativeReportSummary:
|
||||
type: object
|
||||
description: 'The summary for the native report'
|
||||
properties:
|
||||
report_id:
|
||||
type: string
|
||||
description: 'id of the native scan report'
|
||||
example: '5f62c830-f996-11e9-957f-0242c0a89008'
|
||||
scan_status:
|
||||
type: string
|
||||
description: 'The status of the report generating process'
|
||||
example: 'Success'
|
||||
severity:
|
||||
type: string
|
||||
description: 'The overall severity'
|
||||
example: 'High'
|
||||
duration:
|
||||
type: integer
|
||||
format: int64
|
||||
description: 'The seconds spent for generating the report'
|
||||
example: 300
|
||||
summary:
|
||||
$ref: '#/definitions/VulnerabilitySummary'
|
||||
start_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: 'The start time of the scan process that generating report'
|
||||
example: '2006-01-02T14:04:05'
|
||||
end_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: 'The end time of the scan process that generating report'
|
||||
example: '2006-01-02T15:04:05'
|
||||
VulnerabilitySummary:
|
||||
type: object
|
||||
description: |
|
||||
VulnerabilitySummary contains the total number of the foun d vulnerabilities number and numbers of each severity level.
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
format: int
|
||||
description: 'The total number of the found vulnerabilities'
|
||||
example: 500
|
||||
fixable:
|
||||
type: integer
|
||||
format: int
|
||||
description: 'The number of the fixable vulnerabilities'
|
||||
example: 100
|
||||
summary:
|
||||
type: object
|
||||
description: 'Numbers of the vulnerabilities with different severity'
|
||||
additionalProperties:
|
||||
type: integer
|
||||
format: int
|
||||
example: 10
|
||||
example:
|
||||
'Critical': 5
|
||||
'High': 5
|
||||
|
@ -239,6 +239,11 @@ func (c *controller) List(ctx context.Context, query *q.Query, option *Option) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.populateRepositoryName(ctx, arts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var artifacts []*Artifact
|
||||
for _, art := range arts {
|
||||
artifacts = append(artifacts, c.assembleArtifact(ctx, art, option))
|
||||
@ -516,6 +521,17 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
||||
artifact := &Artifact{
|
||||
Artifact: *art,
|
||||
}
|
||||
|
||||
if artifact.RepositoryName == "" {
|
||||
repo, err := c.repoMgr.Get(ctx, artifact.RepositoryID)
|
||||
if err != nil {
|
||||
log.Errorf("get repository %d failed, error: %v", artifact.RepositoryID, err)
|
||||
return artifact
|
||||
}
|
||||
|
||||
artifact.RepositoryName = repo.Name
|
||||
}
|
||||
|
||||
// populate addition links
|
||||
c.populateAdditionLinks(ctx, artifact)
|
||||
if option == nil {
|
||||
@ -532,6 +548,34 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
||||
return artifact
|
||||
}
|
||||
|
||||
func (c *controller) populateRepositoryName(ctx context.Context, artifacts ...*artifact.Artifact) error {
|
||||
var ids []int64
|
||||
for _, artifact := range artifacts {
|
||||
ids = append(ids, artifact.RepositoryID)
|
||||
}
|
||||
|
||||
repositories, err := c.repoMgr.List(ctx, &q.Query{Keywords: map[string]interface{}{"repository_id__in": ids}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mp := make(map[int64]string, len(repositories))
|
||||
for _, repository := range repositories {
|
||||
mp[repository.RepositoryID] = repository.Name
|
||||
}
|
||||
|
||||
for _, artifact := range artifacts {
|
||||
repositoryName, ok := mp[artifact.RepositoryID]
|
||||
if !ok {
|
||||
return ierror.NotFoundError(nil).WithMessage("repository %d not found", artifact.RepositoryID)
|
||||
}
|
||||
|
||||
artifact.RepositoryName = repositoryName
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) populateTags(ctx context.Context, art *Artifact, option *TagOption) {
|
||||
tags, err := c.tagMgr.List(ctx, &q.Query{
|
||||
Keywords: map[string]interface{}{
|
||||
@ -619,25 +663,11 @@ func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifa
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
if len(types) == 0 {
|
||||
return
|
||||
}
|
||||
repository, err := c.repoMgr.Get(ctx, artifact.RepositoryID)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
pro, repo := utils.ParseRepository(repository.Name)
|
||||
version := internal.GetAPIVersion(ctx)
|
||||
if artifact.AdditionLinks == nil {
|
||||
artifact.AdditionLinks = make(map[string]*AdditionLink)
|
||||
}
|
||||
for _, t := range types {
|
||||
t = strings.ToLower(t)
|
||||
artifact.AdditionLinks[t] = &AdditionLink{
|
||||
HREF: fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/additions/%s",
|
||||
version, pro, repo, artifact.Digest, t),
|
||||
Absolute: false,
|
||||
|
||||
if len(types) > 0 {
|
||||
version := internal.GetAPIVersion(ctx)
|
||||
for _, t := range types {
|
||||
artifact.SetAdditionLink(strings.ToLower(t), version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,8 +134,9 @@ func (c *controllerTestSuite) TestAssembleTag() {
|
||||
|
||||
func (c *controllerTestSuite) TestAssembleArtifact() {
|
||||
art := &artifact.Artifact{
|
||||
ID: 1,
|
||||
Digest: "sha256:123",
|
||||
ID: 1,
|
||||
Digest: "sha256:123",
|
||||
RepositoryName: "library/hello-world",
|
||||
}
|
||||
option := &Option{
|
||||
WithTag: true,
|
||||
@ -297,6 +298,9 @@ func (c *controllerTestSuite) TestList() {
|
||||
c.repoMgr.On("Get").Return(&models.RepoRecord{
|
||||
Name: "library/hello-world",
|
||||
}, nil)
|
||||
c.repoMgr.On("List").Return([]*models.RepoRecord{
|
||||
{RepositoryID: 1, Name: "library/hello-world"},
|
||||
}, nil)
|
||||
artifacts, err := c.ctl.List(nil, query, option)
|
||||
c.Require().Nil(err)
|
||||
c.Require().Len(artifacts, 1)
|
||||
|
@ -15,7 +15,10 @@
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
cmodels "github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/signature"
|
||||
"github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||
@ -29,6 +32,18 @@ type Artifact struct {
|
||||
Labels []*cmodels.Label `json:"labels"`
|
||||
}
|
||||
|
||||
// SetAdditionLink set a addition link
|
||||
func (artifact *Artifact) SetAdditionLink(addition, version string) {
|
||||
if artifact.AdditionLinks == nil {
|
||||
artifact.AdditionLinks = make(map[string]*AdditionLink)
|
||||
}
|
||||
|
||||
projectName, repo := utils.ParseRepository(artifact.RepositoryName)
|
||||
href := fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/additions/%s", version, projectName, repo, artifact.Digest, addition)
|
||||
|
||||
artifact.AdditionLinks[addition] = &AdditionLink{HREF: href, Absolute: false}
|
||||
}
|
||||
|
||||
// Tag is the overall view of tag
|
||||
type Tag struct {
|
||||
tag.Tag
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||
"github.com/goharbor/harbor/src/pkg/robot"
|
||||
@ -261,7 +262,7 @@ func (bc *basicController) GetReport(artifact *v1.Artifact, mimeTypes []string)
|
||||
}
|
||||
|
||||
if r == nil {
|
||||
return nil, errs.WithCode(errs.PreconditionFailed, errs.Errorf("no scanner registration configured for project: %d", artifact.NamespaceID))
|
||||
return nil, ierror.NotFoundError(nil).WithMessage("no scanner registration configured for project: %d", artifact.NamespaceID)
|
||||
}
|
||||
|
||||
return bc.manager.GetBy(artifact.Digest, r.UUID, mimes)
|
||||
|
@ -40,6 +40,8 @@ type Artifact struct {
|
||||
ExtraAttrs map[string]interface{} `json:"extra_attrs"` // only contains the simple attributes specific for the different artifact type, most of them should come from the config layer
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
References []*Reference `json:"references"` // child artifacts referenced by the parent artifact if the artifact is an index
|
||||
|
||||
RepositoryName string `json:"-"` // repository name, eg: library/photon
|
||||
}
|
||||
|
||||
// From converts the database level artifact to the business level object
|
||||
|
@ -17,22 +17,29 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||
"github.com/goharbor/harbor/src/api/repository"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||
"github.com/goharbor/harbor/src/pkg/project"
|
||||
"github.com/goharbor/harbor/src/pkg/q"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/handler/assembler"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/artifact"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
vulnerabilitiesAddition = "vulnerabilities"
|
||||
)
|
||||
|
||||
func newArtifactAPI() *artifactAPI {
|
||||
@ -95,10 +102,11 @@ func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListAr
|
||||
for _, art := range arts {
|
||||
artifact := &model.Artifact{}
|
||||
artifact.Artifact = *art
|
||||
a.assembleArtifact(ctx, artifact, params.WithScanOverview)
|
||||
artifacts = append(artifacts, artifact)
|
||||
}
|
||||
|
||||
assembler.NewVulAssembler(boolValue(params.WithScanOverview)).WithArtifacts(artifacts...).Assemble(ctx)
|
||||
|
||||
// TODO add link header
|
||||
return operation.NewListArtifactsOK().WithXTotalCount(total).WithLink("").WithPayload(artifacts)
|
||||
}
|
||||
@ -118,7 +126,9 @@ func (a *artifactAPI) GetArtifact(ctx context.Context, params operation.GetArtif
|
||||
}
|
||||
art := &model.Artifact{}
|
||||
art.Artifact = *artifact
|
||||
a.assembleArtifact(ctx, art, params.WithScanOverview)
|
||||
|
||||
assembler.NewVulAssembler(boolValue(params.WithScanOverview)).WithArtifacts(art).Assemble(ctx)
|
||||
|
||||
return operation.NewGetArtifactOK().WithPayload(art)
|
||||
}
|
||||
|
||||
@ -243,14 +253,23 @@ func (a *artifactAPI) GetAddition(ctx context.Context, params operation.GetAddit
|
||||
if err := a.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionRead, rbac.ResourceArtifactAddition); err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
|
||||
artifact, err := a.artCtl.GetByReference(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName), params.Reference, nil)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
addition, err := a.artCtl.GetAddition(ctx, artifact.ID, strings.ToUpper(params.Addition))
|
||||
|
||||
var addition *resolver.Addition
|
||||
|
||||
if params.Addition == vulnerabilitiesAddition {
|
||||
addition, err = resolveVulnerabilitiesAddition(ctx, artifact)
|
||||
} else {
|
||||
addition, err = a.artCtl.GetAddition(ctx, artifact.ID, strings.ToUpper(params.Addition))
|
||||
}
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
|
||||
return middleware.ResponderFunc(func(w http.ResponseWriter, p runtime.Producer) {
|
||||
w.Header().Set("Content-Type", addition.ContentType)
|
||||
w.Write(addition.Content)
|
||||
@ -285,31 +304,22 @@ func (a *artifactAPI) RemoveLabel(ctx context.Context, params operation.RemoveLa
|
||||
return operation.NewRemoveLabelOK()
|
||||
}
|
||||
|
||||
func (a *artifactAPI) assembleArtifact(ctx context.Context, artifact *model.Artifact, withScanOverview *bool) {
|
||||
if withScanOverview != nil && *withScanOverview {
|
||||
// TODO populate scan result
|
||||
}
|
||||
// TODO populate vulnerability link
|
||||
}
|
||||
|
||||
func option(withTag, withImmutableStatus, withLabel, withSignature *bool) *artifact.Option {
|
||||
option := &artifact.Option{
|
||||
WithTag: true, // return the tag by default
|
||||
WithTag: true, // return the tag by default
|
||||
WithLabel: boolValue(withLabel),
|
||||
}
|
||||
|
||||
if withTag != nil {
|
||||
option.WithTag = *(withTag)
|
||||
}
|
||||
|
||||
if option.WithTag {
|
||||
option.TagOption = &artifact.TagOption{}
|
||||
if withImmutableStatus != nil {
|
||||
option.TagOption.WithImmutableStatus = *(withImmutableStatus)
|
||||
}
|
||||
if withSignature != nil {
|
||||
option.TagOption.WithSignature = *withSignature
|
||||
option.TagOption = &artifact.TagOption{
|
||||
WithImmutableStatus: boolValue(withImmutableStatus),
|
||||
WithSignature: boolValue(withSignature),
|
||||
}
|
||||
}
|
||||
if withLabel != nil {
|
||||
option.WithLabel = *(withLabel)
|
||||
}
|
||||
|
||||
return option
|
||||
}
|
||||
|
107
src/server/v2.0/handler/assembler/vul.go
Normal file
107
src/server/v2.0/handler/assembler/vul.go
Normal file
@ -0,0 +1,107 @@
|
||||
// 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 assembler
|
||||
|
||||
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"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||
)
|
||||
|
||||
const (
|
||||
vulnerabilitiesAddition = "vulnerabilities"
|
||||
)
|
||||
|
||||
// NewVulAssembler returns vul assembler
|
||||
func NewVulAssembler(withScanOverview bool) *VulAssembler {
|
||||
return &VulAssembler{
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
return assembler
|
||||
}
|
||||
|
||||
// Assemble assemble vul for the artifacts
|
||||
func (assembler *VulAssembler) Assemble(ctx context.Context) error {
|
||||
version := internal.GetAPIVersion(ctx)
|
||||
|
||||
for _, artifact := range assembler.artifacts {
|
||||
hasScanner := assembler.hasScanner(ctx, artifact.ProjectID)
|
||||
|
||||
if !hasScanner {
|
||||
continue
|
||||
}
|
||||
|
||||
artifact.SetAdditionLink(vulnerabilitiesAddition, version)
|
||||
|
||||
if assembler.withScanOverview {
|
||||
art := &v1.Artifact{
|
||||
NamespaceID: artifact.ProjectID,
|
||||
Repository: artifact.RepositoryName,
|
||||
Digest: artifact.Digest,
|
||||
MimeType: artifact.ManifestMediaType,
|
||||
}
|
||||
|
||||
overview, err := assembler.scanCtl.GetSummary(art, []string{v1.MimeTypeNativeReport})
|
||||
if err != nil {
|
||||
log.Warningf("get scan summary of artifact %s failed, error:%v", artifact.Digest, err)
|
||||
} else if len(overview) > 0 {
|
||||
artifact.ScanOverview = overview
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
107
src/server/v2.0/handler/assembler/vul_test.go
Normal file
107
src/server/v2.0/handler/assembler/vul_test.go
Normal file
@ -0,0 +1,107 @@
|
||||
// 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 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/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type VulAssemblerTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *VulAssemblerTestSuite) newVulAssembler(withScanOverview bool) (*VulAssembler, *scan.Controller, *scanner.Controller) {
|
||||
vulAssembler := NewVulAssembler(withScanOverview)
|
||||
|
||||
scanCtl := &scan.Controller{}
|
||||
scannerCtl := &scanner.Controller{}
|
||||
|
||||
vulAssembler.scanCtl = scanCtl
|
||||
vulAssembler.scannerCtl = scannerCtl
|
||||
|
||||
return vulAssembler, scanCtl, scannerCtl
|
||||
}
|
||||
|
||||
func (suite *VulAssemblerTestSuite) TestNotHasScanner() {
|
||||
{
|
||||
assembler, _, scannerCtl := suite.newVulAssembler(true)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(nil, nil)
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 0)
|
||||
}
|
||||
|
||||
{
|
||||
assembler, _, scannerCtl := suite.newVulAssembler(true)
|
||||
scannerCtl.On("GetRegistrationByProject", mock.AnythingOfType("int64")).Return(nil, fmt.Errorf("error"))
|
||||
|
||||
var artifact model.Artifact
|
||||
suite.Nil(assembler.WithArtifacts(&artifact).Assemble(context.TODO()))
|
||||
suite.Len(artifact.AdditionLinks, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *VulAssemblerTestSuite) TestHasScanner() {
|
||||
{
|
||||
assembler, scanCtl, scannerCtl := suite.newVulAssembler(true)
|
||||
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.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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVulAssemblerTestSuite(t *testing.T) {
|
||||
suite.Run(t, &VulAssemblerTestSuite{})
|
||||
}
|
@ -19,5 +19,5 @@ import "github.com/goharbor/harbor/src/api/artifact"
|
||||
// Artifact model
|
||||
type Artifact struct {
|
||||
artifact.Artifact
|
||||
// TODO add other properties: scan result
|
||||
ScanOverview map[string]interface{} `json:"scan_overview"`
|
||||
}
|
||||
|
70
src/server/v2.0/handler/util.go
Normal file
70
src/server/v2.0/handler/util.go
Normal file
@ -0,0 +1,70 @@
|
||||
// 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"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||
"github.com/goharbor/harbor/src/api/scan"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/report"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
)
|
||||
|
||||
func boolValue(v *bool) bool {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func resolveVulnerabilitiesAddition(ctx context.Context, artifact *artifact.Artifact) (*resolver.Addition, error) {
|
||||
art := &v1.Artifact{
|
||||
NamespaceID: artifact.ProjectID,
|
||||
Repository: artifact.RepositoryName,
|
||||
Digest: artifact.Digest,
|
||||
MimeType: artifact.ManifestMediaType,
|
||||
}
|
||||
|
||||
reports, err := scan.DefaultController.GetReport(art, []string{v1.MimeTypeNativeReport})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vulnerabilities := make(map[string]interface{})
|
||||
for _, rp := range reports {
|
||||
// Resolve scan report data only when it is ready
|
||||
if len(rp.Report) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
vrp, err := report.ResolveData(rp.MimeType, []byte(rp.Report))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vulnerabilities[rp.MimeType] = vrp
|
||||
}
|
||||
|
||||
content, _ := json.Marshal(vulnerabilities)
|
||||
|
||||
return &resolver.Addition{
|
||||
Content: content,
|
||||
ContentType: "application/json",
|
||||
}, nil
|
||||
}
|
18
src/testing/api/api.go
Normal file
18
src/testing/api/api.go
Normal file
@ -0,0 +1,18 @@
|
||||
// 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 api
|
||||
|
||||
//go:generate mockery -case snake -dir ../../api/scan -name Controller -output ./scan -outpkg scan
|
||||
//go:generate mockery -case snake -dir ../../api/scanner -name Controller -output ./scanner -outpkg scanner
|
177
src/testing/api/scan/controller.go
Normal file
177
src/testing/api/scan/controller.go
Normal file
@ -0,0 +1,177 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package scan
|
||||
|
||||
import (
|
||||
all "github.com/goharbor/harbor/src/pkg/scan/all"
|
||||
daoscan "github.com/goharbor/harbor/src/pkg/scan/dao/scan"
|
||||
|
||||
job "github.com/goharbor/harbor/src/jobservice/job"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
report "github.com/goharbor/harbor/src/pkg/scan/report"
|
||||
|
||||
scan "github.com/goharbor/harbor/src/api/scan"
|
||||
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
)
|
||||
|
||||
// Controller is an autogenerated mock type for the Controller type
|
||||
type Controller struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// DeleteReports provides a mock function with given fields: digests
|
||||
func (_m *Controller) DeleteReports(digests ...string) error {
|
||||
_va := make([]interface{}, len(digests))
|
||||
for _i := range digests {
|
||||
_va[_i] = digests[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(...string) error); ok {
|
||||
r0 = rf(digests...)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetReport provides a mock function with given fields: artifact, mimeTypes
|
||||
func (_m *Controller) GetReport(artifact *v1.Artifact, mimeTypes []string) ([]*daoscan.Report, error) {
|
||||
ret := _m.Called(artifact, mimeTypes)
|
||||
|
||||
var r0 []*daoscan.Report
|
||||
if rf, ok := ret.Get(0).(func(*v1.Artifact, []string) []*daoscan.Report); ok {
|
||||
r0 = rf(artifact, mimeTypes)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*daoscan.Report)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*v1.Artifact, []string) error); ok {
|
||||
r1 = rf(artifact, mimeTypes)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetScanLog provides a mock function with given fields: uuid
|
||||
func (_m *Controller) GetScanLog(uuid string) ([]byte, error) {
|
||||
ret := _m.Called(uuid)
|
||||
|
||||
var r0 []byte
|
||||
if rf, ok := ret.Get(0).(func(string) []byte); ok {
|
||||
r0 = rf(uuid)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(uuid)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetStats provides a mock function with given fields: requester
|
||||
func (_m *Controller) GetStats(requester string) (*all.Stats, error) {
|
||||
ret := _m.Called(requester)
|
||||
|
||||
var r0 *all.Stats
|
||||
if rf, ok := ret.Get(0).(func(string) *all.Stats); ok {
|
||||
r0 = rf(requester)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*all.Stats)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(requester)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetSummary provides a mock function with given fields: artifact, mimeTypes, options
|
||||
func (_m *Controller) GetSummary(artifact *v1.Artifact, mimeTypes []string, options ...report.Option) (map[string]interface{}, error) {
|
||||
_va := make([]interface{}, len(options))
|
||||
for _i := range options {
|
||||
_va[_i] = options[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, artifact, mimeTypes)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 map[string]interface{}
|
||||
if rf, ok := ret.Get(0).(func(*v1.Artifact, []string, ...report.Option) map[string]interface{}); ok {
|
||||
r0 = rf(artifact, mimeTypes, options...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*v1.Artifact, []string, ...report.Option) error); ok {
|
||||
r1 = rf(artifact, mimeTypes, options...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// HandleJobHooks provides a mock function with given fields: trackID, change
|
||||
func (_m *Controller) HandleJobHooks(trackID string, change *job.StatusChange) error {
|
||||
ret := _m.Called(trackID, change)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, *job.StatusChange) error); ok {
|
||||
r0 = rf(trackID, change)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Scan provides a mock function with given fields: artifact, options
|
||||
func (_m *Controller) Scan(artifact *v1.Artifact, options ...scan.Option) error {
|
||||
_va := make([]interface{}, len(options))
|
||||
for _i := range options {
|
||||
_va[_i] = options[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, artifact)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*v1.Artifact, ...scan.Option) error); ok {
|
||||
r0 = rf(artifact, options...)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
232
src/testing/api/scanner/controller.go
Normal file
232
src/testing/api/scanner/controller.go
Normal file
@ -0,0 +1,232 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package scanner
|
||||
|
||||
import (
|
||||
q "github.com/goharbor/harbor/src/pkg/q"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
scanner "github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
|
||||
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
)
|
||||
|
||||
// Controller is an autogenerated mock type for the Controller type
|
||||
type Controller struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateRegistration provides a mock function with given fields: registration
|
||||
func (_m *Controller) CreateRegistration(registration *scanner.Registration) (string, error) {
|
||||
ret := _m.Called(registration)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(*scanner.Registration) string); ok {
|
||||
r0 = rf(registration)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*scanner.Registration) error); ok {
|
||||
r1 = rf(registration)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteRegistration provides a mock function with given fields: registrationUUID
|
||||
func (_m *Controller) DeleteRegistration(registrationUUID string) (*scanner.Registration, error) {
|
||||
ret := _m.Called(registrationUUID)
|
||||
|
||||
var r0 *scanner.Registration
|
||||
if rf, ok := ret.Get(0).(func(string) *scanner.Registration); ok {
|
||||
r0 = rf(registrationUUID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*scanner.Registration)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(registrationUUID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetMetadata provides a mock function with given fields: registrationUUID
|
||||
func (_m *Controller) GetMetadata(registrationUUID string) (*v1.ScannerAdapterMetadata, error) {
|
||||
ret := _m.Called(registrationUUID)
|
||||
|
||||
var r0 *v1.ScannerAdapterMetadata
|
||||
if rf, ok := ret.Get(0).(func(string) *v1.ScannerAdapterMetadata); ok {
|
||||
r0 = rf(registrationUUID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1.ScannerAdapterMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(registrationUUID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetRegistration provides a mock function with given fields: registrationUUID
|
||||
func (_m *Controller) GetRegistration(registrationUUID string) (*scanner.Registration, error) {
|
||||
ret := _m.Called(registrationUUID)
|
||||
|
||||
var r0 *scanner.Registration
|
||||
if rf, ok := ret.Get(0).(func(string) *scanner.Registration); ok {
|
||||
r0 = rf(registrationUUID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*scanner.Registration)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(registrationUUID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
var r0 *scanner.Registration
|
||||
if rf, ok := ret.Get(0).(func(int64) *scanner.Registration); ok {
|
||||
r0 = rf(projectID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*scanner.Registration)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
||||
r1 = rf(projectID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListRegistrations provides a mock function with given fields: query
|
||||
func (_m *Controller) ListRegistrations(query *q.Query) ([]*scanner.Registration, error) {
|
||||
ret := _m.Called(query)
|
||||
|
||||
var r0 []*scanner.Registration
|
||||
if rf, ok := ret.Get(0).(func(*q.Query) []*scanner.Registration); ok {
|
||||
r0 = rf(query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*scanner.Registration)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*q.Query) error); ok {
|
||||
r1 = rf(query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Ping provides a mock function with given fields: registration
|
||||
func (_m *Controller) Ping(registration *scanner.Registration) (*v1.ScannerAdapterMetadata, error) {
|
||||
ret := _m.Called(registration)
|
||||
|
||||
var r0 *v1.ScannerAdapterMetadata
|
||||
if rf, ok := ret.Get(0).(func(*scanner.Registration) *v1.ScannerAdapterMetadata); ok {
|
||||
r0 = rf(registration)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1.ScannerAdapterMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*scanner.Registration) error); ok {
|
||||
r1 = rf(registration)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RegistrationExists provides a mock function with given fields: registrationUUID
|
||||
func (_m *Controller) RegistrationExists(registrationUUID string) bool {
|
||||
ret := _m.Called(registrationUUID)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(string) bool); ok {
|
||||
r0 = rf(registrationUUID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetDefaultRegistration provides a mock function with given fields: registrationUUID
|
||||
func (_m *Controller) SetDefaultRegistration(registrationUUID string) error {
|
||||
ret := _m.Called(registrationUUID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string) error); ok {
|
||||
r0 = rf(registrationUUID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetRegistrationByProject provides a mock function with given fields: projectID, scannerID
|
||||
func (_m *Controller) SetRegistrationByProject(projectID int64, scannerID string) error {
|
||||
ret := _m.Called(projectID, scannerID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(int64, string) error); ok {
|
||||
r0 = rf(projectID, scannerID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateRegistration provides a mock function with given fields: registration
|
||||
func (_m *Controller) UpdateRegistration(registration *scanner.Registration) error {
|
||||
ret := _m.Called(registration)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*scanner.Registration) error); ok {
|
||||
r0 = rf(registration)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
Loading…
Reference in New Issue
Block a user