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

Ensure all resources are returned for relation check when caveats are specified #2027

Merged
merged 1 commit into from
Aug 15, 2024
Merged
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
133 changes: 124 additions & 9 deletions internal/dispatch/graph/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,14 @@ func TestCheckMetadata(t *testing.T) {

func TestCheckPermissionOverSchema(t *testing.T) {
testCases := []struct {
name string
schema string
relationships []*core.RelationTuple
resource *core.ObjectAndRelation
subject *core.ObjectAndRelation
expectedPermissionship v1.ResourceCheckResult_Membership
expectedCaveat *core.CaveatExpression
name string
schema string
relationships []*core.RelationTuple
resource *core.ObjectAndRelation
subject *core.ObjectAndRelation
expectedPermissionship v1.ResourceCheckResult_Membership
expectedCaveat *core.CaveatExpression
alternativeExpectedCaveat *core.CaveatExpression
}{
{
"basic union",
Expand All @@ -312,6 +313,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic intersection",
Expand All @@ -330,6 +332,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic exclusion",
Expand All @@ -347,6 +350,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic union, multiple branches",
Expand All @@ -365,6 +369,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic union no permission",
Expand All @@ -380,6 +385,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"basic intersection no permission",
Expand All @@ -397,6 +403,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"basic exclusion no permission",
Expand All @@ -415,6 +422,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"exclusion with multiple branches",
Expand All @@ -441,6 +449,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"intersection with multiple branches",
Expand All @@ -467,6 +476,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"exclusion with multiple branches no permission",
Expand Down Expand Up @@ -494,6 +504,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"intersection with multiple branches no permission",
Expand All @@ -519,6 +530,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"basic arrow",
Expand All @@ -541,6 +553,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic any arrow",
Expand All @@ -563,6 +576,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic all arrow negative",
Expand All @@ -585,6 +599,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"basic all arrow positive",
Expand All @@ -608,6 +623,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic all arrow positive with different types",
Expand Down Expand Up @@ -635,6 +651,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"basic all arrow negative over different types",
Expand Down Expand Up @@ -663,6 +680,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"basic all arrow positive over different types",
Expand Down Expand Up @@ -692,6 +710,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"all arrow for single org",
Expand All @@ -713,6 +732,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"all arrow for no orgs",
Expand All @@ -733,6 +753,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"view_by_all negative",
Expand Down Expand Up @@ -766,6 +787,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "fred", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"view_by_any positive",
Expand Down Expand Up @@ -801,6 +823,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "fred", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"view_by_any positive directly",
Expand Down Expand Up @@ -836,6 +859,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "rachel", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"caveated intersection arrow",
Expand All @@ -862,6 +886,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatAndCtx("somecaveat", nil),
nil,
},
{
"intersection arrow with caveated member",
Expand All @@ -888,6 +913,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatAndCtx("somecaveat", nil),
nil,
},
{
"caveated intersection arrow with caveated member",
Expand All @@ -914,6 +940,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatAndCtx("somecaveat", nil),
nil,
},
{
"caveated intersection arrow with caveated member, different context",
Expand Down Expand Up @@ -947,6 +974,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
caveatAndCtx("anothercaveat", map[string]any{"someparam": int64(43)}),
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(42)}),
),
nil,
},
{
"caveated intersection arrow with multiple caveated branches",
Expand Down Expand Up @@ -978,8 +1006,8 @@ func TestCheckPermissionOverSchema(t *testing.T) {
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(41)}),
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(42)}),
),
nil,
},

