Update role importer, add tests
This commit is contained in:
@@ -6,12 +6,14 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza-server/system/importer"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
@@ -24,6 +26,7 @@ func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
var (
|
||||
aux interface{}
|
||||
ff []io.Reader
|
||||
err error
|
||||
)
|
||||
@@ -41,18 +44,25 @@ func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
ff = []io.Reader{os.Stdin}
|
||||
}
|
||||
|
||||
roles := service.DefaultRole.With(ctx)
|
||||
roles, err := service.DefaultRole.With(ctx).Find(&types.RoleFilter{})
|
||||
cli.HandleError(err)
|
||||
|
||||
for i, f := range ff {
|
||||
cmd.Printf("Importing from %s\n", args[i])
|
||||
|
||||
imp := importer.NewImporter(
|
||||
roles,
|
||||
permissions.NewImporter(service.DefaultAccessControl.Whitelist()),
|
||||
cli.HandleError(yaml.NewDecoder(f).Decode(&aux))
|
||||
|
||||
perm := permissions.NewImporter(service.DefaultAccessControl.Whitelist())
|
||||
|
||||
imp := importer.NewImporter(perm,
|
||||
importer.NewRoleImport(perm, roles),
|
||||
)
|
||||
|
||||
cli.HandleError(imp.YAML(f))
|
||||
cli.HandleError(imp.Store(ctx, roles, service.DefaultAccessControl))
|
||||
cli.HandleError(imp.Store(
|
||||
ctx,
|
||||
service.DefaultRole.With(ctx),
|
||||
service.DefaultAccessControl,
|
||||
))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,9 +3,6 @@ package importer
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/pkg/deinterfacer"
|
||||
@@ -14,32 +11,18 @@ import (
|
||||
|
||||
type (
|
||||
Importer struct {
|
||||
roleFinder roleFinder
|
||||
|
||||
roles *RoleImport
|
||||
|
||||
roles *Role
|
||||
permissions importer.PermissionImporter
|
||||
}
|
||||
)
|
||||
|
||||
func NewImporter(rf roleFinder, p importer.PermissionImporter) *Importer {
|
||||
func NewImporter(p importer.PermissionImporter, ri *Role) *Importer {
|
||||
return &Importer{
|
||||
roleFinder: rf,
|
||||
roles: NewRoleImporter(rf, p),
|
||||
roles: ri,
|
||||
permissions: p,
|
||||
}
|
||||
}
|
||||
|
||||
func (imp *Importer) YAML(r io.Reader) (err error) {
|
||||
var aux interface{}
|
||||
|
||||
if err = yaml.NewDecoder(r).Decode(&aux); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return imp.Cast(aux)
|
||||
}
|
||||
|
||||
func (imp *Importer) Cast(in interface{}) (err error) {
|
||||
return deinterfacer.Each(in, func(index int, key string, val interface{}) (err error) {
|
||||
switch key {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
)
|
||||
|
||||
var (
|
||||
pi *permissions.Importer
|
||||
|
||||
imp *Importer
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
resetMocks()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func resetMocks() {
|
||||
// whitelist = nil, anything can be added
|
||||
pi = permissions.NewImporter(service.AccessControl(nil).Whitelist())
|
||||
|
||||
imp = NewImporter(
|
||||
pi,
|
||||
NewRoleImport(pi, nil),
|
||||
)
|
||||
}
|
||||
|
||||
func impFixTester(t *testing.T, name string, tester interface{}) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// We're not calling reset mocks BEFORE calling tester()
|
||||
// because we want to have an option to set it up as we want
|
||||
defer resetMocks()
|
||||
|
||||
var aux interface{}
|
||||
req := require.New(t)
|
||||
f, err := os.Open(fmt.Sprintf("testdata/%s.yaml", name))
|
||||
req.NoError(err)
|
||||
req.NoError(yaml.NewDecoder(f).Decode(&aux))
|
||||
req.NotNil(aux)
|
||||
|
||||
if reqError, ok := tester.(error); ok {
|
||||
req.EqualError(imp.Cast(aux), reqError.Error())
|
||||
return
|
||||
} else {
|
||||
req.NoError(imp.Cast(aux))
|
||||
}
|
||||
|
||||
switch tester := tester.(type) {
|
||||
case func(*testing.T, *Role):
|
||||
tester(t, imp.roles)
|
||||
case func(*testing.T, *Importer):
|
||||
tester(t, imp)
|
||||
default:
|
||||
panic("unsupported tester function signature")
|
||||
}
|
||||
})
|
||||
}
|
||||
+37
-65
@@ -12,17 +12,10 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
RoleImport struct {
|
||||
set types.RoleSet
|
||||
dirty map[string]bool
|
||||
|
||||
Role struct {
|
||||
set types.RoleSet
|
||||
dirty map[uint64]bool
|
||||
permissions importer.PermissionImporter
|
||||
|
||||
finder roleFinder
|
||||
}
|
||||
|
||||
roleFinder interface {
|
||||
FindByHandle(string) (*types.Role, error)
|
||||
}
|
||||
|
||||
roleKeeper interface {
|
||||
@@ -31,31 +24,32 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func NewRoleImporter(finder roleFinder, permissions importer.PermissionImporter) *RoleImport {
|
||||
return &RoleImport{
|
||||
set: types.RoleSet{},
|
||||
dirty: map[string]bool{},
|
||||
permissions: permissions,
|
||||
finder: finder,
|
||||
func NewRoleImport(permissions importer.PermissionImporter, set types.RoleSet) *Role {
|
||||
if set == nil {
|
||||
set = types.RoleSet{}
|
||||
}
|
||||
|
||||
out := &Role{
|
||||
set: set,
|
||||
dirty: make(map[uint64]bool),
|
||||
permissions: permissions,
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Resolves permission rules:
|
||||
// { <role-handle>: { role } } or [ { role }, ... ]
|
||||
func (imp *RoleImport) CastSet(set interface{}) error {
|
||||
func (rImp *Role) CastSet(set interface{}) error {
|
||||
return deinterfacer.Each(set, func(index int, handle string, def interface{}) error {
|
||||
if index > -1 {
|
||||
// Roles defined as collection
|
||||
deinterfacer.KVsetString(&handle, "handle", def)
|
||||
}
|
||||
|
||||
return imp.Cast(handle, def)
|
||||
return rImp.Cast(handle, def)
|
||||
})
|
||||
}
|
||||
|
||||
// Resolves permission rules:
|
||||
// { <role-handle>: { role } } or [ { role }, ... ]
|
||||
func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
|
||||
func (rImp *Role) Cast(handle string, def interface{}) (err error) {
|
||||
var role *types.Role
|
||||
|
||||
if !importer.IsValidHandle(handle) {
|
||||
@@ -63,12 +57,21 @@ func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
|
||||
}
|
||||
|
||||
handle = importer.NormalizeHandle(handle)
|
||||
if role, err = imp.Get(handle); err != nil {
|
||||
if role, err = rImp.Get(handle); err != nil {
|
||||
return err
|
||||
} else if role == nil {
|
||||
role = &types.Role{
|
||||
Handle: handle,
|
||||
}
|
||||
|
||||
rImp.set = append(rImp.set, role)
|
||||
} else if role.ID == 0 {
|
||||
return errors.Errorf("role handle %q already defined in this import session", role.Handle)
|
||||
} else {
|
||||
rImp.dirty[role.ID] = true
|
||||
}
|
||||
|
||||
if name, ok := def.(string); ok && name != "" {
|
||||
imp.dirty[handle] = role.Name != name
|
||||
role.Name = name
|
||||
return nil
|
||||
}
|
||||
@@ -79,11 +82,10 @@ func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
|
||||
// already handled
|
||||
case "name":
|
||||
name := deinterfacer.ToString(val)
|
||||
imp.dirty[handle] = role.Name != name
|
||||
role.Name = name
|
||||
|
||||
case "allow", "deny":
|
||||
return imp.permissions.CastSet(types.RolePermissionResource.String()+role.Handle, key, val)
|
||||
return rImp.permissions.CastSet(types.RolePermissionResource.String()+role.Handle, key, val)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unexpected key %q for role %q", key, role.Handle)
|
||||
@@ -93,62 +95,32 @@ func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
|
||||
})
|
||||
}
|
||||
|
||||
// Exists returns true if role exists in the buffer or
|
||||
// can be loaded from the storage
|
||||
func (imp *RoleImport) Exists(handle string) bool {
|
||||
handle = importer.NormalizeHandle(handle)
|
||||
role := imp.set.FindByHandle(handle)
|
||||
if role != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if imp.finder != nil {
|
||||
role, err := imp.finder.FindByHandle(handle)
|
||||
if err == nil && role != nil {
|
||||
imp.set = append(imp.set, role)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// finds or makes new role
|
||||
func (imp *RoleImport) Get(handle string) (*types.Role, error) {
|
||||
func (rImp *Role) Get(handle string) (*types.Role, error) {
|
||||
handle = importer.NormalizeHandle(handle)
|
||||
|
||||
if !importer.IsValidHandle(handle) {
|
||||
return nil, errors.New("invalid role handle")
|
||||
}
|
||||
|
||||
if !imp.Exists(handle) {
|
||||
imp.set = append(imp.set, &types.Role{
|
||||
Handle: handle,
|
||||
Name: handle,
|
||||
})
|
||||
}
|
||||
|
||||
return imp.set.FindByHandle(handle), nil
|
||||
return rImp.set.FindByHandle(handle), nil
|
||||
}
|
||||
|
||||
func (imp *RoleImport) Store(ctx context.Context, k roleKeeper) error {
|
||||
return imp.set.Walk(func(role *types.Role) (err error) {
|
||||
func (rImp *Role) Store(ctx context.Context, k roleKeeper) error {
|
||||
return rImp.set.Walk(func(role *types.Role) (err error) {
|
||||
var handle = role.Handle
|
||||
|
||||
if role.ID == 0 {
|
||||
role, err = k.Create(role)
|
||||
} else {
|
||||
if imp.dirty[handle] {
|
||||
role, err = k.Update(role)
|
||||
}
|
||||
} else if rImp.dirty[role.ID] {
|
||||
role, err = k.Update(role)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
imp.permissions.UpdateResources(types.RolePermissionResource.String(), handle, role.ID)
|
||||
imp.permissions.UpdateRoles(role.Handle, role.ID)
|
||||
rImp.permissions.UpdateResources(types.RolePermissionResource.String(), handle, role.ID)
|
||||
rImp.permissions.UpdateRoles(role.Handle, role.ID)
|
||||
|
||||
return
|
||||
})
|
||||
|
||||
@@ -2,42 +2,20 @@ package importer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRoleImport_CastSet(t *testing.T) {
|
||||
t.Skip()
|
||||
// tests := []struct {
|
||||
// name string
|
||||
// resource string
|
||||
// yaml string
|
||||
// set types.RoleSet
|
||||
// }{
|
||||
// {name: "empty", yaml: ``},
|
||||
// {name: "empty map", yaml: `{}`},
|
||||
// {name: "empty slice", yaml: `[]`},
|
||||
// {
|
||||
// name: "full",
|
||||
// yaml: `
|
||||
// admins: Admins
|
||||
// foo:
|
||||
// name: Foo
|
||||
// bar:
|
||||
// `,
|
||||
// set: []*types.Role{
|
||||
// {Handle: "admins", Name: "Admins"},
|
||||
// {Handle: "foo", Name: "Foo"},
|
||||
// {Handle: "bar", Name: "bar"},
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
// for _, tt := range tests {
|
||||
// t.Run(tt.name, func(t *testing.T) {
|
||||
// imp := &RoleImport{}
|
||||
//
|
||||
// aux, err := importer.ParseYAML([]byte(tt.yaml))
|
||||
// require.NoError(t, err)
|
||||
// require.NoError(t, imp.CastSet(aux))
|
||||
// require.Equal(t, tt.set, imp.set)
|
||||
// })
|
||||
// }
|
||||
impFixTester(t, "roles", func(t *testing.T, ri *Role) {
|
||||
req := require.New(t)
|
||||
req.NotNil(ri.set)
|
||||
req.Len(ri.set, 2)
|
||||
|
||||
req.NotNil(ri.set.FindByHandle("r1"))
|
||||
req.Equal("Role1", ri.set.FindByHandle("r1").Name)
|
||||
|
||||
req.NotNil(ri.set.FindByHandle("r2"))
|
||||
req.Equal("Role2", ri.set.FindByHandle("r2").Name)
|
||||
})
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
roles:
|
||||
r1: Role1
|
||||
r2:
|
||||
name: Role2
|
||||
Reference in New Issue
Block a user