Skip to content

Commit aad5f48

Browse files
authored
Merge pull request #1925 from Permify/entity-filter-refactor
test(internal): add test case for linked schema entrance validation
2 parents c910e05 + f616e1a commit aad5f48

File tree

8 files changed

+217
-13
lines changed

8 files changed

+217
-13
lines changed

docs/api-reference/apidocs.swagger.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"info": {
44
"title": "Permify API",
55
"description": "Permify is an open source authorization service for creating fine-grained and scalable authorization systems.",
6-
"version": "v1.2.6",
6+
"version": "v1.2.7",
77
"contact": {
88
"name": "API Support",
99
"url": "https://github.com/Permify/permify/issues",

docs/api-reference/openapiv2/apidocs.swagger.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"info": {
44
"title": "Permify API",
55
"description": "Permify is an open source authorization service for creating fine-grained and scalable authorization systems.",
6-
"version": "v1.2.6",
6+
"version": "v1.2.7",
77
"contact": {
88
"name": "API Support",
99
"url": "https://github.com/Permify/permify/issues",

internal/engines/entityFilter.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,7 @@ func (engine *EntityFilter) attributeEntrance(
160160
pagination database.CursorPagination
161161
)
162162

163-
// Determine the pagination settings based on the entity type in the request.
164-
// If the entity type matches the target entrance, use cursor pagination with sorting by "entity_id".
165-
// Otherwise, use the default pagination settings.
166-
if request.GetEntrance().GetType() == entrance.TargetEntrance.GetType() {
167-
pagination = database.NewCursorPagination(database.Cursor(request.GetCursor()), database.Sort("entity_id"))
168-
} else {
169-
pagination = database.NewCursorPagination()
170-
}
163+
pagination = database.NewCursorPagination(database.Cursor(request.GetCursor()), database.Sort("entity_id"))
171164

172165
// Query the relationships using the specified pagination settings.
173166
// The context tuples are filtered based on the provided filter.

internal/engines/lookup_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,6 +3060,149 @@ var _ = Describe("lookup-entity-engine", func() {
30603060
})
30613061
})
30623062

3063+
PropagationAcrossEntitiesEntityFilter := `
3064+
entity user {}
3065+
3066+
entity aaa {
3067+
relation role__admin @user
3068+
permission ccc__read = role__admin
3069+
}
3070+
3071+
entity bbb {
3072+
relation resource__aaa @aaa
3073+
relation role__admin @user
3074+
attribute attr__is_public boolean
3075+
permission ccc__read = role__admin or attr__is_public
3076+
3077+
}
3078+
3079+
entity ccc {
3080+
relation resource__aaa @aaa
3081+
relation resource__bbb @bbb
3082+
permission ccc__read = resource__aaa.ccc__read or resource__bbb.ccc__read
3083+
}`
3084+
3085+
Context("Propagation Across Entities: Entity Filter", func() {
3086+
It("Drive Sample: Case 1", func() {
3087+
db, err := factories.DatabaseFactory(
3088+
config.Database{
3089+
Engine: "memory",
3090+
},
3091+
)
3092+
3093+
Expect(err).ShouldNot(HaveOccurred())
3094+
3095+
conf, err := newSchema(PropagationAcrossEntitiesEntityFilter)
3096+
Expect(err).ShouldNot(HaveOccurred())
3097+
3098+
schemaWriter := factories.SchemaWriterFactory(db)
3099+
err = schemaWriter.WriteSchema(context.Background(), conf)
3100+
3101+
Expect(err).ShouldNot(HaveOccurred())
3102+
3103+
type filter struct {
3104+
entityType string
3105+
subject string
3106+
assertions map[string][]string
3107+
}
3108+
3109+
tests := struct {
3110+
relationships []string
3111+
attributes []string
3112+
filters []filter
3113+
}{
3114+
relationships: []string{
3115+
"aaa:a1#role__admin@user:u1",
3116+
"bbb:b1#resource__aaa@aaa:a1",
3117+
"ccc:c1#resource__aaa@aaa:a1",
3118+
"ccc:c1#resource__bbb@bbb:b1",
3119+
},
3120+
attributes: []string{
3121+
"bbb:b1$attr__is_public|boolean:true",
3122+
},
3123+
filters: []filter{
3124+
{
3125+
entityType: "ccc",
3126+
subject: "user:u1",
3127+
assertions: map[string][]string{
3128+
"ccc__read": {"c1"},
3129+
},
3130+
},
3131+
},
3132+
}
3133+
3134+
schemaReader := factories.SchemaReaderFactory(db)
3135+
dataReader := factories.DataReaderFactory(db)
3136+
dataWriter := factories.DataWriterFactory(db)
3137+
3138+
checkEngine := NewCheckEngine(schemaReader, dataReader)
3139+
3140+
lookupEngine := NewLookupEngine(
3141+
checkEngine,
3142+
schemaReader,
3143+
dataReader,
3144+
)
3145+
3146+
invoker := invoke.NewDirectInvoker(
3147+
schemaReader,
3148+
dataReader,
3149+
checkEngine,
3150+
nil,
3151+
lookupEngine,
3152+
nil,
3153+
)
3154+
3155+
checkEngine.SetInvoker(invoker)
3156+
3157+
var tuples []*base.Tuple
3158+
3159+
for _, relationship := range tests.relationships {
3160+
t, err := tuple.Tuple(relationship)
3161+
Expect(err).ShouldNot(HaveOccurred())
3162+
tuples = append(tuples, t)
3163+
}
3164+
3165+
var attributes []*base.Attribute
3166+
3167+
for _, attr := range tests.attributes {
3168+
a, err := attribute.Attribute(attr)
3169+
Expect(err).ShouldNot(HaveOccurred())
3170+
attributes = append(attributes, a)
3171+
}
3172+
3173+
_, err = dataWriter.Write(context.Background(), "t1", database.NewTupleCollection(tuples...), database.NewAttributeCollection(attributes...))
3174+
Expect(err).ShouldNot(HaveOccurred())
3175+
3176+
for _, filter := range tests.filters {
3177+
ear, err := tuple.EAR(filter.subject)
3178+
Expect(err).ShouldNot(HaveOccurred())
3179+
3180+
subject := &base.Subject{
3181+
Type: ear.GetEntity().GetType(),
3182+
Id: ear.GetEntity().GetId(),
3183+
Relation: ear.GetRelation(),
3184+
}
3185+
3186+
for permission, res := range filter.assertions {
3187+
response, err := invoker.LookupEntity(context.Background(), &base.PermissionLookupEntityRequest{
3188+
TenantId: "t1",
3189+
EntityType: filter.entityType,
3190+
Subject: subject,
3191+
Permission: permission,
3192+
Metadata: &base.PermissionLookupEntityRequestMetadata{
3193+
SnapToken: token.NewNoopToken().Encode().String(),
3194+
SchemaVersion: "",
3195+
Depth: 100,
3196+
},
3197+
})
3198+
3199+
Expect(err).ShouldNot(HaveOccurred())
3200+
Expect(response.GetEntityIds()).Should(Equal(res))
3201+
}
3202+
}
3203+
})
3204+
})
3205+
30633206
driveSchemaSubjectFilter := `
30643207
entity user {}
30653208

internal/info.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var Identifier = ""
2323
*/
2424
const (
2525
// Version is the last release of the Permify (e.g. v0.1.0)
26-
Version = "v1.2.6"
26+
Version = "v1.2.7"
2727
)
2828

2929
// Function to create a single line of the ASCII art with centered content and color

internal/schema/linkedSchema_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,5 +1181,73 @@ var _ = Describe("linked schema", func() {
11811181
},
11821182
}))
11831183
})
1184+
1185+
It("Case 23", func() {
1186+
sch, err := parser.NewParser(`
1187+
entity user {}
1188+
1189+
entity aaa {
1190+
relation role__admin @user
1191+
permission ccc__read = role__admin
1192+
}
1193+
1194+
entity bbb {
1195+
relation resource__aaa @aaa
1196+
relation role__admin @user
1197+
attribute attr__is_public boolean
1198+
permission ccc__read = role__admin or attr__is_public
1199+
1200+
}
1201+
1202+
entity ccc {
1203+
relation resource__aaa @aaa
1204+
relation resource__bbb @bbb
1205+
permission ccc__read = resource__aaa.ccc__read or resource__bbb.ccc__read
1206+
}
1207+
`).Parse()
1208+
1209+
Expect(err).ShouldNot(HaveOccurred())
1210+
1211+
c := compiler.NewCompiler(true, sch)
1212+
a, _, _ := c.Compile()
1213+
1214+
g := NewLinkedGraph(NewSchemaFromEntityAndRuleDefinitions(a, nil))
1215+
1216+
ent, err := g.LinkedEntrances(&base.Entrance{
1217+
Type: "ccc",
1218+
Value: "ccc__read",
1219+
}, &base.Entrance{
1220+
Type: "user",
1221+
Value: "",
1222+
})
1223+
1224+
Expect(err).ShouldNot(HaveOccurred())
1225+
Expect(ent).Should(Equal([]*LinkedEntrance{
1226+
{
1227+
Kind: RelationLinkedEntrance,
1228+
TargetEntrance: &base.Entrance{
1229+
Type: "aaa",
1230+
Value: "role__admin",
1231+
},
1232+
TupleSetRelation: "",
1233+
},
1234+
{
1235+
Kind: RelationLinkedEntrance,
1236+
TargetEntrance: &base.Entrance{
1237+
Type: "bbb",
1238+
Value: "role__admin",
1239+
},
1240+
TupleSetRelation: "",
1241+
},
1242+
{
1243+
Kind: AttributeLinkedEntrance,
1244+
TargetEntrance: &base.Entrance{
1245+
Type: "bbb",
1246+
Value: "attr__is_public",
1247+
},
1248+
TupleSetRelation: "",
1249+
},
1250+
}))
1251+
})
11841252
})
11851253
})

pkg/pb/base/v1/openapi.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/base/v1/openapi.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
99
info: {
1010
title: "Permify API";
1111
description: "Permify is an open source authorization service for creating fine-grained and scalable authorization systems.";
12-
version: "v1.2.6";
12+
version: "v1.2.7";
1313
contact: {
1414
name: "API Support";
1515
url: "https://github.com/Permify/permify/issues";

0 commit comments

Comments
 (0)