diff --git a/pkg/extension/service/extension.go b/pkg/extension/service/extension.go index 995c343467fef3a9b1963ef5d65a1c230ad4c69d..45ed0524f855f888d7baf9befb9080392185dfc1 100644 --- a/pkg/extension/service/extension.go +++ b/pkg/extension/service/extension.go @@ -133,22 +133,38 @@ func (s *Extension) setupExtensionClient(set *setup.Setup, spaceID string) { set.AddClient(&client, setup.OverwriteClient(), setup.DeleteClientIfRemove()) } -func (s *Extension) GetSetup(spaceID, envID string) *setup.Setup { +func (s *Extension) GetSetup(spaceID, envID string) (*setup.Setup, error) { set := s.setupFunc(spaceID, envID) + if set.HasErrors() { + s.Logger.Error("Invalid setup config", zap.Errors("Errors", set.Errors())) + return nil, set.Error() + } s.setupExtensionClient(set, spaceID) - return set + return set, nil } func (s *Extension) Install(ctx context.Context, in *extension.InstallRequest) error { - return s.GetSetup(in.SpaceId, in.EnvId).WithForce(in.Force).Install(ctx) + set, err := s.GetSetup(in.SpaceId, in.EnvId) + if err != nil { + return err + } + return set.WithForce(in.Force).Install(ctx) } func (s *Extension) Check(ctx context.Context, in *extension.CheckRequest) error { - return s.GetSetup(in.SpaceId, in.EnvId).Check(ctx) + set, err := s.GetSetup(in.SpaceId, in.EnvId) + if err != nil { + return err + } + return set.Check(ctx) } func (s *Extension) Uninstall(ctx context.Context, in *extension.UninstallRequest) error { - return s.GetSetup(in.SpaceId, in.EnvId).WithForce(in.Force).WithRemove(in.Remove).Uninstall(ctx) + set, err := s.GetSetup(in.SpaceId, in.EnvId) + if err != nil { + return err + } + return set.WithForce(in.Force).WithRemove(in.Remove).Uninstall(ctx) } // isCorrectExtension проверяет что расширение в url совпадает с расширением расширения diff --git a/pkg/permission/permission.go b/pkg/permission/permission.go index 7a90e5079da08648cbdefe565d39f4d8b801a275..e08579e9c074470a80b8e2ecce3c1e62634b02f1 100644 --- a/pkg/permission/permission.go +++ b/pkg/permission/permission.go @@ -53,12 +53,6 @@ func (p Permission) RemoveFields(in map[string]interface{}) map[string]interface if in == nil { return nil } - out := make(map[string]interface{}) - for k, v := range in { - if data.Contains(k, p.UnallowedFields) { - continue - } - out[k] = v - } - return out + data.DeleteMany(p.UnallowedFields, in) + return in } diff --git a/pkg/permission/permission_test.go b/pkg/permission/permission_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2a365601e201a6fd31a34b89bcc47d3de14b4406 --- /dev/null +++ b/pkg/permission/permission_test.go @@ -0,0 +1,60 @@ +package permission + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPermission_RemoveFields(t *testing.T) { + + tests := []struct { + name string + unallowedFields []string + in map[string]interface{} + want map[string]interface{} + }{ + { + name: "nil", + in: nil, + want: nil, + }, + { + name: "empty", + in: map[string]interface{}{}, + want: map[string]interface{}{}, + }, + { + name: "empty unallowedFields", + in: map[string]interface{}{"f": "v"}, + want: map[string]interface{}{"f": "v"}, + unallowedFields: nil, + }, + { + name: "remove fields", + in: map[string]interface{}{"f": "v", "f1": "v"}, + want: map[string]interface{}{"f": "v"}, + unallowedFields: []string{"f1"}, + }, + { + name: "all present fields allowed", + in: map[string]interface{}{"f": "v", "f1": "v"}, + want: map[string]interface{}{"f": "v", "f1": "v"}, + unallowedFields: []string{"f2"}, + }, + { + name: "unallowed fields in nested object", + in: map[string]interface{}{"obj": map[string]interface{}{"f": "v", "f1": "v"}}, + want: map[string]interface{}{"obj": map[string]interface{}{"f": "v"}}, + unallowedFields: []string{"obj.f1"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := Permission{ + UnallowedFields: tt.unallowedFields, + } + assert.Equal(t, tt.want, p.RemoveFields(tt.in)) + }) + } +} diff --git a/pkg/permission/ruleset.go b/pkg/permission/ruleset.go index b9a84f3747223cf4139c905e3d65ebb9f4dea336..0843afc79922be9a20c06009d4084a281b3cd68f 100644 --- a/pkg/permission/ruleset.go +++ b/pkg/permission/ruleset.go @@ -133,6 +133,8 @@ func (r Rule) GetPermission(action Action) *Permission { p.UnallowedFields = append(p.UnallowedFields, r.ReadonlyFields...) } + p.UnallowedFields = data.SetFromSlice(p.UnallowedFields) + return p } } diff --git a/pkg/permission/ruleset_test.go b/pkg/permission/ruleset_test.go index 47c1f07614b1d2edef196db6238adaf40b33e073..175c36261152afcf2b2c585382588f97b5465591 100644 --- a/pkg/permission/ruleset_test.go +++ b/pkg/permission/ruleset_test.go @@ -49,3 +49,44 @@ func TestMerge(t *testing.T) { }) } } + +func TestRule_GetPermission(t *testing.T) { + tests := []struct { + name string + action Action + rule Rule + unallowedFields []string + want *Permission + }{ + { + name: "ActionRead", + action: ActionRead, + rule: Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f3"}}, + unallowedFields: []string{"f2", "f3"}, + }, + { + name: "ActionRead readonly&writeonly", + action: ActionRead, + rule: Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f1"}}, + unallowedFields: []string{"f1", "f2"}, + }, + { + name: "ActionUpdate", + action: ActionUpdate, + rule: Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f3"}}, + unallowedFields: []string{"f1"}, + }, + { + name: "ActionUpdate readonly&writeonly", + action: ActionUpdate, + rule: Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f1"}}, + unallowedFields: []string{"f1"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := tt.rule.GetPermission(tt.action) + assert.ElementsMatch(t, tt.unallowedFields, p.UnallowedFields) + }) + } +} diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index 6b26f3367a3774f9a29ae18b118cce2dd1a4bd89..e45298241602e6855c63019fe5bebcc4e2df27ee 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -71,6 +71,15 @@ func (s Schema) SetMetadata(md map[string]string) *Schema { return &s } +func (s *Schema) ConvertTypes() error { + b, err := s.MarshalJSON() + if err != nil { + return errors.Wrap(err, "marshal schema") + } + *s = *New() + return errors.Wrap(s.UnmarshalJSON(b), "unmarshal schema") +} + func (s *Schema) Load(ctx context.Context) error { if s.Loaded { return nil diff --git a/pkg/setup/collection.go b/pkg/setup/collection.go index 725a04e390f3b298e612875378f33a62138cce3f..0a7fc65c9da358240980638e82915089b13e5829 100644 --- a/pkg/setup/collection.go +++ b/pkg/setup/collection.go @@ -27,8 +27,19 @@ type CollectionConfig struct { SkipMigration bool } -func NewCollectionConfig(collection *collections.Collection, opt ...CollectionsOption) CollectionConfig { - c := CollectionConfig{collection: collection} +func NewCollectionConfig(collection *collections.Collection, opt ...CollectionsOption) (c CollectionConfig, err error) { + collection = collection.Clone() + + if collection.Schema != nil { + // приведение внутренних типов схемы, чтобы избежать возможного несоответствия типов при + // сравнивании схем (`[]interface{}/[]string`, `int/int64`, etc.) + err = collection.Schema.ConvertTypes() + if err != nil { + return + } + } + + c = CollectionConfig{collection: collection} DefaultUpdateCollectionStrategy()(&c) DeleteCollectionIfRemove()(&c) @@ -37,7 +48,7 @@ func NewCollectionConfig(collection *collections.Collection, opt ...CollectionsO o(&c) } - return c + return c, nil } func SkipMigration() CollectionsOption { diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 6360eadee88a9cc2345e140f7acf5829e0fc9f26..6101e1db13f40027706977dad4b710261d82439d 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -2,6 +2,7 @@ package setup import ( "context" + "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/clients" "git.perx.ru/perxis/perxis-go/pkg/collections" @@ -11,6 +12,10 @@ import ( "go.uber.org/zap" ) +var ( + ErrInvalidSetupConfig = errors.New("invalid setup config") +) + // Setup реализует процесс настройки пространства. Указав необходимые требования к конфигурации пространства можно // выполнить процесс установки, проверки и удаления требований. type Setup struct { @@ -32,12 +37,12 @@ type Setup struct { } func NewSetup(content *content.Content, spaceID, environmentID string, logger *zap.Logger) *Setup { - //logger = logger.With(zap.String("Space", spaceID), zap.String("Environment", environmentID)) - if logger == nil { logger = zap.NewNop() } + logger = logger.With(zap.String("Space", spaceID), zap.String("Environment", environmentID)) + return &Setup{ SpaceID: spaceID, EnvironmentID: environmentID, @@ -74,6 +79,14 @@ func (s *Setup) AddError(err error) { s.errors = append(s.errors, err) } +func (s *Setup) Errors() []error { + return s.errors +} + +func (s *Setup) Error() error { + return errors.WithErrors(ErrInvalidSetupConfig, s.errors...) +} + // AddRoles добавляет требования к настройке ролей в пространстве func (s *Setup) AddRoles(roles []*roles.Role, opt ...RolesOption) *Setup { for _, role := range roles { @@ -109,7 +122,12 @@ func (s *Setup) AddCollections(collections []*collections.Collection, opt ...Col } func (s *Setup) AddCollection(collection *collections.Collection, opt ...CollectionsOption) *Setup { - s.Collections = append(s.Collections, NewCollectionConfig(collection, opt...)) + config, err := NewCollectionConfig(collection, opt...) + if err != nil { + s.AddError(err) + return s + } + s.Collections = append(s.Collections, config) return s } @@ -128,8 +146,6 @@ func (s *Setup) AddItem(item *items.Item, opt ...ItemsOption) *Setup { // Install выполняет установку необходимых требований func (s *Setup) Install(ctx context.Context) error { - s.logger = s.logger.With(zap.String("Space", s.SpaceID), zap.String("Environment", s.EnvironmentID)) - if err := s.InstallRoles(ctx); err != nil { return err } @@ -142,14 +158,11 @@ func (s *Setup) Install(ctx context.Context) error { if err := s.InstallItems(ctx); err != nil { return err } - return nil } // Check выполняет проверку требований func (s *Setup) Check(ctx context.Context) error { - s.logger = s.logger.With(zap.String("Space", s.SpaceID), zap.String("Environment", s.EnvironmentID)) - if err := s.CheckRoles(ctx); err != nil { return err } @@ -162,14 +175,11 @@ func (s *Setup) Check(ctx context.Context) error { if err := s.CheckItems(ctx); err != nil { return err } - return nil } // Uninstall выполняет удаление установленных раннее требований func (s *Setup) Uninstall(ctx context.Context) error { - s.logger = s.logger.With(zap.String("Space", s.SpaceID), zap.String("Environment", s.EnvironmentID)) - // В случае если необходимо удалить данные удаляем все что создано при установке расширения if err := s.UninstallClients(ctx); err != nil { return err @@ -183,6 +193,5 @@ func (s *Setup) Uninstall(ctx context.Context) error { if err := s.UninstallItems(ctx); err != nil { return err } - return nil }