Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support computed sets in arrow operator base #69

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ linters:
- gocritic
- gocyclo
- godot
- godox
- err113
- gofmt
- goimports
Expand All @@ -103,7 +104,6 @@ linters:
# - dupl
# - gochecknoglobals
# - gocognit
# - godox
# - gomnd
# - lll
# - nestif
Expand Down
103 changes: 73 additions & 30 deletions graph/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
dsc "github.com/aserto-dev/go-directory/aserto/directory/common/v3"
dsr "github.com/aserto-dev/go-directory/aserto/directory/reader/v3"
"github.com/aserto-dev/go-directory/pkg/derr"
"github.com/pkg/errors"

"github.com/samber/lo"
)
Expand Down Expand Up @@ -100,7 +101,13 @@ func (c *Checker) check(params *relation) (checkStatus, error) {

func (c *Checker) checkRelation(params *relation) (checkStatus, error) {
r := c.m.Objects[params.ot].Relations[params.rel]
steps := c.m.StepRelation(r, params.st)

subjectTypes := []model.ObjectName{}
if params.tail == "" {
subjectTypes = append(subjectTypes, params.st)
}

steps := c.m.StepRelation(r, subjectTypes...)

// Reuse the same slice in all steps.
relsPtr := c.pool.GetSlice()
Expand All @@ -117,7 +124,7 @@ func (c *Checker) checkRelation(params *relation) (checkStatus, error) {
}

switch {
case step.IsDirect():
case step.IsDirect() && (params.tail == "" || params.tail == params.rel):
req.SubjectId = params.sid.String()
case step.IsWildcard():
req.SubjectId = "*"
Expand All @@ -129,42 +136,77 @@ func (c *Checker) checkRelation(params *relation) (checkStatus, error) {
return checkStatusFalse, err
}

switch {
case step.IsDirect():
for _, rel := range *relsPtr {
if rel.SubjectId == params.sid.String() {
return checkStatusTrue, nil
}
}
if status, err := c.checkRelationStep(params, step, *relsPtr); err != nil || status == checkStatusTrue {
return status, err
}

case step.IsWildcard():
if len(*relsPtr) > 0 {
// We have a wildcard match.
return checkStatusTrue, nil
}

return checkStatusFalse, nil
}

func (c *Checker) checkRelationStep(params *relation, step *model.RelationRef, rels []*dsc.RelationIdentifier) (checkStatus, error) {
switch {
case step.IsDirect():
for _, rel := range rels {
if status, err := c.checkDirectRelation(params, rel); err != nil || status == checkStatusTrue {
return status, err
}
}

case step.IsSubject():
for _, rel := range *relsPtr {
if status, err := c.check(&relation{
ot: step.Object,
oid: ObjectID(rel.SubjectId),
rel: step.Relation,
st: params.st,
sid: params.sid,
}); err != nil {
return checkStatusFalse, err
} else if status == checkStatusTrue {
return status, nil
}
case step.IsWildcard():
if len(rels) > 0 {
// We have a wildcard match.
return checkStatusTrue, nil
}

case step.IsSubject():
for _, rel := range rels {
check := &relation{
ot: step.Object,
oid: ObjectID(rel.SubjectId),
rel: step.Relation,
st: params.st,
sid: params.sid,
tail: params.tail,
}
if status, err := c.check(check); err != nil || status == checkStatusTrue {
return status, err
}
}
}

return checkStatusFalse, nil
return checkStatusPending, nil
}

func (c *Checker) checkDirectRelation(params *relation, rel *dsc.RelationIdentifier) (checkStatus, error) {
if params.tail == "" && rel.SubjectId == params.sid.String() {
return checkStatusTrue, nil
}

if params.tail != "" {
check := &relation{
ot: model.ObjectName(rel.SubjectType),
oid: ObjectID(rel.SubjectId),
rel: params.tail,
st: params.st,
sid: params.sid,
}
if status, err := c.check(check); err != nil {
return checkStatusFalse, err
} else if status == checkStatusTrue {
return status, nil
}
}

return checkStatusPending, nil
}

func (c *Checker) checkPermission(params *relation) (checkStatus, error) {
p := c.m.Objects[params.ot].Permissions[params.rel]
if p == nil {
return checkStatusFalse, errors.Errorf("invalid permission check [%s]", params)
}

if !lo.Contains(p.SubjectTypes, params.st) {
// The subject type cannot have this permission.
Expand Down Expand Up @@ -219,18 +261,19 @@ func (c *Checker) expandTerm(pt *model.PermissionTerm, params *relation) (relati
relsPtr := c.pool.GetSlice()

// Resolve the base of the arrow.
err := c.getRels(query, c.pool, relsPtr)
if err != nil {
if err := c.getRels(query, c.pool, relsPtr); err != nil {
return relations{}, err
}

expanded := lo.Map(*relsPtr, func(rel *dsc.RelationIdentifier, _ int) *relation {
return &relation{
ot: model.ObjectName(rel.SubjectType),
oid: ObjectID(rel.SubjectId),
rel: pt.RelOrPerm,
rel: lo.Ternary(rel.SubjectRelation == "", pt.RelOrPerm, model.RelationName(rel.SubjectRelation)),
st: params.st,
sid: params.sid,

tail: lo.Ternary(rel.SubjectRelation == "", "", pt.RelOrPerm),
}
})

Expand Down
21 changes: 3 additions & 18 deletions graph/check_test.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
# yaml-language-server: $schema=https://www.topaz.sh/schema/manifest.json
---

### filename: manifest.yaml ###
### datetime: 2023-10-22T14:37:25-07:00 ###
### description: Google Drive manifest ###

### model ###
model:
version: 3

### object type definitions ###
types:
### display_name: User ###
identity:

user:
relations:
identifier: identity
manager: user
friend: group#member
permissions:
in_management_chain: manager | manager->in_management_chain
unfriendly_manager: in_management_chain - friend

### display_name: Identity ###
identity:
relations:
### display_name: identity#identifier ###
identifier: user

team:
relations:
Expand Down
30 changes: 30 additions & 0 deletions graph/computed_set.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# yaml-language-server: $schema=https://www.topaz.sh/schema/manifest.json
---

model:
version: 3

types:
identity: {}

user:
relations:
identifier: identity

group:
relations:
member: user | group#member

resource:
relations:
viewer: user | group#member
permissions:
can_view: viewer | viewer->identifier

component:
relations:
part: component | component#part
maintainer: user | group#member

permissions:
can_repair: maintainer | maintainer->identifier | part->can_repair
Loading
Loading