diff --git a/go.mod b/go.mod index 28985d7..987b345 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/aserto-dev/azm go 1.22 -toolchain go1.22.5 - // replace github.com/aserto-dev/go-directory => ../go-directory require ( diff --git a/go.work b/go.work index 064301b..e3436bb 100644 --- a/go.work +++ b/go.work @@ -1,7 +1,5 @@ go 1.22 -toolchain go1.22.5 - use ( . ./cmd/azmcmd diff --git a/graph/check_test.yaml b/graph/check_test.yaml index 89577b9..d576f02 100644 --- a/graph/check_test.yaml +++ b/graph/check_test.yaml @@ -62,6 +62,12 @@ types: can_share: can_write & parent->can_share can_invite: parent->can_read - viewer + # viewer can be user or group but owner can only be user + negation_type_subset: viewer - owner + + # viewer can be user or group but owner can only be user + intersection_type_subset: viewer & owner + cycle: relations: parent: cycle diff --git a/model/inverse.go b/model/inverse.go index 6050511..8a56e52 100644 --- a/model/inverse.go +++ b/model/inverse.go @@ -55,6 +55,22 @@ func (i *inverter) invert() *Model { } } + for _, o := range i.im.Objects { + for _, p := range o.Permissions { + if !p.IsExclusion() { + continue + } + + if p.Exclusion.Exclude == nil { + // It is possible for the 'Exclude' term to be empty in in inverted model if the object type + // cannot have the relation/permission being excluded. + // In this case, the exclusion permission becomes a single-term union. + p.Union = PermissionTerms{p.Exclusion.Include} + p.Exclusion = nil + } + } + } + return i.im } diff --git a/model/types.go b/model/types.go index 2e10dbd..7bd22eb 100644 --- a/model/types.go +++ b/model/types.go @@ -227,6 +227,9 @@ type PermissionTerm struct { } func (pr *PermissionTerm) String() string { + if pr == nil { + return "" + } s := string(pr.RelOrPerm) if pr.Base != "" { s = string(pr.Base) + "->" + s diff --git a/model/validate.go b/model/validate.go index 7ab5867..f45d630 100644 --- a/model/validate.go +++ b/model/validate.go @@ -161,6 +161,12 @@ func (v *validator) validateObjectPerms(on ObjectName, o *Object) error { } for _, term := range terms { + if term == nil { + errs = multierror.Append(errs, derr.ErrInvalidPermission.Msgf( + "permission '%s:%s' has an empty term", on, pn), + ) + continue + } switch { case term.IsArrow(): // this is an arrow operator.