Skip to content

Commit

Permalink
Rhcloud 35058 support namespacing relationship filters (#156)
Browse files Browse the repository at this point in the history
* Refactor tests to better accommodate namespaces.

* Fix relationshipFilter conversion logic and tests.

* Add test for supported combinations of namespace and type in relation filters.

* Fix breaking kessel_test (which was disabled on local due to slowness).

* Update to re-use kesselTypeToSpiceDBType for combining ns and object type.
  • Loading branch information
merlante authored Sep 10, 2024
1 parent be0bb56 commit 0fa484b
Show file tree
Hide file tree
Showing 8 changed files with 362 additions and 143 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/cel-go v0.21.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/subcommands v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
Expand Down Expand Up @@ -82,11 +83,13 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand Down Expand Up @@ -238,6 +239,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -317,6 +320,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
2 changes: 1 addition & 1 deletion internal/data/LocalSpiceDbContainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func (l *LocalSpiceDbContainer) Close() {
}

// CheckForRelationship returns true if the given subject has the given relationship to the given resource, otherwise false
func CheckForRelationship(client *authzed.Client, subjectID string, subjectType string, subjectRelationship string, relationship string, resourceType string, resourceID string) bool {
func CheckForRelationship(client *authzed.Client, resourceType string, resourceID string, relationship string, subjectType string, subjectID string, subjectRelationship string) bool {
ctx := context.TODO()
resp, err := client.ReadRelationships(ctx, &v1.ReadRelationshipsRequest{
Consistency: &v1.Consistency{Requirement: &v1.Consistency_FullyConsistent{FullyConsistent: true}},
Expand Down
59 changes: 46 additions & 13 deletions internal/data/spicedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/authzed/authzed-go/v1"
"github.com/authzed/grpcutil"
kerrors "github.com/go-kratos/kratos/v2/errors"
"github.com/go-kratos/kratos/v2/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
Expand Down Expand Up @@ -240,8 +241,14 @@ func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1
}
}

relationshipFilter, err := createSpiceDbRelationshipFilter(filter)

if err != nil {
return nil, nil, kerrors.BadRequest("SpiceDb request validation", err.Error()).WithCause(err)
}

req := &v1.ReadRelationshipsRequest{
RelationshipFilter: createSpiceDbRelationshipFilter(filter),
RelationshipFilter: relationshipFilter,
OptionalLimit: limit,
OptionalCursor: cursor,
}
Expand Down Expand Up @@ -297,9 +304,15 @@ func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1
}

func (s *SpiceDbRepository) DeleteRelationships(ctx context.Context, filter *apiV1beta1.RelationTupleFilter) error {
req := &v1.DeleteRelationshipsRequest{RelationshipFilter: createSpiceDbRelationshipFilter(filter)}
relationshipFilter, err := createSpiceDbRelationshipFilter(filter)

if err != nil {
return kerrors.BadRequest("SpiceDb request validation", err.Error()).WithCause(err)
}

req := &v1.DeleteRelationshipsRequest{RelationshipFilter: relationshipFilter}

_, err := s.client.DeleteRelationships(ctx, req)
_, err = s.client.DeleteRelationships(ctx, req)

// TODO: we have not specified an option in our API to allow partial deletions, so currently it's all or nothing
if err != nil {
Expand Down Expand Up @@ -362,29 +375,49 @@ func (s *SpiceDbRepository) IsBackendAvailable() error {
return fmt.Errorf("error connecting to backend")
}

func createSpiceDbRelationshipFilter(filter *apiV1beta1.RelationTupleFilter) *v1.RelationshipFilter {
func createSpiceDbRelationshipFilter(filter *apiV1beta1.RelationTupleFilter) (*v1.RelationshipFilter, error) {
// spicedb specific internal validation to reflect spicedb limitations whereby namespace and objectType must be both
// be set if either of them is set in a filter
if filter.GetResourceNamespace() != "" && filter.GetResourceType() == "" {
return nil, fmt.Errorf("due to a spicedb limitation, if resource namespace is specified then resource type must also be specified")
}
if filter.GetResourceNamespace() == "" && filter.GetResourceType() != "" {
return nil, fmt.Errorf("due to a spicedb limitation, if resource type is specified then resource namespace must also be specified")
}

resourceType := &apiV1beta1.ObjectType{Namespace: filter.GetResourceNamespace(), Name: filter.GetResourceType()}
spiceDbRelationshipFilter := &v1.RelationshipFilter{
ResourceType: filter.GetResourceType(),
ResourceType: kesselTypeToSpiceDBType(resourceType),
OptionalResourceId: filter.GetResourceId(),
OptionalRelation: filter.GetRelation(),
}

if filter.GetSubjectFilter() != nil {
subjectFilter := &v1.SubjectFilter{
SubjectType: filter.GetSubjectFilter().GetSubjectType(),
OptionalSubjectId: filter.GetSubjectFilter().GetSubjectId(),
subjectFilter := filter.GetSubjectFilter()

if subjectFilter.GetSubjectNamespace() != "" && subjectFilter.GetSubjectType() == "" {
return nil, fmt.Errorf("due to a spicedb limitation, if subject namespace is specified in subjectFilter then subject type must also be specified")
}
if subjectFilter.GetSubjectNamespace() == "" && subjectFilter.GetSubjectType() != "" {
return nil, fmt.Errorf("due to a spicedb limitation, if subject type is specified in subjectFilter then subject namespace must also be specified")
}

subjectType := &apiV1beta1.ObjectType{Namespace: subjectFilter.GetSubjectNamespace(), Name: subjectFilter.GetSubjectType()}
spiceDbSubjectFilter := &v1.SubjectFilter{
SubjectType: kesselTypeToSpiceDBType(subjectType),
OptionalSubjectId: subjectFilter.GetSubjectId(),
}

if filter.GetSubjectFilter().GetRelation() != "" {
subjectFilter.OptionalRelation = &v1.SubjectFilter_RelationFilter{
Relation: filter.GetSubjectFilter().GetRelation(),
if subjectFilter.GetRelation() != "" {
spiceDbSubjectFilter.OptionalRelation = &v1.SubjectFilter_RelationFilter{
Relation: subjectFilter.GetRelation(),
}
}

spiceDbRelationshipFilter.OptionalSubjectFilter = subjectFilter
spiceDbRelationshipFilter.OptionalSubjectFilter = spiceDbSubjectFilter
}

return spiceDbRelationshipFilter
return spiceDbRelationshipFilter, nil
}

func spicedbTypeToKesselType(spicedbType string) *apiV1beta1.ObjectType {
Expand Down
Loading

0 comments on commit 0fa484b

Please sign in to comment.