Skip to content

Commit

Permalink
Recursive expansion of relations and unions (#14)
Browse files Browse the repository at this point in the history
* Require spaces around negation operator

* Recursive expansion of relations and unions

* Keep unused loadFromManifest in expand_test.go

It's helpful when we need to regenerate expand_test.json
  • Loading branch information
ronenh authored Oct 27, 2023
1 parent 0efb622 commit 2ac2e0d
Show file tree
Hide file tree
Showing 4 changed files with 738 additions and 2,150 deletions.
28 changes: 22 additions & 6 deletions cache/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ func (c *Cache) ExpandRelation(on model.ObjectName, rn model.RelationName) []mod

// iterate through relation set, determine if it "unions" with the given relation.
for _, r := range rs {
if r.Subject != nil && r.Subject.Object == on {
switch {
case r.Subject != nil && r.Subject.Object == on:
results = append(results, r.Subject.Relation)
case r.Direct != "":
results = append(results, c.ExpandRelation(on, model.RelationName(r.Direct))...)
}
}

Expand All @@ -47,15 +50,17 @@ func (c *Cache) ExpandPermission(on model.ObjectName, pn model.PermissionName) [
results := []model.RelationName{}

// starting object type and permission must exist in order to be expanded.
if o, ok := c.model.Objects[on]; !ok {
o, ok := c.model.Objects[on]
if !ok {
return results
} else if _, ok := o.Permissions[pn]; !ok {
}
if _, ok := o.Permissions[pn]; !ok {
return results
}

p := c.model.Objects[on].Permissions[pn]

results = append(results, expandUnion(p.Union)...)
results = append(results, c.expandUnion(o, p.Union...)...)

for _, rn := range results {
results = append(results, c.ExpandRelation(on, rn)...)
Expand All @@ -65,10 +70,21 @@ func (c *Cache) ExpandPermission(on model.ObjectName, pn model.PermissionName) [
}

// convert union []string to []model.RelationName.
func expandUnion(u []string) []model.RelationName {
func (c *Cache) expandUnion(o *model.Object, u ...string) []model.RelationName {
result := []model.RelationName{}
for _, v := range u {
result = append(result, model.RelationName(v))
rn := model.RelationName(v)
result = append(result, rn)

exp := lo.FilterMap(o.Relations[rn], func(r *model.Relation, _ int) (string, bool) {
if r.Direct == "" {
return "", false
}
_, ok := o.Relations[model.RelationName(r.Direct)]
return string(r.Direct), ok

})
result = append(result, c.expandUnion(o, exp...)...)
}
return result
}
27 changes: 25 additions & 2 deletions cache/expand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ package cache_test
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"

"github.com/aserto-dev/azm/cache"
"github.com/aserto-dev/azm/model"
v3 "github.com/aserto-dev/azm/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// load model cache from serialized model file.
func loadModelCache(t *testing.T, filepath string) *cache.Cache {
r, err := os.Open(filepath)
func loadModelCache(t *testing.T, path string) *cache.Cache {
r, err := os.Open(path)
require.NoError(t, err)
defer r.Close()

var mc model.Model
dec := json.NewDecoder(r)
Expand All @@ -25,6 +29,25 @@ func loadModelCache(t *testing.T, filepath string) *cache.Cache {
return cache.New(&mc)
}

// helper to regenerate the serialized cache from a manifest.
func loadFromManifest(t *testing.T, path string) *cache.Cache { // nolint:unused
r, err := os.Open(path)
require.NoError(t, err)
defer r.Close()

m, err := v3.Load(r)
require.NoError(t, err)

cachefile := strings.TrimSuffix(path, filepath.Ext(path)) + ".json"
w, err := os.Create(cachefile)
require.NoError(t, err)
defer w.Close()

require.NoError(t, m.Write(w))

return cache.New(m)
}

func TestExpandRelation(t *testing.T) {
mc := loadModelCache(t, "./expand_test.json")

Expand Down
Loading

0 comments on commit 2ac2e0d

Please sign in to comment.