mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-25 03:35:21 +01:00
enable robot full access (#20754)
* have option to enable robot full access When the system admin enable this option, the robot can be assigned with robot/user/group/quota permissions. Signed-off-by: wang yan <wangyan@vmware.com> * robot account permission enhancement Update codes according to the proposal of https://github.com/goharbor/community/pull/249 Signed-off-by: wang yan <wangyan@vmware.com> --------- Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
parent
d42c34786f
commit
e4fe61ddb7
@ -14,7 +14,9 @@
|
|||||||
|
|
||||||
package rbac
|
package rbac
|
||||||
|
|
||||||
import "github.com/goharbor/harbor/src/pkg/permission/types"
|
import (
|
||||||
|
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||||
|
)
|
||||||
|
|
||||||
// const action variables
|
// const action variables
|
||||||
const (
|
const (
|
||||||
@ -81,9 +83,88 @@ const (
|
|||||||
ResourceSecurityHub = Resource("security-hub")
|
ResourceSecurityHub = Resource("security-hub")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type scope string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ScopeSystem = scope("System")
|
||||||
|
ScopeProject = scope("Project")
|
||||||
|
)
|
||||||
|
|
||||||
|
// RobotPermissionProvider defines the permission provider for robot account
|
||||||
|
type RobotPermissionProvider interface {
|
||||||
|
GetPermissions(s scope) []*types.Policy
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPermissionProvider gives the robot permission provider
|
||||||
|
func GetPermissionProvider() RobotPermissionProvider {
|
||||||
|
// TODO will determine by the ui configuration
|
||||||
|
return &NolimitProvider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseProvider ...
|
||||||
|
type BaseProvider struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPermissions ...
|
||||||
|
func (d *BaseProvider) GetPermissions(s scope) []*types.Policy {
|
||||||
|
return PoliciesMap[s]
|
||||||
|
}
|
||||||
|
|
||||||
|
// NolimitProvider ...
|
||||||
|
type NolimitProvider struct {
|
||||||
|
BaseProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPermissions ...
|
||||||
|
func (n *NolimitProvider) GetPermissions(s scope) []*types.Policy {
|
||||||
|
if s == ScopeSystem {
|
||||||
|
return append(n.BaseProvider.GetPermissions(ScopeSystem),
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionRead},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionUpdate},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionList},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionDelete},
|
||||||
|
|
||||||
|
&types.Policy{Resource: ResourceUser, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceUser, Action: ActionRead},
|
||||||
|
&types.Policy{Resource: ResourceUser, Action: ActionUpdate},
|
||||||
|
&types.Policy{Resource: ResourceUser, Action: ActionList},
|
||||||
|
&types.Policy{Resource: ResourceUser, Action: ActionDelete},
|
||||||
|
|
||||||
|
&types.Policy{Resource: ResourceLdapUser, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceLdapUser, Action: ActionList},
|
||||||
|
|
||||||
|
&types.Policy{Resource: ResourceExportCVE, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceExportCVE, Action: ActionRead},
|
||||||
|
|
||||||
|
&types.Policy{Resource: ResourceQuota, Action: ActionUpdate},
|
||||||
|
|
||||||
|
&types.Policy{Resource: ResourceUserGroup, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceUserGroup, Action: ActionRead},
|
||||||
|
&types.Policy{Resource: ResourceUserGroup, Action: ActionUpdate},
|
||||||
|
&types.Policy{Resource: ResourceUserGroup, Action: ActionList},
|
||||||
|
&types.Policy{Resource: ResourceUserGroup, Action: ActionDelete})
|
||||||
|
}
|
||||||
|
if s == ScopeProject {
|
||||||
|
return append(n.BaseProvider.GetPermissions(ScopeProject),
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionRead},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionUpdate},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionList},
|
||||||
|
&types.Policy{Resource: ResourceRobot, Action: ActionDelete},
|
||||||
|
|
||||||
|
&types.Policy{Resource: ResourceMember, Action: ActionCreate},
|
||||||
|
&types.Policy{Resource: ResourceMember, Action: ActionRead},
|
||||||
|
&types.Policy{Resource: ResourceMember, Action: ActionUpdate},
|
||||||
|
&types.Policy{Resource: ResourceMember, Action: ActionList},
|
||||||
|
&types.Policy{Resource: ResourceMember, Action: ActionDelete})
|
||||||
|
}
|
||||||
|
return []*types.Policy{}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PoliciesMap = map[string][]*types.Policy{
|
PoliciesMap = map[scope][]*types.Policy{
|
||||||
"System": {
|
ScopeSystem: {
|
||||||
{Resource: ResourceAuditLog, Action: ActionList},
|
{Resource: ResourceAuditLog, Action: ActionList},
|
||||||
|
|
||||||
{Resource: ResourcePreatInstance, Action: ActionRead},
|
{Resource: ResourcePreatInstance, Action: ActionRead},
|
||||||
@ -154,7 +235,7 @@ var (
|
|||||||
{Resource: ResourceQuota, Action: ActionRead},
|
{Resource: ResourceQuota, Action: ActionRead},
|
||||||
{Resource: ResourceQuota, Action: ActionList},
|
{Resource: ResourceQuota, Action: ActionList},
|
||||||
},
|
},
|
||||||
"Project": {
|
ScopeProject: {
|
||||||
{Resource: ResourceLog, Action: ActionList},
|
{Resource: ResourceLog, Action: ActionList},
|
||||||
|
|
||||||
{Resource: ResourceProject, Action: ActionRead},
|
{Resource: ResourceProject, Action: ActionRead},
|
||||||
|
36
src/common/rbac/const_test.go
Normal file
36
src/common/rbac/const_test.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package rbac
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBaseProvider(t *testing.T) {
|
||||||
|
permissionProvider := &BaseProvider{}
|
||||||
|
sysPermissions := permissionProvider.GetPermissions(ScopeSystem)
|
||||||
|
|
||||||
|
for _, per := range sysPermissions {
|
||||||
|
if per.Action == ActionCreate && per.Resource == ResourceRobot {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNolimitProvider(t *testing.T) {
|
||||||
|
permissionProvider := &BaseProvider{}
|
||||||
|
sysPermissions := permissionProvider.GetPermissions(ScopeSystem)
|
||||||
|
|
||||||
|
for _, per := range sysPermissions {
|
||||||
|
if per.Action == ActionCreate && per.Resource == ResourceRobot {
|
||||||
|
t.Log("no limit provider has the permission of robot account creation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetPermissionProvider(t *testing.T) {
|
||||||
|
defaultPro := GetPermissionProvider()
|
||||||
|
_, ok := defaultPro.(*NolimitProvider)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
@ -97,10 +97,6 @@ func (d *controller) Count(ctx context.Context, query *q.Query) (int64, error) {
|
|||||||
|
|
||||||
// Create ...
|
// Create ...
|
||||||
func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error) {
|
func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error) {
|
||||||
if err := d.setProject(ctx, r); err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var expiresAt int64
|
var expiresAt int64
|
||||||
if r.Duration == -1 {
|
if r.Duration == -1 {
|
||||||
expiresAt = -1
|
expiresAt = -1
|
||||||
@ -327,22 +323,6 @@ func (d *controller) populatePermissions(ctx context.Context, r *Robot) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the project info if it's a project level robot
|
|
||||||
func (d *controller) setProject(ctx context.Context, r *Robot) error {
|
|
||||||
if r == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if r.Level == LEVELPROJECT {
|
|
||||||
pro, err := d.proMgr.Get(ctx, r.Permissions[0].Namespace)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.ProjectName = pro.Name
|
|
||||||
r.ProjectID = pro.ProjectID
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertScope converts the db scope into robot model
|
// convertScope converts the db scope into robot model
|
||||||
// /system => Kind: system Namespace: /
|
// /system => Kind: system Namespace: /
|
||||||
// /project/* => Kind: project Namespace: *
|
// /project/* => Kind: project Namespace: *
|
||||||
@ -394,6 +374,22 @@ func (d *controller) toScope(ctx context.Context, p *Permission) (string, error)
|
|||||||
return "", errors.New(nil).WithMessage("unknown robot kind").WithCode(errors.BadRequestCode)
|
return "", errors.New(nil).WithMessage("unknown robot kind").WithCode(errors.BadRequestCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the project info if it's a project level robot
|
||||||
|
func SetProject(ctx context.Context, r *Robot) error {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if r.Level == LEVELPROJECT {
|
||||||
|
pro, err := project.New().Get(ctx, r.Permissions[0].Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.ProjectName = pro.Name
|
||||||
|
r.ProjectID = pro.ProjectID
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func CreateSec(salt ...string) (string, string, string, error) {
|
func CreateSec(salt ...string) (string, string, string, error) {
|
||||||
var secret, pwd string
|
var secret, pwd string
|
||||||
options := []retry.Option{
|
options := []retry.Option{
|
||||||
|
@ -40,6 +40,7 @@ const (
|
|||||||
type Robot struct {
|
type Robot struct {
|
||||||
model.Robot
|
model.Robot
|
||||||
ProjectName string
|
ProjectName string
|
||||||
|
ProjectNameOrID interface{}
|
||||||
Level string
|
Level string
|
||||||
Editable bool `json:"editable"`
|
Editable bool `json:"editable"`
|
||||||
Permissions []*Permission `json:"permissions"`
|
Permissions []*Permission `json:"permissions"`
|
||||||
|
@ -867,6 +867,7 @@ func (bc *basicController) makeRobotAccount(ctx context.Context, projectID int64
|
|||||||
CreatorType: "local",
|
CreatorType: "local",
|
||||||
CreatorRef: int64(0),
|
CreatorRef: int64(0),
|
||||||
},
|
},
|
||||||
|
ProjectName: projectName,
|
||||||
Level: robot.LEVELPROJECT,
|
Level: robot.LEVELPROJECT,
|
||||||
Permissions: []*robot.Permission{
|
Permissions: []*robot.Permission{
|
||||||
{
|
{
|
||||||
|
@ -238,6 +238,7 @@ func (suite *ControllerTestSuite) SetupSuite() {
|
|||||||
CreatorType: "local",
|
CreatorType: "local",
|
||||||
CreatorRef: int64(0),
|
CreatorRef: int64(0),
|
||||||
},
|
},
|
||||||
|
ProjectName: "library",
|
||||||
Level: robot.LEVELPROJECT,
|
Level: robot.LEVELPROJECT,
|
||||||
Permissions: []*robot.Permission{
|
Permissions: []*robot.Permission{
|
||||||
{
|
{
|
||||||
|
@ -79,6 +79,11 @@ export const ACTION_RESOURCE_I18N_MAP = {
|
|||||||
'notification-policy': 'ROBOT_ACCOUNT.NOTIFICATION_POLICY',
|
'notification-policy': 'ROBOT_ACCOUNT.NOTIFICATION_POLICY',
|
||||||
quota: 'ROBOT_ACCOUNT.QUOTA',
|
quota: 'ROBOT_ACCOUNT.QUOTA',
|
||||||
sbom: 'ROBOT_ACCOUNT.SBOM',
|
sbom: 'ROBOT_ACCOUNT.SBOM',
|
||||||
|
robot: 'ROBOT_ACCOUNT.ROBOT',
|
||||||
|
user: 'ROBOT_ACCOUNT.USER',
|
||||||
|
'user-group': 'ROBOT_ACCOUNT.GROUP',
|
||||||
|
'ldap-user': 'ROBOT_ACCOUNT.LDAPUSER',
|
||||||
|
member: 'ROBOT_ACCOUNT.MEMBER',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function convertKey(key: string) {
|
export function convertKey(key: string) {
|
||||||
|
@ -423,7 +423,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Select Permissions",
|
"SELECT_PERMISSIONS": "Select Permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
||||||
"SYSTEM_PERMISSIONS": "System Permissions"
|
"SYSTEM_PERMISSIONS": "System Permissions",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "EDIT",
|
"EDIT_BUTTON": "EDIT",
|
||||||
|
@ -423,7 +423,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Select Permissions",
|
"SELECT_PERMISSIONS": "Select Permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
||||||
"SYSTEM_PERMISSIONS": "System Permissions"
|
"SYSTEM_PERMISSIONS": "System Permissions",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "EDIT",
|
"EDIT_BUTTON": "EDIT",
|
||||||
|
@ -424,7 +424,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Select Permissions",
|
"SELECT_PERMISSIONS": "Select Permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
||||||
"SYSTEM_PERMISSIONS": "System Permissions"
|
"SYSTEM_PERMISSIONS": "System Permissions",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "EDIT",
|
"EDIT_BUTTON": "EDIT",
|
||||||
|
@ -423,7 +423,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Selectionner les permissions",
|
"SELECT_PERMISSIONS": "Selectionner les permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Selectionner les permissions système",
|
"SELECT_SYSTEM_PERMISSIONS": "Selectionner les permissions système",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Selectionner les permissions projet",
|
"SELECT_PROJECT_PERMISSIONS": "Selectionner les permissions projet",
|
||||||
"SYSTEM_PERMISSIONS": "Permissions système"
|
"SYSTEM_PERMISSIONS": "Permissions système",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "Éditer",
|
"EDIT_BUTTON": "Éditer",
|
||||||
|
@ -420,7 +420,12 @@
|
|||||||
"SELECT_PERMISSIONS": "권한 선택",
|
"SELECT_PERMISSIONS": "권한 선택",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "시스템 권한 선택",
|
"SELECT_SYSTEM_PERMISSIONS": "시스템 권한 선택",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "프로젝트 권한 선택",
|
"SELECT_PROJECT_PERMISSIONS": "프로젝트 권한 선택",
|
||||||
"SYSTEM_PERMISSIONS": "시스템 권한"
|
"SYSTEM_PERMISSIONS": "시스템 권한",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "편집",
|
"EDIT_BUTTON": "편집",
|
||||||
|
@ -421,7 +421,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Select Permissions",
|
"SELECT_PERMISSIONS": "Select Permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
||||||
"SYSTEM_PERMISSIONS": "System Permissions"
|
"SYSTEM_PERMISSIONS": "System Permissions",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"GROUP": {
|
"GROUP": {
|
||||||
"GROUP": "Grupo",
|
"GROUP": "Grupo",
|
||||||
|
@ -423,7 +423,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Select Permissions",
|
"SELECT_PERMISSIONS": "Select Permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
||||||
"SYSTEM_PERMISSIONS": "System Permissions"
|
"SYSTEM_PERMISSIONS": "System Permissions",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "DÜZENLE",
|
"EDIT_BUTTON": "DÜZENLE",
|
||||||
|
@ -421,7 +421,12 @@
|
|||||||
"SELECT_PERMISSIONS": "选择权限",
|
"SELECT_PERMISSIONS": "选择权限",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "选择系统权限",
|
"SELECT_SYSTEM_PERMISSIONS": "选择系统权限",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "选择项目权限",
|
"SELECT_PROJECT_PERMISSIONS": "选择项目权限",
|
||||||
"SYSTEM_PERMISSIONS": "系统权限"
|
"SYSTEM_PERMISSIONS": "系统权限",
|
||||||
|
"ROBOT": "机器人账户",
|
||||||
|
"USER": "用户",
|
||||||
|
"LDAPUSER": "LDAP 用户",
|
||||||
|
"GROUP": "用户组",
|
||||||
|
"MEMBER": "项目成员"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "编辑",
|
"EDIT_BUTTON": "编辑",
|
||||||
|
@ -422,7 +422,12 @@
|
|||||||
"SELECT_PERMISSIONS": "Select Permissions",
|
"SELECT_PERMISSIONS": "Select Permissions",
|
||||||
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
|
||||||
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
|
||||||
"SYSTEM_PERMISSIONS": "System Permissions"
|
"SYSTEM_PERMISSIONS": "System Permissions",
|
||||||
|
"ROBOT": "Robot Account",
|
||||||
|
"USER": "User",
|
||||||
|
"LDAPUSER": "LDAP User",
|
||||||
|
"GROUP": "User Group",
|
||||||
|
"MEMBER": "Project Member"
|
||||||
},
|
},
|
||||||
"WEBHOOK": {
|
"WEBHOOK": {
|
||||||
"EDIT_BUTTON": "編輯",
|
"EDIT_BUTTON": "編輯",
|
||||||
|
@ -71,11 +71,12 @@ func (p *permissionsAPI) GetPermissions(ctx context.Context, _ permissions.GetPe
|
|||||||
return p.SendError(ctx, errors.ForbiddenError(errors.New("only admins(system and project) can access permissions")))
|
return p.SendError(ctx, errors.ForbiddenError(errors.New("only admins(system and project) can access permissions")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
provider := rbac.GetPermissionProvider()
|
||||||
sysPermissions := make([]*types.Policy, 0)
|
sysPermissions := make([]*types.Policy, 0)
|
||||||
proPermissions := rbac.PoliciesMap["Project"]
|
proPermissions := provider.GetPermissions(rbac.ScopeProject)
|
||||||
if isSystemAdmin {
|
if isSystemAdmin {
|
||||||
// project admin cannot see the system level permissions
|
// project admin cannot see the system level permissions
|
||||||
sysPermissions = rbac.PoliciesMap["System"]
|
sysPermissions = provider.GetPermissions(rbac.ScopeSystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
return permissions.NewGetPermissionsOK().WithPayload(p.convertPermissions(sysPermissions, proPermissions))
|
return permissions.NewGetPermissionsOK().WithPayload(p.convertPermissions(sysPermissions, proPermissions))
|
||||||
|
@ -31,8 +31,10 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/common/utils"
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
"github.com/goharbor/harbor/src/controller/robot"
|
"github.com/goharbor/harbor/src/controller/robot"
|
||||||
"github.com/goharbor/harbor/src/lib"
|
"github.com/goharbor/harbor/src/lib"
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"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/permission/types"
|
||||||
pkg "github.com/goharbor/harbor/src/pkg/robot/model"
|
pkg "github.com/goharbor/harbor/src/pkg/robot/model"
|
||||||
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||||
@ -60,12 +62,23 @@ func (rAPI *robotAPI) CreateRobot(ctx context.Context, params operation.CreateRo
|
|||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rAPI.requireAccess(ctx, params.Robot.Level, params.Robot.Permissions[0].Namespace, rbac.ActionCreate); err != nil {
|
sc, err := rAPI.GetSecurityContext(ctx)
|
||||||
|
if err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sc, err := rAPI.GetSecurityContext(ctx)
|
r := &robot.Robot{
|
||||||
if err != nil {
|
Robot: pkg.Robot{
|
||||||
|
Name: params.Robot.Name,
|
||||||
|
Description: params.Robot.Description,
|
||||||
|
Duration: params.Robot.Duration,
|
||||||
|
Visible: true,
|
||||||
|
},
|
||||||
|
Level: params.Robot.Level,
|
||||||
|
ProjectNameOrID: params.Robot.Permissions[0].Namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rAPI.requireAccess(ctx, r, rbac.ActionCreate); err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,23 +91,36 @@ func (rAPI *robotAPI) CreateRobot(ctx context.Context, params operation.CreateRo
|
|||||||
default:
|
default:
|
||||||
return rAPI.SendError(ctx, errors.New(nil).WithMessage("invalid security context"))
|
return rAPI.SendError(ctx, errors.New(nil).WithMessage("invalid security context"))
|
||||||
}
|
}
|
||||||
|
r.CreatorType = sc.Name()
|
||||||
r := &robot.Robot{
|
r.CreatorRef = creatorRef
|
||||||
Robot: pkg.Robot{
|
|
||||||
Name: params.Robot.Name,
|
|
||||||
Description: params.Robot.Description,
|
|
||||||
Duration: params.Robot.Duration,
|
|
||||||
Visible: true,
|
|
||||||
CreatorRef: creatorRef,
|
|
||||||
CreatorType: sc.Name(),
|
|
||||||
},
|
|
||||||
Level: params.Robot.Level,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := lib.JSONCopy(&r.Permissions, params.Robot.Permissions); err != nil {
|
if err := lib.JSONCopy(&r.Permissions, params.Robot.Permissions); err != nil {
|
||||||
log.Warningf("failed to call JSONCopy on robot permission when CreateRobot, error: %v", err)
|
log.Warningf("failed to call JSONCopy on robot permission when CreateRobot, error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := robot.SetProject(ctx, r); err != nil {
|
||||||
|
return rAPI.SendError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := sc.(*robotSc.SecurityContext); ok {
|
||||||
|
creatorRobots, err := rAPI.robotCtl.List(ctx, q.New(q.KeyWords{
|
||||||
|
"name": strings.TrimPrefix(sc.GetUsername(), config.RobotPrefix(ctx)),
|
||||||
|
"project_id": r.ProjectID,
|
||||||
|
}), &robot.Option{
|
||||||
|
WithPermission: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return rAPI.SendError(ctx, err)
|
||||||
|
}
|
||||||
|
if len(creatorRobots) == 0 {
|
||||||
|
return rAPI.SendError(ctx, errors.DeniedError(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isValidPermissionScope(params.Robot.Permissions, creatorRobots[0].Permissions) {
|
||||||
|
return rAPI.SendError(ctx, errors.New(nil).WithMessage("permission scope is invalid. It must be equal to or more restrictive than the creator robot's permissions: %s", creatorRobots[0].Name).WithCode(errors.DENIED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rid, pwd, err := rAPI.robotCtl.Create(ctx, r)
|
rid, pwd, err := rAPI.robotCtl.Create(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
@ -125,7 +151,7 @@ func (rAPI *robotAPI) DeleteRobot(ctx context.Context, params operation.DeleteRo
|
|||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rAPI.requireAccess(ctx, r.Level, r.ProjectID, rbac.ActionDelete); err != nil {
|
if err := rAPI.requireAccess(ctx, r, rbac.ActionDelete); err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +200,11 @@ func (rAPI *robotAPI) ListRobot(ctx context.Context, params operation.ListRobotP
|
|||||||
}
|
}
|
||||||
query.Keywords["Visible"] = true
|
query.Keywords["Visible"] = true
|
||||||
|
|
||||||
if err := rAPI.requireAccess(ctx, level, projectID, rbac.ActionList); err != nil {
|
r := &robot.Robot{
|
||||||
|
ProjectNameOrID: projectID,
|
||||||
|
Level: level,
|
||||||
|
}
|
||||||
|
if err := rAPI.requireAccess(ctx, r, rbac.ActionList); err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +242,7 @@ func (rAPI *robotAPI) GetRobotByID(ctx context.Context, params operation.GetRobo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
if err := rAPI.requireAccess(ctx, r.Level, r.ProjectID, rbac.ActionRead); err != nil {
|
if err := rAPI.requireAccess(ctx, r, rbac.ActionRead); err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +283,7 @@ func (rAPI *robotAPI) RefreshSec(ctx context.Context, params operation.RefreshSe
|
|||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rAPI.requireAccess(ctx, r.Level, r.ProjectID, rbac.ActionUpdate); err != nil {
|
if err := rAPI.requireAccess(ctx, r, rbac.ActionUpdate); err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
return rAPI.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,12 +312,21 @@ func (rAPI *robotAPI) RefreshSec(ctx context.Context, params operation.RefreshSe
|
|||||||
return operation.NewRefreshSecOK().WithPayload(robotSec)
|
return operation.NewRefreshSecOK().WithPayload(robotSec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rAPI *robotAPI) requireAccess(ctx context.Context, level string, projectIDOrName interface{}, action rbac.Action) error {
|
func (rAPI *robotAPI) requireAccess(ctx context.Context, r *robot.Robot, action rbac.Action) error {
|
||||||
if level == robot.LEVELSYSTEM {
|
if r.Level == robot.LEVELSYSTEM {
|
||||||
return rAPI.RequireSystemAccess(ctx, action, rbac.ResourceRobot)
|
return rAPI.RequireSystemAccess(ctx, action, rbac.ResourceRobot)
|
||||||
} else if level == robot.LEVELPROJECT {
|
} else if r.Level == robot.LEVELPROJECT {
|
||||||
return rAPI.RequireProjectAccess(ctx, projectIDOrName, action, rbac.ResourceRobot)
|
var ns interface{}
|
||||||
|
if r.ProjectNameOrID != nil {
|
||||||
|
ns = r.ProjectNameOrID
|
||||||
|
} else if r.ProjectID > 0 {
|
||||||
|
ns = r.ProjectID
|
||||||
|
} else if r.ProjectName != "" {
|
||||||
|
ns = r.ProjectName
|
||||||
}
|
}
|
||||||
|
return rAPI.RequireProjectAccess(ctx, ns, action, rbac.ResourceRobot)
|
||||||
|
}
|
||||||
|
|
||||||
return errors.ForbiddenError(nil)
|
return errors.ForbiddenError(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,17 +355,18 @@ func (rAPI *robotAPI) validate(d int64, level string, permissions []*models.Robo
|
|||||||
return errors.New(nil).WithMessage("bad request permission").WithCode(errors.BadRequestCode)
|
return errors.New(nil).WithMessage("bad request permission").WithCode(errors.BadRequestCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
provider := rbac.GetPermissionProvider()
|
||||||
// to validate the access scope
|
// to validate the access scope
|
||||||
for _, perm := range permissions {
|
for _, perm := range permissions {
|
||||||
if perm.Kind == robot.LEVELSYSTEM {
|
if perm.Kind == robot.LEVELSYSTEM {
|
||||||
polices := rbac.PoliciesMap["System"]
|
polices := provider.GetPermissions(rbac.ScopeSystem)
|
||||||
for _, acc := range perm.Access {
|
for _, acc := range perm.Access {
|
||||||
if !containsAccess(polices, acc) {
|
if !containsAccess(polices, acc) {
|
||||||
return errors.New(nil).WithMessage("bad request permission: %s:%s", acc.Resource, acc.Action).WithCode(errors.BadRequestCode)
|
return errors.New(nil).WithMessage("bad request permission: %s:%s", acc.Resource, acc.Action).WithCode(errors.BadRequestCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if perm.Kind == robot.LEVELPROJECT {
|
} else if perm.Kind == robot.LEVELPROJECT {
|
||||||
polices := rbac.PoliciesMap["Project"]
|
polices := provider.GetPermissions(rbac.ScopeProject)
|
||||||
for _, acc := range perm.Access {
|
for _, acc := range perm.Access {
|
||||||
if !containsAccess(polices, acc) {
|
if !containsAccess(polices, acc) {
|
||||||
return errors.New(nil).WithMessage("bad request permission: %s:%s", acc.Resource, acc.Action).WithCode(errors.BadRequestCode)
|
return errors.New(nil).WithMessage("bad request permission: %s:%s", acc.Resource, acc.Action).WithCode(errors.BadRequestCode)
|
||||||
@ -356,7 +396,8 @@ func (rAPI *robotAPI) updateV2Robot(ctx context.Context, params operation.Update
|
|||||||
return errors.BadRequestError(nil).WithMessage("cannot update the project id of robot")
|
return errors.BadRequestError(nil).WithMessage("cannot update the project id of robot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := rAPI.requireAccess(ctx, params.Robot.Level, params.Robot.Permissions[0].Namespace, rbac.ActionUpdate); err != nil {
|
r.ProjectNameOrID = params.Robot.Permissions[0].Namespace
|
||||||
|
if err := rAPI.requireAccess(ctx, r, rbac.ActionUpdate); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if params.Robot.Level != r.Level || params.Robot.Name != r.Name {
|
if params.Robot.Level != r.Level || params.Robot.Name != r.Name {
|
||||||
@ -380,6 +421,42 @@ func (rAPI *robotAPI) updateV2Robot(ctx context.Context, params operation.Update
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
creatorRobot, err := rAPI.robotCtl.Get(ctx, r.CreatorRef, &robot.Option{
|
||||||
|
WithPermission: true,
|
||||||
|
})
|
||||||
|
if err != nil && !errors.IsErr(err, errors.NotFoundCode) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// for nested robot only
|
||||||
|
if creatorRobot != nil && r.CreatorType == "robot" {
|
||||||
|
sc, err := rAPI.GetSecurityContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, ok := sc.(*robotSc.SecurityContext); ok {
|
||||||
|
scRobots, err := rAPI.robotCtl.List(ctx, q.New(q.KeyWords{
|
||||||
|
"name": strings.TrimPrefix(sc.GetUsername(), config.RobotPrefix(ctx)),
|
||||||
|
"project_id": r.ProjectID,
|
||||||
|
}), &robot.Option{
|
||||||
|
WithPermission: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(scRobots) == 0 {
|
||||||
|
return errors.DeniedError(nil)
|
||||||
|
}
|
||||||
|
if scRobots[0].ID != creatorRobot.ID && scRobots[0].ID != r.ID {
|
||||||
|
return errors.New(nil).WithMessage("as for a nested robot account, only person who has the right permission or the creator robot or nested robot itself has the permission to update").WithCode(errors.DENIED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isValidPermissionScope(params.Robot.Permissions, creatorRobot.Permissions) {
|
||||||
|
return errors.New(nil).WithMessage("permission scope is invalid. It must be equal to or more restrictive than the creator robot's permissions: %s", creatorRobot.Name).WithCode(errors.DENIED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := rAPI.robotCtl.Update(ctx, r, &robot.Option{
|
if err := rAPI.robotCtl.Update(ctx, r, &robot.Option{
|
||||||
WithPermission: true,
|
WithPermission: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -414,3 +491,39 @@ func containsAccess(policies []*types.Policy, item *models.Access) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isValidPermissionScope checks if permission slice A is a subset of permission slice B
|
||||||
|
func isValidPermissionScope(creating []*models.RobotPermission, creator []*robot.Permission) bool {
|
||||||
|
creatorMap := make(map[string]*robot.Permission)
|
||||||
|
for _, creatorPerm := range creator {
|
||||||
|
key := fmt.Sprintf("%s:%s", creatorPerm.Kind, creatorPerm.Namespace)
|
||||||
|
creatorMap[key] = creatorPerm
|
||||||
|
}
|
||||||
|
|
||||||
|
hasLessThanOrEqualAccess := func(creating []*models.Access, creator []*types.Policy) bool {
|
||||||
|
creatorMap := make(map[string]*types.Policy)
|
||||||
|
for _, creatorP := range creator {
|
||||||
|
key := fmt.Sprintf("%s:%s:%s", creatorP.Resource, creatorP.Action, creatorP.Effect)
|
||||||
|
creatorMap[key] = creatorP
|
||||||
|
}
|
||||||
|
for _, creatingP := range creating {
|
||||||
|
key := fmt.Sprintf("%s:%s:%s", creatingP.Resource, creatingP.Action, creatingP.Effect)
|
||||||
|
if _, found := creatorMap[key]; !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pCreating := range creating {
|
||||||
|
key := fmt.Sprintf("%s:%s", pCreating.Kind, pCreating.Namespace)
|
||||||
|
creatingPerm, found := creatorMap[key]
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !hasLessThanOrEqualAccess(pCreating.Access, creatingPerm.Access) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/rbac"
|
|
||||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/goharbor/harbor/src/common/rbac"
|
||||||
|
"github.com/goharbor/harbor/src/controller/robot"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||||
|
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidLevel(t *testing.T) {
|
func TestValidLevel(t *testing.T) {
|
||||||
@ -207,3 +212,181 @@ func TestContainsAccess(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidPermissionScope(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
creatingPerms []*models.RobotPermission
|
||||||
|
creatorPerms []*robot.Permission
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Project - subset",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "testSubset",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "testSubset",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
{Resource: "repository", Action: "push", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Project - not Subset",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "testNotSubset",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "repository", Action: "push", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "testNotSubset",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Project - equal",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "library",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "library",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Project - different",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "library",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "other",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Project - empty creator",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "library",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Project - empty creating",
|
||||||
|
creatingPerms: []*models.RobotPermission{},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "project",
|
||||||
|
Namespace: "library",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "repository", Action: "pull", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "System - subset",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "system",
|
||||||
|
Namespace: "admin",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "user", Action: "create", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "system",
|
||||||
|
Namespace: "admin",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "user", Action: "create", Effect: "allow"},
|
||||||
|
{Resource: "user", Action: "delete", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "System - not subset",
|
||||||
|
creatingPerms: []*models.RobotPermission{
|
||||||
|
{
|
||||||
|
Kind: "system",
|
||||||
|
Namespace: "admin",
|
||||||
|
Access: []*models.Access{
|
||||||
|
{Resource: "user", Action: "delete", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creatorPerms: []*robot.Permission{
|
||||||
|
{
|
||||||
|
Kind: "system",
|
||||||
|
Namespace: "admin",
|
||||||
|
Access: []*types.Policy{
|
||||||
|
{Resource: "user", Action: "create", Effect: "allow"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := isValidPermissionScope(tt.creatingPerms, tt.creatorPerms)
|
||||||
|
assert.Equal(t, tt.expected, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user