Base capability definitions

This commit is contained in:
Tomaž Jerman
2022-05-20 15:37:33 +02:00
parent 5add1dcb50
commit 0f4628debf
2 changed files with 288 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
package capabilities
type (
Capability string
Set []Capability
)
const (
Create Capability = "create"
Update Capability = "update"
Delete Capability = "delete"
Search Capability = "search"
Paging Capability = "paging"
Stats Capability = "stats"
Sorting Capability = "sorting"
RBAC Capability = "RBAC"
)
var (
full = Set{
Create,
Update,
Search,
Paging,
Stats,
Sorting,
RBAC,
}
accessControlCapabilities = Set{
RBAC,
}
createCapabilities = Set{
RBAC,
Create,
}
updateCapabilities = Set{
RBAC,
Update,
}
deleteCapabilities = Set{
RBAC,
Update,
}
searchCapabilities = Set{
Search,
Paging,
Sorting,
Stats,
RBAC,
}
)
// FullCapabilities returns all base system defined capabilities
func FullCapabilities() (cc Set) {
// Doing an union just to make a fresh copy
return full.Union(nil)
}
// AccessControlCapabilities returns only requested capabilities used for AccessControl operations
func AccessControlCapabilities(requested ...Capability) (required Set) {
return common(accessControlCapabilities, requested)
}
// CreateCapabilities returns only requested capabilities used for Create operations
func CreateCapabilities(requested ...Capability) (required Set) {
return common(createCapabilities, requested)
}
// UpdateCapabilities returns only requested capabilities used for Update operations
func UpdateCapabilities(requested ...Capability) (required Set) {
return common(updateCapabilities, requested)
}
// DeleteCapabilities returns only requested capabilities used for delete operations
func DeleteCapabilities(requested ...Capability) (required Set) {
return common(deleteCapabilities, requested)
}
// SearchCapabilities returns only requested capabilities used for Search operations
func SearchCapabilities(requested ...Capability) (required Set) {
return common(searchCapabilities, requested)
}
func common(aa, bb Set) Set {
return aa.Intersect(bb)
}
// ---
// IsSuperset is inverse IsSubset
//
// IsSuperset checks if all bb capabilities are inside aa
func (aa Set) IsSuperset(bb ...Capability) bool {
return Set(bb).IsSubset(aa...)
}
// IsSubset checks if all aa capabilities are inside bb
func (aa Set) IsSubset(bb ...Capability) bool {
if len(aa) > len(bb) {
return false
}
// When A is subset of B, the difference between the two must be 0
return len(aa.Diff(bb)) == 0
}
// Intersect returns the intersection between the two sets
func (aa Set) Intersect(bb Set) (cc Set) {
cc = make(Set, 0, len(aa))
for _, a := range aa {
for _, b := range bb {
if a == b {
cc = append(cc, a)
break
}
}
}
return
}
// Intersect returns the union between the two sets
//
// Duplicates are omitted
func (aa Set) Union(bb Set) (cc Set) {
ix := make(map[Capability]bool)
for _, c := range append(aa, bb...) {
if !ix[c] {
ix[c] = true
cc = append(cc, c)
}
}
return
}
// Diff calculates the difference between the two capability sets
//
// The diff uses aa as base
func (aa Set) Diff(bb Set) (cc Set) {
for _, a := range aa {
found := false
for _, b := range bb {
found = a == b
if found {
break
}
}
if found {
continue
}
cc = append(cc, a)
}
return
}
@@ -0,0 +1,127 @@
package capabilities
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestCommonCapabilities(t *testing.T) {
cases := []struct {
name string
aa Set
bb Set
cc Set
}{{
name: "regular",
aa: Set{
Create,
Update,
},
bb: Set{
Update,
Delete,
},
cc: Set{
Update,
},
}, {
name: "no commons",
aa: Set{
Create,
},
bb: Set{
Delete,
},
cc: Set{},
}, {
name: "aa empty",
aa: nil,
bb: Set{
Update,
Delete,
},
cc: Set{},
}, {
name: "bb empty",
aa: Set{
Create,
Update,
},
bb: nil,
cc: Set{},
}}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
cc := common(c.aa, c.bb)
require.Equal(t, c.cc, cc)
})
}
}
func TestCapabilityChecking(t *testing.T) {
cases := []struct {
name string
support Set
require Set
out bool
}{{
name: "passing: complete match",
support: Set{
Create,
Update,
},
require: Set{
Create,
Update,
},
out: true,
}, {
name: "passing: supports more then required",
support: Set{
Create,
Update,
Delete,
},
require: Set{
Create,
Update,
},
out: true,
}, {
name: "passing: no required",
support: Set{
Create,
Update,
Delete,
},
require: Set{},
out: true,
}, {
name: "passing: no required nor supported",
support: Set{},
require: Set{},
out: true,
}, {
name: "failing: missing support",
support: Set{
Create,
Update,
},
require: Set{
Delete,
},
out: false,
}}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
out := c.support.IsSuperset(c.require...)
require.Equal(t, c.out, out)
out = c.require.IsSubset(c.support...)
require.Equal(t, c.out, out)
})
}
}