diff --git a/src/common/dao/base.go b/src/common/dao/base.go index 06ee5bdcc..55d59c220 100644 --- a/src/common/dao/base.go +++ b/src/common/dao/base.go @@ -17,8 +17,8 @@ package dao import ( "errors" "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "strconv" - "strings" "sync" "github.com/astaxie/beego/orm" @@ -104,17 +104,11 @@ func GetOrmer() orm.Ormer { return globalOrm } -// IsDupRecErr checks if the error is due to a duplication of record, currently this -// works only for pgSQL -func IsDupRecErr(e error) bool { - return strings.Contains(e.Error(), "duplicate key value violates unique constraint") -} - // ClearTable is the shortcut for test cases, it should be called only in test cases. func ClearTable(table string) error { o := GetOrmer() sql := fmt.Sprintf("delete from %s where 1=1", table) - if table == models.ProjectTable { + if table == proModels.ProjectTable { sql = fmt.Sprintf("delete from %s where project_id > 1", table) } if table == models.UserTable { @@ -130,22 +124,6 @@ func ClearTable(table string) error { return err } -// PaginateForRawSQL ... -func PaginateForRawSQL(sql string, limit, offset int64) string { - return fmt.Sprintf("%s limit %d offset %d", sql, limit, offset) -} - -// PaginateForQuerySetter ... -func PaginateForQuerySetter(qs orm.QuerySeter, page, size int64) orm.QuerySeter { - if size > 0 { - qs = qs.Limit(size) - if page > 0 { - qs = qs.Offset((page - 1) * size) - } - } - return qs -} - // implements github.com/golang-migrate/migrate/v4.Logger type mLogger struct { logger *log.Logger diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index 3409864d4..12bfb3797 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -16,17 +16,13 @@ package dao import ( "context" - "fmt" - "os" - "testing" - "time" - "github.com/astaxie/beego/orm" "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib/log" libOrm "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/pkg/user" - "github.com/stretchr/testify/assert" + "os" + "testing" ) var testCtx context.Context @@ -99,7 +95,6 @@ func cleanByUser(username string) { const username string = "Tester01" const password string = "Abc12345" const projectName string = "test_project" -const repositoryName string = "test_repository" func TestMain(m *testing.M) { databases := []string{"postgresql"} @@ -153,87 +148,6 @@ func clearAll() { } } -var currentUser *models.User - -func TestAddProject(t *testing.T) { - ctx := libOrm.Context() - var err error - currentUser, err = user.Mgr.GetByName(ctx, username) - if err != nil { - t.Errorf("Failed to get user by username: %s, error: %v", username, err) - } - project := models.Project{ - OwnerID: currentUser.UserID, - Name: projectName, - CreationTime: time.Now(), - OwnerName: currentUser.Username, - } - - _, err = AddProject(project) - if err != nil { - t.Errorf("Error occurred in AddProject: %v", err) - } - - newProject, err := GetProjectByName(projectName) - if err != nil { - t.Errorf("Error occurred in GetProjectByName: %v", err) - } - if newProject == nil { - t.Errorf("No project found queried by project name: %v", projectName) - } -} - -var currentProject *models.Project - -func TestGetProject(t *testing.T) { - var err error - currentProject, err = GetProjectByName(projectName) - if err != nil { - t.Errorf("Error occurred in GetProjectByName: %v", err) - } - if currentProject == nil { - t.Errorf("No project found queried by project name: %v", projectName) - } - if currentProject.Name != projectName { - t.Errorf("Project name does not match, expected: %s, actual: %s", projectName, currentProject.Name) - } -} - -func TestGetProjectById(t *testing.T) { - id := currentProject.ProjectID - p, err := GetProjectByID(id) - if err != nil { - t.Errorf("Error in GetProjectById: %v, id: %d", err, id) - } - if p.Name != currentProject.Name { - t.Errorf("project name does not match, expected: %s, actual: %s", currentProject.Name, p.Name) - } -} - -func TestGetTotalOfProjects(t *testing.T) { - total, err := GetTotalOfProjects(nil) - if err != nil { - t.Fatalf("failed to get total of projects: %v", err) - } - - if total != 2 { - t.Errorf("unexpected total: %d != 2", total) - } -} - -func TestGetProjects(t *testing.T) { - projects, err := GetProjects(nil) - if err != nil { - t.Errorf("Error occurred in GetProjects: %v", err) - } - if len(projects) != 2 { - t.Errorf("Expected length of projects is 2, but actual: %d, the projects: %+v", len(projects), projects) - } - if projects[1].Name != projectName { - t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name) - } -} - var targetID, policyID, policyID2, policyID3, jobID, jobID2, jobID3 int64 func TestGetOrmer(t *testing.T) { @@ -242,8 +156,3 @@ func TestGetOrmer(t *testing.T) { t.Errorf("Error get ormer.") } } - -func TestIsDupRecError(t *testing.T) { - assert.True(t, IsDupRecErr(fmt.Errorf("pq: duplicate key value violates unique constraint \"properties_k_key\""))) - assert.False(t, IsDupRecErr(fmt.Errorf("other error"))) -} diff --git a/src/common/dao/project.go b/src/common/dao/project.go deleted file mode 100644 index 9d754fd84..000000000 --- a/src/common/dao/project.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright Project Harbor Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dao - -import ( - "github.com/goharbor/harbor/src/common" - "github.com/goharbor/harbor/src/common/models" - "github.com/goharbor/harbor/src/common/utils" - "github.com/goharbor/harbor/src/lib/log" - libOrm "github.com/goharbor/harbor/src/lib/orm" - - "fmt" - "time" -) - -// AddProject adds a project to the database along with project roles information and access log records. -func AddProject(project models.Project) (int64, error) { - o := GetOrmer() - - sql := "insert into project (owner_id, name, registry_id, creation_time, update_time, deleted) values (?, ?, ?, ?, ?, ?) RETURNING project_id" - var projectID int64 - now := time.Now() - - err := o.Raw(sql, project.OwnerID, project.Name, project.RegistryID, now, now, project.Deleted).QueryRow(&projectID) - if err != nil { - return 0, err - } - - pmID, err := addProjectMember(models.Member{ - ProjectID: projectID, - EntityID: project.OwnerID, - Role: common.RoleProjectAdmin, - EntityType: common.UserMember, - }) - if err != nil { - return 0, err - } - if pmID == 0 { - return projectID, err - } - return projectID, nil -} - -func addProjectMember(member models.Member) (int, error) { - - log.Debugf("Adding project member %+v", member) - - o := GetOrmer() - - if member.EntityID <= 0 { - return 0, fmt.Errorf("invalid entity_id, member: %+v", member) - } - - if member.ProjectID <= 0 { - return 0, fmt.Errorf("invalid project_id, member: %+v", member) - } - - var pmID int - sql := "insert into project_member (project_id, entity_id , role, entity_type) values (?, ?, ?, ?) RETURNING id" - err := o.Raw(sql, member.ProjectID, member.EntityID, member.Role, member.EntityType).QueryRow(&pmID) - if err != nil { - return 0, err - } - return pmID, err -} - -// GetProjectByID ... -func GetProjectByID(id int64) (*models.Project, error) { - o := GetOrmer() - - sql := `select p.project_id, p.name, p.registry_id, u.username as owner_name, p.owner_id, p.creation_time, p.update_time - from project p left join harbor_user u on p.owner_id = u.user_id where p.deleted = false and p.project_id = ?` - queryParam := make([]interface{}, 1) - queryParam = append(queryParam, id) - - p := []models.Project{} - count, err := o.Raw(sql, queryParam).QueryRows(&p) - - if err != nil { - return nil, err - } - - if count == 0 { - return nil, nil - } - - return &p[0], nil -} - -// GetProjectByName ... -func GetProjectByName(name string) (*models.Project, error) { - o := GetOrmer() - var p []models.Project - n, err := o.Raw(`select * from project where name = ? and deleted = false`, name).QueryRows(&p) - if err != nil { - return nil, err - } - - if n == 0 { - return nil, nil - } - - return &p[0], nil -} - -// ProjectExistsByName returns whether the project exists according to its name. -func ProjectExistsByName(name string) bool { - o := GetOrmer() - return o.QueryTable("project").Filter("name", name).Exist() -} - -// GetTotalOfProjects returns the total count of projects -// according to the query conditions -func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) { - var pagination *models.Pagination - if query != nil { - pagination = query.Pagination - query.Pagination = nil - } - sql, params := projectQueryConditions(query) - if query != nil { - query.Pagination = pagination - } - - sql = `select count(*) ` + sql - - var total int64 - err := GetOrmer().Raw(sql, params).QueryRow(&total) - return total, err -} - -// GetProjects returns a project list according to the query conditions -func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) { - sqlStr, queryParam := projectQueryConditions(query) - sqlStr = `select distinct p.project_id, p.name, p.registry_id, p.owner_id, - p.creation_time, p.update_time ` + sqlStr + ` order by p.name` - sqlStr, queryParam = CreatePagination(query, sqlStr, queryParam) - - var projects []*models.Project - _, err := GetOrmer().Raw(sqlStr, queryParam).QueryRows(&projects) - - return projects, err - -} - -// GetGroupProjects - Get user's all projects, including user is the user member of this project -// and the user is in the group which is a group member of this project. -func GetGroupProjects(groupIDs []int, query *models.ProjectQueryParam) ([]*models.Project, error) { - sql, params := projectQueryConditions(query) - sql = `select distinct p.project_id, p.name, p.registry_id, p.owner_id, - p.creation_time, p.update_time ` + sql - groupIDCondition := JoinNumberConditions(groupIDs) - if len(groupIDs) > 0 { - sql = fmt.Sprintf( - `%s union select distinct p.project_id, p.name, p.registry_id, p.owner_id, p.creation_time, p.update_time - from project p - left join project_member pm on p.project_id = pm.project_id - left join user_group ug on ug.id = pm.entity_id and pm.entity_type = 'g' - where p.deleted=false and ug.id in ( %s )`, - sql, groupIDCondition) - } - sql = sql + ` order by name` - sqlStr, queryParams := CreatePagination(query, sql, params) - log.Debugf("query sql:%v", sql) - var projects []*models.Project - _, err := GetOrmer().Raw(sqlStr, queryParams).QueryRows(&projects) - return projects, err -} - -// GetTotalGroupProjects - Get the total count of projects, including user is the member of this project and the -// user is in the group, which is the group member of this project. -func GetTotalGroupProjects(groupIDs []int, query *models.ProjectQueryParam) (int, error) { - var sql string - sqlCondition, params := projectQueryConditions(query) - groupIDCondition := JoinNumberConditions(groupIDs) - if len(groupIDs) == 0 { - sql = `select count(1) ` + sqlCondition - } else { - sql = fmt.Sprintf( - `select count(1) - from ( select p.project_id %s union select p.project_id - from project p - left join project_member pm on p.project_id = pm.project_id - left join user_group ug on ug.id = pm.entity_id and pm.entity_type = 'g' - where p.deleted=false and ug.id in ( %s )) t`, - sqlCondition, groupIDCondition) - } - log.Debugf("query sql:%v", sql) - var count int - if err := GetOrmer().Raw(sql, params).QueryRow(&count); err != nil { - return 0, err - } - return count, nil -} - -func projectQueryConditions(query *models.ProjectQueryParam) (string, []interface{}) { - params := []interface{}{} - sql := ` from project as p` - if query == nil { - sql += ` where p.deleted=false` - return sql, params - } - // if query.ProjectIDs is not nil but has no element, the query will returns no rows - if query.ProjectIDs != nil && len(query.ProjectIDs) == 0 { - sql += ` where 1 = 0` - return sql, params - } - if len(query.Owner) != 0 { - sql += ` join harbor_user u1 - on p.owner_id = u1.user_id` - } - if query.Member != nil && len(query.Member.Name) != 0 { - sql += ` join project_member pm - on p.project_id = pm.project_id and pm.entity_type = 'u' - join harbor_user u2 - on pm.entity_id=u2.user_id` - } - sql += ` where p.deleted=false` - - if len(query.Owner) != 0 { - sql += ` and u1.username=?` - params = append(params, query.Owner) - } - - if len(query.Name) != 0 { - sql += ` and p.name like ?` - params = append(params, "%"+libOrm.Escape(query.Name)+"%") - } - - if query.RegistryID > 0 { - sql += ` and p.registry_id = ?` - params = append(params, query.RegistryID) - } - - if query.Member != nil && len(query.Member.Name) != 0 { - sql += ` and u2.username=?` - params = append(params, query.Member.Name) - - if query.Member.Role > 0 { - sql += ` and pm.role = ?` - roleID := 0 - switch query.Member.Role { - case common.RoleProjectAdmin: - roleID = 1 - case common.RoleDeveloper: - roleID = 2 - case common.RoleGuest: - roleID = 3 - case common.RoleMaintainer: - roleID = 4 - case common.RoleLimitedGuest: - roleID = 5 - } - params = append(params, roleID) - } - } - if len(query.ProjectIDs) > 0 { - sql += fmt.Sprintf(` and p.project_id in ( %s )`, - utils.ParamPlaceholderForIn(len(query.ProjectIDs))) - params = append(params, query.ProjectIDs) - } - return sql, params -} - -// CreatePagination ... -func CreatePagination(query *models.ProjectQueryParam, sql string, params []interface{}) (string, []interface{}) { - if query != nil && query.Pagination != nil && query.Pagination.Size > 0 { - sql += ` limit ?` - params = append(params, query.Pagination.Size) - - if query.Pagination.Page > 0 { - sql += ` offset ?` - params = append(params, (query.Pagination.Page-1)*query.Pagination.Size) - } - } - return sql, params -} - -// DeleteProject ... -func DeleteProject(id int64) error { - project, err := GetProjectByID(id) - if err != nil { - return err - } - name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID) - sql := `update project - set deleted = true, name = ? - where project_id = ?` - _, err = GetOrmer().Raw(sql, name, id).Exec() - return err -} diff --git a/src/common/dao/project_test.go b/src/common/dao/project_test.go deleted file mode 100644 index 4fd439a77..000000000 --- a/src/common/dao/project_test.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright Project Harbor Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dao - -import ( - "fmt" - "strings" - "testing" - - "github.com/goharbor/harbor/src/common/models" -) - -func TestDeleteProject(t *testing.T) { - name := "project_for_test" - project := models.Project{ - OwnerID: currentUser.UserID, - Name: name, - } - - id, err := AddProject(project) - if err != nil { - t.Fatalf("failed to add project: %v", err) - } - defer func() { - if err := delProjPermanent(id); err != nil { - t.Errorf("failed to clear up project %d: %v", id, err) - } - }() - - if err = DeleteProject(id); err != nil { - t.Fatalf("failed to delete project: %v", err) - } - - p := &models.Project{} - if err = GetOrmer().Raw(`select * from project where project_id = ?`, id). - QueryRow(p); err != nil { - t.Fatalf("failed to get project: %v", err) - } - - if !p.Deleted { - t.Errorf("unexpeced deleted column: %t != %t", p.Deleted, true) - } - - deletedName := fmt.Sprintf("%s#%d", name, id) - if p.Name != deletedName { - t.Errorf("unexpected name: %s != %s", p.Name, deletedName) - } - -} - -func delProjPermanent(id int64) error { - _, err := GetOrmer().Raw(`delete from project_member - where project_id = ?`, id).Exec() - if err != nil { - return err - } - - _, err = GetOrmer().QueryTable("project"). - Filter("ProjectID", id). - Delete() - return err -} - -func Test_projectQueryConditions(t *testing.T) { - type args struct { - query *models.ProjectQueryParam - } - tests := []struct { - name string - args args - want string - want1 []interface{} - }{ - {"Query invalid projectID", - args{query: &models.ProjectQueryParam{ProjectIDs: []int64{}, Owner: "admin"}}, - "from project as p where 1 = 0", - []interface{}{}}, - {"Query with valid projectID", - args{query: &models.ProjectQueryParam{ProjectIDs: []int64{2, 3}, Owner: "admin"}}, - ` from project as p join harbor_user u1 - on p.owner_id = u1.user_id where p.deleted=false and u1.username=? and p.project_id in ( ?,? )`, - []interface{}{2, 3}}, - {"Query with valid page and member", - args{query: &models.ProjectQueryParam{ProjectIDs: []int64{2, 3}, Owner: "admin", Name: "sample", Member: &models.MemberQuery{Name: "name", Role: 1}, Pagination: &models.Pagination{Page: 1, Size: 20}}}, - ` from project as p join harbor_user u1 - on p.owner_id = u1.user_id join project_member pm - on p.project_id = pm.project_id and pm.entity_type = 'u' - join harbor_user u2 - on pm.entity_id=u2.user_id where p.deleted=false and u1.username=? and p.name like ? and u2.username=? and pm.role = ? and p.project_id in ( ?,? )`, - []interface{}{1, []int64{2, 3}, 20, 0}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, _ := projectQueryConditions(tt.args.query) - if strings.TrimSpace(got) != strings.TrimSpace(tt.want) { - t.Errorf("projectQueryConditions() got = %v\n, want %v", got, tt.want) - } - }) - } -} - -func TestProjetExistsByName(t *testing.T) { - name := "project_exist_by_name_test" - exist := ProjectExistsByName(name) - if exist { - t.Errorf("project %s expected to be not exist", name) - } - - project := models.Project{ - OwnerID: currentUser.UserID, - Name: name, - } - id, err := AddProject(project) - if err != nil { - t.Fatalf("failed to add project: %v", err) - } - defer func() { - if err := delProjPermanent(id); err != nil { - t.Errorf("failed to clear up project %d: %v", id, err) - } - }() - - exist = ProjectExistsByName(name) - if !exist { - t.Errorf("project %s expected to be exist", name) - } -} diff --git a/src/common/models/base.go b/src/common/models/base.go index d935e790c..c290c687d 100644 --- a/src/common/models/base.go +++ b/src/common/models/base.go @@ -21,7 +21,6 @@ import ( func init() { orm.RegisterModel( new(User), - new(Project), new(Role), new(ResourceLabel), new(JobLog), diff --git a/src/common/models/member.go b/src/common/models/member.go deleted file mode 100644 index 24aab0aba..000000000 --- a/src/common/models/member.go +++ /dev/null @@ -1,38 +0,0 @@ -// 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 models - -import ( - "github.com/goharbor/harbor/src/pkg/usergroup/model" -) - -// Member holds the details of a member. -type Member struct { - ID int `orm:"pk;column(id)" json:"id"` - ProjectID int64 `orm:"column(project_id)" json:"project_id"` - Entityname string `orm:"column(entity_name)" json:"entity_name"` - Rolename string `json:"role_name"` - Role int `json:"role_id"` - EntityID int `orm:"column(entity_id)" json:"entity_id"` - EntityType string `orm:"column(entity_type)" json:"entity_type"` -} - -// MemberReq - Create Project Member Request -type MemberReq struct { - ProjectID int64 `json:"project_id"` - Role int `json:"role_id,omitempty"` - MemberUser User `json:"member_user,omitempty"` - MemberGroup model.UserGroup `json:"member_group,omitempty"` -} diff --git a/src/common/models/project.go b/src/common/models/project.go deleted file mode 100644 index e8cec85db..000000000 --- a/src/common/models/project.go +++ /dev/null @@ -1,264 +0,0 @@ -// 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 models - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "github.com/astaxie/beego/orm" - "github.com/goharbor/harbor/src/pkg/allowlist/models" - "github.com/lib/pq" -) - -const ( - // ProjectTable is the table name for project - ProjectTable = "project" - // ProjectPublic means project is public - ProjectPublic = "public" - // ProjectPrivate means project is private - ProjectPrivate = "private" -) - -// Project holds the details of a project. -type Project struct { - ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"` - OwnerID int `orm:"column(owner_id)" json:"owner_id"` - Name string `orm:"column(name)" json:"name" sort:"default"` - CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"` - UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` - Deleted bool `orm:"column(deleted)" json:"deleted"` - OwnerName string `orm:"-" json:"owner_name"` - Role int `orm:"-" json:"current_user_role_id"` - RoleList []int `orm:"-" json:"current_user_role_ids"` - RepoCount int64 `orm:"-" json:"repo_count"` - ChartCount uint64 `orm:"-" json:"chart_count"` - Metadata map[string]string `orm:"-" json:"metadata"` - CVEAllowlist models.CVEAllowlist `orm:"-" json:"cve_allowlist"` - RegistryID int64 `orm:"column(registry_id)" json:"registry_id"` -} - -// GetMetadata ... -func (p *Project) GetMetadata(key string) (string, bool) { - if len(p.Metadata) == 0 { - return "", false - } - value, exist := p.Metadata[key] - return value, exist -} - -// SetMetadata ... -func (p *Project) SetMetadata(key, value string) { - if p.Metadata == nil { - p.Metadata = map[string]string{} - } - p.Metadata[key] = value -} - -// IsPublic ... -func (p *Project) IsPublic() bool { - public, exist := p.GetMetadata(ProMetaPublic) - if !exist { - return false - } - - return isTrue(public) -} - -// IsProxy returns true when the project type is proxy cache -func (p *Project) IsProxy() bool { - return p.RegistryID > 0 -} - -// ContentTrustEnabled ... -func (p *Project) ContentTrustEnabled() bool { - enabled, exist := p.GetMetadata(ProMetaEnableContentTrust) - if !exist { - return false - } - return isTrue(enabled) -} - -// VulPrevented ... -func (p *Project) VulPrevented() bool { - prevent, exist := p.GetMetadata(ProMetaPreventVul) - if !exist { - return false - } - return isTrue(prevent) -} - -// ReuseSysCVEAllowlist ... -func (p *Project) ReuseSysCVEAllowlist() bool { - r, ok := p.GetMetadata(ProMetaReuseSysCVEAllowlist) - if !ok { - return true - } - return isTrue(r) -} - -// Severity ... -func (p *Project) Severity() string { - severity, exist := p.GetMetadata(ProMetaSeverity) - if !exist { - return "" - } - return severity -} - -// AutoScan ... -func (p *Project) AutoScan() bool { - auto, exist := p.GetMetadata(ProMetaAutoScan) - if !exist { - return false - } - return isTrue(auto) -} - -// FilterByPublic returns orm.QuerySeter with public filter -func (p *Project) FilterByPublic(ctx context.Context, qs orm.QuerySeter, key string, value interface{}) orm.QuerySeter { - subQuery := `SELECT project_id FROM project_metadata WHERE name = 'public' AND value = '%s'` - if isTrue(value) { - subQuery = fmt.Sprintf(subQuery, "true") - } else { - subQuery = fmt.Sprintf(subQuery, "false") - } - return qs.FilterRaw("project_id", fmt.Sprintf("IN (%s)", subQuery)) -} - -// FilterByOwner returns orm.QuerySeter with owner filter -func (p *Project) FilterByOwner(ctx context.Context, qs orm.QuerySeter, key string, value interface{}) orm.QuerySeter { - username, ok := value.(string) - if !ok { - return qs - } - - return qs.FilterRaw("owner_id", fmt.Sprintf("IN (SELECT user_id FROM harbor_user WHERE username = %s)", pq.QuoteLiteral(username))) -} - -// FilterByMember returns orm.QuerySeter with member filter -func (p *Project) FilterByMember(ctx context.Context, qs orm.QuerySeter, key string, value interface{}) orm.QuerySeter { - query, ok := value.(*MemberQuery) - if !ok { - return qs - } - subQuery := fmt.Sprintf(`SELECT project_id FROM project_member WHERE entity_id = %d AND entity_type = 'u'`, query.UserID) - if query.Role > 0 { - subQuery = fmt.Sprintf("%s AND role = %d", subQuery, query.Role) - } - - if query.WithPublic { - subQuery = fmt.Sprintf("(%s) UNION (SELECT project_id FROM project_metadata WHERE name = 'public' AND value = 'true')", subQuery) - } - - if len(query.GroupIDs) > 0 { - var elems []string - for _, groupID := range query.GroupIDs { - elems = append(elems, strconv.Itoa(groupID)) - } - - tpl := "(%s) UNION (SELECT project_id FROM project_member pm, user_group ug WHERE pm.entity_id = ug.id AND pm.entity_type = 'g' AND ug.id IN (%s))" - subQuery = fmt.Sprintf(tpl, subQuery, strings.TrimSpace(strings.Join(elems, ", "))) - } - - return qs.FilterRaw("project_id", fmt.Sprintf("IN (%s)", subQuery)) -} - -func isTrue(i interface{}) bool { - switch value := i.(type) { - case bool: - return value - case string: - v := strings.ToLower(value) - return v == "true" || v == "1" - default: - return false - } -} - -// ProjectQueryParam can be used to set query parameters when listing projects. -// The query condition will be set in the query if its corresponding field -// is not nil. Leave it empty if you don't want to apply this condition. -// -// e.g. -// List all projects: query := nil -// List all public projects: query := &QueryParam{Public: true} -// List projects the owner of which is user1: query := &QueryParam{Owner:"user1"} -// List all public projects the owner of which is user1: query := &QueryParam{Owner:"user1",Public:true} -// List projects which user1 is member of: query := &QueryParam{Member:&Member{Name:"user1"}} -// List projects which user1 is the project admin : query := &QueryParam{Member:&Member{Name:"user1",Role:1}} -type ProjectQueryParam struct { - Name string // the name of project - Owner string // the username of project owner - Public *bool // the project is public or not, can be ture, false and nil - RegistryID int64 - Member *MemberQuery // the member of project - Pagination *Pagination // pagination information - ProjectIDs []int64 // project ID list -} - -// MemberQuery filter by member's username and role -type MemberQuery struct { - UserID int // the user id - Name string // the username of member - Role int // the role of the member has to the project - GroupIDs []int // the group ID of current user belongs to - - WithPublic bool // include the public projects for the member -} - -// Pagination ... -type Pagination struct { - Page int64 - Size int64 -} - -// Sorting sort by given field, ascending or descending -type Sorting struct { - Sort string // in format [+-]?, e.g. '+creation_time', '-creation_time' -} - -// BaseProjectCollection contains the query conditions which can be used -// to get a project collection. The collection can be used as the base to -// do other filter -type BaseProjectCollection struct { - Public bool - Member string -} - -// ProjectRequest holds informations that need for creating project API -type ProjectRequest struct { - Name string `json:"project_name"` - Public *int `json:"public"` // deprecated, reserved for project creation in replication - Metadata map[string]string `json:"metadata"` - CVEAllowlist models.CVEAllowlist `json:"cve_allowlist"` - - StorageLimit *int64 `json:"storage_limit,omitempty"` - RegistryID int64 `json:"registry_id"` -} - -// ProjectQueryResult ... -type ProjectQueryResult struct { - Total int64 - Projects []*Project -} - -// TableName is required by beego orm to map Project to table project -func (p *Project) TableName() string { - return ProjectTable -} diff --git a/src/common/rbac/project/evaluator.go b/src/common/rbac/project/evaluator.go index d00c8b649..023c91f84 100644 --- a/src/common/rbac/project/evaluator.go +++ b/src/common/rbac/project/evaluator.go @@ -24,14 +24,15 @@ import ( "github.com/goharbor/harbor/src/pkg/permission/evaluator/namespace" "github.com/goharbor/harbor/src/pkg/permission/evaluator/rbac" "github.com/goharbor/harbor/src/pkg/permission/types" + proModels "github.com/goharbor/harbor/src/pkg/project/models" ) // RBACUserBuilder builder to make types.RBACUser for the project -type RBACUserBuilder func(context.Context, *models.Project) types.RBACUser +type RBACUserBuilder func(context.Context, *proModels.Project) types.RBACUser // NewBuilderForUser create a builder for the local user func NewBuilderForUser(user *models.User, ctl project.Controller) RBACUserBuilder { - return func(ctx context.Context, p *models.Project) types.RBACUser { + return func(ctx context.Context, p *proModels.Project) types.RBACUser { if user == nil { // anonymous access return &rbacUser{ @@ -56,9 +57,9 @@ func NewBuilderForUser(user *models.User, ctl project.Controller) RBACUserBuilde // NewBuilderForPolicies create a builder for the policies func NewBuilderForPolicies(username string, policies []*types.Policy, - filters ...func(*models.Project, []*types.Policy) []*types.Policy) RBACUserBuilder { + filters ...func(*proModels.Project, []*types.Policy) []*types.Policy) RBACUserBuilder { - return func(ctx context.Context, p *models.Project) types.RBACUser { + return func(ctx context.Context, p *proModels.Project) types.RBACUser { for _, filter := range filters { policies = filter(p, policies) } diff --git a/src/common/rbac/project/evaluator_test.go b/src/common/rbac/project/evaluator_test.go index d4ab2e7d8..031aaf022 100644 --- a/src/common/rbac/project/evaluator_test.go +++ b/src/common/rbac/project/evaluator_test.go @@ -21,13 +21,14 @@ import ( "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/models" + proModels "github.com/goharbor/harbor/src/pkg/project/models" projecttesting "github.com/goharbor/harbor/src/testing/controller/project" "github.com/goharbor/harbor/src/testing/mock" "github.com/stretchr/testify/assert" ) var ( - public = &models.Project{ + public = &proModels.Project{ ProjectID: 1, Name: "public_project", OwnerID: 1, @@ -36,7 +37,7 @@ var ( }, } - private = &models.Project{ + private = &proModels.Project{ ProjectID: 2, Name: "private_project", OwnerID: 1, diff --git a/src/common/rbac/project/rbac_user.go b/src/common/rbac/project/rbac_user.go index 76a1310e5..6a716de78 100644 --- a/src/common/rbac/project/rbac_user.go +++ b/src/common/rbac/project/rbac_user.go @@ -15,8 +15,8 @@ package project import ( - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/pkg/permission/types" + "github.com/goharbor/harbor/src/pkg/project/models" ) type rbacUser struct { diff --git a/src/common/security/local/context_test.go b/src/common/security/local/context_test.go index 4e9404967..359020f41 100644 --- a/src/common/security/local/context_test.go +++ b/src/common/security/local/context_test.go @@ -16,20 +16,19 @@ package local import ( "context" - rbac_project "github.com/goharbor/harbor/src/common/rbac/project" - "testing" - "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" - "github.com/goharbor/harbor/src/controller/project" + rbac_project "github.com/goharbor/harbor/src/common/rbac/project" + proModels "github.com/goharbor/harbor/src/pkg/project/models" projecttesting "github.com/goharbor/harbor/src/testing/controller/project" "github.com/goharbor/harbor/src/testing/mock" "github.com/stretchr/testify/assert" + "testing" ) var ( - public = &project.Project{ + public = &proModels.Project{ ProjectID: 1, Name: "public_project", OwnerID: 1, @@ -38,7 +37,7 @@ var ( }, } - private = &models.Project{ + private = &proModels.Project{ ProjectID: 2, Name: "private_project", OwnerID: 1, diff --git a/src/common/security/proxycachesecret/context_test.go b/src/common/security/proxycachesecret/context_test.go index 87e67096b..3cb41e4ca 100644 --- a/src/common/security/proxycachesecret/context_test.go +++ b/src/common/security/proxycachesecret/context_test.go @@ -20,8 +20,8 @@ import ( "github.com/goharbor/harbor/src/common/rbac/project" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" + proModels "github.com/goharbor/harbor/src/pkg/project/models" projecttesting "github.com/goharbor/harbor/src/testing/controller/project" "github.com/goharbor/harbor/src/testing/mock" "github.com/stretchr/testify/suite" @@ -85,7 +85,7 @@ func (p *proxyCacheSecretTestSuite) TestCan() { // pass for action pull action = rbac.ActionPull resource = project.NewNamespace(1).Resource(rbac.ResourceRepository) - p.ctl.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ + p.ctl.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ ProjectID: 1, Name: "library", }, nil) @@ -98,7 +98,7 @@ func (p *proxyCacheSecretTestSuite) TestCan() { // pass for action push action = rbac.ActionPush resource = project.NewNamespace(1).Resource(rbac.ResourceRepository) - p.ctl.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ + p.ctl.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ ProjectID: 1, Name: "library", }, nil) diff --git a/src/common/security/robot/context.go b/src/common/security/robot/context.go index 69eeba24b..14b9350a2 100644 --- a/src/common/security/robot/context.go +++ b/src/common/security/robot/context.go @@ -22,11 +22,11 @@ import ( "strings" "sync" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/pkg/permission/evaluator" "github.com/goharbor/harbor/src/pkg/permission/types" + "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/pkg/robot/model" ) diff --git a/src/common/security/robot/context_test.go b/src/common/security/robot/context_test.go index c14547bf8..871b6f83f 100644 --- a/src/common/security/robot/context_test.go +++ b/src/common/security/robot/context_test.go @@ -21,9 +21,9 @@ import ( "reflect" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/pkg/permission/types" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/pkg/robot/model" projecttesting "github.com/goharbor/harbor/src/testing/controller/project" "github.com/goharbor/harbor/src/testing/mock" @@ -31,7 +31,7 @@ import ( ) var ( - private = &models.Project{ + private = &proModels.Project{ Name: "testrobot", OwnerID: 1, } @@ -150,7 +150,7 @@ func TestHasPushPullPerm(t *testing.T) { func Test_filterRobotPolicies(t *testing.T) { type args struct { - p *models.Project + p *proModels.Project policies []*types.Policy } tests := []struct { @@ -161,7 +161,7 @@ func Test_filterRobotPolicies(t *testing.T) { { "policies of one project", args{ - &models.Project{ProjectID: 1}, + &proModels.Project{ProjectID: 1}, []*types.Policy{ {Resource: "/project/1/repository", Action: "pull", Effect: "allow"}, }, @@ -173,7 +173,7 @@ func Test_filterRobotPolicies(t *testing.T) { { "policies of multi projects", args{ - &models.Project{ProjectID: 1}, + &proModels.Project{ProjectID: 1}, []*types.Policy{ {Resource: "/project/1/repository", Action: "pull", Effect: "allow"}, {Resource: "/project/2/repository", Action: "pull", Effect: "allow"}, diff --git a/src/controller/event/handler/internal/util_test.go b/src/controller/event/handler/internal/util_test.go index dcb24e53e..fb018d140 100644 --- a/src/controller/event/handler/internal/util_test.go +++ b/src/controller/event/handler/internal/util_test.go @@ -17,12 +17,12 @@ package internal import ( "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/controller/scan" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/orm" + proModels "github.com/goharbor/harbor/src/pkg/project/models" projecttesting "github.com/goharbor/harbor/src/testing/controller/project" scantesting "github.com/goharbor/harbor/src/testing/controller/scan" ormtesting "github.com/goharbor/harbor/src/testing/lib/orm" @@ -65,9 +65,9 @@ func (suite *AutoScanTestSuite) TestGetProjectFailed() { } func (suite *AutoScanTestSuite) TestAutoScanDisabled() { - mock.OnAnything(suite.projectController, "Get").Return(&models.Project{ + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{ Metadata: map[string]string{ - models.ProMetaAutoScan: "false", + proModels.ProMetaAutoScan: "false", }, }, nil) @@ -78,9 +78,9 @@ func (suite *AutoScanTestSuite) TestAutoScanDisabled() { } func (suite *AutoScanTestSuite) TestAutoScan() { - mock.OnAnything(suite.projectController, "Get").Return(&models.Project{ + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{ Metadata: map[string]string{ - models.ProMetaAutoScan: "true", + proModels.ProMetaAutoScan: "true", }, }, nil) @@ -93,9 +93,9 @@ func (suite *AutoScanTestSuite) TestAutoScan() { } func (suite *AutoScanTestSuite) TestAutoScanFailed() { - mock.OnAnything(suite.projectController, "Get").Return(&models.Project{ + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{ Metadata: map[string]string{ - models.ProMetaAutoScan: "true", + proModels.ProMetaAutoScan: "true", }, }, nil) diff --git a/src/controller/event/handler/webhook/artifact/artifact.go b/src/controller/event/handler/webhook/artifact/artifact.go index a03c8208d..1249669be 100644 --- a/src/controller/event/handler/webhook/artifact/artifact.go +++ b/src/controller/event/handler/webhook/artifact/artifact.go @@ -19,7 +19,6 @@ import ( "fmt" beegorm "github.com/astaxie/beego/orm" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/event/handler/util" "github.com/goharbor/harbor/src/controller/project" @@ -28,6 +27,7 @@ import ( "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/notifier/model" notifyModel "github.com/goharbor/harbor/src/pkg/notifier/model" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/pkg/repository" ) @@ -90,15 +90,15 @@ func (a *Handler) handle(ctx context.Context, event *event.ArtifactEvent) error return nil } -func (a *Handler) constructArtifactPayload(event *event.ArtifactEvent, project *models.Project) (*model.Payload, error) { +func (a *Handler) constructArtifactPayload(event *event.ArtifactEvent, project *proModels.Project) (*model.Payload, error) { repoName := event.Repository if repoName == "" { return nil, fmt.Errorf("invalid %s event with empty repo name", event.EventType) } - repoType := models.ProjectPrivate + repoType := proModels.ProjectPrivate if project.IsPublic() { - repoType = models.ProjectPublic + repoType = proModels.ProjectPublic } imageName := util.GetNameFromImgRepoFullName(repoName) diff --git a/src/controller/event/handler/webhook/artifact/replication.go b/src/controller/event/handler/webhook/artifact/replication.go index 87f489a07..c68dbc19b 100644 --- a/src/controller/event/handler/webhook/artifact/replication.go +++ b/src/controller/event/handler/webhook/artifact/replication.go @@ -4,11 +4,11 @@ import ( "context" "errors" "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "strings" "github.com/goharbor/harbor/src/lib/config" - commonModels "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/event/handler/util" ctlModel "github.com/goharbor/harbor/src/controller/event/model" @@ -73,7 +73,7 @@ func (r *ReplicationHandler) IsStateful() bool { return false } -func constructReplicationPayload(event *event.ReplicationEvent) (*model.Payload, *commonModels.Project, error) { +func constructReplicationPayload(event *event.ReplicationEvent) (*model.Payload, *proModels.Project, error) { ctx := orm.Context() task, err := replication.Ctl.GetTask(ctx, event.ReplicationTaskID) if err != nil { diff --git a/src/controller/event/handler/webhook/artifact/replication_test.go b/src/controller/event/handler/webhook/artifact/replication_test.go index 6c7a0d35c..1d0ec0453 100644 --- a/src/controller/event/handler/webhook/artifact/replication_test.go +++ b/src/controller/event/handler/webhook/artifact/replication_test.go @@ -16,13 +16,13 @@ package artifact import ( "context" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "testing" "time" "github.com/goharbor/harbor/src/lib/config" common_dao "github.com/goharbor/harbor/src/common/dao" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/project" repctl "github.com/goharbor/harbor/src/controller/replication" @@ -67,7 +67,7 @@ func TestReplicationHandler_Handle(t *testing.T) { }, }, nil) - mock.OnAnything(projectCtl, "GetByName").Return(&models.Project{ProjectID: 1}, nil) + mock.OnAnything(projectCtl, "GetByName").Return(&proModels.Project{ProjectID: 1}, nil) handler := &ReplicationHandler{} diff --git a/src/controller/event/handler/webhook/chart/chart.go b/src/controller/event/handler/webhook/chart/chart.go index 3f78f749d..854e7a946 100644 --- a/src/controller/event/handler/webhook/chart/chart.go +++ b/src/controller/event/handler/webhook/chart/chart.go @@ -20,13 +20,13 @@ import ( "fmt" "github.com/goharbor/harbor/src/lib/config" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/event/handler/util" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/notifier/model" + proModels "github.com/goharbor/harbor/src/pkg/project/models" ) // Handler preprocess chart event data @@ -83,10 +83,10 @@ func (cph *Handler) IsStateful() bool { return false } -func constructChartPayload(event *event.ChartEvent, project *models.Project) (*model.Payload, error) { - repoType := models.ProjectPrivate +func constructChartPayload(event *event.ChartEvent, project *proModels.Project) (*model.Payload, error) { + repoType := proModels.ProjectPrivate if project.IsPublic() { - repoType = models.ProjectPublic + repoType = proModels.ProjectPublic } payload := &model.Payload{ diff --git a/src/controller/event/handler/webhook/chart/chart_test.go b/src/controller/event/handler/webhook/chart/chart_test.go index e37c35544..e7f53b5f0 100644 --- a/src/controller/event/handler/webhook/chart/chart_test.go +++ b/src/controller/event/handler/webhook/chart/chart_test.go @@ -20,10 +20,10 @@ import ( "github.com/goharbor/harbor/src/lib/config" _ "github.com/goharbor/harbor/src/pkg/config/db" _ "github.com/goharbor/harbor/src/pkg/config/inmemory" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "os" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/pkg/notification" @@ -57,15 +57,15 @@ func TestChartPreprocessHandler_Handle(t *testing.T) { project.Ctl = projectCtl name := "project_for_test_chart_event_preprocess" - mock.OnAnything(projectCtl, "Get").Return(func(ctx context.Context, projectIDOrName interface{}, options ...project.Option) *models.Project { - return &models.Project{ + mock.OnAnything(projectCtl, "Get").Return(func(ctx context.Context, projectIDOrName interface{}, options ...project.Option) *proModels.Project { + return &proModels.Project{ Name: name, OwnerID: 1, Metadata: map[string]string{ - models.ProMetaEnableContentTrust: "true", - models.ProMetaPreventVul: "true", - models.ProMetaSeverity: "Low", - models.ProMetaReuseSysCVEAllowlist: "false", + proModels.ProMetaEnableContentTrust: "true", + proModels.ProMetaPreventVul: "true", + proModels.ProMetaSeverity: "Low", + proModels.ProMetaReuseSysCVEAllowlist: "false", }, } }, nil) diff --git a/src/controller/event/handler/webhook/quota/quota.go b/src/controller/event/handler/webhook/quota/quota.go index a724195bd..62797b6db 100644 --- a/src/controller/event/handler/webhook/quota/quota.go +++ b/src/controller/event/handler/webhook/quota/quota.go @@ -19,7 +19,6 @@ import ( "errors" "fmt" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/event/handler/util" "github.com/goharbor/harbor/src/controller/project" @@ -28,6 +27,7 @@ import ( "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/notifier/model" notifyModel "github.com/goharbor/harbor/src/pkg/notifier/model" + proModels "github.com/goharbor/harbor/src/pkg/project/models" ) // Handler preprocess image event data @@ -88,9 +88,9 @@ func constructQuotaPayload(event *event.QuotaEvent) (*model.Payload, error) { return nil, fmt.Errorf("invalid %s event with empty repo name", event.EventType) } - repoType := models.ProjectPrivate + repoType := proModels.ProjectPrivate if event.Project.IsPublic() { - repoType = models.ProjectPublic + repoType = proModels.ProjectPublic } imageName := util.GetNameFromImgRepoFullName(repoName) diff --git a/src/controller/event/handler/webhook/quota/quota_test.go b/src/controller/event/handler/webhook/quota/quota_test.go index 9bbaf91e2..78a521ce8 100644 --- a/src/controller/event/handler/webhook/quota/quota_test.go +++ b/src/controller/event/handler/webhook/quota/quota_test.go @@ -21,12 +21,12 @@ import ( "github.com/goharbor/harbor/src/lib/config" _ "github.com/goharbor/harbor/src/pkg/config/inmemory" policy_model "github.com/goharbor/harbor/src/pkg/notification/policy/model" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/testing/mock" "testing" "time" "github.com/goharbor/harbor/src/common" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/notification/policy" "github.com/goharbor/harbor/src/pkg/notifier" @@ -65,7 +65,7 @@ func (suite *QuotaPreprocessHandlerSuite) SetupSuite() { OccurAt: time.Now().UTC(), RepoName: "hello-world", Resource: res, - Project: &models.Project{ + Project: &proModels.Project{ ProjectID: 1, Name: "library", }, diff --git a/src/controller/event/handler/webhook/scan/scan.go b/src/controller/event/handler/webhook/scan/scan.go index a0eba88b0..713adb6b6 100644 --- a/src/controller/event/handler/webhook/scan/scan.go +++ b/src/controller/event/handler/webhook/scan/scan.go @@ -19,7 +19,6 @@ import ( "time" o "github.com/astaxie/beego/orm" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/controller/event/handler/util" @@ -30,6 +29,7 @@ import ( "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/notifier/model" + proModels "github.com/goharbor/harbor/src/pkg/project/models" v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1" ) @@ -88,10 +88,10 @@ func (si *Handler) IsStateful() bool { return false } -func constructScanImagePayload(event *event.ScanImageEvent, project *models.Project) (*model.Payload, error) { - repoType := models.ProjectPrivate +func constructScanImagePayload(event *event.ScanImageEvent, project *proModels.Project) (*model.Payload, error) { + repoType := proModels.ProjectPrivate if project.IsPublic() { - repoType = models.ProjectPublic + repoType = proModels.ProjectPublic } repoName := util.GetNameFromImgRepoFullName(event.Artifact.Repository) diff --git a/src/controller/event/metadata/quota.go b/src/controller/event/metadata/quota.go index 2b30c0574..1f490ccbf 100644 --- a/src/controller/event/metadata/quota.go +++ b/src/controller/event/metadata/quota.go @@ -1,9 +1,9 @@ package metadata import ( + proModels "github.com/goharbor/harbor/src/pkg/project/models" "time" - "github.com/goharbor/harbor/src/common/models" event2 "github.com/goharbor/harbor/src/controller/event" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/pkg/notifier/event" @@ -11,7 +11,7 @@ import ( // QuotaMetaData defines quota related event data type QuotaMetaData struct { - Project *models.Project + Project *proModels.Project RepoName string Tag string Digest string diff --git a/src/controller/event/topic.go b/src/controller/event/topic.go index ca3a76127..26e616323 100644 --- a/src/controller/event/topic.go +++ b/src/controller/event/topic.go @@ -16,9 +16,9 @@ package event import ( "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "time" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib/selector" "github.com/goharbor/harbor/src/pkg/artifact" "github.com/goharbor/harbor/src/pkg/audit/model" @@ -318,7 +318,7 @@ func (c *ChartEvent) String() string { // QuotaEvent is project quota related event data to publish type QuotaEvent struct { EventType string - Project *models.Project + Project *proModels.Project Resource *ImgResource OccurAt time.Time RepoName string diff --git a/src/controller/immutable/controller_test.go b/src/controller/immutable/controller_test.go index 7670b2277..334629080 100644 --- a/src/controller/immutable/controller_test.go +++ b/src/controller/immutable/controller_test.go @@ -3,10 +3,10 @@ package immutable import ( "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg/project" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "testing" - "github.com/goharbor/harbor/src/common/dao" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/utils/test" "github.com/goharbor/harbor/src/pkg/immutable/model" htesting "github.com/goharbor/harbor/src/testing" @@ -37,13 +37,14 @@ func (s *ControllerTestSuite) SetupSuite() { func (s *ControllerTestSuite) TestImmutableRule() { var err error + ctx := s.Context() - projectID, err := dao.AddProject(models.Project{ - Name: "TestImmutableRule", + projectID, err := project.Mgr.Create(ctx, &proModels.Project{ + Name: "testimmutablerule", OwnerID: 1, }) if s.Nil(err) { - defer dao.DeleteProject(projectID) + defer project.Mgr.Delete(ctx, projectID) } rule := &model.Metadata{ diff --git a/src/controller/p2p/preheat/enforcer.go b/src/controller/p2p/preheat/enforcer.go index b3b18e78a..d58a8e6a4 100644 --- a/src/controller/p2p/preheat/enforcer.go +++ b/src/controller/p2p/preheat/enforcer.go @@ -17,10 +17,10 @@ package preheat import ( "context" "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "strings" tk "github.com/docker/distribution/registry/auth/token" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/controller/scan" @@ -344,7 +344,7 @@ func (de *defaultEnforcer) PreheatArtifact(ctx context.Context, art *artifact.Ar } // getCandidates get the initial candidates by evaluating the policy -func (de *defaultEnforcer) getCandidates(ctx context.Context, ps *pol.Schema, p *models.Project) ([]*selector.Candidate, error) { +func (de *defaultEnforcer) getCandidates(ctx context.Context, ps *pol.Schema, p *proModels.Project) ([]*selector.Candidate, error) { // Get the initial candidates // Here we have a hidden filter, the artifact type filter. // Only get the image type at this moment. @@ -480,7 +480,7 @@ func (de *defaultEnforcer) startTask(ctx context.Context, executionID int64, can } // getVulnerabilitySev gets the severity code value for the given artifact with allowlist option set -func (de *defaultEnforcer) getVulnerabilitySev(ctx context.Context, p *models.Project, art *artifact.Artifact) (uint, error) { +func (de *defaultEnforcer) getVulnerabilitySev(ctx context.Context, p *proModels.Project, art *artifact.Artifact) (uint, error) { vulnerable, err := de.scanCtl.GetVulnerable(ctx, art, p.CVEAllowlist.CVESet()) if err != nil { if errors.IsNotFoundErr(err) { @@ -505,7 +505,7 @@ func (de *defaultEnforcer) getVulnerabilitySev(ctx context.Context, p *models.Pr } // toCandidates converts the artifacts to filtering candidates -func (de *defaultEnforcer) toCandidates(ctx context.Context, p *models.Project, arts []*artifact.Artifact) ([]*selector.Candidate, error) { +func (de *defaultEnforcer) toCandidates(ctx context.Context, p *proModels.Project, arts []*artifact.Artifact) ([]*selector.Candidate, error) { // Convert to filtering candidates first candidates := make([]*selector.Candidate, 0) @@ -539,7 +539,7 @@ func (de *defaultEnforcer) toCandidates(ctx context.Context, p *models.Project, } // getProject gets the full metadata of the specified project -func (de *defaultEnforcer) getProject(ctx context.Context, id int64) (*models.Project, error) { +func (de *defaultEnforcer) getProject(ctx context.Context, id int64) (*proModels.Project, error) { // Get project info with CVE allow list and metadata return de.proCtl.Get(ctx, id, project.WithEffectCVEAllowlist()) } @@ -599,7 +599,7 @@ func checkProviderHealthy(inst *provider.Instance) error { // Check the project security settings and override the related settings in the policy if necessary. // NOTES: if the security settings (relevant with signature and vulnerability) are set at the project configuration, // the corresponding filters of P2P preheat policy will be set using the relevant settings of project configurations. -func overrideSecuritySettings(p *pol.Schema, pro *models.Project) [][]interface{} { +func overrideSecuritySettings(p *pol.Schema, pro *proModels.Project) [][]interface{} { if p == nil || pro == nil { return nil } diff --git a/src/controller/p2p/preheat/enforcer_test.go b/src/controller/p2p/preheat/enforcer_test.go index 7d38742b3..50aee4950 100644 --- a/src/controller/p2p/preheat/enforcer_test.go +++ b/src/controller/p2p/preheat/enforcer_test.go @@ -17,12 +17,12 @@ package preheat import ( "context" "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" "time" - "github.com/goharbor/harbor/src/common/models" car "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/scan" "github.com/goharbor/harbor/src/controller/tag" @@ -118,7 +118,7 @@ func (suite *EnforcerTestSuite) SetupSuite() { (int64)(1), mock.Anything, mock.Anything, - ).Return(&models.Project{ + ).Return(&proModels.Project{ ProjectID: 1, Name: "library", CVEAllowlist: models2.CVEAllowlist{}, diff --git a/src/controller/proxy/controller.go b/src/controller/proxy/controller.go index 6589c5633..0feadb960 100644 --- a/src/controller/proxy/controller.go +++ b/src/controller/proxy/controller.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "github.com/goharbor/harbor/src/controller/tag" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "io" "strings" "sync" @@ -25,7 +26,6 @@ import ( "github.com/docker/distribution" "github.com/docker/distribution/manifest/manifestlist" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/blob" "github.com/goharbor/harbor/src/controller/event/operator" @@ -60,7 +60,7 @@ type Controller interface { UseLocalManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (bool, *ManifestList, error) // ProxyBlob proxy the blob request to the remote server, p is the proxy project // art is the ArtifactInfo which includes the digest of the blob - ProxyBlob(ctx context.Context, p *models.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) + ProxyBlob(ctx context.Context, p *proModels.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) // ProxyManifest proxy the manifest request to the remote server, p is the proxy project, // art is the ArtifactInfo which includes the tag or digest of the manifest ProxyManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) @@ -232,7 +232,7 @@ func (c *controller) HeadManifest(ctx context.Context, art lib.ArtifactInfo, rem ref := getReference(art) return remote.ManifestExist(remoteRepo, ref) } -func (c *controller) ProxyBlob(ctx context.Context, p *models.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) { +func (c *controller) ProxyBlob(ctx context.Context, p *proModels.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) { remoteRepo := getRemoteRepo(art) log.Debugf("The blob doesn't exist, proxy the request to the target server, url:%v", remoteRepo) rHelper, err := NewRemoteHelper(p.RegistryID) diff --git a/src/controller/proxy/controller_test.go b/src/controller/proxy/controller_test.go index 85ff442bd..f0156bc7e 100644 --- a/src/controller/proxy/controller_test.go +++ b/src/controller/proxy/controller_test.go @@ -17,12 +17,12 @@ package proxy import ( "context" "github.com/docker/distribution" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/blob" "github.com/goharbor/harbor/src/lib" _ "github.com/goharbor/harbor/src/lib/cache" "github.com/goharbor/harbor/src/lib/errors" + proModels "github.com/goharbor/harbor/src/pkg/project/models" testproxy "github.com/goharbor/harbor/src/testing/controller/proxy" "github.com/opencontainers/go-digest" "github.com/stretchr/testify/mock" @@ -83,13 +83,13 @@ type proxyControllerTestSuite struct { local *localInterfaceMock remote *testproxy.RemoteInterface ctr Controller - proj *models.Project + proj *proModels.Project } func (p *proxyControllerTestSuite) SetupTest() { p.local = &localInterfaceMock{} p.remote = &testproxy.RemoteInterface{} - p.proj = &models.Project{RegistryID: 1} + p.proj = &proModels.Project{RegistryID: 1} p.ctr = &controller{ blobCtl: blob.Ctl, artifactCtl: artifact.Ctl, diff --git a/src/controller/quota/driver/project/project.go b/src/controller/quota/driver/project/project.go index 53d60dd86..734724c4a 100644 --- a/src/controller/quota/driver/project/project.go +++ b/src/controller/quota/driver/project/project.go @@ -19,10 +19,10 @@ import ( "fmt" "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/pkg/config/db" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "strconv" "github.com/goharbor/harbor/src/common" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/blob" "github.com/goharbor/harbor/src/lib/log" dr "github.com/goharbor/harbor/src/pkg/quota/driver" @@ -68,7 +68,7 @@ func (d *driver) Load(ctx context.Context, key string) (dr.RefObject, error) { return nil, err } - project, ok := result.(*models.Project) + project, ok := result.(*proModels.Project) if !ok { return nil, fmt.Errorf("bad result for project: %s", key) } diff --git a/src/controller/quota/driver/project/util.go b/src/controller/quota/driver/project/util.go index 55883a69b..7ad7a83f2 100644 --- a/src/controller/quota/driver/project/util.go +++ b/src/controller/quota/driver/project/util.go @@ -16,6 +16,7 @@ package project import ( "context" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "strconv" "github.com/goharbor/harbor/src/common/models" @@ -50,7 +51,7 @@ func getProjectsBatchFn(ctx context.Context, keys dataloader.Keys) []*dataloader } var ownerIDs []interface{} - var projectsMap = make(map[int64]*models.Project, len(projectIDs)) + var projectsMap = make(map[int64]*proModels.Project, len(projectIDs)) for _, project := range projects { ownerIDs = append(ownerIDs, project.OwnerID) projectsMap[project.ProjectID] = project diff --git a/src/controller/quota/util_test.go b/src/controller/quota/util_test.go index 31c3ecf45..4b7229720 100644 --- a/src/controller/quota/util_test.go +++ b/src/controller/quota/util_test.go @@ -16,11 +16,11 @@ package quota import ( "context" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "math/rand" "testing" "time" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/lib/q" @@ -76,21 +76,21 @@ func (suite *RefreshForProjectsTestSuite) TestRefreshForProjects() { rand.Seed(time.Now().UnixNano()) startProjectID := rand.Int63() - var firstPageProjects, secondPageProjects []*models.Project + var firstPageProjects, secondPageProjects []*proModels.Project for i := 0; i < 50; i++ { - firstPageProjects = append(firstPageProjects, &models.Project{ + firstPageProjects = append(firstPageProjects, &proModels.Project{ ProjectID: startProjectID + int64(i), }) } for i := 0; i < 10; i++ { - secondPageProjects = append(secondPageProjects, &models.Project{ + secondPageProjects = append(secondPageProjects, &proModels.Project{ ProjectID: startProjectID + 50 + int64(i), }) } page := 1 - mock.OnAnything(suite.projectCtl, "List").Return(func(context.Context, *q.Query, ...project.Option) []*models.Project { + mock.OnAnything(suite.projectCtl, "List").Return(func(context.Context, *q.Query, ...project.Option) []*proModels.Project { defer func() { page++ }() diff --git a/src/controller/repository/controller_test.go b/src/controller/repository/controller_test.go index 8a31585e5..2a2d4bcff 100644 --- a/src/controller/repository/controller_test.go +++ b/src/controller/repository/controller_test.go @@ -15,9 +15,9 @@ package repository import ( + proModels "github.com/goharbor/harbor/src/pkg/project/models" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/orm" @@ -71,7 +71,7 @@ func (c *controllerTestSuite) TestEnsure() { // doesn't exist c.repoMgr.On("GetByName", mock.Anything, mock.Anything).Return(nil, errors.NotFoundError(nil)) - c.proMgr.On("Get", mock.AnythingOfType("*context.valueCtx"), "library").Return(&models.Project{ + c.proMgr.On("Get", mock.AnythingOfType("*context.valueCtx"), "library").Return(&proModels.Project{ ProjectID: 1, }, nil) c.repoMgr.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil) diff --git a/src/controller/robot/controller_test.go b/src/controller/robot/controller_test.go index 7732df1e0..b1ca63bc6 100644 --- a/src/controller/robot/controller_test.go +++ b/src/controller/robot/controller_test.go @@ -4,12 +4,12 @@ import ( "context" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils" "github.com/goharbor/harbor/src/common" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/utils/test" "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/q" _ "github.com/goharbor/harbor/src/pkg/config/inmemory" "github.com/goharbor/harbor/src/pkg/permission/types" + proModels "github.com/goharbor/harbor/src/pkg/project/models" rbac_model "github.com/goharbor/harbor/src/pkg/rbac/model" "github.com/goharbor/harbor/src/pkg/robot/model" htesting "github.com/goharbor/harbor/src/testing" @@ -33,7 +33,7 @@ func (suite *ControllerTestSuite) TestGet() { c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr} ctx := context.TODO() - projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) robotMgr.On("Get", mock.Anything, mock.Anything).Return(&model.Robot{ Name: "library+test", Description: "test get method", @@ -101,7 +101,7 @@ func (suite *ControllerTestSuite) TestCreate() { c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr} ctx := context.TODO() - projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) robotMgr.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil) rbacMgr.On("CreateRbacPolicy", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil) rbacMgr.On("CreatePermission", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil) @@ -164,7 +164,7 @@ func (suite *ControllerTestSuite) TestUpdate() { config.InitWithSettings(conf) robotMgr.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) rbacMgr.On("DeletePermissionsByRole", mock.Anything, mock.Anything, mock.Anything).Return(nil) rbacMgr.On("CreateRbacPolicy", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil) @@ -208,7 +208,7 @@ func (suite *ControllerTestSuite) TestList() { c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr} ctx := context.TODO() - projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) robotMgr.On("List", mock.Anything, mock.Anything).Return([]*model.Robot{ { Name: "test", @@ -233,7 +233,7 @@ func (suite *ControllerTestSuite) TestList() { Action: "push", }, }, nil) - projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) rs, err := c.List(ctx, &q.Query{ Keywords: map[string]interface{}{ "name": "test3", @@ -257,7 +257,7 @@ func (suite *ControllerTestSuite) TestToScope() { c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr} ctx := context.TODO() - projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) p := &Permission{ Kind: "system", diff --git a/src/core/api/chart_label.go b/src/core/api/chart_label.go index f7790bb48..c29116bd4 100644 --- a/src/core/api/chart_label.go +++ b/src/core/api/chart_label.go @@ -3,6 +3,7 @@ package api import ( "errors" "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/models" @@ -18,7 +19,7 @@ const ( // ChartLabelAPI handles the requests of marking/removing labels to/from charts. type ChartLabelAPI struct { LabelResourceAPI - project *models.Project + project *proModels.Project chartFullName string } diff --git a/src/core/api/chart_repository_test.go b/src/core/api/chart_repository_test.go index 6b3656e36..5e8f3a7e6 100644 --- a/src/core/api/chart_repository_test.go +++ b/src/core/api/chart_repository_test.go @@ -3,13 +3,13 @@ package api import ( "context" "errors" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" bcontext "github.com/astaxie/beego/context" "github.com/goharbor/harbor/src/chartserver" - "github.com/goharbor/harbor/src/common/models" projecttesting "github.com/goharbor/harbor/src/testing/controller/project" "github.com/goharbor/harbor/src/testing/mock" ) @@ -42,7 +42,7 @@ func TestRequireNamespace(t *testing.T) { projectCtl := &projecttesting.Controller{} chartAPI.ProjectCtl = projectCtl - mock.OnAnything(projectCtl, "List").Return([]*models.Project{ + mock.OnAnything(projectCtl, "List").Return([]*proModels.Project{ {ProjectID: 0, Name: "library"}, {ProjectID: 1, Name: "repo2"}, }, nil) diff --git a/src/core/api/harborapi_test.go b/src/core/api/harborapi_test.go index 99650dd4a..ed67e8577 100644 --- a/src/core/api/harborapi_test.go +++ b/src/core/api/harborapi_test.go @@ -19,6 +19,21 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/astaxie/beego" + "github.com/dghubble/sling" + "github.com/goharbor/harbor/src/common/api" + "github.com/goharbor/harbor/src/common/dao" + "github.com/goharbor/harbor/src/common/job/test" + testutils "github.com/goharbor/harbor/src/common/utils/test" + _ "github.com/goharbor/harbor/src/core/auth/db" + _ "github.com/goharbor/harbor/src/core/auth/ldap" + "github.com/goharbor/harbor/src/lib/config" + libOrm "github.com/goharbor/harbor/src/lib/orm" + proModels "github.com/goharbor/harbor/src/pkg/project/models" + "github.com/goharbor/harbor/src/server/middleware" + "github.com/goharbor/harbor/src/server/middleware/orm" + "github.com/goharbor/harbor/src/server/middleware/security" + "github.com/goharbor/harbor/src/testing/apitests/apilib" "io/ioutil" "log" "net/http" @@ -26,23 +41,6 @@ import ( "path/filepath" "runtime" "strconv" - "strings" - - "github.com/astaxie/beego" - "github.com/dghubble/sling" - "github.com/goharbor/harbor/src/common/api" - "github.com/goharbor/harbor/src/common/dao" - "github.com/goharbor/harbor/src/common/job/test" - "github.com/goharbor/harbor/src/common/models" - testutils "github.com/goharbor/harbor/src/common/utils/test" - _ "github.com/goharbor/harbor/src/core/auth/db" - _ "github.com/goharbor/harbor/src/core/auth/ldap" - "github.com/goharbor/harbor/src/lib/config" - libOrm "github.com/goharbor/harbor/src/lib/orm" - "github.com/goharbor/harbor/src/server/middleware" - "github.com/goharbor/harbor/src/server/middleware/orm" - "github.com/goharbor/harbor/src/server/middleware/security" - "github.com/goharbor/harbor/src/testing/apitests/apilib" ) const ( @@ -298,7 +296,7 @@ func (a testapi) ProjectsGet(query *apilib.ProjectQuery, authInfo ...usrInfo) (i // Update properties for a selected project. func (a testapi) ProjectsPut(prjUsr usrInfo, projectID string, - project *models.Project) (int, error) { + project *proModels.Project) (int, error) { path := "/api/projects/" + projectID _sling := sling.New().Put(a.basePath).Path(path).BodyJSON(project) @@ -367,31 +365,6 @@ func (a testapi) GetProjectMembersByProID(prjUsr usrInfo, projectID string) (int return httpStatusCode, successPayload, err } -// Add project role member accompany with projectID -// func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, roles apilib.RoleParam) (int, int, error) { -func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, member *models.MemberReq) (int, int, error) { - _sling := sling.New().Post(a.basePath) - - path := "/api/projects/" + projectID + "/members/" - _sling = _sling.Path(path) - _sling = _sling.BodyJSON(member) - httpStatusCode, header, _, err := request0(_sling, jsonAcceptHeader, prjUsr) - - var memberID int - location := header.Get("Location") - if location != "" { - parts := strings.Split(location, "/") - if len(parts) > 0 { - i, err := strconv.Atoi(parts[len(parts)-1]) - if err == nil { - memberID = i - } - } - } - - return httpStatusCode, memberID, err -} - // Delete project role member accompany with projectID func (a testapi) DeleteProjectMember(authInfo usrInfo, projectID string, memberID string) (int, error) { _sling := sling.New().Delete(a.basePath) diff --git a/src/core/auth/ldap/ldap_test.go b/src/core/auth/ldap/ldap_test.go index 3691ef084..53069f0ee 100644 --- a/src/core/auth/ldap/ldap_test.go +++ b/src/core/auth/ldap/ldap_test.go @@ -14,6 +14,7 @@ package ldap import ( + "github.com/goharbor/harbor/src/pkg/project" "os" "testing" @@ -358,7 +359,7 @@ func TestSearchAndOnBoardUser(t *testing.T) { func TestAddProjectMemberWithLdapUser(t *testing.T) { memberMgr := member.Mgr ctx := orm.Context() - currentProject, err := dao.GetProjectByName("member_test_01") + currentProject, err := project.Mgr.Get(ctx, "member_test_01") if err != nil { t.Errorf("Error occurred when GetProjectByName: %v", err) } @@ -378,7 +379,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) { t.Errorf("Error occurred in AddOrUpdateProjectMember: pmid:%v", pmid) } - currentProject, err = dao.GetProjectByName("member_test_02") + currentProject, err = project.Mgr.Get(ctx, "member_test_02") if err != nil { t.Errorf("Error occurred when GetProjectByName: %v", err) } @@ -400,7 +401,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) { func TestAddProjectMemberWithLdapGroup(t *testing.T) { memberMgr := member.Mgr ctx := orm.Context() - currentProject, err := dao.GetProjectByName("member_test_01") + currentProject, err := project.Mgr.Get(ctx, "member_test_01") if err != nil { t.Errorf("Error occurred when GetProjectByName: %v", err) } diff --git a/src/core/service/token/token_test.go b/src/core/service/token/token_test.go index eb618975d..cce32793c 100644 --- a/src/core/service/token/token_test.go +++ b/src/core/service/token/token_test.go @@ -25,6 +25,7 @@ import ( "github.com/goharbor/harbor/src/lib/orm" _ "github.com/goharbor/harbor/src/pkg/config/db" _ "github.com/goharbor/harbor/src/pkg/config/inmemory" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "io/ioutil" "net/url" "os" @@ -34,7 +35,6 @@ import ( jwt "github.com/dgrijalva/jwt-go" "github.com/docker/distribution/registry/auth/token" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/common/security" "github.com/stretchr/testify/assert" @@ -247,7 +247,7 @@ func (f *fakeSecurityContext) Can(ctx context.Context, action rbac.Action, resou return false } -func (f *fakeSecurityContext) GetMyProjects() ([]*models.Project, error) { +func (f *fakeSecurityContext) GetMyProjects() ([]*proModels.Project, error) { return nil, nil } func (f *fakeSecurityContext) GetProjectRoles(interface{}) []int { diff --git a/src/jobservice/job/impl/gc/garbage_collection_test.go b/src/jobservice/job/impl/gc/garbage_collection_test.go index fd80272b9..77e7d53f0 100644 --- a/src/jobservice/job/impl/gc/garbage_collection_test.go +++ b/src/jobservice/job/impl/gc/garbage_collection_test.go @@ -15,11 +15,11 @@ package gc import ( + proModels "github.com/goharbor/harbor/src/pkg/project/models" "os" "testing" "github.com/docker/distribution/manifest/schema2" - "github.com/goharbor/harbor/src/common/models" commom_regctl "github.com/goharbor/harbor/src/common/registryctl" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/jobservice/job" @@ -117,7 +117,7 @@ func (suite *gcTestSuite) TestRemoveUntaggedBlobs() { logger := &mockjobservice.MockJobLogger{} ctx.On("GetLogger").Return(logger) - mock.OnAnything(suite.projectCtl, "List").Return([]*models.Project{ + mock.OnAnything(suite.projectCtl, "List").Return([]*proModels.Project{ { ProjectID: 1234, Name: "test GC", @@ -226,7 +226,7 @@ func (suite *gcTestSuite) TestRun() { suite.artifactCtl.On("Delete").Return(nil) suite.artrashMgr.On("Filter").Return([]model.ArtifactTrash{}, nil) - mock.OnAnything(suite.projectCtl, "List").Return([]*models.Project{ + mock.OnAnything(suite.projectCtl, "List").Return([]*proModels.Project{ { ProjectID: 12345, Name: "test GC", @@ -301,7 +301,7 @@ func (suite *gcTestSuite) TestMark() { }, }, nil) - mock.OnAnything(suite.projectCtl, "List").Return([]*models.Project{ + mock.OnAnything(suite.projectCtl, "List").Return([]*proModels.Project{ { ProjectID: 1234, Name: "test GC", diff --git a/src/pkg/exporter/project_collector_test.go b/src/pkg/exporter/project_collector_test.go index 67c278bd5..2d297db3d 100644 --- a/src/pkg/exporter/project_collector_test.go +++ b/src/pkg/exporter/project_collector_test.go @@ -1,6 +1,7 @@ package exporter import ( + proModels "github.com/goharbor/harbor/src/pkg/project/models" "strconv" "testing" "time" @@ -27,8 +28,8 @@ var ( alice = models.User{Username: "alice", Password: "password", Email: "alice@test.com"} bob = models.User{Username: "bob", Password: "password", Email: "bob@test.com"} eve = models.User{Username: "eve", Password: "password", Email: "eve@test.com"} - testPro1 = models.Project{OwnerID: 1, Name: "test1", Metadata: map[string]string{"public": "true"}} - testPro2 = models.Project{OwnerID: 1, Name: "test2", Metadata: map[string]string{"public": "false"}} + testPro1 = proModels.Project{OwnerID: 1, Name: "test1", Metadata: map[string]string{"public": "true"}} + testPro2 = proModels.Project{OwnerID: 1, Name: "test2", Metadata: map[string]string{"public": "false"}} rs1 = qtypes.ResourceList{qtypes.ResourceStorage: 100} rs2 = qtypes.ResourceList{qtypes.ResourceStorage: 200} repo1 = model.RepoRecord{Name: "repo1"} diff --git a/src/pkg/project/dao/dao.go b/src/pkg/project/dao/dao.go index 420f4e77f..68339240b 100644 --- a/src/pkg/project/dao/dao.go +++ b/src/pkg/project/dao/dao.go @@ -70,7 +70,7 @@ func (d *dao) Create(ctx context.Context, project *models.Project) (int64, error return orm.WrapConflictError(err, "The project named %s already exists", project.Name) } - member := &Member{ + member := &models.Member{ ProjectID: projectID, EntityID: project.OwnerID, Role: common.RoleProjectAdmin, @@ -170,7 +170,7 @@ func (d *dao) List(ctx context.Context, query *q.Query) ([]*models.Project, erro } func (d *dao) ListRoles(ctx context.Context, projectID int64, userID int, groupIDs ...int) ([]int, error) { - qs, err := orm.QuerySetter(ctx, &Member{}, nil) + qs, err := orm.QuerySetter(ctx, &models.Member{}, nil) if err != nil { return nil, err } diff --git a/src/pkg/project/dao/model.go b/src/pkg/project/models/member.go similarity index 80% rename from src/pkg/project/dao/model.go rename to src/pkg/project/models/member.go index c6ee3d491..70f002c0c 100644 --- a/src/pkg/project/dao/model.go +++ b/src/pkg/project/models/member.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dao +package models import ( "time" @@ -37,6 +37,16 @@ type Member struct { UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` } +// MemberQuery ... +type MemberQuery struct { + UserID int // the user id + Name string // the username of member + Role int // the role of the member has to the project + GroupIDs []int // the group ID of current user belongs to + + WithPublic bool // include the public projects for the member +} + // TableName ... func (*Member) TableName() string { return "project_member" diff --git a/src/common/models/pro_meta.go b/src/pkg/project/models/pro_meta.go similarity index 100% rename from src/common/models/pro_meta.go rename to src/pkg/project/models/pro_meta.go diff --git a/src/pkg/project/models/project.go b/src/pkg/project/models/project.go index d3a9146d4..3cfa42493 100644 --- a/src/pkg/project/models/project.go +++ b/src/pkg/project/models/project.go @@ -15,14 +15,192 @@ package models import ( - "github.com/goharbor/harbor/src/common/models" + "context" + "fmt" + "github.com/astaxie/beego/orm" + allowlist "github.com/goharbor/harbor/src/pkg/allowlist/models" + "github.com/lib/pq" + "strconv" + "strings" + "time" ) -// Project ... -type Project = models.Project +const ( + // ProjectTable is the table name for project + ProjectTable = "project" + // ProjectPublic means project is public + ProjectPublic = "public" + // ProjectPrivate means project is private + ProjectPrivate = "private" +) + +func init() { + orm.RegisterModel(&Project{}) +} + +// Project holds the details of a project. +type Project struct { + ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"` + OwnerID int `orm:"column(owner_id)" json:"owner_id"` + Name string `orm:"column(name)" json:"name" sort:"default"` + CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"` + UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` + Deleted bool `orm:"column(deleted)" json:"deleted"` + OwnerName string `orm:"-" json:"owner_name"` + Role int `orm:"-" json:"current_user_role_id"` + RoleList []int `orm:"-" json:"current_user_role_ids"` + RepoCount int64 `orm:"-" json:"repo_count"` + ChartCount uint64 `orm:"-" json:"chart_count"` + Metadata map[string]string `orm:"-" json:"metadata"` + CVEAllowlist allowlist.CVEAllowlist `orm:"-" json:"cve_allowlist"` + RegistryID int64 `orm:"column(registry_id)" json:"registry_id"` +} + +// GetMetadata ... +func (p *Project) GetMetadata(key string) (string, bool) { + if len(p.Metadata) == 0 { + return "", false + } + value, exist := p.Metadata[key] + return value, exist +} + +// SetMetadata ... +func (p *Project) SetMetadata(key, value string) { + if p.Metadata == nil { + p.Metadata = map[string]string{} + } + p.Metadata[key] = value +} + +// IsPublic ... +func (p *Project) IsPublic() bool { + public, exist := p.GetMetadata(ProMetaPublic) + if !exist { + return false + } + + return isTrue(public) +} + +// IsProxy returns true when the project type is proxy cache +func (p *Project) IsProxy() bool { + return p.RegistryID > 0 +} + +// ContentTrustEnabled ... +func (p *Project) ContentTrustEnabled() bool { + enabled, exist := p.GetMetadata(ProMetaEnableContentTrust) + if !exist { + return false + } + return isTrue(enabled) +} + +// VulPrevented ... +func (p *Project) VulPrevented() bool { + prevent, exist := p.GetMetadata(ProMetaPreventVul) + if !exist { + return false + } + return isTrue(prevent) +} + +// ReuseSysCVEAllowlist ... +func (p *Project) ReuseSysCVEAllowlist() bool { + r, ok := p.GetMetadata(ProMetaReuseSysCVEAllowlist) + if !ok { + return true + } + return isTrue(r) +} + +// Severity ... +func (p *Project) Severity() string { + severity, exist := p.GetMetadata(ProMetaSeverity) + if !exist { + return "" + } + return severity +} + +// AutoScan ... +func (p *Project) AutoScan() bool { + auto, exist := p.GetMetadata(ProMetaAutoScan) + if !exist { + return false + } + return isTrue(auto) +} + +// FilterByPublic returns orm.QuerySeter with public filter +func (p *Project) FilterByPublic(ctx context.Context, qs orm.QuerySeter, key string, value interface{}) orm.QuerySeter { + subQuery := `SELECT project_id FROM project_metadata WHERE name = 'public' AND value = '%s'` + if isTrue(value) { + subQuery = fmt.Sprintf(subQuery, "true") + } else { + subQuery = fmt.Sprintf(subQuery, "false") + } + return qs.FilterRaw("project_id", fmt.Sprintf("IN (%s)", subQuery)) +} + +// FilterByOwner returns orm.QuerySeter with owner filter +func (p *Project) FilterByOwner(ctx context.Context, qs orm.QuerySeter, key string, value interface{}) orm.QuerySeter { + username, ok := value.(string) + if !ok { + return qs + } + + return qs.FilterRaw("owner_id", fmt.Sprintf("IN (SELECT user_id FROM harbor_user WHERE username = %s)", pq.QuoteLiteral(username))) +} + +// FilterByMember returns orm.QuerySeter with member filter +func (p *Project) FilterByMember(ctx context.Context, qs orm.QuerySeter, key string, value interface{}) orm.QuerySeter { + query, ok := value.(*MemberQuery) + if !ok { + return qs + } + subQuery := fmt.Sprintf(`SELECT project_id FROM project_member WHERE entity_id = %d AND entity_type = 'u'`, query.UserID) + if query.Role > 0 { + subQuery = fmt.Sprintf("%s AND role = %d", subQuery, query.Role) + } + + if query.WithPublic { + subQuery = fmt.Sprintf("(%s) UNION (SELECT project_id FROM project_metadata WHERE name = 'public' AND value = 'true')", subQuery) + } + + if len(query.GroupIDs) > 0 { + var elems []string + for _, groupID := range query.GroupIDs { + elems = append(elems, strconv.Itoa(groupID)) + } + + tpl := "(%s) UNION (SELECT project_id FROM project_member pm, user_group ug WHERE pm.entity_id = ug.id AND pm.entity_type = 'g' AND ug.id IN (%s))" + subQuery = fmt.Sprintf(tpl, subQuery, strings.TrimSpace(strings.Join(elems, ", "))) + } + + return qs.FilterRaw("project_id", fmt.Sprintf("IN (%s)", subQuery)) +} + +func isTrue(i interface{}) bool { + switch value := i.(type) { + case bool: + return value + case string: + v := strings.ToLower(value) + return v == "true" || v == "1" + default: + return false + } +} + +// TableName is required by beego orm to map Project to table project +func (p *Project) TableName() string { + return ProjectTable +} // Projects the connection for Project -type Projects []*models.Project +type Projects []*Project // OwnerIDs returns all the owner ids from the projects func (projects Projects) OwnerIDs() []int { @@ -32,9 +210,3 @@ func (projects Projects) OwnerIDs() []int { } return ownerIDs } - -// Member ... -type Member = models.Member - -// MemberQuery ... -type MemberQuery = models.MemberQuery diff --git a/src/pkg/retention/launcher_test.go b/src/pkg/retention/launcher_test.go index 7540aa2ee..36758f72c 100644 --- a/src/pkg/retention/launcher_test.go +++ b/src/pkg/retention/launcher_test.go @@ -17,10 +17,10 @@ package retention import ( "context" "github.com/goharbor/harbor/src/lib/orm" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "testing" "github.com/goharbor/harbor/src/common/job" - "github.com/goharbor/harbor/src/common/models" _ "github.com/goharbor/harbor/src/lib/selector/selectors/doublestar" "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/repository/model" @@ -116,16 +116,16 @@ type launchTestSuite struct { } func (l *launchTestSuite) SetupTest() { - pro1 := &models.Project{ + pro1 := &proModels.Project{ ProjectID: 1, Name: "library", } - pro2 := &models.Project{ + pro2 := &proModels.Project{ ProjectID: 2, Name: "test", } projectMgr := &projecttesting.Manager{} - mock.OnAnything(projectMgr, "List").Return([]*models.Project{ + mock.OnAnything(projectMgr, "List").Return([]*proModels.Project{ pro1, pro2, }, nil) l.projectMgr = projectMgr diff --git a/src/server/middleware/contenttrust/contenttrust_test.go b/src/server/middleware/contenttrust/contenttrust_test.go index 637642428..9e87adea3 100644 --- a/src/server/middleware/contenttrust/contenttrust_test.go +++ b/src/server/middleware/contenttrust/contenttrust_test.go @@ -16,11 +16,11 @@ package contenttrust import ( "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/artifact/processor/image" @@ -43,7 +43,7 @@ type MiddlewareTestSuite struct { projectController *projecttesting.Controller artifact *artifact.Artifact - project *models.Project + project *proModels.Project isArtifactSigned func(req *http.Request, art lib.ArtifactInfo) (bool, error) next http.Handler @@ -65,11 +65,11 @@ func (suite *MiddlewareTestSuite) SetupTest() { suite.artifact.RepositoryName = "library/photon" suite.artifact.Digest = "digest" - suite.project = &models.Project{ + suite.project = &proModels.Project{ ProjectID: suite.artifact.ProjectID, Name: "library", Metadata: map[string]string{ - models.ProMetaEnableContentTrust: "true", + proModels.ProMetaEnableContentTrust: "true", }, } @@ -121,7 +121,7 @@ func (suite *MiddlewareTestSuite) TestGetProjectFailed() { func (suite *MiddlewareTestSuite) TestContentTrustDisabled() { mock.OnAnything(suite.artifactController, "GetByReference").Return(suite.artifact, nil) - suite.project.Metadata[models.ProMetaEnableContentTrust] = "false" + suite.project.Metadata[proModels.ProMetaEnableContentTrust] = "false" mock.OnAnything(suite.projectController, "GetByName").Return(suite.project, nil) req := suite.makeRequest() diff --git a/src/server/middleware/immutable/pushmf_test.go b/src/server/middleware/immutable/pushmf_test.go index e5e40a601..82788dcb5 100644 --- a/src/server/middleware/immutable/pushmf_test.go +++ b/src/server/middleware/immutable/pushmf_test.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "github.com/goharbor/harbor/src/controller/immutable" + "github.com/goharbor/harbor/src/pkg/project" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "math/rand" "net/http" "net/http/httptest" @@ -12,7 +14,6 @@ import ( "time" "github.com/goharbor/harbor/src/common/dao" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib" internal_orm "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/pkg/artifact" @@ -71,8 +72,8 @@ func randomString(n int) string { return string(b) } -func (suite *HandlerSuite) addProject(projectName string) int64 { - projectID, err := dao.AddProject(models.Project{ +func (suite *HandlerSuite) addProject(ctx context.Context, projectName string) int64 { + projectID, err := project.Mgr.Create(ctx, &proModels.Project{ Name: projectName, OwnerID: 1, }) @@ -153,14 +154,14 @@ func (suite *HandlerSuite) TestPutDeleteManifestCreated() { dgt := digest.FromString(randomString(15)).String() ctx := internal_orm.NewContext(context.TODO(), dao.GetOrmer()) - projectID := suite.addProject(projectName) + projectID := suite.addProject(ctx, projectName) immuRuleID := suite.addImmutableRule(projectID) repoID := suite.addRepo(ctx, projectID, repoName) afID := suite.addArt(ctx, projectID, repoID, repoName, dgt) tagID := suite.addTags(ctx, repoID, afID, "release-1.10") defer func() { - dao.DeleteProject(projectID) + project.Mgr.Delete(ctx, projectID) artifact.Mgr.Delete(ctx, afID) repository.Mgr.Delete(ctx, repoID) tag.Mgr.Delete(ctx, tagID) diff --git a/src/server/middleware/quota/copy_artifact_test.go b/src/server/middleware/quota/copy_artifact_test.go index 8ce720422..352d1696a 100644 --- a/src/server/middleware/quota/copy_artifact_test.go +++ b/src/server/middleware/quota/copy_artifact_test.go @@ -29,11 +29,11 @@ package quota import ( + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" - commonmodels "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/quota" @@ -84,7 +84,7 @@ func (suite *CopyArtifactMiddlewareTestSuite) SetupTest() { walkFn(suite.artifact) }) - mock.OnAnything(suite.projectController, "Get").Return(&commonmodels.Project{}, nil) + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{}, nil) } func (suite *CopyArtifactMiddlewareTestSuite) TestResourcesWarning() { diff --git a/src/server/middleware/quota/put_blob_upload_test.go b/src/server/middleware/quota/put_blob_upload_test.go index b700935d2..914044c89 100644 --- a/src/server/middleware/quota/put_blob_upload_test.go +++ b/src/server/middleware/quota/put_blob_upload_test.go @@ -16,12 +16,12 @@ package quota import ( "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "strconv" "testing" - commonmodels "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/quota" @@ -118,7 +118,7 @@ func (suite *PutBlobUploadMiddlewareTestSuite) TestBlobExistFailed() { func (suite *PutBlobUploadMiddlewareTestSuite) TestResourcesExceeded() { mock.OnAnything(suite.quotaController, "IsEnabled").Return(true, nil) mock.OnAnything(suite.blobController, "Exist").Return(false, nil) - mock.OnAnything(suite.projectController, "Get").Return(&commonmodels.Project{}, nil) + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{}, nil) { var errs quota.Errors diff --git a/src/server/middleware/quota/put_manifest_test.go b/src/server/middleware/quota/put_manifest_test.go index d7198f3be..b5001628e 100644 --- a/src/server/middleware/quota/put_manifest_test.go +++ b/src/server/middleware/quota/put_manifest_test.go @@ -17,13 +17,13 @@ package quota import ( "context" std_err "errors" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "strings" "testing" "github.com/docker/distribution/manifest/schema2" - commonmodels "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/pkg/blob/models" "github.com/goharbor/harbor/src/pkg/distribution" @@ -187,7 +187,7 @@ func (suite *PutManifestMiddlewareTestSuite) TestResourcesExceeded() { mock.OnAnything(suite.quotaController, "IsEnabled").Return(true, nil) mock.OnAnything(suite.blobController, "Exist").Return(false, nil) mock.OnAnything(suite.blobController, "FindMissingAssociationsForProject").Return(nil, nil) - mock.OnAnything(suite.projectController, "Get").Return(&commonmodels.Project{}, nil) + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{}, nil) next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) @@ -235,7 +235,7 @@ func (suite *PutManifestMiddlewareTestSuite) TestResourcesWarning() { f := args.Get(4).(func() error) f() }) - mock.OnAnything(suite.projectController, "Get").Return(&commonmodels.Project{}, nil) + mock.OnAnything(suite.projectController, "Get").Return(&proModels.Project{}, nil) next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) diff --git a/src/server/middleware/quota/quota_test.go b/src/server/middleware/quota/quota_test.go index af8852087..e81ab74ae 100644 --- a/src/server/middleware/quota/quota_test.go +++ b/src/server/middleware/quota/quota_test.go @@ -16,11 +16,11 @@ package quota import ( "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/blob" "github.com/goharbor/harbor/src/controller/project" @@ -64,7 +64,7 @@ func (suite *RequestMiddlewareTestSuite) SetupTest() { suite.projectController = &projecttesting.Controller{} projectController = suite.projectController - mock.OnAnything(suite.projectController, "GetByName").Return(&models.Project{ProjectID: 1, Name: "library"}, nil) + mock.OnAnything(suite.projectController, "GetByName").Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) suite.originallQuotaController = quotaController suite.quotaController = "atesting.Controller{} diff --git a/src/server/middleware/quota/util_test.go b/src/server/middleware/quota/util_test.go index 20a8f3679..879a2ff2f 100644 --- a/src/server/middleware/quota/util_test.go +++ b/src/server/middleware/quota/util_test.go @@ -17,18 +17,18 @@ package quota import ( "context" "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/testing/controller/project" "github.com/stretchr/testify/mock" ) func Test_projectReferenceObject(t *testing.T) { ctl := &project.Controller{} - ctl.On("GetByName", mock.AnythingOfType(""), "library").Return(&models.Project{ProjectID: 1}, nil) + ctl.On("GetByName", mock.AnythingOfType(""), "library").Return(&proModels.Project{ProjectID: 1}, nil) ctl.On("GetByName", mock.AnythingOfType(""), "demo").Return(nil, fmt.Errorf("not found")) originalProjectController := projectController diff --git a/src/server/middleware/repoproxy/proxy.go b/src/server/middleware/repoproxy/proxy.go index efc76271f..d121921d3 100644 --- a/src/server/middleware/repoproxy/proxy.go +++ b/src/server/middleware/repoproxy/proxy.go @@ -17,7 +17,6 @@ package repoproxy import ( "context" "fmt" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/common/security/proxycachesecret" "github.com/goharbor/harbor/src/controller/project" @@ -28,6 +27,7 @@ import ( httpLib "github.com/goharbor/harbor/src/lib/http" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/orm" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/pkg/reg/model" "github.com/goharbor/harbor/src/server/middleware" "io" @@ -80,7 +80,7 @@ func handleBlob(w http.ResponseWriter, r *http.Request, next http.Handler) error return nil } -func preCheck(ctx context.Context) (art lib.ArtifactInfo, p *models.Project, ctl proxy.Controller, err error) { +func preCheck(ctx context.Context) (art lib.ArtifactInfo, p *proModels.Project, ctl proxy.Controller, err error) { none := lib.ArtifactInfo{} art = lib.GetArtifactInfo(ctx) if art == none { @@ -152,7 +152,7 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e return nil } -func proxyManifestGet(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { +func proxyManifestGet(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *proModels.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { man, err := ctl.ProxyManifest(ctx, art, remote) if err != nil { return err @@ -168,7 +168,7 @@ func proxyManifestGet(ctx context.Context, w http.ResponseWriter, ctl proxy.Cont return nil } -func canProxy(p *models.Project) bool { +func canProxy(p *proModels.Project) bool { if p.RegistryID < 1 { return false } @@ -227,7 +227,7 @@ func DisableBlobAndManifestUploadMiddleware() func(http.Handler) http.Handler { }) } -func proxyManifestHead(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { +func proxyManifestHead(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *proModels.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error { exist, desc, err := ctl.HeadManifest(ctx, art, remote) if err != nil { return err diff --git a/src/server/middleware/v2auth/auth_test.go b/src/server/middleware/v2auth/auth_test.go index c32712eb1..ec6f07b24 100644 --- a/src/server/middleware/v2auth/auth_test.go +++ b/src/server/middleware/v2auth/auth_test.go @@ -19,6 +19,7 @@ import ( "fmt" testutils "github.com/goharbor/harbor/src/common/utils/test" "github.com/goharbor/harbor/src/lib/config" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" @@ -28,7 +29,6 @@ import ( "testing" "github.com/goharbor/harbor/src/common" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/controller/project" @@ -46,20 +46,20 @@ func TestMain(m *testing.M) { ctl := &projecttesting.Controller{} mockGet := func(ctx context.Context, - projectIDOrName interface{}, options ...project.Option) (*models.Project, error) { + projectIDOrName interface{}, options ...project.Option) (*proModels.Project, error) { name := projectIDOrName.(string) id, _ := strconv.Atoi(strings.TrimPrefix(name, "project_")) if id == 0 { return nil, fmt.Errorf("%s not found", name) } - return &models.Project{ + return &proModels.Project{ ProjectID: int64(id), Name: name, }, nil } mock.OnAnything(ctl, "Get").Return( func(ctx context.Context, - projectIDOrName interface{}, options ...project.Option) *models.Project { + projectIDOrName interface{}, options ...project.Option) *proModels.Project { p, _ := mockGet(ctx, projectIDOrName, options...) return p }, diff --git a/src/server/middleware/vulnerable/vulnerable_test.go b/src/server/middleware/vulnerable/vulnerable_test.go index b39f12e5d..9f2fd45bf 100644 --- a/src/server/middleware/vulnerable/vulnerable_test.go +++ b/src/server/middleware/vulnerable/vulnerable_test.go @@ -16,12 +16,12 @@ package vulnerable import ( "fmt" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "net/http" "net/http/httptest" "testing" "github.com/docker/distribution/manifest/manifestlist" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/artifact/processor/image" @@ -54,7 +54,7 @@ type MiddlewareTestSuite struct { scanChecker func() scan.Checker artifact *artifact.Artifact - project *models.Project + project *proModels.Project next http.Handler } @@ -85,12 +85,12 @@ func (suite *MiddlewareTestSuite) SetupTest() { suite.artifact.RepositoryName = "library/photon" suite.artifact.Digest = "digest" - suite.project = &models.Project{ + suite.project = &proModels.Project{ ProjectID: suite.artifact.ProjectID, Name: "library", Metadata: map[string]string{ - models.ProMetaPreventVul: "true", - models.ProMetaSeverity: vuln.High.String(), + proModels.ProMetaPreventVul: "true", + proModels.ProMetaSeverity: vuln.High.String(), }, } @@ -153,7 +153,7 @@ func (suite *MiddlewareTestSuite) TestGetProjectFailed() { func (suite *MiddlewareTestSuite) TestPreventionDisabled() { mock.OnAnything(suite.artifactController, "GetByReference").Return(suite.artifact, nil) - suite.project.Metadata[models.ProMetaPreventVul] = "false" + suite.project.Metadata[proModels.ProMetaPreventVul] = "false" mock.OnAnything(suite.projectController, "Get").Return(suite.project, nil) req := suite.makeRequest() diff --git a/src/server/v2.0/handler/project_metadata.go b/src/server/v2.0/handler/project_metadata.go index be7a0ff45..db2efda48 100644 --- a/src/server/v2.0/handler/project_metadata.go +++ b/src/server/v2.0/handler/project_metadata.go @@ -17,11 +17,11 @@ package handler import ( "context" "github.com/go-openapi/runtime/middleware" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/controller/project/metadata" "github.com/goharbor/harbor/src/lib/errors" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/pkg/scan/vuln" operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/project_metadata" "strconv" @@ -140,19 +140,19 @@ func (p *projectMetadataAPI) validate(metas map[string]string) (map[string]strin } switch key { - case models.ProMetaPublic, models.ProMetaEnableContentTrust, - models.ProMetaPreventVul, models.ProMetaAutoScan: + case proModels.ProMetaPublic, proModels.ProMetaEnableContentTrust, + proModels.ProMetaPreventVul, proModels.ProMetaAutoScan: v, err := strconv.ParseBool(value) if err != nil { return nil, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("invalid value: %s", value) } metas[key] = strconv.FormatBool(v) - case models.ProMetaSeverity: + case proModels.ProMetaSeverity: severity := vuln.ParseSeverityVersion3(strings.ToLower(value)) if severity == vuln.Unknown { return nil, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("invalid value: %s", value) } - metas[models.ProMetaSeverity] = strings.ToLower(severity.String()) + metas[proModels.ProMetaSeverity] = strings.ToLower(severity.String()) default: return nil, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("invalid key: %s", key) } diff --git a/src/testing/apitests/apilib/search.go b/src/testing/apitests/apilib/search.go index e25ba0847..2bb4bb0e6 100644 --- a/src/testing/apitests/apilib/search.go +++ b/src/testing/apitests/apilib/search.go @@ -23,13 +23,13 @@ package apilib import ( - "github.com/goharbor/harbor/src/common/models" + proModels "github.com/goharbor/harbor/src/pkg/project/models" ) type Search struct { // Search results of the projects that matched the filter keywords. - Projects []models.Project `json:"project,omitempty"` + Projects []proModels.Project `json:"project,omitempty"` // Search results of the repositories that matched the filter keywords. Repositories []SearchRepository `json:"repository,omitempty"` diff --git a/src/testing/controller/project/controller.go b/src/testing/controller/project/controller.go index 65bfdb81d..f09270ba5 100644 --- a/src/testing/controller/project/controller.go +++ b/src/testing/controller/project/controller.go @@ -5,9 +5,12 @@ package project import ( context "context" - models "github.com/goharbor/harbor/src/common/models" + commonmodels "github.com/goharbor/harbor/src/common/models" + mock "github.com/stretchr/testify/mock" + models "github.com/goharbor/harbor/src/pkg/project/models" + project "github.com/goharbor/harbor/src/controller/project" q "github.com/goharbor/harbor/src/lib/q" @@ -186,11 +189,11 @@ func (_m *Controller) List(ctx context.Context, query *q.Query, options ...proje } // ListRoles provides a mock function with given fields: ctx, projectID, u -func (_m *Controller) ListRoles(ctx context.Context, projectID int64, u *models.User) ([]int, error) { +func (_m *Controller) ListRoles(ctx context.Context, projectID int64, u *commonmodels.User) ([]int, error) { ret := _m.Called(ctx, projectID, u) var r0 []int - if rf, ok := ret.Get(0).(func(context.Context, int64, *models.User) []int); ok { + if rf, ok := ret.Get(0).(func(context.Context, int64, *commonmodels.User) []int); ok { r0 = rf(ctx, projectID, u) } else { if ret.Get(0) != nil { @@ -199,7 +202,7 @@ func (_m *Controller) ListRoles(ctx context.Context, projectID int64, u *models. } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, int64, *models.User) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, int64, *commonmodels.User) error); ok { r1 = rf(ctx, projectID, u) } else { r1 = ret.Error(1) diff --git a/src/testing/pkg/project/manager.go b/src/testing/pkg/project/manager.go index 16e1e68e9..d6b7bba90 100644 --- a/src/testing/pkg/project/manager.go +++ b/src/testing/pkg/project/manager.go @@ -5,7 +5,7 @@ package project import ( context "context" - models "github.com/goharbor/harbor/src/common/models" + models "github.com/goharbor/harbor/src/pkg/project/models" mock "github.com/stretchr/testify/mock" q "github.com/goharbor/harbor/src/lib/q" diff --git a/src/testing/suite.go b/src/testing/suite.go index 832179adb..cf0b0440f 100644 --- a/src/testing/suite.go +++ b/src/testing/suite.go @@ -16,7 +16,10 @@ package testing import ( "context" + "fmt" + "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/lib/config" + proModels "github.com/goharbor/harbor/src/pkg/project/models" "io" "math/rand" "net/http" @@ -26,7 +29,6 @@ import ( o "github.com/astaxie/beego/orm" "github.com/goharbor/harbor/src/common/dao" - "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/orm" "github.com/opencontainers/go-digest" @@ -101,7 +103,9 @@ func (suite *Suite) WithProject(f func(int64, string), projectNames ...string) { projectName = suite.RandString(5) } - projectID, err := dao.AddProject(models.Project{ + ctx := suite.Context() + + projectID, err := suite.AddProject(ctx, &proModels.Project{ Name: projectName, OwnerID: 1, }) @@ -110,7 +114,7 @@ func (suite *Suite) WithProject(f func(int64, string), projectNames ...string) { } defer func() { - dao.DeleteProject(projectID) + suite.DeleteProject(ctx, projectName, projectID) }() f(projectID, projectName) @@ -158,3 +162,60 @@ func (suite *Suite) ExecSQL(query string, args ...interface{}) { func (suite *Suite) IsNotFoundErr(err error) bool { return suite.True(errors.IsNotFoundErr(err)) } + +// AddProject put here is to avoid import cycle +func (suite *Suite) AddProject(ctx context.Context, project *proModels.Project) (int64, error) { + // Create create a project instance + var projectID int64 + + h := func(ctx context.Context) error { + o, err := orm.FromContext(ctx) + if err != nil { + return err + } + + now := time.Now() + project.CreationTime = now + project.UpdateTime = now + + projectID, err = o.Insert(project) + if err != nil { + return orm.WrapConflictError(err, "The project named %s already exists", project.Name) + } + + member := &proModels.Member{ + ProjectID: projectID, + EntityID: project.OwnerID, + Role: common.RoleProjectAdmin, + EntityType: common.UserMember, + CreationTime: now, + UpdateTime: now, + } + + if _, err := o.Insert(member); err != nil { + return err + } + + return nil + } + + if err := orm.WithTransaction(h)(ctx); err != nil { + return 0, err + } + + return projectID, nil +} + +// DeleteProject put here is to avoid import cycle +func (suite *Suite) DeleteProject(ctx context.Context, projectName string, projectID int64) error { + o, err := orm.FromContext(ctx) + if err != nil { + return err + } + name := fmt.Sprintf("%s#%d", projectName, projectID) + sql := `update project + set deleted = true, name = ? + where project_id = ?` + _, err = o.Raw(sql, name, projectID).Exec() + return err +}