mirror of
https://github.com/goharbor/harbor
synced 2025-05-21 12:39:07 +00:00
add robot account version 2 controller (#13472)
the controller is for the enhanced robot account Signed-off-by: Wang Yan <wangyan@vmware.com>
This commit is contained in:
parent
def782b6f8
commit
04c4354df9
343
src/controller/robot/controller.go
Normal file
343
src/controller/robot/controller.go
Normal file
@ -0,0 +1,343 @@
|
||||
package robot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
rbac_common "github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
"github.com/goharbor/harbor/src/pkg/project"
|
||||
"github.com/goharbor/harbor/src/pkg/rbac"
|
||||
rbac_model "github.com/goharbor/harbor/src/pkg/rbac/model"
|
||||
robot "github.com/goharbor/harbor/src/pkg/robot2"
|
||||
"github.com/goharbor/harbor/src/pkg/robot2/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// Ctl is a global variable for the default robot account controller implementation
|
||||
Ctl = NewController()
|
||||
)
|
||||
|
||||
// Controller to handle the requests related with robot account
|
||||
type Controller interface {
|
||||
// Get ...
|
||||
Get(ctx context.Context, id int64, option *Option) (*Robot, error)
|
||||
|
||||
// Count returns the total count of robots according to the query
|
||||
Count(ctx context.Context, query *q.Query) (total int64, err error)
|
||||
|
||||
// Create ...
|
||||
Create(ctx context.Context, r *Robot) (int64, error)
|
||||
|
||||
// Delete ...
|
||||
Delete(ctx context.Context, id int64) error
|
||||
|
||||
// Update ...
|
||||
Update(ctx context.Context, r *Robot) error
|
||||
|
||||
// List ...
|
||||
List(ctx context.Context, query *q.Query, option *Option) ([]*Robot, error)
|
||||
}
|
||||
|
||||
// controller ...
|
||||
type controller struct {
|
||||
robotMgr robot.Manager
|
||||
proMgr project.Manager
|
||||
rbacMgr rbac.Manager
|
||||
}
|
||||
|
||||
// NewController ...
|
||||
func NewController() Controller {
|
||||
return &controller{
|
||||
robotMgr: robot.Mgr,
|
||||
proMgr: project.Mgr,
|
||||
rbacMgr: rbac.Mgr,
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (d *controller) Get(ctx context.Context, id int64, option *Option) (*Robot, error) {
|
||||
robot, err := d.robotMgr.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.populate(ctx, robot, option)
|
||||
}
|
||||
|
||||
// Count ...
|
||||
func (d *controller) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
return d.robotMgr.Count(ctx, query)
|
||||
}
|
||||
|
||||
// Create ...
|
||||
func (d *controller) Create(ctx context.Context, r *Robot) (int64, error) {
|
||||
if err := d.setProjectID(ctx, r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if r.ExpiresAt == 0 {
|
||||
tokenDuration := time.Duration(config.RobotTokenDuration()) * time.Minute
|
||||
r.ExpiresAt = time.Now().UTC().Add(tokenDuration).Unix()
|
||||
}
|
||||
|
||||
key, err := config.SecretKey()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
str := utils.GenerateRandomString()
|
||||
secret, err := utils.ReversibleEncrypt(str, key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
robotID, err := d.robotMgr.Create(ctx, &model.Robot{
|
||||
Name: r.Name,
|
||||
Description: r.Description,
|
||||
ProjectID: r.ProjectID,
|
||||
ExpiresAt: r.ExpiresAt,
|
||||
Secret: secret,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := d.createPermission(ctx, r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return robotID, nil
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (d *controller) Delete(ctx context.Context, id int64) error {
|
||||
if err := d.robotMgr.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.rbacMgr.DeletePermissionsByRole(ctx, ROBOTTYPE, id); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update ...
|
||||
func (d *controller) Update(ctx context.Context, r *Robot) error {
|
||||
if r == nil {
|
||||
return errors.New("cannot update a nil robot").WithCode(errors.BadRequestCode)
|
||||
}
|
||||
if err := d.robotMgr.Update(ctx, &r.Robot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.setProjectID(ctx, r); err != nil {
|
||||
return err
|
||||
}
|
||||
// update the permission
|
||||
if err := d.rbacMgr.DeletePermissionsByRole(ctx, ROBOTTYPE, r.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.createPermission(ctx, r); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List ...
|
||||
func (d *controller) List(ctx context.Context, query *q.Query, option *Option) ([]*Robot, error) {
|
||||
robots, err := d.robotMgr.List(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var robotAccounts []*Robot
|
||||
for _, r := range robots {
|
||||
rb, err := d.populate(ctx, r, option)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
robotAccounts = append(robotAccounts, rb)
|
||||
}
|
||||
return robotAccounts, nil
|
||||
}
|
||||
|
||||
func (d *controller) createPermission(ctx context.Context, r *Robot) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, per := range r.Permissions {
|
||||
policy := &rbac_model.PermissionPolicy{}
|
||||
scope, err := d.toScope(ctx, per)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policy.Scope = scope
|
||||
|
||||
for _, access := range per.Access {
|
||||
policy.Resource = access.Resource.String()
|
||||
policy.Action = access.Action.String()
|
||||
policy.Effect = access.Effect.String()
|
||||
|
||||
policyID, err := d.rbacMgr.CreateRbacPolicy(ctx, policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = d.rbacMgr.CreatePermission(ctx, &rbac_model.RolePermission{
|
||||
RoleType: ROBOTTYPE,
|
||||
RoleID: r.ID,
|
||||
PermissionPolicyID: policyID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *controller) populate(ctx context.Context, r *model.Robot, option *Option) (*Robot, error) {
|
||||
if r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
robot := &Robot{
|
||||
Robot: *r,
|
||||
}
|
||||
robot.Name = fmt.Sprintf("%s%s", config.RobotPrefix(), r.Name)
|
||||
robot.setLevel()
|
||||
if option == nil {
|
||||
return robot, nil
|
||||
}
|
||||
if option.WithPermission {
|
||||
if err := d.populatePermissions(ctx, robot); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return robot, nil
|
||||
}
|
||||
|
||||
func (d *controller) populatePermissions(ctx context.Context, r *Robot) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
rolePermissions, err := d.rbacMgr.GetPermissionsByRole(ctx, ROBOTTYPE, r.ID)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get permissions of robot %d: %v", r.ID, err)
|
||||
return err
|
||||
}
|
||||
if len(rolePermissions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// scope: accesses
|
||||
accessMap := make(map[string][]*types.Policy)
|
||||
|
||||
// group by scope
|
||||
for _, rp := range rolePermissions {
|
||||
_, exist := accessMap[rp.Scope]
|
||||
if !exist {
|
||||
accessMap[rp.Scope] = []*types.Policy{{
|
||||
Resource: types.Resource(rp.Resource),
|
||||
Action: types.Action(rp.Action),
|
||||
Effect: types.Effect(rp.Effect),
|
||||
}}
|
||||
} else {
|
||||
accesses := accessMap[rp.Scope]
|
||||
accesses = append(accesses, &types.Policy{
|
||||
Resource: types.Resource(rp.Resource),
|
||||
Action: types.Action(rp.Action),
|
||||
Effect: types.Effect(rp.Effect),
|
||||
})
|
||||
accessMap[rp.Scope] = accesses
|
||||
}
|
||||
}
|
||||
|
||||
var permissions []*Permission
|
||||
for scope, accesses := range accessMap {
|
||||
p := &Permission{}
|
||||
kind, namespace, err := d.convertScope(ctx, scope)
|
||||
if err != nil {
|
||||
log.Errorf("failed to decode scope of robot %d: %v", r.ID, err)
|
||||
return err
|
||||
}
|
||||
p.Kind = kind
|
||||
p.Namespace = namespace
|
||||
p.Access = accesses
|
||||
permissions = append(permissions, p)
|
||||
}
|
||||
r.Permissions = permissions
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *controller) setProjectID(ctx context.Context, r *Robot) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
var projectID int64
|
||||
switch r.Level {
|
||||
case LEVELSYSTEM:
|
||||
projectID = 0
|
||||
case LEVELPROJECT:
|
||||
pro, err := d.proMgr.Get(ctx, r.Permissions[0].Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectID = pro.ProjectID
|
||||
default:
|
||||
return errors.New(nil).WithMessage("unknown robot account level").WithCode(errors.BadRequestCode)
|
||||
}
|
||||
r.ProjectID = projectID
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertScope converts the db scope into robot model
|
||||
// /system => Kind: system Namespace: /
|
||||
// /project/* => Kind: project Namespace: *
|
||||
// /project/1 => Kind: project Namespace: library
|
||||
func (d *controller) convertScope(ctx context.Context, scope string) (kind, namespace string, err error) {
|
||||
if scope == "" {
|
||||
return
|
||||
}
|
||||
if scope == SCOPESYSTEM {
|
||||
kind = LEVELSYSTEM
|
||||
namespace = "/"
|
||||
} else if scope == SCOPEALLPROJECT {
|
||||
kind = LEVELPROJECT
|
||||
namespace = "*"
|
||||
} else {
|
||||
kind = LEVELPROJECT
|
||||
ns, ok := rbac_common.ProjectNamespaceParse(types.Resource(scope))
|
||||
if !ok {
|
||||
log.Debugf("got no namespace from the resource %s", scope)
|
||||
return "", "", errors.Errorf("got no namespace from the resource %s", scope)
|
||||
}
|
||||
pro, err := d.proMgr.Get(ctx, ns.Identity())
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
namespace = pro.Name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// toScope ...
|
||||
func (d *controller) toScope(ctx context.Context, p *Permission) (string, error) {
|
||||
switch p.Kind {
|
||||
case LEVELSYSTEM:
|
||||
if p.Namespace != "/" {
|
||||
return "", errors.New(nil).WithMessage("unknown namespace").WithCode(errors.BadRequestCode)
|
||||
}
|
||||
return SCOPESYSTEM, nil
|
||||
case LEVELPROJECT:
|
||||
if p.Namespace == "*" {
|
||||
return SCOPEALLPROJECT, nil
|
||||
}
|
||||
pro, err := d.proMgr.Get(ctx, p.Namespace)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("/project/%d", pro.ProjectID), nil
|
||||
}
|
||||
return "", errors.New(nil).WithMessage("unknown robot kind").WithCode(errors.BadRequestCode)
|
||||
}
|
288
src/controller/robot/controller_test.go
Normal file
288
src/controller/robot/controller_test.go
Normal file
@ -0,0 +1,288 @@
|
||||
package robot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
core_cfg "github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
rbac_model "github.com/goharbor/harbor/src/pkg/rbac/model"
|
||||
"github.com/goharbor/harbor/src/pkg/robot2/model"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/project"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/rbac"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/robot2"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ControllerTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestGet() {
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil)
|
||||
robotMgr.On("Get", mock.Anything, mock.Anything).Return(&model.Robot{
|
||||
Name: "test",
|
||||
Description: "test get method",
|
||||
ProjectID: 1,
|
||||
Secret: utils.RandStringBytes(10),
|
||||
}, nil)
|
||||
rbacMgr.On("GetPermissionsByRole", mock.Anything, mock.Anything, mock.Anything).Return([]*rbac_model.UniversalRolePermission{
|
||||
{
|
||||
RoleType: ROBOTTYPE,
|
||||
RoleID: 1,
|
||||
Scope: "/project/1",
|
||||
Resource: "repository",
|
||||
Action: "pull",
|
||||
},
|
||||
{
|
||||
RoleType: ROBOTTYPE,
|
||||
RoleID: 1,
|
||||
Scope: "/project/1",
|
||||
Resource: "repository",
|
||||
Action: "push",
|
||||
},
|
||||
}, nil)
|
||||
robot, err := c.Get(ctx, int64(1), &Option{
|
||||
WithPermission: true,
|
||||
})
|
||||
suite.Nil(err)
|
||||
|
||||
suite.Equal("project", robot.Permissions[0].Kind)
|
||||
suite.Equal("library", robot.Permissions[0].Namespace)
|
||||
suite.Equal("pull", robot.Permissions[0].Access[0].Action.String())
|
||||
suite.Equal("project", robot.Level)
|
||||
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestCount() {
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
|
||||
robotMgr.On("Count", mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
|
||||
ct, err := c.Count(ctx, nil)
|
||||
suite.Nil(err)
|
||||
suite.Equal(int64(1), ct)
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestCreate() {
|
||||
secretKeyPath := "/tmp/secretkey"
|
||||
_, err := test.GenerateKey(secretKeyPath)
|
||||
suite.Nil(err)
|
||||
defer os.Remove(secretKeyPath)
|
||||
os.Setenv("KEY_PATH", secretKeyPath)
|
||||
|
||||
conf := map[string]interface{}{
|
||||
common.RobotTokenDuration: "30",
|
||||
}
|
||||
core_cfg.InitWithSettings(conf)
|
||||
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil)
|
||||
robotMgr.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
rbacMgr.On("CreateRbacPolicy", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
rbacMgr.On("CreatePermission", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
|
||||
id, err := c.Create(ctx, &Robot{
|
||||
Robot: model.Robot{
|
||||
Name: "testcreate",
|
||||
Description: "testcreate",
|
||||
ExpiresAt: 0,
|
||||
},
|
||||
ProjectName: "library",
|
||||
Level: LEVELPROJECT,
|
||||
Permissions: []*Permission{
|
||||
{
|
||||
Kind: "project",
|
||||
Namespace: "library",
|
||||
Access: []*types.Policy{
|
||||
{
|
||||
Resource: "repository",
|
||||
Action: "push",
|
||||
},
|
||||
{
|
||||
Resource: "repository",
|
||||
Action: "pull",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
suite.Nil(err)
|
||||
suite.Equal(int64(1), id)
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestDelete() {
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
|
||||
robotMgr.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
rbacMgr.On("DeletePermissionsByRole", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
err := c.Delete(ctx, int64(1))
|
||||
suite.Nil(err)
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestUpdate() {
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
|
||||
robotMgr.On("Update", mock.Anything, mock.Anything).Return(nil)
|
||||
projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil)
|
||||
rbacMgr.On("DeletePermissionsByRole", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
rbacMgr.On("CreateRbacPolicy", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
rbacMgr.On("CreatePermission", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
|
||||
err := c.Update(ctx, &Robot{
|
||||
Robot: model.Robot{
|
||||
Name: "testcreate",
|
||||
Description: "testcreate",
|
||||
ExpiresAt: 0,
|
||||
},
|
||||
ProjectName: "library",
|
||||
Level: LEVELPROJECT,
|
||||
Permissions: []*Permission{
|
||||
{
|
||||
Kind: "project",
|
||||
Namespace: "library",
|
||||
Access: []*types.Policy{
|
||||
{
|
||||
Resource: "repository",
|
||||
Action: "push",
|
||||
},
|
||||
{
|
||||
Resource: "repository",
|
||||
Action: "pull",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
suite.Nil(err)
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestList() {
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
|
||||
projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil)
|
||||
robotMgr.On("List", mock.Anything, mock.Anything).Return([]*model.Robot{
|
||||
{
|
||||
Name: "test",
|
||||
Description: "test list method",
|
||||
ProjectID: 1,
|
||||
Secret: utils.RandStringBytes(10),
|
||||
},
|
||||
}, nil)
|
||||
rbacMgr.On("GetPermissionsByRole", mock.Anything, mock.Anything, mock.Anything).Return([]*rbac_model.UniversalRolePermission{
|
||||
{
|
||||
RoleType: ROBOTTYPE,
|
||||
RoleID: 1,
|
||||
Scope: "/project/1",
|
||||
Resource: "repository",
|
||||
Action: "pull",
|
||||
},
|
||||
{
|
||||
RoleType: ROBOTTYPE,
|
||||
RoleID: 1,
|
||||
Scope: "/project/1",
|
||||
Resource: "repository",
|
||||
Action: "push",
|
||||
},
|
||||
}, nil)
|
||||
projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil)
|
||||
rs, err := c.List(ctx, &q.Query{
|
||||
Keywords: map[string]interface{}{
|
||||
"name": "test3",
|
||||
},
|
||||
}, &Option{
|
||||
WithPermission: true,
|
||||
})
|
||||
suite.Nil(err)
|
||||
suite.Equal("project", rs[0].Permissions[0].Kind)
|
||||
suite.Equal("library", rs[0].Permissions[0].Namespace)
|
||||
suite.Equal("pull", rs[0].Permissions[0].Access[0].Action.String())
|
||||
suite.Equal("project", rs[0].Level)
|
||||
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestToScope() {
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
robotMgr := &robot2.Manager{}
|
||||
|
||||
c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr}
|
||||
ctx := context.TODO()
|
||||
|
||||
projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{ProjectID: 1, Name: "library"}, nil)
|
||||
|
||||
p := &Permission{
|
||||
Kind: "system",
|
||||
Namespace: "/",
|
||||
}
|
||||
scope, err := c.toScope(ctx, p)
|
||||
suite.Nil(err)
|
||||
suite.Equal("/system", scope)
|
||||
|
||||
p = &Permission{
|
||||
Kind: "system",
|
||||
Namespace: "&",
|
||||
}
|
||||
_, err = c.toScope(ctx, p)
|
||||
suite.NotNil(err)
|
||||
|
||||
p = &Permission{
|
||||
Kind: "project",
|
||||
Namespace: "library",
|
||||
}
|
||||
scope, err = c.toScope(ctx, p)
|
||||
suite.Nil(err)
|
||||
suite.Equal("/project/1", scope)
|
||||
|
||||
p = &Permission{
|
||||
Kind: "project",
|
||||
Namespace: "*",
|
||||
}
|
||||
scope, err = c.toScope(ctx, p)
|
||||
suite.Nil(err)
|
||||
suite.Equal("/project/*", scope)
|
||||
|
||||
}
|
||||
|
||||
func TestControllerTestSuite(t *testing.T) {
|
||||
suite.Run(t, &ControllerTestSuite{})
|
||||
}
|
50
src/controller/robot/model.go
Normal file
50
src/controller/robot/model.go
Normal file
@ -0,0 +1,50 @@
|
||||
package robot
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
"github.com/goharbor/harbor/src/pkg/robot2/model"
|
||||
)
|
||||
|
||||
const (
|
||||
// LEVELSYSTEM ...
|
||||
LEVELSYSTEM = "system"
|
||||
// LEVELPROJECT ...
|
||||
LEVELPROJECT = "project"
|
||||
|
||||
// SCOPESYSTEM ...
|
||||
SCOPESYSTEM = "/system"
|
||||
// SCOPEALLPROJECT ...
|
||||
SCOPEALLPROJECT = "/project/*"
|
||||
|
||||
// ROBOTTYPE ...
|
||||
ROBOTTYPE = "robotaccount"
|
||||
)
|
||||
|
||||
// Robot ...
|
||||
type Robot struct {
|
||||
model.Robot
|
||||
ProjectName string
|
||||
Level string
|
||||
Permissions []*Permission `json:"permissions"`
|
||||
}
|
||||
|
||||
// setLevel, 0 is a system level robot, others are project level.
|
||||
func (r *Robot) setLevel() {
|
||||
if r.ProjectID == 0 {
|
||||
r.Level = LEVELSYSTEM
|
||||
} else {
|
||||
r.Level = LEVELPROJECT
|
||||
}
|
||||
}
|
||||
|
||||
// Permission ...
|
||||
type Permission struct {
|
||||
Kind string `json:"kind"`
|
||||
Namespace string `json:"namespace"`
|
||||
Access []*types.Policy `json:"access"`
|
||||
}
|
||||
|
||||
// Option ...
|
||||
type Option struct {
|
||||
WithPermission bool
|
||||
}
|
34
src/controller/robot/model_test.go
Normal file
34
src/controller/robot/model_test.go
Normal file
@ -0,0 +1,34 @@
|
||||
package robot
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/pkg/robot2/model"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ModelTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *ModelTestSuite) TestSetLevel() {
|
||||
r := Robot{
|
||||
Robot: model.Robot{
|
||||
ProjectID: 0,
|
||||
},
|
||||
}
|
||||
r.setLevel()
|
||||
|
||||
suite.Equal(LEVELSYSTEM, r.Level)
|
||||
|
||||
r = Robot{
|
||||
Robot: model.Robot{
|
||||
ProjectID: 1,
|
||||
},
|
||||
}
|
||||
r.setLevel()
|
||||
suite.Equal(LEVELPROJECT, r.Level)
|
||||
}
|
||||
|
||||
func TestModelTestSuite(t *testing.T) {
|
||||
suite.Run(t, &ModelTestSuite{})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user