{
"caveated intersection arrow with multiple caveated members",
`definition user {}
Expand Down Expand Up @@ -1010,6 +1038,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(41)}),
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(42)}),
),
nil,
},
{
"caveated intersection arrow with one caveated branch",
Expand Down Expand Up @@ -1038,6 +1067,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(42)}),
nil,
},
{
"caveated intersection arrow with one caveated member",
Expand Down Expand Up @@ -1066,6 +1096,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatAndCtx("somecaveat", map[string]any{"someparam": int64(42)}),
nil,
},
{
"caveated intersection arrow multiple paths to the same subject",
Expand Down Expand Up @@ -1093,6 +1124,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatAndCtx("somecaveat", nil),
nil,
},
{
"recursive all arrow positive result",
Expand Down Expand Up @@ -1129,6 +1161,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "fred", "..."),
v1.ResourceCheckResult_MEMBER,
nil,
nil,
},
{
"recursive all arrow negative result",
Expand Down Expand Up @@ -1165,6 +1198,7 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "tom", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"recursive all arrow negative result due to recursion missing a folder",
Expand Down Expand Up @@ -1202,6 +1236,79 @@ func TestCheckPermissionOverSchema(t *testing.T) {
ONR("user", "fred", "..."),
v1.ResourceCheckResult_NOT_MEMBER,
nil,
nil,
},
{
"caveated over multiple branches",
`
caveat somecaveat(somevalue int) {
somevalue == 42
}

definition user {}

definition role {
relation member: user
}

definition resource {
relation viewer: role#member with somecaveat
permission view = viewer
}
`,
[]*core.RelationTuple{
tuple.MustParse(`role:firstrole#member@user:tom[somecaveat:{"somevalue":40}]`),
tuple.MustParse(`role:secondrole#member@user:tom[somecaveat:{"somevalue":42}]`),
tuple.MustParse(`resource:doc1#viewer@role:firstrole#member`),
tuple.MustParse(`resource:doc1#viewer@role:secondrole#member`),
},
ONR("resource", "doc1", "view"),
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatOr(
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(40)}),
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(42)}),
),
caveatOr(
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(42)}),
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(40)}),
),
},
{
"caveated over multiple branches reversed",
`
caveat somecaveat(somevalue int) {
somevalue == 42
}

definition user {}

definition role {
relation member: user
}

definition resource {
relation viewer: role#member with somecaveat
permission view = viewer
}
`,
[]*core.RelationTuple{
tuple.MustParse(`role:secondrole#member@user:tom[somecaveat:{"somevalue":42}]`),
tuple.MustParse(`role:firstrole#member@user:tom[somecaveat:{"somevalue":40}]`),
tuple.MustParse(`resource:doc1#viewer@role:secondrole#member`),
tuple.MustParse(`resource:doc1#viewer@role:firstrole#member`),
},
ONR("resource", "doc1", "view"),
ONR("user", "tom", "..."),
v1.ResourceCheckResult_CAVEATED_MEMBER,
caveatOr(
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(40)}),
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(42)}),
),
caveatOr(
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(42)}),
caveatAndCtx("somecaveat", map[string]any{"somevalue": int64(40)}),
),
},
}

Expand Down Expand Up @@ -1239,10 +1346,18 @@ func TestCheckPermissionOverSchema(t *testing.T) {

require.Equal(tc.expectedPermissionship, membership)

if tc.expectedCaveat != nil {
if tc.expectedCaveat != nil && tc.alternativeExpectedCaveat == nil {
require.NotEmpty(resp.ResultsByResourceId[tc.resource.ObjectId].Expression)
testutil.RequireProtoEqual(t, tc.expectedCaveat, resp.ResultsByResourceId[tc.resource.ObjectId].Expression, "mismatch in caveat")
}

if tc.expectedCaveat != nil && tc.alternativeExpectedCaveat != nil {
require.NotEmpty(resp.ResultsByResourceId[tc.resource.ObjectId].Expression)

if testutil.AreProtoEqual(tc.expectedCaveat, resp.ResultsByResourceId[tc.resource.ObjectId].Expression, "mismatch in caveat") != nil {
testutil.RequireProtoEqual(t, tc.alternativeExpectedCaveat, resp.ResultsByResourceId[tc.resource.ObjectId].Expression, "mismatch in caveat")
}
}
})
}
}
Expand Down
Loading
Loading