Skip to content

Commit

Permalink
Merge pull request #45 from aserto-dev/fix-inverted-negation-and-inte…
Browse files Browse the repository at this point in the history
…rsection

Fix inversion of negation and intersection permissions
  • Loading branch information
ronenh authored May 24, 2024
2 parents ab12b4f + 63b541a commit b9b290d
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 16 deletions.
4 changes: 4 additions & 0 deletions graph/check_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ types:
user:
relations:
manager: user
friend: group#member
permissions:
in_management_chain: manager | manager->in_management_chain
unfriendly_manager: in_management_chain - friend

### display_name: Identity ###
identity:
Expand Down
7 changes: 6 additions & 1 deletion graph/objects_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ func TestSearchObjects(t *testing.T) {
require.NoError(err)
require.NotNil(m)

mnfst := manifest(m.Invert())
im := m.Invert()
mnfst := manifest(im)

b, err := yaml.Marshal(mnfst)
require.NoError(err)

t.Logf("inverted model:\n%s\n", b)

require.NoError(
im.Validate(model.SkipNameValidation, model.AllowPermissionInArrowBase),
)

for _, test := range searchObjectsTests {
t.Run(test.search, func(tt *testing.T) {
assert := assert.New(tt)
Expand Down
46 changes: 37 additions & 9 deletions model/inverse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package model
import (
"fmt"

set "github.com/deckarep/golang-set/v2"
"github.com/samber/lo"
)

Expand Down Expand Up @@ -94,8 +95,28 @@ func (i *inverter) applySubstitutions(o *Object) {
}

func (i *inverter) invertPermission(on ObjectName, pn RelationName, o *Object, p *Permission) {
var typeSet relSet

switch {
case p.IsUnion():
typeSet = set.NewSet(p.Types()...)
case p.IsIntersection():
typeSet = lo.Reduce(p.Terms(), func(acc relSet, pt *PermissionTerm, i int) relSet {
s := set.NewSet(pt.Types()...)
if i == 0 {
return s
}
if s.IsEmpty() {
return acc
}
return acc.Intersect(s)
}, nil)
case p.IsExclusion():
typeSet = set.NewSet(p.Exclusion.Include.Types()...)
}

for _, pt := range p.Terms() {
newTermInverter(i, on, pn, o, p, pt).invert()
newTermInverter(i, on, pn, o, p, pt, typeSet).invert()
}
}

Expand All @@ -122,17 +143,19 @@ type termInverter struct {
obj *Object
perm *Permission
term *PermissionTerm
typeSet relSet
kind permissionKind
}

func newTermInverter(i *inverter, on ObjectName, pn RelationName, o *Object, p *Permission, pt *PermissionTerm) *termInverter {
func newTermInverter(i *inverter, on ObjectName, pn RelationName, o *Object, p *Permission, pt *PermissionTerm, typeSet relSet) *termInverter {
return &termInverter{
inv: i,
objName: on,
permName: pn,
obj: o,
perm: p,
term: pt,
typeSet: typeSet,
kind: kindOf(p),
}
}
Expand All @@ -155,7 +178,8 @@ func (ti *termInverter) invertArrow() {
itip := ti.inv.irelSub(ti.objName, ti.term.Base)
baseRel := ti.obj.Relations[ti.term.Base]

for _, rr := range ti.perm.Types() {
typeRefs := set.NewSet(ti.perm.Types()...)
typeRefs.Intersect(ti.typeSet).Each(func(rr RelationRef) bool {
iName := InverseRelation(ti.objName, ti.permName, rr.Relation)
iPerm := permissionOrNew(ti.inv.im.Objects[rr.Object], iName, ti.kind)
for _, baseRR := range baseRel.Types() {
Expand All @@ -165,24 +189,28 @@ func (ti *termInverter) invertArrow() {
rel := relationOrNew(ti.inv.im.Objects[baseRR.Object], itip)
rel.AddRef(&RelationRef{Object: baseRR.Object, Relation: itip})
}
}
return false // resume iteration
})
}

func (ti *termInverter) invertRelation() {
for _, rr := range ti.obj.Relations[ti.term.RelOrPerm].Types() {
typeRefs := set.NewSet(ti.obj.Relations[ti.term.RelOrPerm].Types()...)
typeRefs.Intersect(ti.typeSet).Each(func(rr RelationRef) bool {
iName := InverseRelation(ti.objName, ti.permName, rr.Relation)
ip := permissionOrNew(ti.inv.im.Objects[rr.Object], iName, ti.kind)
ip.AddTerm(&PermissionTerm{RelOrPerm: ti.inv.irelSub(ti.objName, ti.term.RelOrPerm, rr.Relation)})
}
return false // resume iteration
})
}

func (ti *termInverter) invertPermission() {
for _, rr := range types(ti.obj, ti.term.RelOrPerm) {
typeRefs := set.NewSet(types(ti.obj, ti.term.RelOrPerm)...)
typeRefs.Intersect(ti.typeSet).Each(func(rr RelationRef) bool {
iName := InverseRelation(ti.objName, ti.permName, rr.Relation)
ip := permissionOrNew(ti.inv.im.Objects[rr.Object], iName, ti.kind)
ip.AddTerm(&PermissionTerm{RelOrPerm: ti.inv.irelSub(ti.objName, ti.term.RelOrPerm, rr.Relation)})

}
return false // resume iteration
})
}

type permissionKind int
Expand Down
20 changes: 14 additions & 6 deletions model/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,7 @@ func (p *Permission) AddTerm(pt *PermissionTerm) {
}

func (p *Permission) Types() RelationRefs {
return append(
lo.Map(p.SubjectTypes, func(on ObjectName, _ int) RelationRef {
return RelationRef{Object: on}
}),
p.Intermediates...,
)
return append(objectNamesToRelationRefs(p.SubjectTypes), p.Intermediates...)
}

type PermissionTerm struct {
Expand All @@ -243,6 +238,13 @@ func (pr *PermissionTerm) IsArrow() bool {
return pr.Base != ""
}

func (pr *PermissionTerm) Types() RelationRefs {
return append(
objectNamesToRelationRefs(pr.SubjectTypes),
pr.Intermediates...,
)
}

type PermissionTerms []*PermissionTerm

func (pts PermissionTerms) Contains(pt *PermissionTerm) bool {
Expand All @@ -254,6 +256,12 @@ func (pts PermissionTerms) Contains(pt *PermissionTerm) bool {
return false
}

func objectNamesToRelationRefs(names []ObjectName) RelationRefs {
return lo.Map(names, func(on ObjectName, _ int) RelationRef {
return RelationRef{Object: on}
})
}

type ExclusionPermission struct {
Include *PermissionTerm `json:"include,omitempty"`
Exclude *PermissionTerm `json:"exclude,omitempty"`
Expand Down

0 comments on commit b9b290d

Please sign in to comment.