diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_delete_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_delete_test.go new file mode 100644 index 0000000000..9be3ace27d --- /dev/null +++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_delete_test.go @@ -0,0 +1,505 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_add_docactor + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerGivesDeleteWriteAccessToAnotherActorTwice_ShowThatTheRelationshipAlreadyExists(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(delete) access to another actor twice, no-op", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can not delete yet. + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: true, // is a no-op + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesDeleteWriteAccessToAnotherActor_OtherActorCanDelete(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(delete) access to another actor", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can not delete yet. + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can now read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can now delete. + + DocID: 0, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Check if actually deleted. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesDeleteWriteAccessToAnotherActor_OtherActorCanDeleteSoCanTheOwner(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(delete) access to another actor, both can read", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(1), // Owner can still also delete (ownership not transferred) + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(1), // Owner can still also delete. + + DocID: 0, + }, + + testUtils.Request{ + Identity: immutable.Some(1), // Check if actually deleted. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_test.go new file mode 100644 index 0000000000..8de4d546f8 --- /dev/null +++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_test.go @@ -0,0 +1,1271 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_add_docactor + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_ManagerGivesReadAccessToAnotherActor_OtherActorCanRead(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to another actor", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(3), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.AddDocActorRelationship{ // Make admin / manager + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "admin", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ // Admin makes another actor a reader + RequestorIdentity: 2, + + TargetIdentity: 3, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(3), // The other actor can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(3), // The other actor can not update + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(3), // The other actor can not delete + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_ManagerGivesReadAccessToAnotherActor_OtherActorCanWrite(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write access to another actor", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - writer + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(3), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.AddDocActorRelationship{ // Make admin / manager + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "admin", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ // Admin makes another actor a writer + RequestorIdentity: 2, + + TargetIdentity: 3, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(3), // The other actor can update + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(3), // The other actor can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad Lone", // Updated name + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(3), // The other actor can delete + + DocID: 0, + }, + + testUtils.Request{ + Identity: immutable.Some(3), + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ // Check actually deleted + "Users": []map[string]any{}, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerMakesAManagerThatGivesItSelfReadAccess_ManagerCanRead(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner makes a manager that gives itself read access", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity (to be manager) can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.AddDocActorRelationship{ // Make admin / manager + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "admin", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ // Manager makes itself a reader + RequestorIdentity: 2, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Manager can read now + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager still can't update + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager still can't delete + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerMakesAManagerThatGivesItSelfReadAndWriteAccess_ManagerCanReadAndWrite(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner makes a manager that gives itself read and write access", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + - writer + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity (to be manager) can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager can't update yet. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager can't delete yet. + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ // Make admin / manager + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "admin", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ // Manager makes itself a writer + RequestorIdentity: 2, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + // Note: It is not neccesary to make itself a reader, as becoming a writer allows reading. + testUtils.AddDocActorRelationship{ // Manager makes itself a reader + RequestorIdentity: 2, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager can now update. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Manager can read now + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad Lone", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager can now delete. + + DocID: 0, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Make sure manager was able to delete the document. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_ManagerCanNotGivesAccessNotDefinedInPolicyToAnotherActor_Error(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner tries to give access to another actor not defined in policy", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ // Make admin / manager + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "admin", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ // Admin tries to make another actor a writer + RequestorIdentity: 2, + + TargetIdentity: 3, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedError: "acp protocol violation", + }, + + testUtils.Request{ + Identity: immutable.Some(3), // The other actor can't read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(3), // The other actor can not update + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(3), // The other actor can not delete + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerMakesManagerButManagerCanNotPerformOperations_ManagerCantReadOrWrite(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner makes a manager, manager can't read or write", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ // Make admin / manager + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "admin", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Manager can not read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager can not update. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // Manager can not delete. + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ // Manager can manger only. + RequestorIdentity: 2, + + TargetIdentity: 3, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_CantMakeRelationshipIfNotOwnerOrManager_Error(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, cant make relation if identity doesn't own or manage object, return error", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 2, // This identity can not manage as not an admin yet + + TargetIdentity: 3, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + + ExpectedError: "failed to add document actor relationship with acp", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_test.go new file mode 100644 index 0000000000..20c4fa6086 --- /dev/null +++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_test.go @@ -0,0 +1,354 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_add_docactor + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorWithoutExplicitReadPerm_OtherActorCantUpdate(t *testing.T) { + expectedPolicyID := "0a243b1e61f990bccde41db7e81a915ffa1507c1403ae19727ce764d3b08846b" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(update) access to another actor, without explicit read permission", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can not update yet. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can still not update. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can still not read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesDeleteWriteAccessToAnotherActorWithoutExplicitReadPerm_OtherActorCantDelete(t *testing.T) { + expectedPolicyID := "0a243b1e61f990bccde41db7e81a915ffa1507c1403ae19727ce764d3b08846b" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(delete) access to another actor, without explicit read permission", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can not delete yet. + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can still not read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, + }, + }, + + testUtils.DeleteDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can still not delete. + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_test.go new file mode 100644 index 0000000000..4e31aafd83 --- /dev/null +++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_test.go @@ -0,0 +1,803 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_add_docactor + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerGivesReadAccessToAnotherActorTwice_ShowThatTheRelationshipAlreadyExists(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to another actor twice, no-op", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: true, // is a no-op + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesReadAccessToAnotherActor_OtherActorCanRead(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to another actor", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Now this identity can read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesReadAccessToAnotherActor_OtherActorCanReadSoCanTheOwner(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to another actor, both can read", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Now this identity can read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: immutable.Some(1), // And so can the owner (ownership not transferred). + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_OtherActorCanReadButNotUpdate(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to another actor, but the other actor can't update", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.UpdateDoc{ // Since it can't read, it can't update either. + CollectionID: 0, + + Identity: immutable.Some(2), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Now this identity can read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ // But this actor still can't update. + CollectionID: 0, + + Identity: immutable.Some(2), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_OtherActorCanReadButNotDelete(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to another actor, but the other actor can't delete", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ // Since it can't read, it can't delete either. + CollectionID: 0, + + Identity: immutable.Some(2), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Now this identity can read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDoc{ // But this actor still can't delete. + CollectionID: 0, + + Identity: immutable.Some(2), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_test.go new file mode 100644 index 0000000000..caa14b99ec --- /dev/null +++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_test.go @@ -0,0 +1,531 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_add_docactor + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorTwice_ShowThatTheRelationshipAlreadyExists(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(update) access to another actor twice, no-op", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can not update yet. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: true, // is a no-op + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_OtherActorCanUpdate(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(update) access to another actor", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can not update yet. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can now update. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can now also read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad Lone", // Note: updated name + "age": int64(28), + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_OtherActorCanUpdateSoCanTheOwner(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives write(update) access to another actor, both can read", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: immutable.Some(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: immutable.Some(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: 1, + + TargetIdentity: 2, + + CollectionID: 0, + + DocID: 0, + + Relation: "writer", + + ExpectedExistence: false, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(2), // This identity can now update. + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // This identity can now also read. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad Lone", // Note: updated name + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ + CollectionID: 0, + + Identity: immutable.Some(1), // Owner can still also update (ownership not transferred) + + DocID: 0, + + Doc: ` + { + "name": "Lone" + } + `, + }, + + testUtils.Request{ + Identity: immutable.Some(2), // Owner can still also read (ownership not transferred) + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Lone", // Note: updated name + "age": int64(28), + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +}