fix: resolve the oidc or ldap group user cannot export cve (#18219)

Remove the project filter in the scan data export job as they have been
validated by API handler, fix the oidc or ldap group users cannot export
cve.

Fixes: #18112

Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
Chlins Zhang 2023-02-20 14:22:27 +08:00 committed by GitHub
parent 94dbc3fa8f
commit da1637e1d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 22 additions and 281 deletions

View File

@ -7,7 +7,6 @@ import (
"time"
"github.com/goharbor/harbor/src/jobservice/job"
"github.com/goharbor/harbor/src/jobservice/logger"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/orm"
@ -66,6 +65,7 @@ func (c *controller) ListExecutions(ctx context.Context, userName string) ([]*ex
}
func (c *controller) GetTask(ctx context.Context, executionID int64) (*task.Task, error) {
logger := log.GetLogger(ctx)
query := q2.New(q2.KeyWords{})
keywords := make(map[string]interface{})
@ -90,6 +90,7 @@ func (c *controller) GetTask(ctx context.Context, executionID int64) (*task.Task
}
func (c *controller) GetExecution(ctx context.Context, executionID int64) (*export.Execution, error) {
logger := log.GetLogger(ctx)
exec, err := c.execMgr.Get(ctx, executionID)
if err != nil {
logger.Errorf("Error when fetching execution status for ExecutionId: %d error : %v", executionID, err)
@ -103,6 +104,7 @@ func (c *controller) GetExecution(ctx context.Context, executionID int64) (*expo
}
func (c *controller) DeleteExecution(ctx context.Context, executionID int64) error {
logger := log.GetLogger(ctx)
err := c.execMgr.Delete(ctx, executionID)
if err != nil {
logger.Errorf("Error when deleting execution for ExecutionId: %d, error : %v", executionID, err)
@ -188,12 +190,17 @@ func (c *controller) convertToExportExecStatus(ctx context.Context, exec *task.E
if statusMessage, ok := exec.ExtraAttrs[export.StatusMessageAttribute]; ok {
execStatus.StatusMessage = statusMessage.(string)
}
if len(execStatus.ExportDataDigest) > 0 {
artifactExists := c.isCsvArtifactPresent(ctx, exec.ID, execStatus.ExportDataDigest)
execStatus.FilePresent = artifactExists
}
return execStatus
}
func (c *controller) isCsvArtifactPresent(ctx context.Context, execID int64, digest string) bool {
logger := log.GetLogger(ctx)
repositoryName := fmt.Sprintf("scandata_export_%v", execID)
exists, err := c.sysArtifactMgr.Exists(ctx, strings.ToLower(export.Vendor), repositoryName, digest)
if err != nil {

View File

@ -97,6 +97,7 @@ func (suite *ScanDataExportExecutionTestSuite) TestGetExecution() {
attrs := make(map[string]interface{})
attrs[export.JobNameAttribute] = "test-job"
attrs[export.UserNameAttribute] = "test-user"
attrs[export.DigestKey] = "sha256:d04b98f48e8f8bcc15c6ae5ac050801cd6dcfd428fb5f9e65c4e16e7807340fa"
attrs["status_message"] = "test-message"
{
exec := task.Execution{

View File

@ -184,14 +184,7 @@ func (sde *ScanDataExport) writeCsvFile(ctx job.Context, params job.Parameters,
return err
}
// check if any projects are specified. If not then fetch all the projects
// of which the current user is a project admin.
projectIds, err := sde.filterProcessor.ProcessProjectFilter(systemContext, filterCriteria.UserName, filterCriteria.Projects)
if err != nil {
return err
}
projectIds := filterCriteria.Projects
if len(projectIds) == 0 {
return nil
}

View File

@ -73,7 +73,6 @@ func (suite *ScanDataExportJobTestSuite) TestRun() {
data := suite.createDataRecords(3)
mock.OnAnything(suite.exportMgr, "Fetch").Return(data, nil).Once()
mock.OnAnything(suite.digestCalculator, "Calculate").Return(digest.Digest(MockDigest), nil)
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return([]*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1}}}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessLabelFilter").Return([]*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1}}}, nil).Once()
@ -86,7 +85,9 @@ func (suite *ScanDataExportJobTestSuite) TestRun() {
params := job.Parameters{}
params[export.JobModeKey] = export.JobModeExport
params["JobId"] = JobId
params["Request"] = map[string]interface{}{}
params["Request"] = map[string]interface{}{
"projects": []int64{1},
}
ctx := &mockjobservice.MockJobContext{}
err := suite.job.Run(ctx, params)
@ -138,7 +139,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunAttributeUpdateError() {
data := suite.createDataRecords(3)
mock.OnAnything(suite.exportMgr, "Fetch").Return(data, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return([]*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1}}}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessLabelFilter").Return([]*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1}}}, nil).Once()
@ -152,7 +152,9 @@ func (suite *ScanDataExportJobTestSuite) TestRunAttributeUpdateError() {
params := job.Parameters{}
params[export.JobModeKey] = export.JobModeExport
params["JobId"] = JobId
params["Request"] = map[string]interface{}{}
params["Request"] = map[string]interface{}{
"projects": []int{1},
}
ctx := &mockjobservice.MockJobContext{}
err := suite.job.Run(ctx, params)
@ -209,7 +211,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteria() {
repoCandidates := []int64{1}
artCandidates := []*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1, Digest: "digest1"}}}
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return(repoCandidates, nil)
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return(artCandidates, nil)
mock.OnAnything(suite.filterProcessor, "ProcessLabelFilter").Return(artCandidates, nil)
@ -274,7 +275,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteria() {
repoCandidate1 := &selector.Candidate{NamespaceID: 1}
repoCandidates := []*selector.Candidate{repoCandidate1}
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return(repoCandidates, nil)
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return(repoCandidates, nil)
@ -321,111 +321,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteria() {
}
}
func (suite *ScanDataExportJobTestSuite) TestRunWithCriteriaForProjectIdFilter() {
{
data := suite.createDataRecords(3)
mock.OnAnything(suite.exportMgr, "Fetch").Return(data, nil).Once()
mock.OnAnything(suite.exportMgr, "Fetch").Return(make([]export.Data, 0), nil).Once()
mock.OnAnything(suite.digestCalculator, "Calculate").Return(digest.Digest(MockDigest), nil)
mock.OnAnything(suite.exportMgr, "Fetch").Return(data, nil).Once()
mock.OnAnything(suite.exportMgr, "Fetch").Return(make([]export.Data, 0), nil).Once()
mock.OnAnything(suite.digestCalculator, "Calculate").Return(digest.Digest(MockDigest), nil)
execAttrs := make(map[string]interface{})
execAttrs[export.JobNameAttribute] = "test-job"
execAttrs[export.UserNameAttribute] = "test-user"
mock.OnAnything(suite.execMgr, "Get").Return(&task.Execution{ID: int64(JobId), ExtraAttrs: execAttrs}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return(nil, errors.New("test error")).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return(nil, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return(nil, nil).Once()
criteria := export.Request{
CVEIds: "CVE-123",
Labels: []int64{1},
Projects: []int64{1},
Repositories: "test-repo",
Tags: "test-tag",
}
criteriaMap := make(map[string]interface{})
bytes, _ := json.Marshal(criteria)
json.Unmarshal(bytes, &criteriaMap)
params := job.Parameters{}
params[export.JobModeKey] = export.JobModeExport
params["JobId"] = JobId
params["Request"] = criteriaMap
ctx := &mockjobservice.MockJobContext{}
ctx.On("SystemContext").Return(context.TODO()).Once()
err := suite.job.Run(ctx, params)
suite.Error(err)
sysArtifactRecordMatcher := testifymock.MatchedBy(func(sa *model.SystemArtifact) bool {
return sa.Repository == "scandata_export_100" && sa.Vendor == strings.ToLower(export.Vendor) && sa.Digest == MockDigest
})
suite.sysArtifactMgr.AssertNotCalled(suite.T(), "Create", mock.Anything, sysArtifactRecordMatcher, mock.Anything)
suite.execMgr.AssertNotCalled(suite.T(), "UpdateExtraAttrs", mock.Anything, int64(JobId), mock.Anything)
_, err = os.Stat("/tmp/scandata_export_100.csv")
suite.exportMgr.AssertNotCalled(suite.T(), "Fetch", mock.Anything, mock.Anything)
suite.Truef(os.IsNotExist(err), "Expected CSV file to be deleted")
}
// empty list of projects
{
data := suite.createDataRecords(3)
mock.OnAnything(suite.exportMgr, "Fetch").Return(data, nil).Once()
mock.OnAnything(suite.exportMgr, "Fetch").Return(make([]export.Data, 0), nil).Once()
mock.OnAnything(suite.digestCalculator, "Calculate").Return(digest.Digest(MockDigest), nil)
mock.OnAnything(suite.exportMgr, "Fetch").Return(data, nil).Once()
mock.OnAnything(suite.exportMgr, "Fetch").Return(make([]export.Data, 0), nil).Once()
mock.OnAnything(suite.digestCalculator, "Calculate").Return(digest.Digest(MockDigest), nil)
execAttrs := make(map[string]interface{})
execAttrs[export.JobNameAttribute] = "test-job"
execAttrs[export.UserNameAttribute] = "test-user"
mock.OnAnything(suite.execMgr, "Get").Return(&task.Execution{ID: int64(JobId), ExtraAttrs: execAttrs}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return([]*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1}}}, nil).Once()
criteria := export.Request{
CVEIds: "CVE-123",
Labels: []int64{1},
Projects: []int64{1},
Repositories: "test-repo",
Tags: "test-tag",
}
criteriaMap := make(map[string]interface{})
bytes, _ := json.Marshal(criteria)
json.Unmarshal(bytes, &criteriaMap)
params := job.Parameters{}
params[export.JobModeKey] = export.JobModeExport
params["JobId"] = JobId
params["Request"] = criteriaMap
ctx := &mockjobservice.MockJobContext{}
ctx.On("SystemContext").Return(context.TODO()).Once()
err := suite.job.Run(ctx, params)
suite.NoError(err)
sysArtifactRecordMatcher := testifymock.MatchedBy(func(sa *model.SystemArtifact) bool {
return sa.Repository == "scandata_export_100" && sa.Vendor == strings.ToLower(export.Vendor) && sa.Digest == MockDigest
})
suite.sysArtifactMgr.AssertNotCalled(suite.T(), "Create", mock.Anything, sysArtifactRecordMatcher, mock.Anything)
suite.execMgr.AssertCalled(suite.T(), "UpdateExtraAttrs", mock.Anything, int64(JobId), mock.Anything)
_, err = os.Stat("/tmp/scandata_export_100.csv")
suite.exportMgr.AssertNotCalled(suite.T(), "Fetch", mock.Anything, mock.Anything)
suite.Truef(os.IsNotExist(err), "Expected CSV file to be deleted")
}
}
func (suite *ScanDataExportJobTestSuite) TestRunWithCriteriaForRepositoryIdFilter() {
{
data := suite.createDataRecords(3)
@ -441,7 +336,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteriaForRepositoryIdFilte
execAttrs[export.UserNameAttribute] = "test-user"
mock.OnAnything(suite.execMgr, "Get").Return(&task.Execution{ID: int64(JobId), ExtraAttrs: execAttrs}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{1}, errors.New("test error")).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{1}, errors.New("test error")).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return([]*artifact.Artifact{{Artifact: artpkg.Artifact{ID: 1}}}, nil).Once()
@ -492,7 +386,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteriaForRepositoryIdFilte
execAttrs[export.UserNameAttribute] = "test-user"
mock.OnAnything(suite.execMgr, "Get").Return(&task.Execution{ID: int64(JobId), ExtraAttrs: execAttrs}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return([]*artifact.Artifact{}, nil).Once()
@ -545,7 +438,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteriaForRepositoryIdWithT
execAttrs[export.UserNameAttribute] = "test-user"
mock.OnAnything(suite.execMgr, "Get").Return(&task.Execution{ID: int64(JobId), ExtraAttrs: execAttrs}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{1}, errors.New("test error")).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{1}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return(nil, errors.New("test error")).Once()
@ -596,7 +488,6 @@ func (suite *ScanDataExportJobTestSuite) TestRunWithCriteriaForRepositoryIdWithT
execAttrs[export.UserNameAttribute] = "test-user"
mock.OnAnything(suite.execMgr, "Get").Return(&task.Execution{ID: int64(JobId), ExtraAttrs: execAttrs}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessProjectFilter").Return([]int64{}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessRepositoryFilter").Return([]int64{}, nil).Once()
mock.OnAnything(suite.filterProcessor, "ProcessTagFilter").Return(nil, nil).Once()

View File

@ -3,24 +3,19 @@ package export
import (
"context"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/security/local"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/controller/artifact"
"github.com/goharbor/harbor/src/jobservice/logger"
"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/lib/selector"
"github.com/goharbor/harbor/src/lib/selector/selectors/doublestar"
"github.com/goharbor/harbor/src/pkg"
artpkg "github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/project"
"github.com/goharbor/harbor/src/pkg/project/models"
"github.com/goharbor/harbor/src/pkg/repository"
"github.com/goharbor/harbor/src/pkg/user"
)
type FilterProcessor interface {
ProcessProjectFilter(ctx context.Context, userName string, projectsToFilter []int64) ([]int64, error)
ProcessRepositoryFilter(ctx context.Context, filter string, projectIds []int64) ([]int64, error)
ProcessTagFilter(ctx context.Context, filter string, repositoryIds []int64) ([]*artifact.Artifact, error)
ProcessLabelFilter(ctx context.Context, labelIDs []int64, arts []*artifact.Artifact) ([]*artifact.Artifact, error)
@ -43,50 +38,6 @@ func NewFilterProcessor() FilterProcessor {
}
}
func (dfp *DefaultFilterProcessor) ProcessProjectFilter(ctx context.Context, userName string, projectIdsToFilter []int64) ([]int64, error) {
// get the user id of the current user
usr, err := dfp.usrMgr.GetByName(ctx, userName)
if err != nil {
return nil, err
}
logger.Infof("Retrieved user id :%d for user name : %s", usr.UserID, userName)
if err != nil {
return nil, err
}
query := dfp.getProjectQueryFilter(usr)
projects, err := dfp.projectMgr.List(ctx, query)
if err != nil {
return nil, err
}
logger.Infof("Selected %d projects administered by user %s ", len(projects), userName)
projectIds := make([]int64, 0)
for _, proj := range projects {
projectIds = append(projectIds, proj.ProjectID)
}
// check if the project ids specified in the filter are present in the list
// of projects of which the current user is a project admin
if len(projectIdsToFilter) == 0 {
return projectIds, nil
}
m := make(map[int64]bool)
for _, projectID := range projectIds {
m[projectID] = true
}
filtered := make([]int64, 0)
for _, filteredProjID := range projectIdsToFilter {
if m[filteredProjID] {
filtered = append(filtered, filteredProjID)
}
}
return filtered, nil
}
func (dfp *DefaultFilterProcessor) ProcessRepositoryFilter(ctx context.Context, filter string, projectIds []int64) ([]int64, error) {
sel := doublestar.New(doublestar.RepoMatches, filter, "")
candidates := make([]*selector.Candidate, 0)
@ -223,14 +174,3 @@ func (dfp *DefaultFilterProcessor) ProcessLabelFilter(ctx context.Context, label
return filteredArts, nil
}
func (dfp *DefaultFilterProcessor) getProjectQueryFilter(user *commonmodels.User) *q.Query {
secContext := local.NewSecurityContext(user)
if secContext.IsSysAdmin() {
logger.Infof("User %v is sys admin. Selecting all projects for export.", user.Username)
return q.New(q.KeyWords{})
}
logger.Infof("User %v is not sys admin. Selecting projects with admin roles for export.", user.Username)
return q.New(q.KeyWords{"member": &models.MemberQuery{UserID: user.UserID, GroupIDs: user.GroupIDs}})
}

View File

@ -3,21 +3,15 @@ package export
import (
"context"
"errors"
"reflect"
"testing"
"time"
testifymock "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/controller/artifact"
project3 "github.com/goharbor/harbor/src/controller/project"
"github.com/goharbor/harbor/src/controller/tag"
"github.com/goharbor/harbor/src/lib/q"
artpkg "github.com/goharbor/harbor/src/pkg/artifact"
labelmodel "github.com/goharbor/harbor/src/pkg/label/model"
"github.com/goharbor/harbor/src/pkg/project/models"
"github.com/goharbor/harbor/src/pkg/repository/model"
tagmodel "github.com/goharbor/harbor/src/pkg/tag/model/tag"
artifactctl "github.com/goharbor/harbor/src/testing/controller/artifact"
@ -53,70 +47,6 @@ func (suite *FilterProcessorTestSuite) SetupTest() {
}
}
func (suite *FilterProcessorTestSuite) TestProcessProjectFilter() {
project1 := &models.Project{ProjectID: 1}
project2 := &models.Project{ProjectID: 2}
// no filtered projects returns all projects
{
suite.usrMgr.On("GetByName", mock.Anything, "test-user").Return(&commonmodels.User{UserID: 1}, nil).Once()
suite.projectMgr.On("List", mock.Anything, mock.Anything).Return([]*models.Project{project1, project2}, nil).Once()
projectIds, err := suite.filterProcessor.ProcessProjectFilter(context.TODO(), "test-user", []int64{})
suite.Equal(2, len(projectIds))
suite.NoError(err)
}
// filtered project
{
suite.usrMgr.On("GetByName", mock.Anything, "test-user").Return(&commonmodels.User{UserID: 1}, nil).Once()
suite.projectMgr.On("List", mock.Anything, mock.Anything).Return([]*models.Project{project1, project2}, nil).Once()
projectIds, err := suite.filterProcessor.ProcessProjectFilter(context.TODO(), "test-user", []int64{1})
suite.Equal(1, len(projectIds))
suite.Equal(int64(1), projectIds[0])
suite.NoError(err)
}
// filtered project with group ids
{
groupIDs := []int{4, 5}
suite.usrMgr.On("GetByName", mock.Anything, "test-user").Return(&commonmodels.User{UserID: 1, GroupIDs: groupIDs}, nil).Once()
suite.projectMgr.On("List", mock.Anything, mock.Anything).Return([]*models.Project{project1, project2}, nil).Once()
projectIds, err := suite.filterProcessor.ProcessProjectFilter(context.TODO(), "test-user", []int64{1})
suite.Equal(1, len(projectIds))
suite.Equal(int64(1), projectIds[0])
suite.NoError(err)
memberQueryMatcher := testifymock.MatchedBy(func(query *q.Query) bool {
memberQuery := query.Keywords["member"].(*project3.MemberQuery)
return len(memberQuery.GroupIDs) == 2 && reflect.DeepEqual(memberQuery.GroupIDs, groupIDs) && memberQuery.Role == 0
})
suite.projectMgr.AssertCalled(suite.T(), "List", mock.Anything, memberQueryMatcher)
}
// project listing for admin user
{
suite.usrMgr.On("GetByName", mock.Anything, "test-user").Return(&commonmodels.User{UserID: 1, SysAdminFlag: true}, nil).Once()
suite.projectMgr.On("List", mock.Anything, mock.Anything).Return([]*models.Project{project1, project2}, nil).Once()
_, err := suite.filterProcessor.ProcessProjectFilter(context.TODO(), "test-user", []int64{1})
suite.NoError(err)
queryArgumentMatcher := testifymock.MatchedBy(func(query *q.Query) bool {
return len(query.Keywords) == 0
})
suite.projectMgr.AssertCalled(suite.T(), "List", mock.Anything, queryArgumentMatcher)
}
// project listing returns an error
// filtered project
{
suite.usrMgr.On("GetByName", mock.Anything, "test-user").Return(&commonmodels.User{UserID: 1}, nil).Once()
suite.projectMgr.On("List", mock.Anything, mock.Anything).Return(nil, errors.New("test-error")).Once()
projectIds, err := suite.filterProcessor.ProcessProjectFilter(context.TODO(), "test-user", []int64{1})
suite.Error(err)
suite.Nil(projectIds)
}
}
func (suite *FilterProcessorTestSuite) TestProcessRepositoryFilter() {
repoRecord1 := model.RepoRecord{

View File

@ -54,9 +54,11 @@ func (se *scanDataExportAPI) ExportScanData(ctx context.Context, params operatio
return se.SendError(ctx, err)
}
if err := se.RequireProjectAccess(ctx, params.Criteria.Projects[0], rbac.ActionCreate, rbac.ResourceExportCVE); err != nil {
for _, pid := range params.Criteria.Projects {
if err := se.RequireProjectAccess(ctx, pid, rbac.ActionCreate, rbac.ResourceExportCVE); err != nil {
return se.SendError(ctx, err)
}
}
scanDataExportJob := new(models.ScanDataExportJob)

View File

@ -38,29 +38,6 @@ func (_m *FilterProcessor) ProcessLabelFilter(ctx context.Context, labelIDs []in
return r0, r1
}
// ProcessProjectFilter provides a mock function with given fields: ctx, userName, projectsToFilter
func (_m *FilterProcessor) ProcessProjectFilter(ctx context.Context, userName string, projectsToFilter []int64) ([]int64, error) {
ret := _m.Called(ctx, userName, projectsToFilter)
var r0 []int64
if rf, ok := ret.Get(0).(func(context.Context, string, []int64) []int64); ok {
r0 = rf(ctx, userName, projectsToFilter)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]int64)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string, []int64) error); ok {
r1 = rf(ctx, userName, projectsToFilter)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ProcessRepositoryFilter provides a mock function with given fields: ctx, filter, projectIds
func (_m *FilterProcessor) ProcessRepositoryFilter(ctx context.Context, filter string, projectIds []int64) ([]int64, error) {
ret := _m.Called(ctx, filter, projectIds)