3
0

Refactor sensitivity levels to be consistent with connections

This commit is contained in:
Tomaž Jerman
2022-07-15 10:13:11 +02:00
parent af8aa9893d
commit 85bb86c5cd
5 changed files with 158 additions and 233 deletions
+6
View File
@@ -14,6 +14,12 @@ func errConnectionNotFound(connectionID uint64) error {
return fmt.Errorf("connection %d does not exist", connectionID)
}
// Sensitivity level errors
// - remove
func errSensitivityLevelRemoveNotFound(sensitivityLevelID uint64) error {
return fmt.Errorf("cannot remove sensitivity level %d: sensitivity level does not exist", sensitivityLevelID)
}
// Connection errors
// - create
func errConnectionCreateMissingSensitivityLevel(connectionID, sensitivityLevelID uint64) error {
+28 -7
View File
@@ -1,5 +1,7 @@
package dal
import "sort"
type (
SensitivityLevel struct {
Handle string
@@ -32,6 +34,29 @@ func SensitivityLevelIndex(levels ...SensitivityLevel) *sensitivityLevelIndex {
return out
}
func (sli sensitivityLevelIndex) with(levels ...SensitivityLevel) *sensitivityLevelIndex {
slvls := append(sli.set, levels...)
sort.Sort(slvls)
return SensitivityLevelIndex(slvls...)
}
func (sli sensitivityLevelIndex) without(levels ...SensitivityLevel) *sensitivityLevelIndex {
nn := make(SensitivityLevelSet, 0, len(sli.set))
remIndex := SensitivityLevelIndex(levels...)
for _, existing := range sli.set {
if !remIndex.includes(existing.ID) {
nn = append(nn, existing)
}
}
sort.Sort(nn)
return SensitivityLevelIndex(nn...)
}
func (sli sensitivityLevelIndex) includes(l uint64) (ok bool) {
if l == 0 {
return true
@@ -69,10 +94,6 @@ func (sli sensitivityLevelIndex) isSubset(a, b uint64) (ok bool) {
return lvlA <= lvlB
}
func (ss SensitivityLevelSet) includes(l uint64) (ok bool) {
for _, s := range ss {
ok = ok || s.ID == l
}
return
}
func (a SensitivityLevelSet) Len() int { return len(a) }
func (a SensitivityLevelSet) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SensitivityLevelSet) Less(i, j int) bool { return a[i].Level < a[j].Level }
+83 -129
View File
@@ -3,6 +3,8 @@ package dal
import (
"context"
"fmt"
"strconv"
"github.com/cortezaproject/corteza-server/pkg/dal/capabilities"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/pkg/filter"
@@ -13,14 +15,7 @@ type (
ConnectionWrap struct {
connectionID uint64
// @todo remove it and use value from connection meta
label string
// @todo remove it and use value from connection meta
sensitivityLevel uint64
connection Connection
connection Connection
params ConnectionParams
meta ConnectionMeta
capabilities capabilities.Set
@@ -60,7 +55,7 @@ type (
logger *zap.Logger
inDev bool
sensitivityLevels sensitivityLevelIndex
sensitivityLevels *sensitivityLevelIndex
connectionIssues dalIssueIndex
modelIssues dalIssueIndex
@@ -80,8 +75,9 @@ func SetGlobal(svc *service) {
// It needs an established and working connection to the primary store
func New(log *zap.Logger, inDev bool) (*service, error) {
svc := &service{
connections: make(map[uint64]*ConnectionWrap),
models: make(map[uint64]ModelSet),
connections: make(map[uint64]*ConnectionWrap),
models: make(map[uint64]ModelSet),
sensitivityLevels: SensitivityLevelIndex(),
logger: log,
inDev: inDev,
@@ -115,66 +111,87 @@ func (svc *service) Drivers() (drivers []Driver) {
return
}
func (svc *service) ReloadSensitivityLevels(levels ...SensitivityLevel) (err error) {
svc.logger.Debug("reloading sensitivity levels", zap.Any("sensitivity levels", levels))
newLevelIndex := svc.newSensitivityLevelIndex(levels)
func MakeSensitivityLevel(ID uint64, level int, handle string) SensitivityLevel {
return SensitivityLevel{
ID: ID,
Level: level,
Handle: handle,
}
}
func (svc *service) ReplaceSensitivityLevel(levels ...SensitivityLevel) (err error) {
var (
log = svc.logger.Named("sensitivity level")
)
log.Debug("replacing levels", zap.Any("levels", levels))
if svc.sensitivityLevels == nil {
svc.sensitivityLevels = SensitivityLevelIndex()
}
nx := svc.sensitivityLevels
for _, l := range levels {
log := log.With(zap.Uint64("ID", l.ID), zap.Int("level", l.Level), zap.String("handle", l.Handle))
if nx.includes(l.ID) {
log.Debug("found existing")
} else {
log.Debug("adding new")
}
}
nx = svc.sensitivityLevels.with(levels...)
// Validate state after sensitivity level change
if err = svc.validateNewSensitivityLevels(newLevelIndex); err != nil {
log.Debug("validating new levels")
if err = svc.validateNewSensitivityLevels(nx); err != nil {
return
}
// Replace old ones
svc.sensitivityLevels = newLevelIndex
// Replace the old one
svc.sensitivityLevels = nx
svc.logger.Debug("reloaded sensitivity levels")
return
}
func (svc *service) CreateSensitivityLevel(levels ...SensitivityLevel) (err error) {
svc.logger.Debug("creating sensitivity levels", zap.Any("sensitivity levels", levels))
newIndex := svc.newAddedSensitivityLevelIndex(svc.sensitivityLevels, levels...)
func (svc *service) RemoveSensitivityLevel(levelIDs ...uint64) (err error) {
var (
log = svc.logger.Named("sensitivity level")
)
log.Debug("removing levels", zap.Any("levels", levelIDs))
levels := make(SensitivityLevelSet, len(levelIDs))
for i, lID := range levelIDs {
levels[i] = MakeSensitivityLevel(lID, i, strconv.FormatUint(lID, 10))
}
if svc.sensitivityLevels == nil {
svc.sensitivityLevels = SensitivityLevelIndex()
}
nx := svc.sensitivityLevels
for _, l := range levels {
log := log.With(zap.Uint64("ID", l.ID))
if !nx.includes(l.ID) {
log.Debug("sensitivity level not found")
return errSensitivityLevelRemoveNotFound(l.ID)
}
}
nx = svc.sensitivityLevels.without(levels...)
// Validate state after sensitivity level change
if err = svc.validateNewSensitivityLevels(newIndex); err != nil {
log.Debug("validating new levels")
if err = svc.validateNewSensitivityLevels(nx); err != nil {
return
}
// Replace old ones
svc.sensitivityLevels = newIndex
svc.logger.Debug("created sensitivity levels")
return
}
func (svc *service) UpdateSensitivityLevel(levels ...SensitivityLevel) (err error) {
svc.logger.Debug("updating sensitivity levels", zap.Any("sensitivity levels", levels))
newIndex := svc.newRemovedSensitivityLevelIndex(svc.sensitivityLevels, levels...)
newIndex = svc.newAddedSensitivityLevelIndex(newIndex, levels...)
// Validate state after sensitivity level change
if err = svc.validateNewSensitivityLevels(newIndex); err != nil {
return
}
// Replace old ones
svc.sensitivityLevels = newIndex
svc.logger.Debug("updated sensitivity levels")
return
}
func (svc *service) DeleteSensitivityLevel(levels ...SensitivityLevel) (err error) {
svc.logger.Debug("deleting sensitivity levels", zap.Any("sensitivity levels", levels))
newIndex := svc.newRemovedSensitivityLevelIndex(svc.sensitivityLevels, levels...)
// Validate state after sensitivity level change
if err = svc.validateNewSensitivityLevels(newIndex); err != nil {
return
}
// Replace old ones
svc.sensitivityLevels = newIndex
svc.logger.Debug("deleted sensitivity levels")
// Replace the old one
svc.sensitivityLevels = nx
svc.logger.Debug("removed sensitivity levels")
return
}
@@ -189,12 +206,8 @@ func MakeConnection(ID uint64, conn Connection, p ConnectionParams, m Connection
connectionID: ID,
connection: conn,
params: p,
meta: m,
sensitivityLevel: m.SensitivityLevel,
label: m.Label,
params: p,
meta: m,
capabilities: cap,
}
}
@@ -228,7 +241,7 @@ func (svc *service) ReplaceConnection(ctx context.Context, cw *ConnectionWrap, i
} else if svc.defConnID != ID {
// default connection set but ID is different.
// this does not make any sense
return fmt.Errorf("different ID for default connection detecte (old: %d, new: %d)", svc.defConnID, ID)
return fmt.Errorf("different ID for default connection detected (old: %d, new: %d)", svc.defConnID, ID)
}
}
@@ -522,8 +535,8 @@ func (svc *service) CreateModel(ctx context.Context, models ...*Model) (err erro
issues.addModelIssue(model.ConnectionID, model.ResourceID, errModelCreateMissingSensitivityLevel(model.ConnectionID, model.ResourceID, model.SensitivityLevel))
} else {
// Only check if it is present
if !svc.sensitivityLevels.isSubset(model.SensitivityLevel, conn.sensitivityLevel) {
issues.addModelIssue(model.ConnectionID, model.ResourceID, errModelCreateGreaterSensitivityLevel(model.ConnectionID, model.ResourceID, model.SensitivityLevel, conn.sensitivityLevel))
if !svc.sensitivityLevels.isSubset(model.SensitivityLevel, conn.meta.SensitivityLevel) {
issues.addModelIssue(model.ConnectionID, model.ResourceID, errModelCreateGreaterSensitivityLevel(model.ConnectionID, model.ResourceID, model.SensitivityLevel, conn.meta.SensitivityLevel))
}
}
// - attributes
@@ -722,8 +735,8 @@ func (svc *service) UpdateModel(ctx context.Context, old *Model, new *Model) (er
if !svc.sensitivityLevels.includes(new.SensitivityLevel) {
issues.addModelIssue(new.ConnectionID, new.ResourceID, errModelUpdateMissingSensitivityLevel(new.ConnectionID, new.ResourceID, new.SensitivityLevel))
} else {
if !svc.sensitivityLevels.isSubset(new.SensitivityLevel, conn.sensitivityLevel) {
issues.addModelIssue(new.ConnectionID, new.ResourceID, errModelUpdateGreaterSensitivityLevel(new.ConnectionID, new.ResourceID, new.SensitivityLevel, conn.sensitivityLevel))
if !svc.sensitivityLevels.isSubset(new.SensitivityLevel, conn.meta.SensitivityLevel) {
issues.addModelIssue(new.ConnectionID, new.ResourceID, errModelUpdateGreaterSensitivityLevel(new.ConnectionID, new.ResourceID, new.SensitivityLevel, conn.meta.SensitivityLevel))
}
}
@@ -988,66 +1001,7 @@ func (svc *service) getModelByFilter(mf ModelFilter) *Model {
return svc.FindModelByResourceIdent(mf.ConnectionID, mf.ResourceType, mf.Resource)
}
func (svc *service) newAddedSensitivityLevelIndex(sli sensitivityLevelIndex, add ...SensitivityLevel) (out sensitivityLevelIndex) {
newLevels := make(SensitivityLevelSet, 0, len(sli.set)+len(add))
var (
i = 0
j = 0
)
for i < len(sli.set) {
for j < len(add) {
if sli.set[i].Level <= add[j].Level {
newLevels = append(newLevels, sli.set[i])
i++
}
if sli.set[i].Level > add[j].Level {
newLevels = append(newLevels, add[j])
j++
}
}
}
if j < len(add)-1 {
newLevels = append(newLevels, add[j:]...)
}
return svc.newSensitivityLevelIndex(newLevels)
}
func (svc *service) newRemovedSensitivityLevelIndex(sli sensitivityLevelIndex, remove ...SensitivityLevel) (out sensitivityLevelIndex) {
newLevels := make(SensitivityLevelSet, 0, len(sli.set)+len(remove))
removeSet := SensitivityLevelSet(remove)
for _, l := range sli.set {
if !removeSet.includes(l.ID) {
newLevels = append(newLevels, l)
}
}
return svc.newSensitivityLevelIndex(newLevels)
}
func (svc *service) newSensitivityLevelIndex(levels SensitivityLevelSet) (out sensitivityLevelIndex) {
out = sensitivityLevelIndex{
byID: make(map[uint64]int),
byHandle: make(map[string]int),
set: make(SensitivityLevelSet, len(levels)),
}
for i, l := range levels {
out.set[i] = l
out.byID[l.ID] = i
out.byHandle[l.Handle] = i
}
return
}
func (svc *service) validateNewSensitivityLevels(levels sensitivityLevelIndex) (err error) {
func (svc *service) validateNewSensitivityLevels(levels *sensitivityLevelIndex) (err error) {
err = func() (err error) {
cIndex := make(map[uint64]*ConnectionWrap)
@@ -1056,8 +1010,8 @@ func (svc *service) validateNewSensitivityLevels(levels sensitivityLevelIndex) (
c := _c
cIndex[c.connectionID] = c
if !levels.includes(c.sensitivityLevel) {
return fmt.Errorf("connection sensitivity level missing %d", c.sensitivityLevel)
if !levels.includes(c.meta.SensitivityLevel) {
return fmt.Errorf("connection sensitivity level missing %d", c.meta.SensitivityLevel)
}
}
@@ -1067,7 +1021,7 @@ func (svc *service) validateNewSensitivityLevels(levels sensitivityLevelIndex) (
if !levels.includes(m.SensitivityLevel) {
return fmt.Errorf("model sensitivity level missing %d", m.SensitivityLevel)
}
if !levels.isSubset(m.SensitivityLevel, cIndex[m.ConnectionID].sensitivityLevel) {
if !levels.isSubset(m.SensitivityLevel, cIndex[m.ConnectionID].meta.SensitivityLevel) {
return fmt.Errorf("model sensitivity level missing %d", m.SensitivityLevel)
}
-83
View File
@@ -1,83 +0,0 @@
package dalutils
import (
"context"
"sort"
"github.com/cortezaproject/corteza-server/pkg/dal"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
sensitivityLevelCreator interface {
CreateSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
}
sensitivityLevelUpdater interface {
UpdateSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
}
sensitivityLevelDeleter interface {
DeleteSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
}
sensitivityLevelReloader interface {
ReloadSensitivityLevels(levels ...dal.SensitivityLevel) (err error)
}
)
func DalSensitivityLevelReload(ctx context.Context, s store.Storer, r sensitivityLevelReloader) (err error) {
ll, _, err := store.SearchDalSensitivityLevels(ctx, s, types.DalSensitivityLevelFilter{Deleted: filter.StateExcluded})
if err != nil {
return
}
// @todo temporary
ll = append(types.DalSensitivityLevelSet{{
ID: 1,
Handle: "private",
Level: 1,
}}, ll...)
sort.Sort(ll)
levels := make(dal.SensitivityLevelSet, 0, len(ll))
for _, l := range ll {
levels = append(levels, systemToPkgType(l))
}
return r.ReloadSensitivityLevels(levels...)
}
func DalSensitivityLevelCreate(c sensitivityLevelCreator, levels ...*types.DalSensitivityLevel) (err error) {
return c.CreateSensitivityLevel(systemToPkgTypeSet(levels)...)
}
func DalSensitivityLevelUpdate(u sensitivityLevelUpdater, levels ...*types.DalSensitivityLevel) (err error) {
return u.UpdateSensitivityLevel(systemToPkgTypeSet(levels)...)
}
func DalSensitivityLevelDelete(d sensitivityLevelDeleter, levels ...*types.DalSensitivityLevel) (err error) {
return d.DeleteSensitivityLevel(systemToPkgTypeSet(levels)...)
}
// // // // // // // // // // // // // // // // // // // // // // // // //
// Utils
func systemToPkgType(level *types.DalSensitivityLevel) dal.SensitivityLevel {
return dal.SensitivityLevel{
ID: level.ID,
Handle: level.Handle,
Level: level.Level,
}
}
func systemToPkgTypeSet(levels types.DalSensitivityLevelSet) dal.SensitivityLevelSet {
out := make(dal.SensitivityLevelSet, 0, len(levels))
for _, l := range levels {
out = append(out, systemToPkgType(l))
}
return out
}
+41 -14
View File
@@ -10,7 +10,6 @@ import (
"github.com/cortezaproject/corteza-server/pkg/dal"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/dalutils"
"github.com/cortezaproject/corteza-server/system/types"
)
@@ -19,22 +18,20 @@ type (
actionlog actionlog.Recorder
store store.Storer
ac sensitivityLevelAccessController
dal dalSensitivityLevels
dal dalSensitivityLevelManager
}
sensitivityLevelAccessController interface {
CanManageDalSensitivityLevel(context.Context) bool
}
dalSensitivityLevels interface {
ReloadSensitivityLevels(levels ...dal.SensitivityLevel) (err error)
CreateSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
UpdateSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
DeleteSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
dalSensitivityLevelManager interface {
ReplaceSensitivityLevel(levels ...dal.SensitivityLevel) (err error)
RemoveSensitivityLevel(levels ...uint64) (err error)
}
)
func SensitivityLevel(ctx context.Context, dal dalSensitivityLevels) *dalSensitivityLevel {
func SensitivityLevel(ctx context.Context, dal dalSensitivityLevelManager) *dalSensitivityLevel {
return &dalSensitivityLevel{
ac: DefaultAccessControl,
actionlog: DefaultActionlog,
@@ -95,7 +92,7 @@ func (svc *dalSensitivityLevel) Create(ctx context.Context, new *types.DalSensit
q = new
return dalutils.DalSensitivityLevelCreate(svc.dal, new)
return dalSensitivityLevelReplace(ctx, svc.dal, new)
})
return q, svc.recordAction(ctx, qProps, DalSensitivityLevelActionCreate, err)
@@ -132,7 +129,7 @@ func (svc *dalSensitivityLevel) Update(ctx context.Context, upd *types.DalSensit
q = upd
return dalutils.DalSensitivityLevelUpdate(svc.dal, upd)
return dalSensitivityLevelReplace(ctx, svc.dal, upd)
})
return q, svc.recordAction(ctx, qProps, DalSensitivityLevelActionUpdate, err)
@@ -184,10 +181,10 @@ func (svc *dalSensitivityLevel) DeleteByID(ctx context.Context, ID uint64) (err
}
}
if err = dalutils.DalSensitivityLevelUpdate(svc.dal, uu...); err != nil {
if err = dalSensitivityLevelReplace(ctx, svc.dal, uu...); err != nil {
return err
}
if err = dalutils.DalSensitivityLevelDelete(svc.dal, dd...); err != nil {
if err = dalSensitivityLevelRemove(ctx, svc.dal, dd...); err != nil {
return err
}
return nil
@@ -224,7 +221,7 @@ func (svc *dalSensitivityLevel) UndeleteByID(ctx context.Context, ID uint64) (er
return
}
return dalutils.DalSensitivityLevelCreate(svc.dal, q)
return dalSensitivityLevelReplace(ctx, svc.dal, q)
})
return svc.recordAction(ctx, qProps, DalSensitivityLevelActionDelete, err)
@@ -260,7 +257,7 @@ func (svc *dalSensitivityLevel) Search(ctx context.Context, filter types.DalSens
}
func (svc *dalSensitivityLevel) ReloadSensitivityLevels(ctx context.Context, s store.Storer) (err error) {
return dalutils.DalSensitivityLevelReload(ctx, s, svc.dal)
return dalSensitivityLevelReload(ctx, svc.store, svc.dal)
}
func (svc *dalSensitivityLevel) prepare(ctx context.Context, s store.Storer, sl *types.DalSensitivityLevel) (_ types.DalSensitivityLevelSet, err error) {
@@ -334,3 +331,33 @@ func (svc *dalSensitivityLevel) prepare(ctx context.Context, s store.Storer, sl
return set, err
}
func dalSensitivityLevelReload(ctx context.Context, s store.Storer, dsm dalSensitivityLevelManager) (err error) {
// Get all available sensitivityLevels
ll, _, err := store.SearchDalSensitivityLevels(ctx, s, types.DalSensitivityLevelFilter{})
if err != nil {
return
}
return dalSensitivityLevelReplace(ctx, dsm, ll...)
}
func dalSensitivityLevelReplace(ctx context.Context, dsm dalSensitivityLevelManager, ll ...*types.DalSensitivityLevel) (err error) {
for _, l := range ll {
sl := dal.MakeSensitivityLevel(l.ID, l.Level, l.Handle)
if err = dsm.ReplaceSensitivityLevel(sl); err != nil {
return
}
}
return nil
}
func dalSensitivityLevelRemove(ctx context.Context, dsm dalSensitivityLevelManager, ll ...*types.DalSensitivityLevel) (err error) {
dd := make([]uint64, len(ll))
for i, l := range ll {
dd[i] = l.ID
}
return dsm.RemoveSensitivityLevel(dd...)
}