fix: validate the existence of project for export cve api (#17437)

Validate the existence of the project for export CVE API handler, return
not found error if the project is not exist.

Closes: #17430

Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
Chenyu Zhang 2022-08-22 15:44:57 +08:00 committed by GitHub
parent 5d7a549620
commit 31a3c6d18c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 17 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/go-openapi/strfmt"
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/controller/project"
"github.com/goharbor/harbor/src/controller/scandataexport"
"github.com/goharbor/harbor/src/jobservice/job"
"github.com/goharbor/harbor/src/lib/log"
@ -29,6 +30,7 @@ import (
func newScanDataExportAPI() *scanDataExportAPI {
return &scanDataExportAPI{
scanDataExportCtl: scandataexport.Ctl,
proCtl: project.Ctl,
sysArtifactMgr: systemartifact.Mgr,
userMgr: user.Mgr,
}
@ -37,6 +39,7 @@ func newScanDataExportAPI() *scanDataExportAPI {
type scanDataExportAPI struct {
BaseAPI
scanDataExportCtl scandataexport.Controller
proCtl project.Controller
sysArtifactMgr systemartifact.Manager
userMgr user.Manager
}
@ -47,7 +50,7 @@ func (se *scanDataExportAPI) Prepare(ctx context.Context, operation string, para
func (se *scanDataExportAPI) ExportScanData(ctx context.Context, params operation.ExportScanDataParams) middleware.Responder {
// validate the request params
if err := validateScanExportParams(params); err != nil {
if err := se.validateScanExportParams(ctx, params); err != nil {
return se.SendError(ctx, err)
}
@ -55,13 +58,6 @@ func (se *scanDataExportAPI) ExportScanData(ctx context.Context, params operatio
return se.SendError(ctx, err)
}
// check if the MIME type for the export is the Generic vulnerability data
if params.XScanDataType != v1.MimeTypeGenericVulnerabilityReport {
error := &models.Error{Message: fmt.Sprintf("Unsupported MIME type : %s", params.XScanDataType)}
errors := &models.Errors{Errors: []*models.Error{error}}
return operation.NewExportScanDataBadRequest().WithPayload(errors)
}
scanDataExportJob := new(models.ScanDataExportJob)
secContext, err := se.GetSecurityContext(ctx)
@ -309,10 +305,17 @@ func (se *scanDataExportAPI) requireProjectsAccess(ctx context.Context, pids []i
// validateScanExportParams validates scan data export request parameters by
// following policies.
// rules:
// 1. the criteria should not be empty
// 2. currently only the export of single project is open
// 3. do not allow to input space in the repo/tag/cve_id (space will lead to misjudge for doublestar filter)
func validateScanExportParams(params operation.ExportScanDataParams) error {
// 1. check the scan data type
// 2. the criteria should not be empty
// 3. currently only the export of single project is open
// 4. check the existence of project
// 5. do not allow to input space in the repo/tag/cve_id (space will lead to misjudge for doublestar filter)
func (se *scanDataExportAPI) validateScanExportParams(ctx context.Context, params operation.ExportScanDataParams) error {
// check if the MIME type for the export is the Generic vulnerability data
if params.XScanDataType != v1.MimeTypeGenericVulnerabilityReport {
return errors.BadRequestError(errors.Errorf("Unsupported MIME type : %s", params.XScanDataType))
}
criteria := params.Criteria
if criteria == nil {
return errors.BadRequestError(errors.Errorf("criteria is invalid: %v", criteria))
@ -323,6 +326,16 @@ func validateScanExportParams(params operation.ExportScanDataParams) error {
return errors.BadRequestError(errors.Errorf("only support export single project, invalid value: %v", criteria.Projects))
}
// check whether the project exists
exist, err := se.proCtl.Exists(ctx, criteria.Projects[0])
if err != nil {
return errors.UnknownError(errors.Errorf("check the existence of project error: %v", err))
}
if !exist {
return errors.NotFoundError(errors.Errorf("project %d not found", criteria.Projects[0]))
}
// check spaces
space := " "
inspectList := []string{criteria.Repositories, criteria.Tags, criteria.CVEIds}

View File

@ -2,6 +2,7 @@ package handler
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
@ -22,6 +23,7 @@ import (
"github.com/goharbor/harbor/src/server/v2.0/models"
"github.com/goharbor/harbor/src/server/v2.0/restapi"
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/scan_data_export"
"github.com/goharbor/harbor/src/testing/controller/project"
"github.com/goharbor/harbor/src/testing/controller/scandataexport"
"github.com/goharbor/harbor/src/testing/mock"
systemartifacttesting "github.com/goharbor/harbor/src/testing/pkg/systemartifact"
@ -32,6 +34,7 @@ import (
type ScanExportTestSuite struct {
htesting.Suite
scanExportCtl *scandataexport.Controller
proCtl *project.Controller
sysArtifactMgr *systemartifacttesting.Manager
userMgr *user.Manager
}
@ -43,15 +46,18 @@ func (suite *ScanExportTestSuite) SetupSuite() {
func (suite *ScanExportTestSuite) SetupTest() {
suite.scanExportCtl = &scandataexport.Controller{}
suite.proCtl = &project.Controller{}
suite.sysArtifactMgr = &systemartifacttesting.Manager{}
suite.userMgr = &user.Manager{}
suite.Config = &restapi.Config{
ScanDataExportAPI: &scanDataExportAPI{
scanDataExportCtl: suite.scanExportCtl,
proCtl: suite.proCtl,
sysArtifactMgr: suite.sysArtifactMgr,
userMgr: suite.userMgr,
},
}
mock.OnAnything(suite.proCtl, "Exists").Return(true, nil)
suite.Suite.SetupSuite()
}
@ -95,8 +101,17 @@ func (suite *ScanExportTestSuite) TestAuthorization() {
}
func (suite *ScanExportTestSuite) TestValidateScanExportParams() {
// empty criteria should return error
err := validateScanExportParams(operation.ExportScanDataParams{})
api := newScanDataExportAPI()
api.proCtl = suite.proCtl
ctx := context.TODO()
// no scan data type should return error
err := api.validateScanExportParams(ctx, operation.ExportScanDataParams{})
suite.Error(err)
suite.True(errors.IsErr(err, errors.BadRequestCode))
xScanDataType := v1.MimeTypeGenericVulnerabilityReport
// empty params should return error
err = api.validateScanExportParams(ctx, operation.ExportScanDataParams{XScanDataType: xScanDataType})
suite.Error(err)
suite.True(errors.IsErr(err, errors.BadRequestCode))
@ -104,7 +119,7 @@ func (suite *ScanExportTestSuite) TestValidateScanExportParams() {
criteria := models.ScanDataExportRequest{
Projects: []int64{200, 300},
}
err = validateScanExportParams(operation.ExportScanDataParams{Criteria: &criteria})
err = api.validateScanExportParams(ctx, operation.ExportScanDataParams{XScanDataType: xScanDataType, Criteria: &criteria})
suite.Error(err)
suite.True(errors.IsErr(err, errors.BadRequestCode))
@ -116,7 +131,7 @@ func (suite *ScanExportTestSuite) TestValidateScanExportParams() {
Repositories: "test-repo1, test-repo2",
Tags: "{test-tag1, test-tag2}",
}
err = validateScanExportParams(operation.ExportScanDataParams{Criteria: &criteria})
err = api.validateScanExportParams(ctx, operation.ExportScanDataParams{XScanDataType: xScanDataType, Criteria: &criteria})
suite.Error(err)
suite.True(errors.IsErr(err, errors.BadRequestCode))
@ -128,8 +143,22 @@ func (suite *ScanExportTestSuite) TestValidateScanExportParams() {
Repositories: "test-repo1,test-repo2",
Tags: "{test-tag1,test-tag2}",
}
err = validateScanExportParams(operation.ExportScanDataParams{Criteria: &criteria})
err = api.validateScanExportParams(ctx, operation.ExportScanDataParams{XScanDataType: xScanDataType, Criteria: &criteria})
suite.NoError(err)
// none exist project should return error
api.proCtl = &project.Controller{}
mock.OnAnything(api.proCtl, "Exists").Return(false, nil)
criteria = models.ScanDataExportRequest{
CVEIds: "CVE-123,CVE-456",
Labels: []int64{100},
Projects: []int64{200},
Repositories: "test-repo1,test-repo2",
Tags: "{test-tag1,test-tag2}",
}
err = api.validateScanExportParams(ctx, operation.ExportScanDataParams{XScanDataType: xScanDataType, Criteria: &criteria})
suite.Error(err)
suite.True(errors.IsErr(err, errors.NotFoundCode))
}
func (suite *ScanExportTestSuite) TestExportScanData() {