mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-14 22:35:36 +01:00
Apply project level policies to standalone Harbor
The following features are only enabled in integration mode, this commit moves these to standalone Harbor: - Content trust policy: only signed images can be pulled - Vulnerability policy: only images whose severity is below the threshold can be pulled - Automatic scan policy: automatic scan pushed images
This commit is contained in:
parent
a1b8969793
commit
66b2d0d3f3
@ -167,6 +167,38 @@ paths:
|
|||||||
description: User need to log in first.
|
description: User need to log in first.
|
||||||
'500':
|
'500':
|
||||||
description: Internal errors.
|
description: Internal errors.
|
||||||
|
put:
|
||||||
|
summary: Update properties for a selected project.
|
||||||
|
description: |
|
||||||
|
This endpoint is aimed to update the properties of a project.
|
||||||
|
parameters:
|
||||||
|
- name: project_id
|
||||||
|
in: path
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
required: true
|
||||||
|
description: Selected project ID.
|
||||||
|
- name: project
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Project'
|
||||||
|
description: Updates of project.
|
||||||
|
tags:
|
||||||
|
- Products
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Updated project properties successfully.
|
||||||
|
'400':
|
||||||
|
description: Illegal format of provided ID value.
|
||||||
|
'401':
|
||||||
|
description: User need to log in first.
|
||||||
|
'403':
|
||||||
|
description: User does not have permission to the project.
|
||||||
|
'404':
|
||||||
|
description: Project ID does not exist.
|
||||||
|
'500':
|
||||||
|
description: Unexpected internal errors.
|
||||||
delete:
|
delete:
|
||||||
summary: Delete project by projectID
|
summary: Delete project by projectID
|
||||||
description: |
|
description: |
|
||||||
@ -193,39 +225,6 @@ paths:
|
|||||||
description: 'Project contains policies, can not be deleted.'
|
description: 'Project contains policies, can not be deleted.'
|
||||||
'500':
|
'500':
|
||||||
description: Internal errors.
|
description: Internal errors.
|
||||||
'/projects/{project_id}/publicity':
|
|
||||||
put:
|
|
||||||
summary: Update properties for a selected project.
|
|
||||||
description: |
|
|
||||||
This endpoint is aimed to toggle a project publicity status.
|
|
||||||
parameters:
|
|
||||||
- name: project_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
required: true
|
|
||||||
description: Selected project ID.
|
|
||||||
- name: project
|
|
||||||
in: body
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/Project'
|
|
||||||
description: Updates of project.
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Updated project publicity status successfully.
|
|
||||||
'400':
|
|
||||||
description: Illegal format of provided ID value.
|
|
||||||
'401':
|
|
||||||
description: User need to log in first.
|
|
||||||
'403':
|
|
||||||
description: User does not have permission to the project.
|
|
||||||
'404':
|
|
||||||
description: Project ID does not exist.
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
'/projects/{project_id}/logs':
|
'/projects/{project_id}/logs':
|
||||||
get:
|
get:
|
||||||
summary: Get access logs accompany with a relevant project.
|
summary: Get access logs accompany with a relevant project.
|
||||||
@ -2016,10 +2015,6 @@ definitions:
|
|||||||
owner_name:
|
owner_name:
|
||||||
type: string
|
type: string
|
||||||
description: The owner name of the project.
|
description: The owner name of the project.
|
||||||
public:
|
|
||||||
type: integer
|
|
||||||
format: int
|
|
||||||
description: The public status of the project.
|
|
||||||
Togglable:
|
Togglable:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: >-
|
description: >-
|
||||||
@ -2031,6 +2026,18 @@ definitions:
|
|||||||
repo_count:
|
repo_count:
|
||||||
type: integer
|
type: integer
|
||||||
description: The number of the repositories under this project.
|
description: The number of the repositories under this project.
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
description: The metadata of the project.
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/ProjectMetadata'
|
||||||
|
ProjectMetadata:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
public:
|
||||||
|
type: integer
|
||||||
|
format: int
|
||||||
|
description: The public status of the project.
|
||||||
enable_content_trust:
|
enable_content_trust:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: >-
|
description: >-
|
||||||
|
@ -73,14 +73,13 @@ create table project (
|
|||||||
creation_time timestamp,
|
creation_time timestamp,
|
||||||
update_time timestamp,
|
update_time timestamp,
|
||||||
deleted tinyint (1) DEFAULT 0 NOT NULL,
|
deleted tinyint (1) DEFAULT 0 NOT NULL,
|
||||||
public tinyint (1) DEFAULT 0 NOT NULL,
|
|
||||||
primary key (project_id),
|
primary key (project_id),
|
||||||
FOREIGN KEY (owner_id) REFERENCES user(user_id),
|
FOREIGN KEY (owner_id) REFERENCES user(user_id),
|
||||||
UNIQUE (name)
|
UNIQUE (name)
|
||||||
);
|
);
|
||||||
|
|
||||||
insert into project (owner_id, name, creation_time, update_time, public) values
|
insert into project (owner_id, name, creation_time, update_time) values
|
||||||
(1, 'library', NOW(), NOW(), 1);
|
(1, 'library', NOW(), NOW());
|
||||||
|
|
||||||
create table project_member (
|
create table project_member (
|
||||||
project_id int NOT NULL,
|
project_id int NOT NULL,
|
||||||
|
@ -71,13 +71,12 @@ create table project (
|
|||||||
creation_time timestamp,
|
creation_time timestamp,
|
||||||
update_time timestamp,
|
update_time timestamp,
|
||||||
deleted tinyint (1) DEFAULT 0 NOT NULL,
|
deleted tinyint (1) DEFAULT 0 NOT NULL,
|
||||||
public tinyint (1) DEFAULT 0 NOT NULL,
|
|
||||||
FOREIGN KEY (owner_id) REFERENCES user(user_id),
|
FOREIGN KEY (owner_id) REFERENCES user(user_id),
|
||||||
UNIQUE (name)
|
UNIQUE (name)
|
||||||
);
|
);
|
||||||
|
|
||||||
insert into project (owner_id, name, creation_time, update_time, public) values
|
insert into project (owner_id, name, creation_time, update_time) values
|
||||||
(1, 'library', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1);
|
(1, 'library', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
||||||
|
|
||||||
create table project_member (
|
create table project_member (
|
||||||
project_id int NOT NULL,
|
project_id int NOT NULL,
|
||||||
|
@ -420,19 +420,6 @@ func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) {
|
|
||||||
projects, err := GetHasReadPermProjects(currentUser.Username)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in QueryRelevantProjects: %v", err)
|
|
||||||
}
|
|
||||||
if len(projects) != 1 {
|
|
||||||
t.Errorf("Expected only one project in DB, but actual: %d", len(projects))
|
|
||||||
}
|
|
||||||
if projects[0].Name != "library" {
|
|
||||||
t.Errorf("There name of the project does not match, expected: %s, actual: %s", "library", projects[0].Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddProject(t *testing.T) {
|
func TestAddProject(t *testing.T) {
|
||||||
|
|
||||||
project := models.Project{
|
project := models.Project{
|
||||||
@ -657,43 +644,6 @@ func TestGetUserByProject(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToggleProjectPublicity(t *testing.T) {
|
|
||||||
err := ToggleProjectPublicity(currentProject.ProjectID, publicityOn)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in ToggleProjectPublicity: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentProject, err = GetProjectByName(projectName)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetProjectByName: %v", err)
|
|
||||||
}
|
|
||||||
if currentProject.Public != publicityOn {
|
|
||||||
t.Errorf("project, id: %d, its publicity is not on", currentProject.ProjectID)
|
|
||||||
}
|
|
||||||
err = ToggleProjectPublicity(currentProject.ProjectID, publicityOff)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in ToggleProjectPublicity: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentProject, err = GetProjectByName(projectName)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetProjectByName: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if currentProject.Public != publicityOff {
|
|
||||||
t.Errorf("project, id: %d, its publicity is not off", currentProject.ProjectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func TestIsProjectPublic(t *testing.T) {
|
|
||||||
|
|
||||||
if isPublic := IsProjectPublic(projectName); isPublic {
|
|
||||||
t.Errorf("project, id: %d, its publicity is not false after turning off", currentProject.ProjectID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func TestGetUserProjectRoles(t *testing.T) {
|
func TestGetUserProjectRoles(t *testing.T) {
|
||||||
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID)
|
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -710,17 +660,6 @@ func TestGetUserProjectRoles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func TestProjectPermission(t *testing.T) {
|
|
||||||
roleCode, err := GetPermission(currentUser.Username, currentProject.Name)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetPermission: %v", err)
|
|
||||||
}
|
|
||||||
if roleCode != "MDRWS" {
|
|
||||||
t.Errorf("The expected role code is MDRWS,but actual: %s", roleCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func TestGetTotalOfProjects(t *testing.T) {
|
func TestGetTotalOfProjects(t *testing.T) {
|
||||||
total, err := GetTotalOfProjects(nil)
|
total, err := GetTotalOfProjects(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -745,22 +684,6 @@ func TestGetProjects(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPublicProjects(t *testing.T) {
|
|
||||||
value := true
|
|
||||||
projects, err := GetProjects(&models.ProjectQueryParam{
|
|
||||||
Public: &value,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in getProjects: %v", err)
|
|
||||||
}
|
|
||||||
if len(projects) != 1 {
|
|
||||||
t.Errorf("Expected length of projects is 1, but actual: %d, the projects: %+v", len(projects), projects)
|
|
||||||
}
|
|
||||||
if projects[0].Name != "library" {
|
|
||||||
t.Errorf("Expected project name in the list: %s, actual: %s", "library", projects[0].Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddProjectMember(t *testing.T) {
|
func TestAddProjectMember(t *testing.T) {
|
||||||
err := AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER)
|
err := AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -91,3 +91,12 @@ func paramPlaceholder(n int) string {
|
|||||||
}
|
}
|
||||||
return strings.Join(placeholders, ",")
|
return strings.Join(placeholders, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListProjectMetadata ...
|
||||||
|
func ListProjectMetadata(name, value string) ([]*models.ProjectMetadata, error) {
|
||||||
|
sql := `select * from project_metadata
|
||||||
|
where name = ? and value = ? and deleted = 0`
|
||||||
|
metadatas := []*models.ProjectMetadata{}
|
||||||
|
_, err := GetOrmer().Raw(sql, name, value).QueryRows(&metadatas)
|
||||||
|
return metadatas, err
|
||||||
|
}
|
||||||
|
@ -64,6 +64,12 @@ func TestProMetaDaoMethods(t *testing.T) {
|
|||||||
assert.Equal(t, value1, m[name1].Value)
|
assert.Equal(t, value1, m[name1].Value)
|
||||||
assert.Equal(t, value2, m[name2].Value)
|
assert.Equal(t, value2, m[name2].Value)
|
||||||
|
|
||||||
|
// test list
|
||||||
|
metas, err = ListProjectMetadata(name1, value1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(metas))
|
||||||
|
assert.Equal(t, int64(1), metas[0].ProjectID)
|
||||||
|
|
||||||
// test update
|
// test update
|
||||||
newValue1 := "new_value1"
|
newValue1 := "new_value1"
|
||||||
meta1.Value = newValue1
|
meta1.Value = newValue1
|
||||||
|
@ -30,13 +30,13 @@ import (
|
|||||||
func AddProject(project models.Project) (int64, error) {
|
func AddProject(project models.Project) (int64, error) {
|
||||||
|
|
||||||
o := GetOrmer()
|
o := GetOrmer()
|
||||||
p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
|
p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted) values (?, ?, ?, ?, ?)").Prepare()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public)
|
r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -50,49 +50,11 @@ func AddProject(project models.Project) (int64, error) {
|
|||||||
return projectID, err
|
return projectID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// IsProjectPublic ...
|
|
||||||
func IsProjectPublic(projectName string) bool {
|
|
||||||
project, err := GetProjectByName(projectName)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetProjectByName: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if project == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return project.Public == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
//ProjectExists returns whether the project exists according to its name of ID.
|
|
||||||
func ProjectExists(nameOrID interface{}) (bool, error) {
|
|
||||||
o := GetOrmer()
|
|
||||||
type dummy struct{}
|
|
||||||
sql := `select project_id from project where deleted = 0 and `
|
|
||||||
switch nameOrID.(type) {
|
|
||||||
case int64:
|
|
||||||
sql += `project_id = ?`
|
|
||||||
case string:
|
|
||||||
sql += `name = ?`
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("Invalid nameOrId: %v", nameOrID)
|
|
||||||
}
|
|
||||||
|
|
||||||
var d []dummy
|
|
||||||
num, err := o.Raw(sql, nameOrID).QueryRows(&d)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return num > 0, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// GetProjectByID ...
|
// GetProjectByID ...
|
||||||
func GetProjectByID(id int64) (*models.Project, error) {
|
func GetProjectByID(id int64) (*models.Project, error) {
|
||||||
o := GetOrmer()
|
o := GetOrmer()
|
||||||
|
|
||||||
sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
|
sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time
|
||||||
from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
|
from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
|
||||||
queryParam := make([]interface{}, 1)
|
queryParam := make([]interface{}, 1)
|
||||||
queryParam = append(queryParam, id)
|
queryParam = append(queryParam, id)
|
||||||
@ -127,95 +89,19 @@ func GetProjectByName(name string) (*models.Project, error) {
|
|||||||
return &p[0], nil
|
return &p[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// GetPermission gets roles that the user has according to the project.
|
|
||||||
func GetPermission(username, projectName string) (string, error) {
|
|
||||||
o := GetOrmer()
|
|
||||||
|
|
||||||
sql := `select r.role_code from role as r
|
|
||||||
inner join project_member as pm on r.role_id = pm.role
|
|
||||||
inner join user as u on u.user_id = pm.user_id
|
|
||||||
inner join project p on p.project_id = pm.project_id
|
|
||||||
where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0`
|
|
||||||
|
|
||||||
var r []models.Role
|
|
||||||
n, err := o.Raw(sql, username, projectName).QueryRows(&r)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return r[0].RoleCode, nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ToggleProjectPublicity toggles the publicity of the project.
|
|
||||||
func ToggleProjectPublicity(projectID int64, publicity int) error {
|
|
||||||
o := GetOrmer()
|
|
||||||
sql := "update project set public = ? where project_id = ?"
|
|
||||||
_, err := o.Raw(sql, publicity, projectID).Exec()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHasReadPermProjects returns a project list,
|
|
||||||
// which satisfies the following conditions:
|
|
||||||
// 1. the project is not deleted
|
|
||||||
// 2. the prject is public or the user is a member of the project
|
|
||||||
func GetHasReadPermProjects(username string) ([]*models.Project, error) {
|
|
||||||
user, err := GetUser(models.User{
|
|
||||||
Username: username,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
o := GetOrmer()
|
|
||||||
|
|
||||||
sql :=
|
|
||||||
`select distinct p.project_id, p.name, p.public,
|
|
||||||
p.owner_id, p.creation_time, p.update_time
|
|
||||||
from project p
|
|
||||||
left join project_member pm
|
|
||||||
on p.project_id = pm.project_id
|
|
||||||
where (pm.user_id = ? or p.public = 1)
|
|
||||||
and p.deleted = 0 `
|
|
||||||
|
|
||||||
var projects []*models.Project
|
|
||||||
|
|
||||||
if _, err := o.Raw(sql, user.UserID).QueryRows(&projects); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return projects, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTotalOfProjects returns the total count of projects
|
// GetTotalOfProjects returns the total count of projects
|
||||||
// according to the query conditions
|
// according to the query conditions
|
||||||
func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {
|
func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) {
|
||||||
|
var pagination *models.Pagination
|
||||||
var (
|
|
||||||
owner string
|
|
||||||
name string
|
|
||||||
public *bool
|
|
||||||
member string
|
|
||||||
role int
|
|
||||||
)
|
|
||||||
|
|
||||||
if query != nil {
|
if query != nil {
|
||||||
owner = query.Owner
|
pagination = query.Pagination
|
||||||
name = query.Name
|
query.Pagination = nil
|
||||||
public = query.Public
|
|
||||||
if query.Member != nil {
|
|
||||||
member = query.Member.Name
|
|
||||||
role = query.Member.Role
|
|
||||||
}
|
}
|
||||||
|
sql, params := projectQueryConditions(query)
|
||||||
|
if query != nil {
|
||||||
|
query.Pagination = pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
sql, params := projectQueryConditions(owner, name, public, member, role, base...)
|
|
||||||
|
|
||||||
sql = `select count(*) ` + sql
|
sql = `select count(*) ` + sql
|
||||||
|
|
||||||
var total int64
|
var total int64
|
||||||
@ -224,86 +110,39 @@ func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BasePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetProjects returns a project list according to the query conditions
|
// GetProjects returns a project list according to the query conditions
|
||||||
func GetProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {
|
func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||||
|
sql, params := projectQueryConditions(query)
|
||||||
|
|
||||||
var (
|
sql = `select distinct p.project_id, p.name, p.owner_id,
|
||||||
owner string
|
|
||||||
name string
|
|
||||||
public *bool
|
|
||||||
member string
|
|
||||||
role int
|
|
||||||
page int64
|
|
||||||
size int64
|
|
||||||
)
|
|
||||||
|
|
||||||
if query != nil {
|
|
||||||
owner = query.Owner
|
|
||||||
name = query.Name
|
|
||||||
public = query.Public
|
|
||||||
if query.Member != nil {
|
|
||||||
member = query.Member.Name
|
|
||||||
role = query.Member.Role
|
|
||||||
}
|
|
||||||
if query.Pagination != nil {
|
|
||||||
page = query.Pagination.Page
|
|
||||||
size = query.Pagination.Size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sql, params := projectQueryConditions(owner, name, public, member, role, base...)
|
|
||||||
|
|
||||||
sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
|
|
||||||
p.creation_time, p.update_time ` + sql
|
p.creation_time, p.update_time ` + sql
|
||||||
if size > 0 {
|
|
||||||
sql += ` limit ?`
|
|
||||||
params = append(params, size)
|
|
||||||
|
|
||||||
if page > 0 {
|
|
||||||
sql += ` offset ?`
|
|
||||||
params = append(params, (page-1)*size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var projects []*models.Project
|
var projects []*models.Project
|
||||||
_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
|
_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
|
||||||
return projects, err
|
return projects, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func projectQueryConditions(owner, name string, public *bool, member string,
|
func projectQueryConditions(query *models.ProjectQueryParam) (string, []interface{}) {
|
||||||
role int, base ...*models.BaseProjectCollection) (string, []interface{}) {
|
|
||||||
params := []interface{}{}
|
params := []interface{}{}
|
||||||
|
|
||||||
// the base project collections:
|
sql := ` from project as p`
|
||||||
// 1. all projects
|
|
||||||
// 2. public projects
|
if query == nil {
|
||||||
// 3. public projects and projects which the user is a member of
|
sql += ` where p.deleted=0 order by p.name`
|
||||||
collection := `project `
|
return sql, params
|
||||||
if len(base) != 0 && base[0] != nil {
|
|
||||||
if len(base[0].Member) == 0 && base[0].Public {
|
|
||||||
collection = `(select * from project pr
|
|
||||||
where pr.public=1) `
|
|
||||||
}
|
|
||||||
if len(base[0].Member) > 0 && base[0].Public {
|
|
||||||
collection = `(select pr.project_id, pr.owner_id, pr.name, pr.
|
|
||||||
creation_time, pr.update_time, pr.deleted, pr.public
|
|
||||||
from project pr
|
|
||||||
join project_member prm
|
|
||||||
on pr.project_id = prm.project_id
|
|
||||||
join user ur
|
|
||||||
on prm.user_id=ur.user_id
|
|
||||||
where ur.username=? or pr.public=1 )`
|
|
||||||
params = append(params, base[0].Member)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sql := ` from ` + collection + ` as p`
|
// 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(owner) != 0 {
|
if len(query.Owner) != 0 {
|
||||||
sql += ` join user u1
|
sql += ` join user u1
|
||||||
on p.owner_id = u1.user_id`
|
on p.owner_id = u1.user_id`
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(member) != 0 {
|
if query.Member != nil && len(query.Member.Name) != 0 {
|
||||||
sql += ` join project_member pm
|
sql += ` join project_member pm
|
||||||
on p.project_id = pm.project_id
|
on p.project_id = pm.project_id
|
||||||
join user u2
|
join user u2
|
||||||
@ -311,33 +150,24 @@ func projectQueryConditions(owner, name string, public *bool, member string,
|
|||||||
}
|
}
|
||||||
sql += ` where p.deleted=0`
|
sql += ` where p.deleted=0`
|
||||||
|
|
||||||
if len(owner) != 0 {
|
if len(query.Owner) != 0 {
|
||||||
sql += ` and u1.username=?`
|
sql += ` and u1.username=?`
|
||||||
params = append(params, owner)
|
params = append(params, query.Owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(name) != 0 {
|
if len(query.Name) != 0 {
|
||||||
sql += ` and p.name like ?`
|
sql += ` and p.name like ?`
|
||||||
params = append(params, "%"+escape(name)+"%")
|
params = append(params, "%"+escape(query.Name)+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
if public != nil {
|
if query.Member != nil && len(query.Member.Name) != 0 {
|
||||||
sql += ` and p.public = ?`
|
|
||||||
if *public {
|
|
||||||
params = append(params, 1)
|
|
||||||
} else {
|
|
||||||
params = append(params, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(member) != 0 {
|
|
||||||
sql += ` and u2.username=?`
|
sql += ` and u2.username=?`
|
||||||
params = append(params, member)
|
params = append(params, query.Member.Name)
|
||||||
|
|
||||||
if role > 0 {
|
if query.Member.Role > 0 {
|
||||||
sql += ` and pm.role = ?`
|
sql += ` and pm.role = ?`
|
||||||
roleID := 0
|
roleID := 0
|
||||||
switch role {
|
switch query.Member.Role {
|
||||||
case common.RoleProjectAdmin:
|
case common.RoleProjectAdmin:
|
||||||
roleID = 1
|
roleID = 1
|
||||||
case common.RoleDeveloper:
|
case common.RoleDeveloper:
|
||||||
@ -350,8 +180,24 @@ func projectQueryConditions(owner, name string, public *bool, member string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(query.ProjectIDs) > 0 {
|
||||||
|
sql += fmt.Sprintf(` and p.project_id in ( %s )`,
|
||||||
|
paramPlaceholder(len(query.ProjectIDs)))
|
||||||
|
params = append(params, query.ProjectIDs)
|
||||||
|
}
|
||||||
|
|
||||||
sql += ` order by p.name`
|
sql += ` order by p.name`
|
||||||
|
|
||||||
|
if 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
|
return sql, params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ func TestGetTopRepos(t *testing.T) {
|
|||||||
project1 := models.Project{
|
project1 := models.Project{
|
||||||
OwnerID: 1,
|
OwnerID: 1,
|
||||||
Name: "project1",
|
Name: "project1",
|
||||||
Public: 0,
|
|
||||||
}
|
}
|
||||||
project1.ProjectID, err = AddProject(project1)
|
project1.ProjectID, err = AddProject(project1)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
@ -112,7 +111,6 @@ func TestGetTopRepos(t *testing.T) {
|
|||||||
project2 := models.Project{
|
project2 := models.Project{
|
||||||
OwnerID: 1,
|
OwnerID: 1,
|
||||||
Name: "project2",
|
Name: "project2",
|
||||||
Public: 0,
|
|
||||||
}
|
}
|
||||||
project2.ProjectID, err = AddProject(project2)
|
project2.ProjectID, err = AddProject(project2)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
@ -232,7 +230,6 @@ func TestGetAllRepositories(t *testing.T) {
|
|||||||
project1 := models.Project{
|
project1 := models.Project{
|
||||||
OwnerID: 1,
|
OwnerID: 1,
|
||||||
Name: "projectRepo",
|
Name: "projectRepo",
|
||||||
Public: 0,
|
|
||||||
}
|
}
|
||||||
var err2 error
|
var err2 error
|
||||||
project1.ProjectID, err2 = AddProject(project1)
|
project1.ProjectID, err2 = AddProject(project1)
|
||||||
|
@ -18,13 +18,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// keys of project metadata
|
// keys of project metadata and severity values
|
||||||
const (
|
const (
|
||||||
ProMetaPublic = "public"
|
ProMetaPublic = "public"
|
||||||
ProMetaEnableContentTrust = "enable_content_trust"
|
ProMetaEnableContentTrust = "enable_content_trust"
|
||||||
ProMetaPreventVul = "prevent_vul"
|
ProMetaPreventVul = "prevent_vul" //prevent vulnerable images from being pulled
|
||||||
ProMetaSeverity = "severity"
|
ProMetaSeverity = "severity"
|
||||||
ProMetaAutoScan = "auto_scan"
|
ProMetaAutoScan = "auto_scan"
|
||||||
|
SeverityNone = "negligible"
|
||||||
|
SeverityLow = "low"
|
||||||
|
SeverityMedium = "medium"
|
||||||
|
SeverityHigh = "high"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProjectMetadata holds the metadata of a project.
|
// ProjectMetadata holds the metadata of a project.
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Project holds the details of a project.
|
// Project holds the details of a project.
|
||||||
// TODO remove useless attrs
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"`
|
ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"`
|
||||||
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
|
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
|
||||||
@ -27,19 +27,79 @@ type Project struct {
|
|||||||
CreationTime time.Time `orm:"column(creation_time)" json:"creation_time"`
|
CreationTime time.Time `orm:"column(creation_time)" json:"creation_time"`
|
||||||
UpdateTime time.Time `orm:"update_time" json:"update_time"`
|
UpdateTime time.Time `orm:"update_time" json:"update_time"`
|
||||||
Deleted int `orm:"column(deleted)" json:"deleted"`
|
Deleted int `orm:"column(deleted)" json:"deleted"`
|
||||||
CreationTimeStr string `orm:"-" json:"creation_time_str"`
|
|
||||||
OwnerName string `orm:"-" json:"owner_name"`
|
OwnerName string `orm:"-" json:"owner_name"`
|
||||||
Togglable bool `orm:"-"`
|
Togglable bool `orm:"-" json:"togglable"`
|
||||||
Role int `orm:"-" json:"current_user_role_id"`
|
Role int `orm:"-" json:"current_user_role_id"`
|
||||||
RepoCount int `orm:"-" json:"repo_count"`
|
RepoCount int `orm:"-" json:"repo_count"`
|
||||||
Metadata map[string]string `orm:"-" json:"metadata"`
|
Metadata map[string]string `orm:"-" json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
// TODO remove
|
// GetMetadata ...
|
||||||
Public int `orm:"column(public)" json:"public"`
|
func (p *Project) GetMetadata(key string) (string, bool) {
|
||||||
EnableContentTrust bool `orm:"-" json:"enable_content_trust"`
|
if len(p.Metadata) == 0 {
|
||||||
PreventVulnerableImagesFromRunning bool `orm:"-" json:"prevent_vulnerable_images_from_running"`
|
return "", false
|
||||||
PreventVulnerableImagesFromRunningSeverity string `orm:"-" json:"prevent_vulnerable_images_from_running_severity"`
|
}
|
||||||
AutomaticallyScanImagesOnPush bool `orm:"-" json:"automatically_scan_images_on_push"`
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTrue(value string) bool {
|
||||||
|
return strings.ToLower(value) == "true" ||
|
||||||
|
strings.ToLower(value) == "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProjectSorter holds an array of projects
|
// ProjectSorter holds an array of projects
|
||||||
@ -79,6 +139,7 @@ type ProjectQueryParam struct {
|
|||||||
Public *bool // the project is public or not, can be ture, false and nil
|
Public *bool // the project is public or not, can be ture, false and nil
|
||||||
Member *MemberQuery // the member of project
|
Member *MemberQuery // the member of project
|
||||||
Pagination *Pagination // pagination information
|
Pagination *Pagination // pagination information
|
||||||
|
ProjectIDs []int64 // project ID list
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemberQuery fitler by member's username and role
|
// MemberQuery fitler by member's username and role
|
||||||
@ -104,11 +165,8 @@ type BaseProjectCollection struct {
|
|||||||
// ProjectRequest holds informations that need for creating project API
|
// ProjectRequest holds informations that need for creating project API
|
||||||
type ProjectRequest struct {
|
type ProjectRequest struct {
|
||||||
Name string `json:"project_name"`
|
Name string `json:"project_name"`
|
||||||
Public int `json:"public"`
|
Public *int `json:"public"` //deprecated, reserved for project creation in replication
|
||||||
EnableContentTrust bool `json:"enable_content_trust"`
|
Metadata map[string]string `json:"metadata"`
|
||||||
PreventVulnerableImagesFromRunning bool `json:"prevent_vulnerable_images_from_running"`
|
|
||||||
PreventVulnerableImagesFromRunningSeverity string `json:"prevent_vulnerable_images_from_running_severity"`
|
|
||||||
AutomaticallyScanImagesOnPush bool `json:"automatically_scan_images_on_push"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProjectQueryResult ...
|
// ProjectQueryResult ...
|
||||||
|
@ -30,13 +30,13 @@ import (
|
|||||||
func ParseClairSev(clairSev string) models.Severity {
|
func ParseClairSev(clairSev string) models.Severity {
|
||||||
sev := strings.ToLower(clairSev)
|
sev := strings.ToLower(clairSev)
|
||||||
switch sev {
|
switch sev {
|
||||||
case "negligible":
|
case models.SeverityNone:
|
||||||
return models.SevNone
|
return models.SevNone
|
||||||
case "low":
|
case models.SeverityLow:
|
||||||
return models.SevLow
|
return models.SevLow
|
||||||
case "medium":
|
case models.SeverityMedium:
|
||||||
return models.SevMedium
|
return models.SevMedium
|
||||||
case "high":
|
case models.SeverityHigh:
|
||||||
return models.SevHigh
|
return models.SevHigh
|
||||||
default:
|
default:
|
||||||
return models.SevUnknown
|
return models.SevUnknown
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
@ -258,13 +259,23 @@ func getProject(name string) (*models.Project, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checker) createProject(project *models.Project) error {
|
func (c *Checker) createProject(project *models.Project) error {
|
||||||
pro := &models.ProjectRequest{
|
// only replicate the public property of project
|
||||||
|
pro := struct {
|
||||||
|
models.ProjectRequest
|
||||||
|
Public int `json:"public"`
|
||||||
|
}{
|
||||||
|
ProjectRequest: models.ProjectRequest{
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
Public: project.Public,
|
Metadata: map[string]string{
|
||||||
EnableContentTrust: project.EnableContentTrust,
|
models.ProMetaPublic: strconv.FormatBool(project.IsPublic()),
|
||||||
PreventVulnerableImagesFromRunning: project.PreventVulnerableImagesFromRunning,
|
},
|
||||||
PreventVulnerableImagesFromRunningSeverity: project.PreventVulnerableImagesFromRunningSeverity,
|
},
|
||||||
AutomaticallyScanImagesOnPush: project.AutomaticallyScanImagesOnPush,
|
}
|
||||||
|
|
||||||
|
// put "public" property in both metadata and public field to keep compatibility
|
||||||
|
// with old version API(<=1.2.0)
|
||||||
|
if project.IsPublic() {
|
||||||
|
pro.Public = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(pro)
|
data, err := json.Marshal(pro)
|
||||||
|
@ -93,12 +93,11 @@ func init() {
|
|||||||
|
|
||||||
beego.Router("/api/search/", &SearchAPI{})
|
beego.Router("/api/search/", &SearchAPI{})
|
||||||
beego.Router("/api/projects/", &ProjectAPI{}, "get:List;post:Post;head:Head")
|
beego.Router("/api/projects/", &ProjectAPI{}, "get:List;post:Post;head:Head")
|
||||||
beego.Router("/api/projects/:id", &ProjectAPI{}, "delete:Delete;get:Get")
|
beego.Router("/api/projects/:id", &ProjectAPI{}, "delete:Delete;get:Get;put:Put")
|
||||||
beego.Router("/api/users/:id", &UserAPI{}, "get:Get")
|
beego.Router("/api/users/:id", &UserAPI{}, "get:Get")
|
||||||
beego.Router("/api/users", &UserAPI{}, "get:List;post:Post;delete:Delete;put:Put")
|
beego.Router("/api/users", &UserAPI{}, "get:List;post:Post;delete:Delete;put:Put")
|
||||||
beego.Router("/api/users/:id([0-9]+)/password", &UserAPI{}, "put:ChangePassword")
|
beego.Router("/api/users/:id([0-9]+)/password", &UserAPI{}, "put:ChangePassword")
|
||||||
beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
|
beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
|
||||||
beego.Router("/api/projects/:id/publicity", &ProjectAPI{}, "put:ToggleProjectPublic")
|
|
||||||
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable")
|
beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable")
|
||||||
beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &ProjectMemberAPI{}, "get:Get;post:Post;delete:Delete;put:Put")
|
beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &ProjectMemberAPI{}, "get:Get;post:Post;delete:Delete;put:Put")
|
||||||
@ -359,18 +358,10 @@ func (a testapi) ProjectsGet(query *apilib.ProjectQuery, authInfo ...usrInfo) (i
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Update properties for a selected project.
|
//Update properties for a selected project.
|
||||||
func (a testapi) ToggleProjectPublicity(prjUsr usrInfo, projectID string, ispublic int32) (int, error) {
|
func (a testapi) ProjectsPut(prjUsr usrInfo, projectID string,
|
||||||
// create path and map variables
|
project *models.Project) (int, error) {
|
||||||
path := "/api/projects/" + projectID + "/publicity/"
|
path := "/api/projects/" + projectID
|
||||||
_sling := sling.New().Put(a.basePath)
|
_sling := sling.New().Put(a.basePath).Path(path).BodyJSON(project)
|
||||||
|
|
||||||
_sling = _sling.Path(path)
|
|
||||||
|
|
||||||
type QueryParams struct {
|
|
||||||
Public int32 `json:"public,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
_sling = _sling.BodyJSON(&QueryParams{Public: ispublic})
|
|
||||||
|
|
||||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
|
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
|
||||||
return httpStatusCode, err
|
return httpStatusCode, err
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/tests/apitests/apilib"
|
"github.com/vmware/harbor/tests/apitests/apilib"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ func TestLogGet(t *testing.T) {
|
|||||||
fmt.Println("add the project first.")
|
fmt.Println("add the project first.")
|
||||||
project := apilib.ProjectReq{
|
project := apilib.ProjectReq{
|
||||||
ProjectName: "project_for_test_log",
|
ProjectName: "project_for_test_log",
|
||||||
Public: 1,
|
Metadata: map[string]string{models.ProMetaPublic: "true"},
|
||||||
}
|
}
|
||||||
|
|
||||||
reply, err := apiTest.ProjectsPost(*testUser, project)
|
reply, err := apiTest.ProjectsPost(*testUser, project)
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
@ -120,14 +121,23 @@ func (p *ProjectAPI) Post() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pro.Metadata == nil {
|
||||||
|
pro.Metadata = map[string]string{}
|
||||||
|
}
|
||||||
|
// accept the "public" property to make replication work well with old versions(<=1.2.0)
|
||||||
|
if pro.Public != nil && len(pro.Metadata[models.ProMetaPublic]) == 0 {
|
||||||
|
pro.Metadata[models.ProMetaPublic] = strconv.FormatBool(*pro.Public == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate public metadata as false if it isn't set
|
||||||
|
if _, ok := pro.Metadata[models.ProMetaPublic]; !ok {
|
||||||
|
pro.Metadata[models.ProMetaPublic] = strconv.FormatBool(false)
|
||||||
|
}
|
||||||
|
|
||||||
projectID, err := p.ProjectMgr.Create(&models.Project{
|
projectID, err := p.ProjectMgr.Create(&models.Project{
|
||||||
Name: pro.Name,
|
Name: pro.Name,
|
||||||
Public: pro.Public,
|
|
||||||
OwnerName: p.SecurityCtx.GetUsername(),
|
OwnerName: p.SecurityCtx.GetUsername(),
|
||||||
EnableContentTrust: pro.EnableContentTrust,
|
Metadata: pro.Metadata,
|
||||||
PreventVulnerableImagesFromRunning: pro.PreventVulnerableImagesFromRunning,
|
|
||||||
PreventVulnerableImagesFromRunningSeverity: pro.PreventVulnerableImagesFromRunningSeverity,
|
|
||||||
AutomaticallyScanImagesOnPush: pro.AutomaticallyScanImagesOnPush,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errutil.ErrDupProject {
|
if err == errutil.ErrDupProject {
|
||||||
@ -178,7 +188,7 @@ func (p *ProjectAPI) Head() {
|
|||||||
|
|
||||||
// Get ...
|
// Get ...
|
||||||
func (p *ProjectAPI) Get() {
|
func (p *ProjectAPI) Get() {
|
||||||
if p.project.Public == 0 {
|
if !p.project.IsPublic() {
|
||||||
if !p.SecurityCtx.IsAuthenticated() {
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
p.HandleUnauthorized()
|
p.HandleUnauthorized()
|
||||||
return
|
return
|
||||||
@ -311,21 +321,52 @@ func (p *ProjectAPI) List() {
|
|||||||
query.Public = &pub
|
query.Public = &pub
|
||||||
}
|
}
|
||||||
|
|
||||||
// base project collection from which filter is done
|
// standalone, filter projects according to the privilleges of the user first
|
||||||
base := &models.BaseProjectCollection{}
|
if !config.WithAdmiral() {
|
||||||
|
var projects []*models.Project
|
||||||
if !p.SecurityCtx.IsAuthenticated() {
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
// not login, only get public projects
|
// not login, only get public projects
|
||||||
base.Public = true
|
pros, err := p.ProjectMgr.GetPublic()
|
||||||
|
if err != nil {
|
||||||
|
p.HandleInternalServerError(fmt.Sprintf("failed to get public projects: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
projects = []*models.Project{}
|
||||||
|
projects = append(projects, pros...)
|
||||||
} else {
|
} else {
|
||||||
if !(p.SecurityCtx.IsSysAdmin() || p.SecurityCtx.IsSolutionUser()) {
|
if !(p.SecurityCtx.IsSysAdmin() || p.SecurityCtx.IsSolutionUser()) {
|
||||||
// login, but not system admin, get public projects and
|
projects = []*models.Project{}
|
||||||
|
// login, but not system admin or solution user, get public projects and
|
||||||
// projects that the user is member of
|
// projects that the user is member of
|
||||||
base.Member = p.SecurityCtx.GetUsername()
|
pros, err := p.ProjectMgr.GetPublic()
|
||||||
base.Public = true
|
if err != nil {
|
||||||
|
p.HandleInternalServerError(fmt.Sprintf("failed to get public projects: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
projects = append(projects, pros...)
|
||||||
|
|
||||||
|
mps, err := p.ProjectMgr.List(&models.ProjectQueryParam{
|
||||||
|
Member: &models.MemberQuery{
|
||||||
|
Name: p.SecurityCtx.GetUsername(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
p.HandleInternalServerError(fmt.Sprintf("failed to list projects: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
projects = append(projects, mps.Projects...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if projects != nil {
|
||||||
|
projectIDs := []int64{}
|
||||||
|
for _, project := range projects {
|
||||||
|
projectIDs = append(projectIDs, project.ProjectID)
|
||||||
|
}
|
||||||
|
query.ProjectIDs = projectIDs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := p.ProjectMgr.List(query, base)
|
result, err := p.ProjectMgr.List(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.ParseAndHandleError("failed to list projects", err)
|
p.ParseAndHandleError("failed to list projects", err)
|
||||||
return
|
return
|
||||||
@ -358,8 +399,8 @@ func (p *ProjectAPI) List() {
|
|||||||
p.ServeJSON()
|
p.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleProjectPublic ...
|
// Put ...
|
||||||
func (p *ProjectAPI) ToggleProjectPublic() {
|
func (p *ProjectAPI) Put() {
|
||||||
if !p.SecurityCtx.IsAuthenticated() {
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
p.HandleUnauthorized()
|
p.HandleUnauthorized()
|
||||||
return
|
return
|
||||||
@ -372,16 +413,10 @@ func (p *ProjectAPI) ToggleProjectPublic() {
|
|||||||
|
|
||||||
var req *models.ProjectRequest
|
var req *models.ProjectRequest
|
||||||
p.DecodeJSONReq(&req)
|
p.DecodeJSONReq(&req)
|
||||||
if req.Public != 0 && req.Public != 1 {
|
|
||||||
p.HandleBadRequest("public should be 0 or 1")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := p.ProjectMgr.Update(p.project.ProjectID,
|
if err := p.ProjectMgr.Update(p.project.ProjectID,
|
||||||
&models.Project{
|
&models.Project{
|
||||||
Metadata: map[string]string{
|
Metadata: req.Metadata,
|
||||||
models.ProMetaPublic: strconv.Itoa(req.Public),
|
|
||||||
},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
p.ParseAndHandleError(fmt.Sprintf("failed to update project %d",
|
p.ParseAndHandleError(fmt.Sprintf("failed to update project %d",
|
||||||
p.project.ProjectID), err)
|
p.project.ProjectID), err)
|
||||||
@ -464,5 +499,39 @@ func validateProjectReq(req *models.ProjectRequest) error {
|
|||||||
if !legal {
|
if !legal {
|
||||||
return fmt.Errorf("project name is not in lower case or contains illegal characters")
|
return fmt.Errorf("project name is not in lower case or contains illegal characters")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Metadata != nil {
|
||||||
|
metas := req.Metadata
|
||||||
|
req.Metadata = map[string]string{}
|
||||||
|
|
||||||
|
boolMetas := []string{
|
||||||
|
models.ProMetaPublic,
|
||||||
|
models.ProMetaEnableContentTrust,
|
||||||
|
models.ProMetaPreventVul,
|
||||||
|
models.ProMetaAutoScan}
|
||||||
|
|
||||||
|
for _, boolMeta := range boolMetas {
|
||||||
|
value, exist := metas[boolMeta]
|
||||||
|
if exist {
|
||||||
|
b, err := strconv.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to parse %s to bool: %v", value, err)
|
||||||
|
b = false
|
||||||
|
}
|
||||||
|
req.Metadata[boolMeta] = strconv.FormatBool(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value, exist := metas[models.ProMetaSeverity]
|
||||||
|
if exist {
|
||||||
|
switch strings.ToLower(value) {
|
||||||
|
case models.SeverityHigh, models.SeverityMedium, models.SeverityLow, models.SeverityNone:
|
||||||
|
req.Metadata[models.ProMetaSeverity] = strings.ToLower(value)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid severity %s", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ var addProject *apilib.ProjectReq
|
|||||||
var addPID int
|
var addPID int
|
||||||
|
|
||||||
func InitAddPro() {
|
func InitAddPro() {
|
||||||
addProject = &apilib.ProjectReq{"add_project", 1}
|
addProject = &apilib.ProjectReq{"add_project", map[string]string{models.ProMetaPublic: "true"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddProject(t *testing.T) {
|
func TestAddProject(t *testing.T) {
|
||||||
@ -82,7 +82,7 @@ func TestAddProject(t *testing.T) {
|
|||||||
//case 4: reponse code = 400 : Project name is illegal in length
|
//case 4: reponse code = 400 : Project name is illegal in length
|
||||||
fmt.Println("case 4 : reponse code = 400 : Project name is illegal in length ")
|
fmt.Println("case 4 : reponse code = 400 : Project name is illegal in length ")
|
||||||
|
|
||||||
result, err = apiTest.ProjectsPost(*admin, apilib.ProjectReq{"t", 1})
|
result, err = apiTest.ProjectsPost(*admin, apilib.ProjectReq{"t", map[string]string{models.ProMetaPublic: "true"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error while creat project", err.Error())
|
t.Error("Error while creat project", err.Error())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@ -112,7 +112,7 @@ func TestListProjects(t *testing.T) {
|
|||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
||||||
assert.Equal(int32(1), result[0].Public, "Public is wrong")
|
assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong")
|
||||||
|
|
||||||
//find add projectID
|
//find add projectID
|
||||||
addPID = int(result[0].ProjectId)
|
addPID = int(result[0].ProjectId)
|
||||||
@ -130,7 +130,7 @@ func TestListProjects(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
||||||
assert.Equal(int32(1), result[0].Public, "Public is wrong")
|
assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong")
|
||||||
assert.Equal(int32(1), result[0].CurrentUserRoleId, "User project role is wrong")
|
assert.Equal(int32(1), result[0].CurrentUserRoleId, "User project role is wrong")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ func TestListProjects(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
||||||
assert.Equal(int32(1), result[0].Public, "Public is wrong")
|
assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong")
|
||||||
assert.Equal(int32(2), result[0].CurrentUserRoleId, "User project role is wrong")
|
assert.Equal(int32(2), result[0].CurrentUserRoleId, "User project role is wrong")
|
||||||
}
|
}
|
||||||
id := strconv.Itoa(CommonGetUserID())
|
id := strconv.Itoa(CommonGetUserID())
|
||||||
@ -187,7 +187,7 @@ func TestProGetByID(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal(addProject.ProjectName, result.ProjectName, "ProjectName is wrong")
|
assert.Equal(addProject.ProjectName, result.ProjectName, "ProjectName is wrong")
|
||||||
assert.Equal(int32(1), result.Public, "Public is wrong")
|
assert.Equal("true", result.Metadata[models.ProMetaPublic], "Public is wrong")
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
@ -273,48 +273,37 @@ func TestProHead(t *testing.T) {
|
|||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToggleProjectPublicity(t *testing.T) {
|
func TestPut(t *testing.T) {
|
||||||
fmt.Println("\nTest for Project PUT API: Update properties for a selected project")
|
fmt.Println("\nTest for Project PUT API: Update properties for a selected project")
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
apiTest := newHarborAPI()
|
apiTest := newHarborAPI()
|
||||||
|
|
||||||
//-------------------case1: Response Code=200------------------------------//
|
project := &models.Project{
|
||||||
|
Metadata: map[string]string{
|
||||||
|
models.ProMetaPublic: "true",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("case 1: respose code:200")
|
fmt.Println("case 1: respose code:200")
|
||||||
httpStatusCode, err := apiTest.ToggleProjectPublicity(*admin, "1", 1)
|
code, err := apiTest.ProjectsPut(*admin, "1", project)
|
||||||
if err != nil {
|
require.Nil(t, err)
|
||||||
t.Error("Error while search project by proId", err.Error())
|
assert.Equal(int(200), code)
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
|
||||||
}
|
|
||||||
//-------------------case2: Response Code=401 User need to log in first. ------------------------------//
|
|
||||||
fmt.Println("case 2: respose code:401, User need to log in first.")
|
fmt.Println("case 2: respose code:401, User need to log in first.")
|
||||||
httpStatusCode, err = apiTest.ToggleProjectPublicity(*unknownUsr, "1", 1)
|
code, err = apiTest.ProjectsPut(*unknownUsr, "1", project)
|
||||||
if err != nil {
|
require.Nil(t, err)
|
||||||
t.Error("Error while search project by proId", err.Error())
|
assert.Equal(int(401), code)
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401")
|
|
||||||
}
|
|
||||||
//-------------------case3: Response Code=400 Invalid project id------------------------------//
|
|
||||||
fmt.Println("case 3: respose code:400, Invalid project id")
|
fmt.Println("case 3: respose code:400, Invalid project id")
|
||||||
httpStatusCode, err = apiTest.ToggleProjectPublicity(*admin, "cc", 1)
|
code, err = apiTest.ProjectsPut(*admin, "cc", project)
|
||||||
if err != nil {
|
require.Nil(t, err)
|
||||||
t.Error("Error while search project by proId", err.Error())
|
assert.Equal(int(400), code)
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(400), httpStatusCode, "httpStatusCode should be 400")
|
|
||||||
}
|
|
||||||
//-------------------case4: Response Code=404 Not found the project------------------------------//
|
|
||||||
fmt.Println("case 4: respose code:404, Not found the project")
|
fmt.Println("case 4: respose code:404, Not found the project")
|
||||||
httpStatusCode, err = apiTest.ToggleProjectPublicity(*admin, "1234", 1)
|
code, err = apiTest.ProjectsPut(*admin, "1234", project)
|
||||||
if err != nil {
|
require.Nil(t, err)
|
||||||
t.Error("Error while search project by proId", err.Error())
|
assert.Equal(int(404), code)
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func filterRepositories(projects []*models.Project, keyword string) (
|
|||||||
entry["repository_name"] = r.Name
|
entry["repository_name"] = r.Name
|
||||||
entry["project_name"] = projects[j].Name
|
entry["project_name"] = projects[j].Name
|
||||||
entry["project_id"] = projects[j].ProjectID
|
entry["project_id"] = projects[j].ProjectID
|
||||||
entry["project_public"] = projects[j].Public
|
entry["project_public"] = projects[j].IsPublic()
|
||||||
entry["pull_count"] = r.PullCount
|
entry["pull_count"] = r.PullCount
|
||||||
|
|
||||||
tags, err := getTags(r.Name)
|
tags, err := getTags(r.Name)
|
||||||
|
@ -37,7 +37,7 @@ func TestSearch(t *testing.T) {
|
|||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal(int64(1), result.Projects[0].ProjectID, "Project id should be equal")
|
assert.Equal(int64(1), result.Projects[0].ProjectID, "Project id should be equal")
|
||||||
assert.Equal("library", result.Projects[0].Name, "Project name should be library")
|
assert.Equal("library", result.Projects[0].Name, "Project name should be library")
|
||||||
assert.Equal(1, result.Projects[0].Public, "Project public status should be 1 (true)")
|
assert.True(result.Projects[0].IsPublic(), "Project public status should be 1 (true)")
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------case 2 : Response Code = 200, sysAdmin and search repo--------//
|
//--------case 2 : Response Code = 200, sysAdmin and search repo--------//
|
||||||
@ -49,7 +49,7 @@ func TestSearch(t *testing.T) {
|
|||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal("library", result.Repositories[0].ProjectName, "Project name should be library")
|
assert.Equal("library", result.Repositories[0].ProjectName, "Project name should be library")
|
||||||
assert.Equal("library/docker", result.Repositories[0].RepositoryName, "Repository name should be library/docker")
|
assert.Equal("library/docker", result.Repositories[0].RepositoryName, "Repository name should be library/docker")
|
||||||
assert.Equal(int32(1), result.Repositories[0].ProjectPublic, "Project public status should be 1 (true)")
|
assert.True(result.Repositories[0].ProjectPublic, "Project public status should be 1 (true)")
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------case 3 : Response Code = 200, normal user and search repo--------//
|
//--------case 3 : Response Code = 200, normal user and search repo--------//
|
||||||
@ -61,7 +61,7 @@ func TestSearch(t *testing.T) {
|
|||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||||
assert.Equal("library", result.Repositories[0].ProjectName, "Project name should be library")
|
assert.Equal("library", result.Repositories[0].ProjectName, "Project name should be library")
|
||||||
assert.Equal("library/docker", result.Repositories[0].RepositoryName, "Repository name should be library/docker")
|
assert.Equal("library/docker", result.Repositories[0].RepositoryName, "Repository name should be library/docker")
|
||||||
assert.Equal(int32(1), result.Repositories[0].ProjectPublic, "Project public status should be 1 (true)")
|
assert.True(result.Repositories[0].ProjectPublic, "Project public status should be 1 (true)")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -108,8 +108,6 @@ func initSecretStore() {
|
|||||||
func initProjectManager() {
|
func initProjectManager() {
|
||||||
var driver pmsdriver.PMSDriver
|
var driver pmsdriver.PMSDriver
|
||||||
if WithAdmiral() {
|
if WithAdmiral() {
|
||||||
// TODO add support for admiral
|
|
||||||
/*
|
|
||||||
// integration with admiral
|
// integration with admiral
|
||||||
log.Info("initializing the project manager based on PMS...")
|
log.Info("initializing the project manager based on PMS...")
|
||||||
// TODO read ca/cert file and pass it to the TLS config
|
// TODO read ca/cert file and pass it to the TLS config
|
||||||
@ -129,17 +127,13 @@ func initProjectManager() {
|
|||||||
TokenReader = &admiral.FileTokenReader{
|
TokenReader = &admiral.FileTokenReader{
|
||||||
Path: path,
|
Path: path,
|
||||||
}
|
}
|
||||||
GlobalProjectMgr = admiral.NewProjectManager(AdmiralClient,
|
driver = admiral.NewDriver(AdmiralClient, AdmiralEndpoint(), TokenReader)
|
||||||
AdmiralEndpoint(), TokenReader)
|
|
||||||
*/
|
|
||||||
GlobalProjectMgr = nil
|
|
||||||
} else {
|
} else {
|
||||||
// standalone
|
// standalone
|
||||||
log.Info("initializing the project manager based on local database...")
|
log.Info("initializing the project manager based on local database...")
|
||||||
driver = local.NewDriver()
|
driver = local.NewDriver()
|
||||||
// TODO move the statement out of the else block when admiral driver is completed
|
|
||||||
GlobalProjectMgr = promgr.NewDefaultProjectManager(driver, true)
|
|
||||||
}
|
}
|
||||||
|
GlobalProjectMgr = promgr.NewDefaultProjectManager(driver, true)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
"github.com/vmware/harbor/src/ui/auth"
|
"github.com/vmware/harbor/src/ui/auth"
|
||||||
"github.com/vmware/harbor/src/ui/config"
|
"github.com/vmware/harbor/src/ui/config"
|
||||||
"github.com/vmware/harbor/src/ui/promgr"
|
"github.com/vmware/harbor/src/ui/promgr"
|
||||||
//"github.com/vmware/harbor/src/ui/promgr/pmsdriver/admiral"
|
"github.com/vmware/harbor/src/ui/promgr/pmsdriver/admiral"
|
||||||
)
|
)
|
||||||
|
|
||||||
type key string
|
type key string
|
||||||
@ -264,15 +264,13 @@ func (t *tokenReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
log.Debug("creating PMS project manager...")
|
log.Debug("creating PMS project manager...")
|
||||||
pm := admiral.NewProjectManager(config.AdmiralClient,
|
driver := admiral.NewDriver(config.AdmiralClient,
|
||||||
config.AdmiralEndpoint(), &admiral.RawTokenReader{
|
config.AdmiralEndpoint(), &admiral.RawTokenReader{
|
||||||
Token: token,
|
Token: token,
|
||||||
})
|
})
|
||||||
*/
|
|
||||||
// TODO create the DefaultProjectManager with the real admiral PMSDriver
|
pm := promgr.NewDefaultProjectManager(driver, false)
|
||||||
pm := promgr.NewDefaultProjectManager(nil, false)
|
|
||||||
|
|
||||||
log.Debug("creating admiral security context...")
|
log.Debug("creating admiral security context...")
|
||||||
securCtx := admr.NewSecurityContext(authContext, pm)
|
securCtx := admr.NewSecurityContext(authContext, pm)
|
||||||
@ -291,13 +289,10 @@ func (u *unauthorizedReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
|||||||
var pm promgr.ProjectManager
|
var pm promgr.ProjectManager
|
||||||
if config.WithAdmiral() {
|
if config.WithAdmiral() {
|
||||||
// integration with admiral
|
// integration with admiral
|
||||||
/*
|
|
||||||
log.Debug("creating PMS project manager...")
|
log.Debug("creating PMS project manager...")
|
||||||
pm = admiral.NewProjectManager(config.AdmiralClient,
|
driver := admiral.NewDriver(config.AdmiralClient,
|
||||||
config.AdmiralEndpoint(), nil)
|
config.AdmiralEndpoint(), nil)
|
||||||
*/
|
pm = promgr.NewDefaultProjectManager(driver, false)
|
||||||
// TODO create the DefaultProjectManager with the real admiral PMSDriver
|
|
||||||
pm = promgr.NewDefaultProjectManager(nil, false)
|
|
||||||
log.Debug("creating admiral security context...")
|
log.Debug("creating admiral security context...")
|
||||||
securCtx = admr.NewSecurityContext(nil, pm)
|
securCtx = admr.NewSecurityContext(nil, pm)
|
||||||
} else {
|
} else {
|
||||||
|
@ -15,15 +15,13 @@
|
|||||||
package metamgr
|
package metamgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProjectMetadataManaegr defines the operations that a project metadata manager should
|
// ProjectMetadataManager defines the operations that a project metadata manager should
|
||||||
// implement
|
// implement
|
||||||
type ProjectMetadataManaegr interface {
|
type ProjectMetadataManager interface {
|
||||||
// Add metadatas for project specified by projectID
|
// Add metadatas for project specified by projectID
|
||||||
Add(projectID int64, meta map[string]string) error
|
Add(projectID int64, meta map[string]string) error
|
||||||
// Delete metadatas whose keys are specified in parameter meta, if it
|
// Delete metadatas whose keys are specified in parameter meta, if it
|
||||||
@ -34,16 +32,18 @@ type ProjectMetadataManaegr interface {
|
|||||||
// Get metadatas whose keys are specified in parameter meta, if it is
|
// Get metadatas whose keys are specified in parameter meta, if it is
|
||||||
// absent, get all
|
// absent, get all
|
||||||
Get(projectID int64, meta ...string) (map[string]string, error)
|
Get(projectID int64, meta ...string) (map[string]string, error)
|
||||||
|
// List metadata according to the name and value
|
||||||
|
List(name, value string) ([]*models.ProjectMetadata, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultProjectMetadataManaegr struct{}
|
type defaultProjectMetadataManager struct{}
|
||||||
|
|
||||||
// NewDefaultProjectMetadataManager ...
|
// NewDefaultProjectMetadataManager ...
|
||||||
func NewDefaultProjectMetadataManager() ProjectMetadataManaegr {
|
func NewDefaultProjectMetadataManager() ProjectMetadataManager {
|
||||||
return &defaultProjectMetadataManaegr{}
|
return &defaultProjectMetadataManager{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultProjectMetadataManaegr) Add(projectID int64, meta map[string]string) error {
|
func (d *defaultProjectMetadataManager) Add(projectID int64, meta map[string]string) error {
|
||||||
for k, v := range meta {
|
for k, v := range meta {
|
||||||
proMeta := &models.ProjectMetadata{
|
proMeta := &models.ProjectMetadata{
|
||||||
ProjectID: projectID,
|
ProjectID: projectID,
|
||||||
@ -57,11 +57,11 @@ func (d *defaultProjectMetadataManaegr) Add(projectID int64, meta map[string]str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultProjectMetadataManaegr) Delete(projectID int64, meta ...string) error {
|
func (d *defaultProjectMetadataManager) Delete(projectID int64, meta ...string) error {
|
||||||
return dao.DeleteProjectMetadata(projectID, meta...)
|
return dao.DeleteProjectMetadata(projectID, meta...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultProjectMetadataManaegr) Update(projectID int64, meta map[string]string) error {
|
func (d *defaultProjectMetadataManager) Update(projectID int64, meta map[string]string) error {
|
||||||
for k, v := range meta {
|
for k, v := range meta {
|
||||||
if err := dao.UpdateProjectMetadata(&models.ProjectMetadata{
|
if err := dao.UpdateProjectMetadata(&models.ProjectMetadata{
|
||||||
ProjectID: projectID,
|
ProjectID: projectID,
|
||||||
@ -72,20 +72,10 @@ func (d *defaultProjectMetadataManaegr) Update(projectID int64, meta map[string]
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove the logic
|
|
||||||
public, ok := meta[models.ProMetaPublic]
|
|
||||||
if ok {
|
|
||||||
i, err := strconv.Atoi(public)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return dao.ToggleProjectPublicity(projectID, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultProjectMetadataManaegr) Get(projectID int64, meta ...string) (map[string]string, error) {
|
func (d *defaultProjectMetadataManager) Get(projectID int64, meta ...string) (map[string]string, error) {
|
||||||
proMetas, err := dao.GetProjectMetadata(projectID, meta...)
|
proMetas, err := dao.GetProjectMetadata(projectID, meta...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -98,3 +88,14 @@ func (d *defaultProjectMetadataManaegr) Get(projectID int64, meta ...string) (ma
|
|||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *defaultProjectMetadataManager) List(name, value string) ([]*models.ProjectMetadata, error) {
|
||||||
|
metas := []*models.ProjectMetadata{}
|
||||||
|
mds, err := dao.ListProjectMetadata(name, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
metas = append(metas, mds...)
|
||||||
|
return metas, nil
|
||||||
|
}
|
||||||
|
@ -54,6 +54,12 @@ func TestMetaMgrMethods(t *testing.T) {
|
|||||||
assert.Equal(t, 1, len(m))
|
assert.Equal(t, 1, len(m))
|
||||||
assert.Equal(t, value, m[key])
|
assert.Equal(t, value, m[key])
|
||||||
|
|
||||||
|
// test list
|
||||||
|
metas, err := mgr.List(key, value)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(metas))
|
||||||
|
assert.Equal(t, int64(1), metas[0].ProjectID)
|
||||||
|
|
||||||
// test update
|
// test update
|
||||||
require.Nil(t, mgr.Update(1, map[string]string{
|
require.Nil(t, mgr.Update(1, map[string]string{
|
||||||
key: newValue,
|
key: newValue,
|
||||||
|
@ -30,13 +30,12 @@ import (
|
|||||||
"github.com/vmware/harbor/src/common/utils"
|
"github.com/vmware/harbor/src/common/utils"
|
||||||
er "github.com/vmware/harbor/src/common/utils/error"
|
er "github.com/vmware/harbor/src/common/utils/error"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
|
"github.com/vmware/harbor/src/ui/promgr/pmsdriver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dupProjectPattern = `Project name '\w+' is already used`
|
const dupProjectPattern = `Project name '\w+' is already used`
|
||||||
|
|
||||||
// ProjectManager implements projectmanager.ProjecdtManager interface
|
type driver struct {
|
||||||
// base on project management service
|
|
||||||
type ProjectManager struct {
|
|
||||||
client *http.Client
|
client *http.Client
|
||||||
endpoint string
|
endpoint string
|
||||||
tokenReader TokenReader
|
tokenReader TokenReader
|
||||||
@ -57,10 +56,10 @@ type project struct {
|
|||||||
Guests []*user `json:"viewers"`
|
Guests []*user `json:"viewers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProjectManager returns an instance of ProjectManager
|
// NewDriver returns an instance of driver
|
||||||
func NewProjectManager(client *http.Client, endpoint string,
|
func NewDriver(client *http.Client, endpoint string,
|
||||||
tokenReader TokenReader) *ProjectManager {
|
tokenReader TokenReader) pmsdriver.PMSDriver {
|
||||||
return &ProjectManager{
|
return &driver{
|
||||||
client: client,
|
client: client,
|
||||||
endpoint: strings.TrimRight(endpoint, "/"),
|
endpoint: strings.TrimRight(endpoint, "/"),
|
||||||
tokenReader: tokenReader,
|
tokenReader: tokenReader,
|
||||||
@ -68,8 +67,8 @@ func NewProjectManager(client *http.Client, endpoint string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get ...
|
// Get ...
|
||||||
func (p *ProjectManager) Get(projectIDOrName interface{}) (*models.Project, error) {
|
func (d *driver) Get(projectIDOrName interface{}) (*models.Project, error) {
|
||||||
project, err := p.get(projectIDOrName)
|
project, err := d.get(projectIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -77,10 +76,10 @@ func (p *ProjectManager) Get(projectIDOrName interface{}) (*models.Project, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get Admiral project with Harbor project ID or name
|
// get Admiral project with Harbor project ID or name
|
||||||
func (p *ProjectManager) get(projectIDOrName interface{}) (*project, error) {
|
func (d *driver) get(projectIDOrName interface{}) (*project, error) {
|
||||||
// if token is provided, search project from my projects list first
|
// if token is provided, search project from my projects list first
|
||||||
if len(p.getToken()) != 0 {
|
if len(d.getToken()) != 0 {
|
||||||
project, err := p.getFromMy(projectIDOrName)
|
project, err := d.getFromMy(projectIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -90,18 +89,18 @@ func (p *ProjectManager) get(projectIDOrName interface{}) (*project, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try to get project from public projects list
|
// try to get project from public projects list
|
||||||
return p.getFromPublic(projectIDOrName)
|
return d.getFromPublic(projectIDOrName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// call GET /projects?$filter=xxx eq xxx, the API can only filter projects
|
// call GET /projects?$filter=xxx eq xxx, the API can only filter projects
|
||||||
// which the user is a member of
|
// which the user is a member of
|
||||||
func (p *ProjectManager) getFromMy(projectIDOrName interface{}) (*project, error) {
|
func (d *driver) getFromMy(projectIDOrName interface{}) (*project, error) {
|
||||||
return p.getAdmiralProject(projectIDOrName, false)
|
return d.getAdmiralProject(projectIDOrName, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// call GET /projects?public=true&$filter=xxx eq xxx
|
// call GET /projects?public=true&$filter=xxx eq xxx
|
||||||
func (p *ProjectManager) getFromPublic(projectIDOrName interface{}) (*project, error) {
|
func (d *driver) getFromPublic(projectIDOrName interface{}) (*project, error) {
|
||||||
project, err := p.getAdmiralProject(projectIDOrName, true)
|
project, err := d.getAdmiralProject(projectIDOrName, true)
|
||||||
if project != nil {
|
if project != nil {
|
||||||
// the projects returned by GET /projects?public=true&xxx have no
|
// the projects returned by GET /projects?public=true&xxx have no
|
||||||
// "public" property, populate it here
|
// "public" property, populate it here
|
||||||
@ -110,7 +109,7 @@ func (p *ProjectManager) getFromPublic(projectIDOrName interface{}) (*project, e
|
|||||||
return project, err
|
return project, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProjectManager) getAdmiralProject(projectIDOrName interface{}, public bool) (*project, error) {
|
func (d *driver) getAdmiralProject(projectIDOrName interface{}, public bool) (*project, error) {
|
||||||
m := map[string]string{}
|
m := map[string]string{}
|
||||||
|
|
||||||
id, name, err := utils.ParseProjectIDOrName(projectIDOrName)
|
id, name, err := utils.ParseProjectIDOrName(projectIDOrName)
|
||||||
@ -126,7 +125,7 @@ func (p *ProjectManager) getAdmiralProject(projectIDOrName interface{}, public b
|
|||||||
m["public"] = "true"
|
m["public"] = "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
projects, err := p.filter(m)
|
projects, err := d.filter(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -145,7 +144,7 @@ func (p *ProjectManager) getAdmiralProject(projectIDOrName interface{}, public b
|
|||||||
return projects[0], nil
|
return projects[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProjectManager) filter(m map[string]string) ([]*project, error) {
|
func (d *driver) filter(m map[string]string) ([]*project, error) {
|
||||||
query := ""
|
query := ""
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
if len(query) == 0 {
|
if len(query) == 0 {
|
||||||
@ -165,7 +164,7 @@ func (p *ProjectManager) filter(m map[string]string) ([]*project, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path := "/projects" + query
|
path := "/projects" + query
|
||||||
data, err := p.send(http.MethodGet, path, nil)
|
data, err := d.send(http.MethodGet, path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -201,7 +200,7 @@ func convert(p *project) (*models.Project, error) {
|
|||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
}
|
}
|
||||||
if p.Public {
|
if p.Public {
|
||||||
project.Public = 1
|
project.SetMetadata(models.ProMetaPublic, "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
value := p.CustomProperties["__projectIndex"]
|
value := p.CustomProperties["__projectIndex"]
|
||||||
@ -221,7 +220,7 @@ func convert(p *project) (*models.Project, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse __enableContentTrust %s to bool: %v", value, err)
|
return nil, fmt.Errorf("failed to parse __enableContentTrust %s to bool: %v", value, err)
|
||||||
}
|
}
|
||||||
project.EnableContentTrust = enable
|
project.SetMetadata(models.ProMetaEnableContentTrust, strconv.FormatBool(enable))
|
||||||
}
|
}
|
||||||
|
|
||||||
value = p.CustomProperties["__preventVulnerableImagesFromRunning"]
|
value = p.CustomProperties["__preventVulnerableImagesFromRunning"]
|
||||||
@ -230,12 +229,12 @@ func convert(p *project) (*models.Project, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse __preventVulnerableImagesFromRunning %s to bool: %v", value, err)
|
return nil, fmt.Errorf("failed to parse __preventVulnerableImagesFromRunning %s to bool: %v", value, err)
|
||||||
}
|
}
|
||||||
project.PreventVulnerableImagesFromRunning = prevent
|
project.SetMetadata(models.ProMetaPreventVul, strconv.FormatBool(prevent))
|
||||||
}
|
}
|
||||||
|
|
||||||
value = p.CustomProperties["__preventVulnerableImagesFromRunningSeverity"]
|
value = p.CustomProperties["__preventVulnerableImagesFromRunningSeverity"]
|
||||||
if len(value) != 0 {
|
if len(value) != 0 {
|
||||||
project.PreventVulnerableImagesFromRunningSeverity = value
|
project.SetMetadata(models.ProMetaSeverity, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
value = p.CustomProperties["__automaticallyScanImagesOnPush"]
|
value = p.CustomProperties["__automaticallyScanImagesOnPush"]
|
||||||
@ -244,93 +243,14 @@ func convert(p *project) (*models.Project, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse __automaticallyScanImagesOnPush %s to bool: %v", value, err)
|
return nil, fmt.Errorf("failed to parse __automaticallyScanImagesOnPush %s to bool: %v", value, err)
|
||||||
}
|
}
|
||||||
project.AutomaticallyScanImagesOnPush = scan
|
project.SetMetadata(models.ProMetaAutoScan, strconv.FormatBool(scan))
|
||||||
}
|
}
|
||||||
|
|
||||||
return project, nil
|
return project, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPublic ...
|
func (d *driver) getIDbyHarborIDOrName(projectIDOrName interface{}) (string, error) {
|
||||||
func (p *ProjectManager) IsPublic(projectIDOrName interface{}) (bool, error) {
|
pro, err := d.get(projectIDOrName)
|
||||||
project, err := p.get(projectIDOrName)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if project == nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return project.Public, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exist ...
|
|
||||||
func (p *ProjectManager) Exist(projectIDOrName interface{}) (bool, error) {
|
|
||||||
project, err := p.get(projectIDOrName)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return project != nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// GetRoles gets roles that the user has to the project
|
|
||||||
// This method is used in GET /projects API.
|
|
||||||
// Jobservice calls GET /projects API to get information of source
|
|
||||||
// project when trying to replicate the project. There is no auth
|
|
||||||
// context in this use case, so the method is needed.
|
|
||||||
func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{}) ([]int, error) {
|
|
||||||
if len(username) == 0 || projectIDOrName == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := p.getIDbyHarborIDOrName(projectIDOrName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// get expanded project which contains role info by GET /projects/id?expand=true
|
|
||||||
path := fmt.Sprintf("/projects/%s?expand=true", id)
|
|
||||||
data, err := p.send(http.MethodGet, path, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pro := &project{}
|
|
||||||
if err = json.Unmarshal(data, pro); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
roles := []int{}
|
|
||||||
|
|
||||||
for _, user := range pro.Administrators {
|
|
||||||
if user.Email == username {
|
|
||||||
roles = append(roles, common.RoleProjectAdmin)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range pro.Developers {
|
|
||||||
if user.Email == username {
|
|
||||||
roles = append(roles, common.RoleDeveloper)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range pro.Guests {
|
|
||||||
if user.Email == username {
|
|
||||||
roles = append(roles, common.RoleGuest)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return roles, nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (p *ProjectManager) getIDbyHarborIDOrName(projectIDOrName interface{}) (string, error) {
|
|
||||||
pro, err := p.get(projectIDOrName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -342,32 +262,24 @@ func (p *ProjectManager) getIDbyHarborIDOrName(projectIDOrName interface{}) (str
|
|||||||
return pro.ID, nil
|
return pro.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublic ...
|
|
||||||
func (p *ProjectManager) GetPublic() ([]*models.Project, error) {
|
|
||||||
t := true
|
|
||||||
return p.GetAll(&models.ProjectQueryParam{
|
|
||||||
Public: &t,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ...
|
// Create ...
|
||||||
func (p *ProjectManager) Create(pro *models.Project) (int64, error) {
|
func (d *driver) Create(pro *models.Project) (int64, error) {
|
||||||
proj := &project{
|
proj := &project{
|
||||||
CustomProperties: make(map[string]string),
|
CustomProperties: make(map[string]string),
|
||||||
}
|
}
|
||||||
proj.Name = pro.Name
|
proj.Name = pro.Name
|
||||||
proj.Public = pro.Public == 1
|
proj.Public = pro.IsPublic()
|
||||||
proj.CustomProperties["__enableContentTrust"] = strconv.FormatBool(pro.EnableContentTrust)
|
proj.CustomProperties["__enableContentTrust"] = strconv.FormatBool(pro.ContentTrustEnabled())
|
||||||
proj.CustomProperties["__preventVulnerableImagesFromRunning"] = strconv.FormatBool(pro.PreventVulnerableImagesFromRunning)
|
proj.CustomProperties["__preventVulnerableImagesFromRunning"] = strconv.FormatBool(pro.VulPrevented())
|
||||||
proj.CustomProperties["__preventVulnerableImagesFromRunningSeverity"] = pro.PreventVulnerableImagesFromRunningSeverity
|
proj.CustomProperties["__preventVulnerableImagesFromRunningSeverity"] = pro.Severity()
|
||||||
proj.CustomProperties["__automaticallyScanImagesOnPush"] = strconv.FormatBool(pro.AutomaticallyScanImagesOnPush)
|
proj.CustomProperties["__automaticallyScanImagesOnPush"] = strconv.FormatBool(pro.AutoScan())
|
||||||
|
|
||||||
data, err := json.Marshal(proj)
|
data, err := json.Marshal(proj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := p.send(http.MethodPost, "/projects", bytes.NewBuffer(data))
|
b, err := d.send(http.MethodPost, "/projects", bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// when creating a project with a duplicate name in Admiral, a 500 error
|
// when creating a project with a duplicate name in Admiral, a 500 error
|
||||||
// with a specific message will be returned for now.
|
// with a specific message will be returned for now.
|
||||||
@ -413,23 +325,23 @@ func (p *ProjectManager) Create(pro *models.Project) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete ...
|
// Delete ...
|
||||||
func (p *ProjectManager) Delete(projectIDOrName interface{}) error {
|
func (d *driver) Delete(projectIDOrName interface{}) error {
|
||||||
id, err := p.getIDbyHarborIDOrName(projectIDOrName)
|
id, err := d.getIDbyHarborIDOrName(projectIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = p.send(http.MethodDelete, fmt.Sprintf("/projects/%s", id), nil)
|
_, err = d.send(http.MethodDelete, fmt.Sprintf("/projects/%s", id), nil)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update ...
|
// Update ...
|
||||||
func (p *ProjectManager) Update(projectIDOrName interface{}, project *models.Project) error {
|
func (d *driver) Update(projectIDOrName interface{}, project *models.Project) error {
|
||||||
return errors.New("project update is unsupported")
|
return errors.New("project update is unsupported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAll ...
|
// List ...
|
||||||
func (p *ProjectManager) GetAll(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {
|
func (d *driver) List(query *models.ProjectQueryParam) (*models.ProjectQueryResult, error) {
|
||||||
m := map[string]string{}
|
m := map[string]string{}
|
||||||
if query != nil {
|
if query != nil {
|
||||||
if len(query.Name) > 0 {
|
if len(query.Name) > 0 {
|
||||||
@ -440,7 +352,7 @@ func (p *ProjectManager) GetAll(query *models.ProjectQueryParam, base ...*models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
projects, err := p.filter(m)
|
projects, err := d.filter(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -454,27 +366,24 @@ func (p *ProjectManager) GetAll(query *models.ProjectQueryParam, base ...*models
|
|||||||
list = append(list, project)
|
list = append(list, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
return list, nil
|
return &models.ProjectQueryResult{
|
||||||
|
Total: int64(len(list)),
|
||||||
|
Projects: list,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTotal ...
|
func (d *driver) send(method, path string, body io.Reader) ([]byte, error) {
|
||||||
func (p *ProjectManager) GetTotal(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {
|
req, err := http.NewRequest(method, d.endpoint+path, body)
|
||||||
projects, err := p.GetAll(query)
|
|
||||||
return int64(len(projects)), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectManager) send(method, path string, body io.Reader) ([]byte, error) {
|
|
||||||
req, err := http.NewRequest(method, p.endpoint+path, body)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("x-xenon-auth-token", p.getToken())
|
req.Header.Add("x-xenon-auth-token", d.getToken())
|
||||||
|
|
||||||
url := req.URL.String()
|
url := req.URL.String()
|
||||||
|
|
||||||
req.URL.RawQuery = req.URL.Query().Encode()
|
req.URL.RawQuery = req.URL.Query().Encode()
|
||||||
resp, err := p.client.Do(req)
|
resp, err := d.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("\"%s %s\" failed", req.Method, url)
|
log.Debugf("\"%s %s\" failed", req.Method, url)
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -497,12 +406,12 @@ func (p *ProjectManager) send(method, path string, body io.Reader) ([]byte, erro
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProjectManager) getToken() string {
|
func (d *driver) getToken() string {
|
||||||
if p.tokenReader == nil {
|
if d.tokenReader == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := p.tokenReader.ReadToken()
|
token, err := d.tokenReader.ReadToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
token = ""
|
token = ""
|
||||||
log.Errorf("failed to read token: %v", err)
|
log.Errorf("failed to read token: %v", err)
|
||||||
|
@ -101,12 +101,12 @@ func TestConvert(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, pro)
|
assert.NotNil(t, pro)
|
||||||
assert.Equal(t, "test", pro.Name)
|
assert.Equal(t, "test", pro.Name)
|
||||||
assert.Equal(t, 1, pro.Public)
|
assert.True(t, pro.IsPublic())
|
||||||
assert.Equal(t, int64(1), pro.ProjectID)
|
assert.Equal(t, int64(1), pro.ProjectID)
|
||||||
assert.True(t, pro.EnableContentTrust)
|
assert.True(t, pro.ContentTrustEnabled())
|
||||||
assert.True(t, pro.PreventVulnerableImagesFromRunning)
|
assert.True(t, pro.VulPrevented())
|
||||||
assert.Equal(t, "medium", pro.PreventVulnerableImagesFromRunningSeverity)
|
assert.Equal(t, "medium", pro.Severity())
|
||||||
assert.True(t, pro.AutomaticallyScanImagesOnPush)
|
assert.True(t, pro.AutoScan())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
@ -182,233 +182,130 @@ func TestParse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
func TestGet(t *testing.T) {
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
d := NewDriver(client, endpoint, tokenReader)
|
||||||
name := "project_for_test_get"
|
name := "project_for_test_get"
|
||||||
id, err := pm.Create(&models.Project{
|
id, err := d.Create(&models.Project{
|
||||||
Name: name,
|
Name: name,
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer delete(t, id)
|
defer delete(t, id)
|
||||||
|
|
||||||
// get by invalid input type
|
// get by invalid input type
|
||||||
_, err = pm.Get([]string{})
|
_, err = d.Get([]string{})
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
// get by invalid ID
|
// get by invalid ID
|
||||||
project, err := pm.Get(int64(0))
|
project, err := d.Get(int64(0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, project)
|
assert.Nil(t, project)
|
||||||
|
|
||||||
// get by invalid name
|
// get by invalid name
|
||||||
project, err = pm.Get("invalid_name")
|
project, err = d.Get("invalid_name")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, project)
|
assert.Nil(t, project)
|
||||||
|
|
||||||
// get by valid ID
|
// get by valid ID
|
||||||
project, err = pm.Get(id)
|
project, err = d.Get(id)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, id, project.ProjectID)
|
assert.Equal(t, id, project.ProjectID)
|
||||||
|
|
||||||
// get by valid name
|
// get by valid name
|
||||||
project, err = pm.Get(name)
|
project, err = d.Get(name)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, id, project.ProjectID)
|
assert.Equal(t, id, project.ProjectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsPublic(t *testing.T) {
|
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
|
||||||
|
|
||||||
// invalid input type
|
|
||||||
public, err := pm.IsPublic([]string{})
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.False(t, public)
|
|
||||||
|
|
||||||
// non-exist project
|
|
||||||
public, err = pm.IsPublic(int64(2))
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.False(t, public)
|
|
||||||
|
|
||||||
// public project
|
|
||||||
name := "project_for_pm_based_on_pms_public"
|
|
||||||
id, err := pm.Create(&models.Project{
|
|
||||||
Name: name,
|
|
||||||
Public: 1,
|
|
||||||
})
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer delete(t, id)
|
|
||||||
|
|
||||||
public, err = pm.IsPublic(id)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, public)
|
|
||||||
|
|
||||||
public, err = pm.IsPublic(name)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, public)
|
|
||||||
|
|
||||||
// private project
|
|
||||||
name = "project_for_pm_based_on_pms_private"
|
|
||||||
id, err = pm.Create(&models.Project{
|
|
||||||
Name: name,
|
|
||||||
Public: 0,
|
|
||||||
})
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer delete(t, id)
|
|
||||||
|
|
||||||
public, err = pm.IsPublic(id)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.False(t, public)
|
|
||||||
|
|
||||||
public, err = pm.IsPublic(name)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.False(t, public)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExist(t *testing.T) {
|
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
|
||||||
|
|
||||||
// invalid input type
|
|
||||||
exist, err := pm.Exist([]string{})
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.False(t, exist)
|
|
||||||
|
|
||||||
// non-exist project
|
|
||||||
exist, err = pm.Exist(int64(2))
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.False(t, exist)
|
|
||||||
|
|
||||||
// exist project
|
|
||||||
name := "project_for_test_exist"
|
|
||||||
id, err := pm.Create(&models.Project{
|
|
||||||
Name: name,
|
|
||||||
})
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer delete(t, id)
|
|
||||||
|
|
||||||
exist, err = pm.Exist(id)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, exist)
|
|
||||||
|
|
||||||
exist, err = pm.Exist(name)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, exist)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetPublic(t *testing.T) {
|
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
|
||||||
|
|
||||||
projects, err := pm.GetPublic()
|
|
||||||
assert.Nil(t, nil)
|
|
||||||
size := len(projects)
|
|
||||||
|
|
||||||
name := "project_for_test_get_public"
|
|
||||||
id, err := pm.Create(&models.Project{
|
|
||||||
Name: name,
|
|
||||||
Public: 1,
|
|
||||||
})
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer delete(t, id)
|
|
||||||
|
|
||||||
projects, err = pm.GetPublic()
|
|
||||||
assert.Nil(t, nil)
|
|
||||||
assert.Equal(t, size+1, len(projects))
|
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, project := range projects {
|
|
||||||
if project.ProjectID == id {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert.True(t, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
d := NewDriver(client, endpoint, tokenReader)
|
||||||
|
|
||||||
name := "project_for_test_create"
|
name := "project_for_test_create"
|
||||||
id, err := pm.Create(&models.Project{
|
id, err := d.Create(&models.Project{
|
||||||
Name: name,
|
Name: name,
|
||||||
Public: 1,
|
Metadata: map[string]string{
|
||||||
EnableContentTrust: true,
|
models.ProMetaPublic: "true",
|
||||||
PreventVulnerableImagesFromRunning: true,
|
models.ProMetaEnableContentTrust: "true",
|
||||||
PreventVulnerableImagesFromRunningSeverity: "medium",
|
models.ProMetaPreventVul: "true",
|
||||||
AutomaticallyScanImagesOnPush: true,
|
models.ProMetaSeverity: "medium",
|
||||||
|
models.ProMetaAutoScan: "true",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer delete(t, id)
|
defer delete(t, id)
|
||||||
|
|
||||||
project, err := pm.Get(id)
|
project, err := d.Get(id)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, name, project.Name)
|
assert.Equal(t, name, project.Name)
|
||||||
assert.Equal(t, 1, project.Public)
|
assert.True(t, project.IsPublic())
|
||||||
assert.True(t, project.EnableContentTrust)
|
assert.True(t, project.ContentTrustEnabled())
|
||||||
assert.True(t, project.PreventVulnerableImagesFromRunning)
|
assert.True(t, project.VulPrevented())
|
||||||
assert.Equal(t, "medium", project.PreventVulnerableImagesFromRunningSeverity)
|
assert.Equal(t, "medium", project.Severity())
|
||||||
assert.True(t, project.AutomaticallyScanImagesOnPush)
|
assert.True(t, project.AutoScan())
|
||||||
|
|
||||||
// duplicate project name
|
// duplicate project name
|
||||||
_, err = pm.Create(&models.Project{
|
_, err = d.Create(&models.Project{
|
||||||
Name: name,
|
Name: name,
|
||||||
})
|
})
|
||||||
assert.Equal(t, errutil.ErrDupProject, err)
|
assert.Equal(t, errutil.ErrDupProject, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDelete(t *testing.T) {
|
func TestDelete(t *testing.T) {
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
d := NewDriver(client, endpoint, tokenReader)
|
||||||
|
|
||||||
// non-exist project
|
// non-exist project
|
||||||
err := pm.Delete(int64(0))
|
err := d.Delete(int64(0))
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
// delete by ID
|
// delete by ID
|
||||||
name := "project_for_pm_based_on_pms_id"
|
name := "project_for_pm_based_on_pms_id"
|
||||||
id, err := pm.Create(&models.Project{
|
id, err := d.Create(&models.Project{
|
||||||
Name: name,
|
Name: name,
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
err = pm.Delete(id)
|
err = d.Delete(id)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// delete by name
|
// delete by name
|
||||||
name = "project_for_pm_based_on_pms_name"
|
name = "project_for_pm_based_on_pms_name"
|
||||||
id, err = pm.Create(&models.Project{
|
id, err = d.Create(&models.Project{
|
||||||
Name: name,
|
Name: name,
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
err = pm.Delete(name)
|
err = d.Delete(name)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdate(t *testing.T) {
|
func TestUpdate(t *testing.T) {
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
d := NewDriver(client, endpoint, tokenReader)
|
||||||
err := pm.Update(nil, nil)
|
err := d.Update(nil, nil)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAll(t *testing.T) {
|
func TestList(t *testing.T) {
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
d := NewDriver(client, endpoint, tokenReader)
|
||||||
|
|
||||||
name1 := "project_for_test_get_all_01"
|
name1 := "project_for_test_get_all_01"
|
||||||
id1, err := pm.Create(&models.Project{
|
id1, err := d.Create(&models.Project{
|
||||||
Name: name1,
|
Name: name1,
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer delete(t, id1)
|
defer delete(t, id1)
|
||||||
|
|
||||||
name2 := "project_for_test_get_all_02"
|
name2 := "project_for_test_get_all_02"
|
||||||
id2, err := pm.Create(&models.Project{
|
id2, err := d.Create(&models.Project{
|
||||||
Name: name2,
|
Name: name2,
|
||||||
Public: 1,
|
Metadata: map[string]string{
|
||||||
|
models.ProMetaPublic: "true",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer delete(t, id2)
|
defer delete(t, id2)
|
||||||
|
|
||||||
// no filter
|
// no filter
|
||||||
projects, err := pm.GetAll(nil)
|
result, err := d.List(nil)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
found1 := false
|
found1 := false
|
||||||
found2 := false
|
found2 := false
|
||||||
for _, project := range projects {
|
for _, project := range result.Projects {
|
||||||
if project.ProjectID == id1 {
|
if project.ProjectID == id1 {
|
||||||
found1 = true
|
found1 = true
|
||||||
}
|
}
|
||||||
@ -420,12 +317,12 @@ func TestGetAll(t *testing.T) {
|
|||||||
assert.True(t, found2)
|
assert.True(t, found2)
|
||||||
|
|
||||||
// filter by name
|
// filter by name
|
||||||
projects, err = pm.GetAll(&models.ProjectQueryParam{
|
result, err = d.List(&models.ProjectQueryParam{
|
||||||
Name: name1,
|
Name: name1,
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
found1 = false
|
found1 = false
|
||||||
for _, project := range projects {
|
for _, project := range result.Projects {
|
||||||
if project.ProjectID == id1 {
|
if project.ProjectID == id1 {
|
||||||
found1 = true
|
found1 = true
|
||||||
break
|
break
|
||||||
@ -435,12 +332,12 @@ func TestGetAll(t *testing.T) {
|
|||||||
|
|
||||||
// filter by public
|
// filter by public
|
||||||
value := true
|
value := true
|
||||||
projects, err = pm.GetAll(&models.ProjectQueryParam{
|
result, err = d.List(&models.ProjectQueryParam{
|
||||||
Public: &value,
|
Public: &value,
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
found2 = false
|
found2 = false
|
||||||
for _, project := range projects {
|
for _, project := range result.Projects {
|
||||||
if project.ProjectID == id2 {
|
if project.ProjectID == id2 {
|
||||||
found2 = true
|
found2 = true
|
||||||
break
|
break
|
||||||
@ -449,27 +346,9 @@ func TestGetAll(t *testing.T) {
|
|||||||
assert.True(t, found2)
|
assert.True(t, found2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTotal(t *testing.T) {
|
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
|
||||||
|
|
||||||
total1, err := pm.GetTotal(nil)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
name := "project_for_test_get_total"
|
|
||||||
id, err := pm.Create(&models.Project{
|
|
||||||
Name: name,
|
|
||||||
})
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer delete(t, id)
|
|
||||||
|
|
||||||
total2, err := pm.GetTotal(nil)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, total1+1, total2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete(t *testing.T, id int64) {
|
func delete(t *testing.T, id int64) {
|
||||||
pm := NewProjectManager(client, endpoint, tokenReader)
|
d := NewDriver(client, endpoint, tokenReader)
|
||||||
if err := pm.Delete(id); err != nil {
|
if err := d.Delete(id); err != nil {
|
||||||
t.Logf("failed to delete project %d: %v", id, err)
|
t.Logf("failed to delete project %d: %v", id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,5 @@ type PMSDriver interface {
|
|||||||
// Update the properties of a project
|
// Update the properties of a project
|
||||||
Update(projectIDOrName interface{}, project *models.Project) error
|
Update(projectIDOrName interface{}, project *models.Project) error
|
||||||
// List lists projects according to the query conditions
|
// List lists projects according to the query conditions
|
||||||
// TODO remove base
|
List(query *models.ProjectQueryParam) (*models.ProjectQueryResult, error)
|
||||||
List(query *models.ProjectQueryParam,
|
|
||||||
base ...*models.BaseProjectCollection) (*models.ProjectQueryResult, error)
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,6 @@ func (d *driver) Create(project *models.Project) (int64, error) {
|
|||||||
t := time.Now()
|
t := time.Now()
|
||||||
pro := &models.Project{
|
pro := &models.Project{
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
Public: project.Public,
|
|
||||||
OwnerID: project.OwnerID,
|
OwnerID: project.OwnerID,
|
||||||
CreationTime: t,
|
CreationTime: t,
|
||||||
UpdateTime: t,
|
UpdateTime: t,
|
||||||
@ -129,16 +128,15 @@ func (d *driver) Update(projectIDOrName interface{},
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove base
|
|
||||||
// List returns a project list according to the query parameters
|
// List returns a project list according to the query parameters
|
||||||
func (d *driver) List(query *models.ProjectQueryParam,
|
func (d *driver) List(query *models.ProjectQueryParam) (
|
||||||
base ...*models.BaseProjectCollection) (
|
|
||||||
*models.ProjectQueryResult, error) {
|
*models.ProjectQueryResult, error) {
|
||||||
total, err := dao.GetTotalOfProjects(query, base...)
|
total, err := dao.GetTotalOfProjects(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
projects, err := dao.GetProjects(query, base...)
|
|
||||||
|
projects, err := dao.GetProjects(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,9 @@ func TestList(t *testing.T) {
|
|||||||
id, err := pm.Create(&models.Project{
|
id, err := pm.Create(&models.Project{
|
||||||
Name: "get_all_test",
|
Name: "get_all_test",
|
||||||
OwnerID: 1,
|
OwnerID: 1,
|
||||||
Public: 1,
|
Metadata: map[string]string{
|
||||||
|
models.ProMetaPublic: "true",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
defer pm.Delete(id)
|
defer pm.Delete(id)
|
||||||
|
@ -16,6 +16,7 @@ package promgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
@ -30,9 +31,7 @@ type ProjectManager interface {
|
|||||||
Create(*models.Project) (int64, error)
|
Create(*models.Project) (int64, error)
|
||||||
Delete(projectIDOrName interface{}) error
|
Delete(projectIDOrName interface{}) error
|
||||||
Update(projectIDOrName interface{}, project *models.Project) error
|
Update(projectIDOrName interface{}, project *models.Project) error
|
||||||
// TODO remove base
|
List(query *models.ProjectQueryParam) (*models.ProjectQueryResult, error)
|
||||||
List(query *models.ProjectQueryParam,
|
|
||||||
base ...*models.BaseProjectCollection) (*models.ProjectQueryResult, error)
|
|
||||||
IsPublic(projectIDOrName interface{}) (bool, error)
|
IsPublic(projectIDOrName interface{}) (bool, error)
|
||||||
Exists(projectIDOrName interface{}) (bool, error)
|
Exists(projectIDOrName interface{}) (bool, error)
|
||||||
// get all public project
|
// get all public project
|
||||||
@ -42,7 +41,7 @@ type ProjectManager interface {
|
|||||||
type defaultProjectManager struct {
|
type defaultProjectManager struct {
|
||||||
pmsDriver pmsdriver.PMSDriver
|
pmsDriver pmsdriver.PMSDriver
|
||||||
metaMgrEnabled bool // if metaMgrEnabled is enabled, metaMgr will be used to CURD metadata
|
metaMgrEnabled bool // if metaMgrEnabled is enabled, metaMgr will be used to CURD metadata
|
||||||
metaMgr metamgr.ProjectMetadataManaegr
|
metaMgr metamgr.ProjectMetadataManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultProjectManager returns an instance of defaultProjectManager,
|
// NewDefaultProjectManager returns an instance of defaultProjectManager,
|
||||||
@ -117,7 +116,25 @@ func (d *defaultProjectManager) Update(projectIDOrName interface{}, project *mod
|
|||||||
if pro == nil {
|
if pro == nil {
|
||||||
return fmt.Errorf("project %v not found", projectIDOrName)
|
return fmt.Errorf("project %v not found", projectIDOrName)
|
||||||
}
|
}
|
||||||
if err = d.metaMgr.Update(pro.ProjectID, project.Metadata); err != nil {
|
|
||||||
|
// TODO transaction?
|
||||||
|
metaNeedUpdated := map[string]string{}
|
||||||
|
metaNeedCreated := map[string]string{}
|
||||||
|
if pro.Metadata == nil {
|
||||||
|
pro.Metadata = map[string]string{}
|
||||||
|
}
|
||||||
|
for key, value := range project.Metadata {
|
||||||
|
_, exist := pro.Metadata[key]
|
||||||
|
if exist {
|
||||||
|
metaNeedUpdated[key] = value
|
||||||
|
} else {
|
||||||
|
metaNeedCreated[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = d.metaMgr.Add(pro.ProjectID, metaNeedCreated); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = d.metaMgr.Update(pro.ProjectID, metaNeedUpdated); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,13 +142,32 @@ func (d *defaultProjectManager) Update(projectIDOrName interface{}, project *mod
|
|||||||
return d.pmsDriver.Update(projectIDOrName, project)
|
return d.pmsDriver.Update(projectIDOrName, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove base
|
func (d *defaultProjectManager) List(query *models.ProjectQueryParam) (*models.ProjectQueryResult, error) {
|
||||||
func (d *defaultProjectManager) List(query *models.ProjectQueryParam,
|
// query by public/private property with ProjectMetadataManager first
|
||||||
base ...*models.BaseProjectCollection) (*models.ProjectQueryResult, error) {
|
if d.metaMgrEnabled && query != nil && query.Public != nil {
|
||||||
result, err := d.pmsDriver.List(query, base...)
|
projectIDs, err := d.filterByPublic(*query.Public)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(projectIDs) == 0 {
|
||||||
|
return &models.ProjectQueryResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.ProjectIDs == nil {
|
||||||
|
query.ProjectIDs = projectIDs
|
||||||
|
} else {
|
||||||
|
query.ProjectIDs = findInBoth(query.ProjectIDs, projectIDs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// query by other properties
|
||||||
|
result, err := d.pmsDriver.List(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate metadata
|
||||||
if d.metaMgrEnabled {
|
if d.metaMgrEnabled {
|
||||||
for _, project := range result.Projects {
|
for _, project := range result.Projects {
|
||||||
meta, err := d.metaMgr.Get(project.ProjectID)
|
meta, err := d.metaMgr.Get(project.ProjectID)
|
||||||
@ -144,6 +180,35 @@ func (d *defaultProjectManager) List(query *models.ProjectQueryParam,
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *defaultProjectManager) filterByPublic(public bool) ([]int64, error) {
|
||||||
|
metas, err := d.metaMgr.List(models.ProMetaPublic, strconv.FormatBool(public))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
projectIDs := []int64{}
|
||||||
|
for _, meta := range metas {
|
||||||
|
projectIDs = append(projectIDs, meta.ProjectID)
|
||||||
|
}
|
||||||
|
return projectIDs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInBoth(ids1 []int64, ids2 []int64) []int64 {
|
||||||
|
m := map[int64]struct{}{}
|
||||||
|
for _, id := range ids1 {
|
||||||
|
m[id] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ids := []int64{}
|
||||||
|
for _, id := range ids2 {
|
||||||
|
if _, exist := m[id]; exist {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
func (d *defaultProjectManager) IsPublic(projectIDOrName interface{}) (bool, error) {
|
func (d *defaultProjectManager) IsPublic(projectIDOrName interface{}) (bool, error) {
|
||||||
project, err := d.Get(projectIDOrName)
|
project, err := d.Get(projectIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -152,7 +217,7 @@ func (d *defaultProjectManager) IsPublic(projectIDOrName interface{}) (bool, err
|
|||||||
if project == nil {
|
if project == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return project.Public == 1, nil
|
return project.IsPublic(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultProjectManager) Exists(projectIDOrName interface{}) (bool, error) {
|
func (d *defaultProjectManager) Exists(projectIDOrName interface{}) (bool, error) {
|
||||||
|
@ -32,7 +32,9 @@ func newFakePMSDriver() pmsdriver.PMSDriver {
|
|||||||
project: &models.Project{
|
project: &models.Project{
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
Name: "library",
|
Name: "library",
|
||||||
Public: 1,
|
Metadata: map[string]string{
|
||||||
|
models.ProMetaPublic: "true",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,8 +55,7 @@ func (f *fakePMSDriver) Update(projectIDOrName interface{}, project *models.Proj
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakePMSDriver) List(query *models.ProjectQueryParam,
|
func (f *fakePMSDriver) List(query *models.ProjectQueryParam) (*models.ProjectQueryResult, error) {
|
||||||
base ...*models.BaseProjectCollection) (*models.ProjectQueryResult, error) {
|
|
||||||
return &models.ProjectQueryResult{
|
return &models.ProjectQueryResult{
|
||||||
Total: 1,
|
Total: 1,
|
||||||
Projects: []*models.Project{f.project},
|
Projects: []*models.Project{f.project},
|
||||||
@ -116,5 +117,5 @@ func TestGetPublic(t *testing.T) {
|
|||||||
projects, err := proMgr.GetPublic()
|
projects, err := proMgr.GetPublic()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(projects))
|
assert.Equal(t, 1, len(projects))
|
||||||
assert.Equal(t, 1, projects[0].Public)
|
assert.True(t, projects[0].IsPublic())
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
//"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/vmware/harbor/src/adminserver/client"
|
"github.com/vmware/harbor/src/adminserver/client"
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
notarytest "github.com/vmware/harbor/src/common/utils/notary/test"
|
notarytest "github.com/vmware/harbor/src/common/utils/notary/test"
|
||||||
utilstest "github.com/vmware/harbor/src/common/utils/test"
|
utilstest "github.com/vmware/harbor/src/common/utils/test"
|
||||||
"github.com/vmware/harbor/src/ui/config"
|
"github.com/vmware/harbor/src/ui/config"
|
||||||
//"github.com/vmware/harbor/src/ui/promgr/pmsdriver/admiral"
|
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@ -110,33 +110,19 @@ func TestMatchListRepos(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvPolicyChecker(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
if err := os.Setenv("PROJECT_CONTENT_TRUST", "1"); err != nil {
|
|
||||||
t.Fatalf("Failed to set env variable: %v", err)
|
|
||||||
}
|
|
||||||
if err2 := os.Setenv("PROJECT_VULNERABLE", "1"); err2 != nil {
|
|
||||||
t.Fatalf("Failed to set env variable: %v", err2)
|
|
||||||
}
|
|
||||||
if err3 := os.Setenv("PROJECT_SEVERITY", "negligible"); err3 != nil {
|
|
||||||
t.Fatalf("Failed to set env variable: %v", err3)
|
|
||||||
}
|
|
||||||
contentTrustFlag := getPolicyChecker().contentTrustEnabled("whatever")
|
|
||||||
vulFlag, sev := getPolicyChecker().vulnerablePolicy("whatever")
|
|
||||||
assert.True(contentTrustFlag)
|
|
||||||
assert.True(vulFlag)
|
|
||||||
assert.Equal(sev, models.SevNone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO uncheck after admiral pms driver is implemented
|
|
||||||
/*
|
|
||||||
func TestPMSPolicyChecker(t *testing.T) {
|
func TestPMSPolicyChecker(t *testing.T) {
|
||||||
var defaultConfigAdmiral = map[string]interface{}{
|
var defaultConfigAdmiral = map[string]interface{}{
|
||||||
common.ExtEndpoint: "https://" + endpoint,
|
common.ExtEndpoint: "https://" + endpoint,
|
||||||
common.WithNotary: true,
|
common.WithNotary: true,
|
||||||
common.CfgExpiration: 5,
|
common.CfgExpiration: 5,
|
||||||
common.AdmiralEndpoint: admiralEndpoint,
|
|
||||||
common.TokenExpiration: 30,
|
common.TokenExpiration: 30,
|
||||||
|
common.DatabaseType: "mysql",
|
||||||
|
common.MySQLHost: "127.0.0.1",
|
||||||
|
common.MySQLPort: 3306,
|
||||||
|
common.MySQLUsername: "root",
|
||||||
|
common.MySQLPassword: "root123",
|
||||||
|
common.MySQLDatabase: "registry",
|
||||||
|
common.SQLiteFile: "/tmp/registry.db",
|
||||||
}
|
}
|
||||||
adminServer, err := utilstest.NewAdminserver(defaultConfigAdmiral)
|
adminServer, err := utilstest.NewAdminserver(defaultConfigAdmiral)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,34 +135,38 @@ func TestPMSPolicyChecker(t *testing.T) {
|
|||||||
if err := config.Init(); err != nil {
|
if err := config.Init(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
pm := admiral.NewProjectManager(http.DefaultClient,
|
database, err := config.Database()
|
||||||
admiralEndpoint, &admiral.RawTokenReader{
|
if err != nil {
|
||||||
Token: "token",
|
panic(err)
|
||||||
})
|
}
|
||||||
|
if err := dao.InitDatabase(database); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
name := "project_for_test_get_sev_low"
|
name := "project_for_test_get_sev_low"
|
||||||
id, err := pm.Create(&models.Project{
|
id, err := config.GlobalProjectMgr.Create(&models.Project{
|
||||||
Name: name,
|
Name: name,
|
||||||
EnableContentTrust: true,
|
OwnerID: 1,
|
||||||
PreventVulnerableImagesFromRunning: false,
|
Metadata: map[string]string{
|
||||||
PreventVulnerableImagesFromRunningSeverity: "low",
|
models.ProMetaEnableContentTrust: "true",
|
||||||
|
models.ProMetaPreventVul: "true",
|
||||||
|
models.ProMetaSeverity: "low",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer func(id int64) {
|
defer func(id int64) {
|
||||||
if err := pm.Delete(id); err != nil {
|
if err := config.GlobalProjectMgr.Delete(id); err != nil {
|
||||||
t.Logf("failed to delete project %d: %v", id, err)
|
t.Logf("failed to delete project %d: %v", id, err)
|
||||||
}
|
}
|
||||||
}(id)
|
}(id)
|
||||||
project, err := pm.Get(id)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, id, project.ProjectID)
|
|
||||||
|
|
||||||
contentTrustFlag := getPolicyChecker().contentTrustEnabled("project_for_test_get_sev_low")
|
contentTrustFlag := getPolicyChecker().contentTrustEnabled("project_for_test_get_sev_low")
|
||||||
assert.True(t, contentTrustFlag)
|
assert.True(t, contentTrustFlag)
|
||||||
projectVulnerableEnabled, projectVulnerableSeverity := getPolicyChecker().vulnerablePolicy("project_for_test_get_sev_low")
|
projectVulnerableEnabled, projectVulnerableSeverity := getPolicyChecker().vulnerablePolicy("project_for_test_get_sev_low")
|
||||||
assert.False(t, projectVulnerableEnabled)
|
assert.True(t, projectVulnerableEnabled)
|
||||||
assert.Equal(t, projectVulnerableSeverity, models.SevLow)
|
assert.Equal(t, projectVulnerableSeverity, models.SevLow)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
func TestMatchNotaryDigest(t *testing.T) {
|
func TestMatchNotaryDigest(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
//The data from common/utils/notary/helper_test.go
|
//The data from common/utils/notary/helper_test.go
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -38,9 +37,6 @@ var rec *httptest.ResponseRecorder
|
|||||||
// NotaryEndpoint , exported for testing.
|
// NotaryEndpoint , exported for testing.
|
||||||
var NotaryEndpoint = config.InternalNotaryEndpoint()
|
var NotaryEndpoint = config.InternalNotaryEndpoint()
|
||||||
|
|
||||||
// EnvChecker is the instance of envPolicyChecker
|
|
||||||
var EnvChecker = envPolicyChecker{}
|
|
||||||
|
|
||||||
// MatchPullManifest checks if the request looks like a request to pull manifest. If it is returns the image and tag/sha256 digest as 2nd and 3rd return values
|
// MatchPullManifest checks if the request looks like a request to pull manifest. If it is returns the image and tag/sha256 digest as 2nd and 3rd return values
|
||||||
func MatchPullManifest(req *http.Request) (bool, string, string) {
|
func MatchPullManifest(req *http.Request) (bool, string, string) {
|
||||||
//TODO: add user agent check.
|
//TODO: add user agent check.
|
||||||
@ -77,16 +73,6 @@ type policyChecker interface {
|
|||||||
vulnerablePolicy(name string) (bool, models.Severity)
|
vulnerablePolicy(name string) (bool, models.Severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
//For testing
|
|
||||||
type envPolicyChecker struct{}
|
|
||||||
|
|
||||||
func (ec envPolicyChecker) contentTrustEnabled(name string) bool {
|
|
||||||
return os.Getenv("PROJECT_CONTENT_TRUST") == "1"
|
|
||||||
}
|
|
||||||
func (ec envPolicyChecker) vulnerablePolicy(name string) (bool, models.Severity) {
|
|
||||||
return os.Getenv("PROJECT_VULNERABLE") == "1", clair.ParseClairSev(os.Getenv("PROJECT_SEVERITY"))
|
|
||||||
}
|
|
||||||
|
|
||||||
type pmsPolicyChecker struct {
|
type pmsPolicyChecker struct {
|
||||||
pm promgr.ProjectManager
|
pm promgr.ProjectManager
|
||||||
}
|
}
|
||||||
@ -97,7 +83,7 @@ func (pc pmsPolicyChecker) contentTrustEnabled(name string) bool {
|
|||||||
log.Errorf("Unexpected error when getting the project, error: %v", err)
|
log.Errorf("Unexpected error when getting the project, error: %v", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return project.EnableContentTrust
|
return project.ContentTrustEnabled()
|
||||||
}
|
}
|
||||||
func (pc pmsPolicyChecker) vulnerablePolicy(name string) (bool, models.Severity) {
|
func (pc pmsPolicyChecker) vulnerablePolicy(name string) (bool, models.Severity) {
|
||||||
project, err := pc.pm.Get(name)
|
project, err := pc.pm.Get(name)
|
||||||
@ -105,7 +91,7 @@ func (pc pmsPolicyChecker) vulnerablePolicy(name string) (bool, models.Severity)
|
|||||||
log.Errorf("Unexpected error when getting the project, error: %v", err)
|
log.Errorf("Unexpected error when getting the project, error: %v", err)
|
||||||
return true, models.SevUnknown
|
return true, models.SevUnknown
|
||||||
}
|
}
|
||||||
return project.PreventVulnerableImagesFromRunning, clair.ParseClairSev(project.PreventVulnerableImagesFromRunningSeverity)
|
return project.VulPrevented(), clair.ParseClairSev(project.Severity())
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPMSPolicyChecker returns an instance of an pmsPolicyChecker
|
// newPMSPolicyChecker returns an instance of an pmsPolicyChecker
|
||||||
@ -116,11 +102,8 @@ func newPMSPolicyChecker(pm promgr.ProjectManager) policyChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPolicyChecker() policyChecker {
|
func getPolicyChecker() policyChecker {
|
||||||
if config.WithAdmiral() {
|
|
||||||
return newPMSPolicyChecker(config.GlobalProjectMgr)
|
return newPMSPolicyChecker(config.GlobalProjectMgr)
|
||||||
}
|
}
|
||||||
return EnvChecker
|
|
||||||
}
|
|
||||||
|
|
||||||
type imageInfo struct {
|
type imageInfo struct {
|
||||||
repository string
|
repository string
|
||||||
|
@ -70,7 +70,6 @@ func initRouters() {
|
|||||||
beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &api.ProjectMemberAPI{})
|
beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &api.ProjectMemberAPI{})
|
||||||
beego.Router("/api/projects/", &api.ProjectAPI{}, "head:Head")
|
beego.Router("/api/projects/", &api.ProjectAPI{}, "head:Head")
|
||||||
beego.Router("/api/projects/:id([0-9]+)", &api.ProjectAPI{})
|
beego.Router("/api/projects/:id([0-9]+)", &api.ProjectAPI{})
|
||||||
beego.Router("/api/projects/:id([0-9]+)/publicity", &api.ProjectAPI{}, "put:ToggleProjectPublic")
|
|
||||||
|
|
||||||
beego.Router("/api/users/:id", &api.UserAPI{}, "get:Get;delete:Delete;put:Put")
|
beego.Router("/api/users/:id", &api.UserAPI{}, "get:Get;delete:Delete;put:Put")
|
||||||
beego.Router("/api/users", &api.UserAPI{}, "get:List;post:Post")
|
beego.Router("/api/users", &api.UserAPI{}, "get:List;post:Post")
|
||||||
|
@ -16,7 +16,6 @@ package registry
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -170,10 +169,8 @@ func autoScanEnabled(project *models.Project) bool {
|
|||||||
log.Debugf("Auto Scan disabled because Harbor is not deployed with Clair")
|
log.Debugf("Auto Scan disabled because Harbor is not deployed with Clair")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if config.WithAdmiral() {
|
|
||||||
return project.AutomaticallyScanImagesOnPush
|
return project.AutoScan()
|
||||||
}
|
|
||||||
return os.Getenv("ENABLE_HARBOR_SCAN_ON_PUSH") == "1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render returns nil as it won't render any template.
|
// Render returns nil as it won't render any template.
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<div class="form-group" style="padding-left: 135px;">
|
<div class="form-group" style="padding-left: 135px;">
|
||||||
<label class="col-md-4 form-group-label-override">{{'PROJECT.ACCESS_LEVEL' | translate}}</label>
|
<label class="col-md-4 form-group-label-override">{{'PROJECT.ACCESS_LEVEL' | translate}}</label>
|
||||||
<div class="checkbox-inline">
|
<div class="checkbox-inline">
|
||||||
<input type="checkbox" id="create_project_public" [(ngModel)]="project.public" name="public">
|
<input type="checkbox" id="create_project_public" [(ngModel)]="project.metadata.public" name="public">
|
||||||
<label for="create_project_public"></label>
|
<label for="create_project_public"></label>
|
||||||
<span class="access-level-label">{{ accessLevelDisplayText | translate}}</span>
|
<span class="access-level-label">{{ accessLevelDisplayText | translate}}</span>
|
||||||
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-md tooltip-bottom-right" style="top:-8px; left:-8px;">
|
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-md tooltip-bottom-right" style="top:-8px; left:-8px;">
|
||||||
|
@ -73,7 +73,7 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
private messageHandlerService: MessageHandlerService) { }
|
private messageHandlerService: MessageHandlerService) { }
|
||||||
|
|
||||||
public get accessLevelDisplayText(): string {
|
public get accessLevelDisplayText(): string {
|
||||||
return this.project.public ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE';
|
return this.project.metadata.public ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE';
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@ -115,7 +115,7 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
|
|
||||||
this.isSubmitOnGoing=true;
|
this.isSubmitOnGoing=true;
|
||||||
this.projectService
|
this.projectService
|
||||||
.createProject(this.project.name, this.project.public ? 1 : 0)
|
.createProject(this.project.name, this.project.metadata)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
status => {
|
status => {
|
||||||
this.isSubmitOnGoing=false;
|
this.isSubmitOnGoing=false;
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
<clr-dg-row *ngFor="let p of projects">
|
<clr-dg-row *ngFor="let p of projects">
|
||||||
<clr-dg-action-overflow [hidden]="!(p.current_user_role_id === 1 || isSystemAdmin)">
|
<clr-dg-action-overflow [hidden]="!(p.current_user_role_id === 1 || isSystemAdmin)">
|
||||||
<button class="action-item" (click)="newReplicationRule(p)" [hidden]="!isSystemAdmin">{{'PROJECT.REPLICATION_RULE' | translate}}</button>
|
<button class="action-item" (click)="newReplicationRule(p)" [hidden]="!isSystemAdmin">{{'PROJECT.REPLICATION_RULE' | translate}}</button>
|
||||||
<button class="action-item" (click)="toggleProject(p)">{{'PROJECT.MAKE' | translate}} {{(p.public === 0 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} </button>
|
<button class="action-item" (click)="toggleProject(p)">{{'PROJECT.MAKE' | translate}} {{(p.metadata.public === 'false' ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} </button>
|
||||||
<button class="action-item" (click)="deleteProject(p)">{{'PROJECT.DELETE' | translate}}</button>
|
<button class="action-item" (click)="deleteProject(p)">{{'PROJECT.DELETE' | translate}}</button>
|
||||||
</clr-dg-action-overflow>
|
</clr-dg-action-overflow>
|
||||||
<clr-dg-cell><a href="javascript:void(0)" (click)="goToLink(p.project_id)">{{p.name}}</a></clr-dg-cell>
|
<clr-dg-cell><a href="javascript:void(0)" (click)="goToLink(p.project_id)">{{p.name}}</a></clr-dg-cell>
|
||||||
<clr-dg-cell>{{ (p.public === 1 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}}</clr-dg-cell>
|
<clr-dg-cell>{{ (p.metadata.public === 'true' ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}}</clr-dg-cell>
|
||||||
<clr-dg-cell *ngIf="showRoleInfo">{{roleInfo[p.current_user_role_id] | translate}}</clr-dg-cell>
|
<clr-dg-cell *ngIf="showRoleInfo">{{roleInfo[p.current_user_role_id] | translate}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{p.repo_count}}</clr-dg-cell>
|
<clr-dg-cell>{{p.repo_count}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
|
@ -173,15 +173,15 @@ export class ListProjectComponent implements OnDestroy {
|
|||||||
|
|
||||||
toggleProject(p: Project) {
|
toggleProject(p: Project) {
|
||||||
if (p) {
|
if (p) {
|
||||||
p.public === 0 ? p.public = 1 : p.public = 0;
|
p.metadata.public === 'true' ? p.metadata.public = 'false' : p.metadata.public = 'true';
|
||||||
this.proService
|
this.proService
|
||||||
.toggleProjectPublic(p.project_id, p.public)
|
.toggleProjectPublic(p.project_id, p.metadata.public)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.msgHandler.showSuccess('PROJECT.TOGGLED_SUCCESS');
|
this.msgHandler.showSuccess('PROJECT.TOGGLED_SUCCESS');
|
||||||
let pp: Project = this.projects.find((item: Project) => item.project_id === p.project_id);
|
let pp: Project = this.projects.find((item: Project) => item.project_id === p.project_id);
|
||||||
if (pp) {
|
if (pp) {
|
||||||
pp.public = p.public;
|
pp.metadata.public = p.metadata.public;
|
||||||
this.statisticHandler.refresh();
|
this.statisticHandler.refresh();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -58,18 +58,20 @@ export class ProjectService {
|
|||||||
.catch(error=>Observable.throw(error));
|
.catch(error=>Observable.throw(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
createProject(name: string, isPublic: number): Observable<any> {
|
createProject(name: string, metadata: any): Observable<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.post(`/api/projects`,
|
.post(`/api/projects`,
|
||||||
JSON.stringify({'project_name': name, 'public': isPublic})
|
JSON.stringify({'project_name': name, 'metadata': {
|
||||||
|
public: metadata.public ? 'true' : 'false',
|
||||||
|
}})
|
||||||
, this.options)
|
, this.options)
|
||||||
.map(response=>response.status)
|
.map(response=>response.status)
|
||||||
.catch(error=>Observable.throw(error));
|
.catch(error=>Observable.throw(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleProjectPublic(projectId: number, isPublic: number): Observable<any> {
|
toggleProjectPublic(projectId: number, isPublic: string): Observable<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.put(`/api/projects/${projectId}/publicity`, { 'public': isPublic }, this.options)
|
.put(`/api/projects/${projectId}`, { 'metadata': {'public': isPublic} }, this.options)
|
||||||
.map(response => response.status)
|
.map(response => response.status)
|
||||||
.catch(error => Observable.throw(error));
|
.catch(error => Observable.throw(error));
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"deleted": 0,
|
"deleted": 0,
|
||||||
"owner_name": "",
|
"owner_name": "",
|
||||||
"public": 1,
|
"public": 1,
|
||||||
"Togglable": true,
|
"togglable": true,
|
||||||
"update_time": "2017-02-10T07:57:56Z",
|
"update_time": "2017-02-10T07:57:56Z",
|
||||||
"current_user_role_id": 1,
|
"current_user_role_id": 1,
|
||||||
"repo_count": 0
|
"repo_count": 0
|
||||||
@ -37,12 +37,22 @@ export class Project {
|
|||||||
creation_time_str: string;
|
creation_time_str: string;
|
||||||
deleted: number;
|
deleted: number;
|
||||||
owner_name: string;
|
owner_name: string;
|
||||||
public: number;
|
togglable: boolean;
|
||||||
Togglable: boolean;
|
|
||||||
update_time: Date;
|
update_time: Date;
|
||||||
current_user_role_id: number;
|
current_user_role_id: number;
|
||||||
repo_count: number;
|
repo_count: number;
|
||||||
has_project_admin_role: boolean;
|
has_project_admin_role: boolean;
|
||||||
is_member: boolean;
|
is_member: boolean;
|
||||||
role_name: string;
|
role_name: string;
|
||||||
|
metadata: {
|
||||||
|
public: string | boolean;
|
||||||
|
enable_content_trust: string | boolean;
|
||||||
|
prevent_vul: string | boolean;
|
||||||
|
severity: string;
|
||||||
|
auto_scan: string | boolean;
|
||||||
|
};
|
||||||
|
constructor () {
|
||||||
|
this.metadata = <any>{};
|
||||||
|
this.metadata.public = false;
|
||||||
|
}
|
||||||
}
|
}
|
@ -45,11 +45,11 @@ type Project struct {
|
|||||||
// The owner name of the project.
|
// The owner name of the project.
|
||||||
OwnerName string `json:"owner_name,omitempty"`
|
OwnerName string `json:"owner_name,omitempty"`
|
||||||
|
|
||||||
// The public status of the project.
|
// The metadata of the project.
|
||||||
Public int32 `json:"public,omitempty"`
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Correspond to the UI about whether the project's publicity is updatable (for UI)
|
// Correspond to the UI about whether the project's publicity is updatable (for UI)
|
||||||
Togglable bool `json:"Togglable,omitempty"`
|
Togglable bool `json:"togglable,omitempty"`
|
||||||
|
|
||||||
// The role ID of the current user who triggered the API (for UI)
|
// The role ID of the current user who triggered the API (for UI)
|
||||||
CurrentUserRoleId int32 `json:"current_user_role_id,omitempty"`
|
CurrentUserRoleId int32 `json:"current_user_role_id,omitempty"`
|
||||||
|
@ -23,10 +23,8 @@
|
|||||||
package apilib
|
package apilib
|
||||||
|
|
||||||
type ProjectReq struct {
|
type ProjectReq struct {
|
||||||
|
|
||||||
// The name of the project.
|
// The name of the project.
|
||||||
ProjectName string `json:"project_name,omitempty"`
|
ProjectName string `json:"project_name,omitempty"`
|
||||||
|
// The metadata of the project.
|
||||||
// The public status of the project.
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
Public int32 `json:"public,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ type SearchRepository struct {
|
|||||||
// The name of the project that the repository belongs to
|
// The name of the project that the repository belongs to
|
||||||
ProjectName string `json:"project_name,omitempty"`
|
ProjectName string `json:"project_name,omitempty"`
|
||||||
|
|
||||||
// The flag to indicate the publicity of the project that the repository belongs to (1 is public, 0 is not)
|
// The flag to indicate the publicity of the project that the repository belongs to
|
||||||
ProjectPublic int32 `json:"project_public,omitempty"`
|
ProjectPublic bool `json:"project_public,omitempty"`
|
||||||
|
|
||||||
// The name of the repository
|
// The name of the repository
|
||||||
RepositoryName string `json:"repository_name,omitempty"`
|
RepositoryName string `json:"repository_name,omitempty"`
|
||||||
|
@ -54,3 +54,4 @@ Changelog for harbor database schema
|
|||||||
|
|
||||||
- create table `project_metadata`
|
- create table `project_metadata`
|
||||||
- insert data into table `project_metadata`
|
- insert data into table `project_metadata`
|
||||||
|
- delete column `public` from table `project`
|
Loading…
Reference in New Issue
Block a user