mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 04:05:40 +01:00
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:
parent
94dbc3fa8f
commit
da1637e1d3
@ -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)
|
||||
}
|
||||
artifactExists := c.isCsvArtifactPresent(ctx, exec.ID, execStatus.ExportDataDigest)
|
||||
execStatus.FilePresent = artifactExists
|
||||
|
||||
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 {
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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}})
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -54,8 +54,10 @@ 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 {
|
||||
return se.SendError(ctx, err)
|
||||
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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user