From 8d20220c866a7f0c700e3b45f5dd018198ff426d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Fri, 6 Feb 2026 14:38:14 +0400 Subject: [PATCH] Fix e2e tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Émile Ré --- e2e/console/asset_test.go | 38 +- e2e/console/continual_improvement_test.go | 28 +- e2e/console/datum_test.go | 132 ++-- e2e/console/document_test.go | 106 +-- e2e/console/document_version_test.go | 17 +- e2e/console/mapping_test.go | 13 +- e2e/console/meeting_test.go | 6 +- e2e/console/nonconformity_test.go | 21 +- e2e/console/obligation_test.go | 21 +- e2e/console/people_test.go | 677 ------------------- e2e/console/rbac_test.go | 155 ----- e2e/console/risk_test.go | 13 +- e2e/console/task_assignment_test.go | 11 +- e2e/console/task_test.go | 11 +- e2e/console/vendor_test.go | 26 +- e2e/internal/factory/factory.go | 65 -- e2e/internal/testutil/client.go | 58 +- e2e/internal/testutil/testutil.go | 4 +- pkg/coredata/membership_profile.go | 3 +- pkg/coredata/migrations/20260203T132700Z.sql | 24 +- pkg/iam/iam_policies.go | 12 + pkg/iam/organization_service.go | 12 +- pkg/iam/policy_set.go | 1 + pkg/probo/meeting_service.go | 4 +- pkg/server/api/connect/v1/v1_resolver.go | 7 +- 25 files changed, 323 insertions(+), 1142 deletions(-) delete mode 100644 e2e/console/people_test.go diff --git a/e2e/console/asset_test.go b/e2e/console/asset_test.go index 7ce812c18..68c45a5f5 100644 --- a/e2e/console/asset_test.go +++ b/e2e/console/asset_test.go @@ -20,7 +20,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" "go.probo.inc/probo/e2e/internal/testutil" ) @@ -28,9 +27,8 @@ func TestAsset_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner). - WithFullName("Asset Owner"). - Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() const query = ` mutation($input: CreateAssetInput!) { @@ -73,7 +71,7 @@ func TestAsset_Create(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "name": "Production Database Server", "amount": 5, - "ownerId": peopleID, + "ownerId": profileID.String(), "assetType": "VIRTUAL", "dataTypesStored": "Customer PII, Financial Records", }, @@ -86,16 +84,15 @@ func TestAsset_Create(t *testing.T) { assert.Equal(t, 5, asset.Amount) assert.Equal(t, "VIRTUAL", asset.AssetType) assert.Equal(t, "Customer PII, Financial Records", asset.DataTypesStored) - assert.Equal(t, peopleID, asset.Owner.ID) + assert.Equal(t, profileID.String(), asset.Owner.ID) } func TestAsset_Update(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner). - WithFullName("Asset Owner for Update"). - Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() const createQuery = ` mutation($input: CreateAssetInput!) { @@ -124,7 +121,7 @@ func TestAsset_Update(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "name": "Test Asset", "amount": 10, - "ownerId": peopleID, + "ownerId": profileID.String(), "assetType": "VIRTUAL", "dataTypesStored": "Test data", }, @@ -175,9 +172,8 @@ func TestAsset_Delete(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner). - WithFullName("Asset Owner for Delete"). - Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() const createQuery = ` mutation($input: CreateAssetInput!) { @@ -206,7 +202,7 @@ func TestAsset_Delete(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "name": "Asset to delete", "amount": 1, - "ownerId": peopleID, + "ownerId": profileID.String(), "assetType": "VIRTUAL", "dataTypesStored": "None", }, @@ -241,9 +237,8 @@ func TestAsset_List(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner). - WithFullName("Asset Owner for List"). - Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() // Create multiple assets for i := 0; i < 3; i++ { @@ -274,7 +269,7 @@ func TestAsset_List(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "name": fmt.Sprintf("Asset %c", 'A'+i), "amount": i + 1, - "ownerId": peopleID, + "ownerId": profileID.String(), "assetType": "VIRTUAL", "dataTypesStored": "Test data", }, @@ -329,9 +324,8 @@ func TestAsset_Types(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner). - WithFullName("Asset Owner for Types"). - Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() assetTypes := []string{"PHYSICAL", "VIRTUAL"} @@ -366,7 +360,7 @@ func TestAsset_Types(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "name": "Asset " + assetType, "amount": 1, - "ownerId": peopleID, + "ownerId": profileID.String(), "assetType": assetType, "dataTypesStored": "Test data", }, diff --git a/e2e/console/continual_improvement_test.go b/e2e/console/continual_improvement_test.go index 35a55fad5..9a6e2e7f7 100644 --- a/e2e/console/continual_improvement_test.go +++ b/e2e/console/continual_improvement_test.go @@ -21,14 +21,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" "go.probo.inc/probo/e2e/internal/testutil" ) func TestContinualImprovement_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("CI Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() query := ` mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { @@ -68,7 +68,7 @@ func TestContinualImprovement_Create(t *testing.T) { "referenceId": fmt.Sprintf("CI-%d", time.Now().UnixNano()), "description": "Improve security training program", "source": "Internal Audit", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", "priority": "HIGH", }, @@ -86,7 +86,8 @@ func TestContinualImprovement_Create(t *testing.T) { func TestContinualImprovement_Update(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("CI Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() createQuery := ` mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { @@ -115,7 +116,7 @@ func TestContinualImprovement_Update(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "referenceId": fmt.Sprintf("CI-UPDATE-%d", time.Now().UnixNano()), "description": "Original description", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", "priority": "LOW", }, @@ -166,7 +167,8 @@ func TestContinualImprovement_Update(t *testing.T) { func TestContinualImprovement_Delete(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("CI Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() createQuery := ` mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { @@ -194,7 +196,7 @@ func TestContinualImprovement_Delete(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "referenceId": fmt.Sprintf("CI-DELETE-%d", time.Now().UnixNano()), - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", "priority": "LOW", }, @@ -228,7 +230,8 @@ func TestContinualImprovement_Delete(t *testing.T) { func TestContinualImprovement_List(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("CI Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() createQuery := ` mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { @@ -248,7 +251,7 @@ func TestContinualImprovement_List(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "referenceId": fmt.Sprintf("CI-LIST-%d-%d", i, time.Now().UnixNano()), "description": fmt.Sprintf("Improvement %d", i), - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", "priority": "MEDIUM", }, @@ -302,7 +305,8 @@ func TestContinualImprovement_List(t *testing.T) { func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("CI Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() t.Run("status values", func(t *testing.T) { statuses := []string{"OPEN", "IN_PROGRESS", "CLOSED"} @@ -337,7 +341,7 @@ func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "referenceId": fmt.Sprintf("CI-STATUS-%s-%d", status, time.Now().UnixNano()), - "ownerId": peopleID, + "ownerId": profileID.String(), "status": status, "priority": "LOW", }, @@ -381,7 +385,7 @@ func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "referenceId": fmt.Sprintf("CI-PRIORITY-%s-%d", priority, time.Now().UnixNano()), - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", "priority": priority, }, diff --git a/e2e/console/datum_test.go b/e2e/console/datum_test.go index 2b0642045..2bc9c3a52 100644 --- a/e2e/console/datum_test.go +++ b/e2e/console/datum_test.go @@ -29,7 +29,8 @@ import ( func TestDatum_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() tests := []struct { name string @@ -102,7 +103,7 @@ func TestDatum_Create(t *testing.T) { input := map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), } for k, v := range tt.input { input[k] = v @@ -139,7 +140,8 @@ func TestDatum_Create(t *testing.T) { func TestDatum_Create_Validation(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Validation Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() tests := []struct { name string @@ -259,7 +261,7 @@ func TestDatum_Create_Validation(t *testing.T) { input["organizationId"] = owner.GetOrganizationID().String() } if !tt.skipOwner { - input["ownerId"] = peopleID + input["ownerId"] = profileID } for k, v := range tt.input { input[k] = v @@ -275,7 +277,8 @@ func TestDatum_Create_Validation(t *testing.T) { func TestDatum_Update(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Update Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() tests := []struct { name string @@ -287,7 +290,7 @@ func TestDatum_Update(t *testing.T) { { name: "update name", setup: func() string { - return factory.NewDatum(owner, peopleID). + return factory.NewDatum(owner, profileID.String()). WithName("Datum to Update"). Create() }, @@ -303,7 +306,7 @@ func TestDatum_Update(t *testing.T) { { name: "update to PUBLIC classification", setup: func() string { - return factory.NewDatum(owner, peopleID). + return factory.NewDatum(owner, profileID.String()). WithName("Classification Test"). WithDataClassification("INTERNAL"). Create() @@ -317,7 +320,7 @@ func TestDatum_Update(t *testing.T) { { name: "update to SECRET classification", setup: func() string { - return factory.NewDatum(owner, peopleID). + return factory.NewDatum(owner, profileID.String()). WithName("Classification Test"). Create() }, @@ -372,8 +375,9 @@ func TestDatum_Update(t *testing.T) { func TestDatum_Update_Validation(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Update Validation Owner").Create() - baseDatumID := factory.NewDatum(owner, peopleID).WithName("Validation Test Datum").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + baseDatumID := factory.NewDatum(owner, profileID.String()).WithName("Validation Test Datum").Create() tests := []struct { name string @@ -487,10 +491,11 @@ func TestDatum_Update_Validation(t *testing.T) { func TestDatum_Delete(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Delete Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() t.Run("delete existing datum", func(t *testing.T) { - datumID := factory.NewDatum(owner, peopleID).WithName("Datum to Delete").Create() + datumID := factory.NewDatum(owner, profileID.String()).WithName("Datum to Delete").Create() query := ` mutation DeleteDatum($input: DeleteDatumInput!) { @@ -552,11 +557,12 @@ func TestDatum_Delete_Validation(t *testing.T) { func TestDatum_List(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum List Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumNames := []string{"Datum A", "Datum B", "Datum C"} for _, name := range datumNames { - factory.NewDatum(owner, peopleID).WithName(name).Create() + factory.NewDatum(owner, profileID.String()).WithName(name).Create() } query := ` @@ -624,7 +630,8 @@ func TestDatum_Query(t *testing.T) { func TestDatum_Timestamps(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Timestamps Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() t.Run("createdAt and updatedAt are set on create", func(t *testing.T) { beforeCreate := time.Now().Add(-time.Second) @@ -658,7 +665,7 @@ func TestDatum_Timestamps(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "name": "Timestamp Test Datum", "dataClassification": "INTERNAL", }, @@ -670,7 +677,7 @@ func TestDatum_Timestamps(t *testing.T) { }) t.Run("updatedAt changes on update", func(t *testing.T) { - datumID := factory.NewDatum(owner, peopleID).WithName("Timestamp Update Test").Create() + datumID := factory.NewDatum(owner, profileID.String()).WithName("Timestamp Update Test").Create() getQuery := ` query($id: ID!) { @@ -734,8 +741,9 @@ func TestDatum_Timestamps(t *testing.T) { func TestDatum_SubResolvers(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum SubResolver Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("SubResolver Test Datum").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("SubResolver Test Datum").Create() t.Run("owner sub-resolver", func(t *testing.T) { query := ` @@ -764,7 +772,7 @@ func TestDatum_SubResolvers(t *testing.T) { err := owner.Execute(query, map[string]any{"id": datumID}, &result) require.NoError(t, err) - assert.Equal(t, peopleID, result.Node.Owner.ID) + assert.Equal(t, profileID.String(), result.Node.Owner.ID) }) t.Run("organization sub-resolver", func(t *testing.T) { @@ -805,7 +813,8 @@ func TestDatum_RBAC(t *testing.T) { t.Run("create", func(t *testing.T) { t.Run("owner can create", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() _, err := owner.Do(` mutation CreateDatum($input: CreateDatumInput!) { @@ -816,7 +825,7 @@ func TestDatum_RBAC(t *testing.T) { `, map[string]any{ "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "name": "RBAC Test Datum", "dataClassification": "INTERNAL", }, @@ -827,7 +836,8 @@ func TestDatum_RBAC(t *testing.T) { t.Run("admin can create", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() _, err := admin.Do(` mutation CreateDatum($input: CreateDatumInput!) { @@ -838,7 +848,7 @@ func TestDatum_RBAC(t *testing.T) { `, map[string]any{ "input": map[string]any{ "organizationId": admin.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "name": "RBAC Test Datum", "dataClassification": "INTERNAL", }, @@ -849,7 +859,8 @@ func TestDatum_RBAC(t *testing.T) { t.Run("viewer cannot create", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() _, err := viewer.Do(` mutation CreateDatum($input: CreateDatumInput!) { @@ -860,7 +871,7 @@ func TestDatum_RBAC(t *testing.T) { `, map[string]any{ "input": map[string]any{ "organizationId": viewer.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "name": "RBAC Test Datum", "dataClassification": "INTERNAL", }, @@ -872,8 +883,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("update", func(t *testing.T) { t.Run("owner can update", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Update Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Update Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Update Test").Create() _, err := owner.Do(` mutation UpdateDatum($input: UpdateDatumInput!) { @@ -893,8 +905,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("admin can update", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Update Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Update Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Update Test").Create() _, err := admin.Do(` mutation UpdateDatum($input: UpdateDatumInput!) { @@ -914,8 +927,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("viewer cannot update", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Update Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Update Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Update Test").Create() _, err := viewer.Do(` mutation UpdateDatum($input: UpdateDatumInput!) { @@ -936,8 +950,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("delete", func(t *testing.T) { t.Run("owner can delete", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Delete Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Delete Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Delete Test").Create() _, err := owner.Do(` mutation DeleteDatum($input: DeleteDatumInput!) { @@ -954,8 +969,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("admin can delete", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Delete Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Delete Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Delete Test").Create() _, err := admin.Do(` mutation DeleteDatum($input: DeleteDatumInput!) { @@ -972,8 +988,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("viewer cannot delete", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Delete Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Delete Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Delete Test").Create() _, err := viewer.Do(` mutation DeleteDatum($input: DeleteDatumInput!) { @@ -991,8 +1008,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("read", func(t *testing.T) { t.Run("owner can read", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Read Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Read Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Read Test").Create() var result struct { Node *struct { @@ -1015,8 +1033,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("admin can read", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Read Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Read Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Read Test").Create() var result struct { Node *struct { @@ -1039,8 +1058,9 @@ func TestDatum_RBAC(t *testing.T) { t.Run("viewer can read", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Read Owner").Create() - datumID := factory.NewDatum(owner, peopleID).WithName("RBAC Read Test").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Read Test").Create() var result struct { Node *struct { @@ -1065,7 +1085,8 @@ func TestDatum_RBAC(t *testing.T) { func TestDatum_MaxLength_Validation(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Max Length Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() longName := strings.Repeat("a", 1001) @@ -1083,7 +1104,7 @@ func TestDatum_MaxLength_Validation(t *testing.T) { _, err := owner.Do(query, map[string]any{ "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "name": longName, "dataClassification": "INTERNAL", }, @@ -1093,7 +1114,7 @@ func TestDatum_MaxLength_Validation(t *testing.T) { }) t.Run("update", func(t *testing.T) { - datumID := factory.NewDatum(owner, peopleID).WithName("Max Length Test").Create() + datumID := factory.NewDatum(owner, profileID.String()).WithName("Max Length Test").Create() query := ` mutation UpdateDatum($input: UpdateDatumInput!) { @@ -1117,10 +1138,11 @@ func TestDatum_MaxLength_Validation(t *testing.T) { func TestDatum_Pagination(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Pagination Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() for i := 0; i < 5; i++ { - factory.NewDatum(owner, peopleID). + factory.NewDatum(owner, profileID.String()). WithName(fmt.Sprintf("Pagination Datum %d", i)). Create() } @@ -1266,8 +1288,9 @@ func TestDatum_TenantIsolation(t *testing.T) { org1Owner := testutil.NewClient(t, testutil.RoleOwner) org2Owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(org1Owner).WithFullName("Org1 Datum Owner").Create() - datumID := factory.NewDatum(org1Owner, peopleID).WithName("Org1 Datum").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, org1Owner).GetProfileID() + datumID := factory.NewDatum(org1Owner, profileID.String()).WithName("Org1 Datum").Create() t.Run("cannot read datum from another organization", func(t *testing.T) { query := ` @@ -1373,10 +1396,11 @@ func TestDatum_TenantIsolation(t *testing.T) { func TestDatum_Ordering(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Datum Ordering Owner").Create() + // TODO: right now we need to invite and accept invite to get new profile. + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() - factory.NewDatum(owner, peopleID).WithName("AAA Order Test").Create() - factory.NewDatum(owner, peopleID).WithName("ZZZ Order Test").Create() + factory.NewDatum(owner, profileID.String()).WithName("AAA Order Test").Create() + factory.NewDatum(owner, profileID.String()).WithName("ZZZ Order Test").Create() t.Run("order by created_at descending", func(t *testing.T) { query := ` diff --git a/e2e/console/document_test.go b/e2e/console/document_test.go index c0fc5c9ce..778e7e1bc 100644 --- a/e2e/console/document_test.go +++ b/e2e/console/document_test.go @@ -29,7 +29,7 @@ import ( func TestDocument_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() tests := []struct { name string @@ -113,7 +113,7 @@ func TestDocument_Create(t *testing.T) { input := map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": ownerPeopleID, + "ownerId": ownerProfileID.String(), } for k, v := range tt.input { input[k] = v @@ -151,7 +151,7 @@ func TestDocument_Create(t *testing.T) { func TestDocument_Create_Validation(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Validation Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() tests := []struct { name string @@ -293,7 +293,7 @@ func TestDocument_Create_Validation(t *testing.T) { input["organizationId"] = owner.GetOrganizationID().String() } if !tt.skipOwner { - input["ownerId"] = ownerPeopleID + input["ownerId"] = ownerProfileID.String() } for k, v := range tt.input { input[k] = v @@ -309,7 +309,7 @@ func TestDocument_Create_Validation(t *testing.T) { func TestDocument_Update(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Update Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() tests := []struct { name string @@ -321,7 +321,7 @@ func TestDocument_Update(t *testing.T) { { name: "update title", setup: func() string { - return factory.NewDocument(owner, ownerPeopleID). + return factory.NewDocument(owner, ownerProfileID.String()). WithTitle("Document to Update"). Create() }, @@ -337,7 +337,7 @@ func TestDocument_Update(t *testing.T) { { name: "update document type", setup: func() string { - return factory.NewDocument(owner, ownerPeopleID). + return factory.NewDocument(owner, ownerProfileID.String()). WithTitle("Type Test"). WithDocumentType("POLICY"). Create() @@ -393,8 +393,8 @@ func TestDocument_Update(t *testing.T) { func TestDocument_Update_Validation(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Update Validation Owner").Create() - baseDocumentID := factory.NewDocument(owner, ownerPeopleID).WithTitle("Validation Test Document").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + baseDocumentID := factory.NewDocument(owner, ownerProfileID.String()).WithTitle("Validation Test Document").Create() tests := []struct { name string @@ -484,10 +484,10 @@ func TestDocument_Update_Validation(t *testing.T) { func TestDocument_Delete(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Delete Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() t.Run("delete existing document", func(t *testing.T) { - documentID := factory.NewDocument(owner, ownerPeopleID).WithTitle("Document to Delete").Create() + documentID := factory.NewDocument(owner, ownerProfileID.String()).WithTitle("Document to Delete").Create() query := ` mutation DeleteDocument($input: DeleteDocumentInput!) { @@ -549,11 +549,11 @@ func TestDocument_Delete_Validation(t *testing.T) { func TestDocument_List(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document List Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() documentTitles := []string{"Document A", "Document B", "Document C"} for _, title := range documentTitles { - factory.NewDocument(owner, ownerPeopleID).WithTitle(title).Create() + factory.NewDocument(owner, ownerProfileID.String()).WithTitle(title).Create() } query := ` @@ -621,7 +621,7 @@ func TestDocument_Query(t *testing.T) { func TestDocument_Timestamps(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Timestamps Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() t.Run("createdAt and updatedAt are set on create", func(t *testing.T) { beforeCreate := time.Now().Add(-time.Second) @@ -655,7 +655,7 @@ func TestDocument_Timestamps(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": ownerPeopleID, + "ownerId": ownerProfileID.String(), "title": "Timestamp Test Document", "content": "Test content", "documentType": "POLICY", @@ -669,7 +669,7 @@ func TestDocument_Timestamps(t *testing.T) { }) t.Run("updatedAt changes on update", func(t *testing.T) { - documentID := factory.NewDocument(owner, ownerPeopleID).WithTitle("Timestamp Update Test").Create() + documentID := factory.NewDocument(owner, ownerProfileID.String()).WithTitle("Timestamp Update Test").Create() getQuery := ` query($id: ID!) { @@ -733,8 +733,8 @@ func TestDocument_Timestamps(t *testing.T) { func TestDocument_SubResolvers(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document SubResolver Owner").Create() - documentID := factory.NewDocument(owner, ownerPeopleID).WithTitle("SubResolver Test Document").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, ownerProfileID.String()).WithTitle("SubResolver Test Document").Create() t.Run("owner sub-resolver", func(t *testing.T) { query := ` @@ -763,7 +763,7 @@ func TestDocument_SubResolvers(t *testing.T) { err := owner.Execute(query, map[string]any{"id": documentID}, &result) require.NoError(t, err) - assert.Equal(t, ownerPeopleID, result.Node.Owner.ID) + assert.Equal(t, ownerProfileID.String(), result.Node.Owner.ID) }) t.Run("organization sub-resolver", func(t *testing.T) { @@ -804,7 +804,7 @@ func TestDocument_RBAC(t *testing.T) { t.Run("create", func(t *testing.T) { t.Run("owner can create", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() _, err := owner.Do(` mutation CreateDocument($input: CreateDocumentInput!) { @@ -815,7 +815,7 @@ func TestDocument_RBAC(t *testing.T) { `, map[string]any{ "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "title": "RBAC Test Document", "content": "Test content", "documentType": "POLICY", @@ -828,7 +828,7 @@ func TestDocument_RBAC(t *testing.T) { t.Run("admin can create", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() _, err := admin.Do(` mutation CreateDocument($input: CreateDocumentInput!) { @@ -839,7 +839,7 @@ func TestDocument_RBAC(t *testing.T) { `, map[string]any{ "input": map[string]any{ "organizationId": admin.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "title": "RBAC Test Document", "content": "Test content", "documentType": "POLICY", @@ -852,7 +852,7 @@ func TestDocument_RBAC(t *testing.T) { t.Run("viewer cannot create", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() _, err := viewer.Do(` mutation CreateDocument($input: CreateDocumentInput!) { @@ -863,7 +863,7 @@ func TestDocument_RBAC(t *testing.T) { `, map[string]any{ "input": map[string]any{ "organizationId": viewer.GetOrganizationID().String(), - "ownerId": peopleID, + "ownerId": profileID.String(), "title": "RBAC Test Document", "content": "Test content", "documentType": "POLICY", @@ -877,8 +877,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("update", func(t *testing.T) { t.Run("owner can update", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Update Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Update Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Update Test").Create() _, err := owner.Do(` mutation UpdateDocument($input: UpdateDocumentInput!) { @@ -898,8 +898,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("admin can update", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Update Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Update Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Update Test").Create() _, err := admin.Do(` mutation UpdateDocument($input: UpdateDocumentInput!) { @@ -919,8 +919,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("viewer cannot update", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Update Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Update Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Update Test").Create() _, err := viewer.Do(` mutation UpdateDocument($input: UpdateDocumentInput!) { @@ -941,8 +941,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("delete", func(t *testing.T) { t.Run("owner can delete", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Delete Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Delete Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Delete Test").Create() _, err := owner.Do(` mutation DeleteDocument($input: DeleteDocumentInput!) { @@ -959,8 +959,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("admin can delete", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Delete Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Delete Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Delete Test").Create() _, err := admin.Do(` mutation DeleteDocument($input: DeleteDocumentInput!) { @@ -977,8 +977,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("viewer cannot delete", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Delete Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Delete Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Delete Test").Create() _, err := viewer.Do(` mutation DeleteDocument($input: DeleteDocumentInput!) { @@ -996,8 +996,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("read", func(t *testing.T) { t.Run("owner can read", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Read Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Read Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Read Test").Create() var result struct { Node *struct { @@ -1020,8 +1020,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("admin can read", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Admin Read Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Read Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Read Test").Create() var result struct { Node *struct { @@ -1044,8 +1044,8 @@ func TestDocument_RBAC(t *testing.T) { t.Run("viewer can read", func(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - peopleID := factory.NewPeople(owner).WithFullName("RBAC Viewer Read Owner").Create() - documentID := factory.NewDocument(owner, peopleID).WithTitle("RBAC Read Test").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + documentID := factory.NewDocument(owner, profileID.String()).WithTitle("RBAC Read Test").Create() var result struct { Node *struct { @@ -1070,7 +1070,7 @@ func TestDocument_RBAC(t *testing.T) { func TestDocument_MaxLength_Validation(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Max Length Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() longTitle := strings.Repeat("a", 1001) @@ -1088,7 +1088,7 @@ func TestDocument_MaxLength_Validation(t *testing.T) { _, err := owner.Do(query, map[string]any{ "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), - "ownerId": ownerPeopleID, + "ownerId": ownerProfileID.String(), "title": longTitle, "content": "Test content", "documentType": "POLICY", @@ -1100,7 +1100,7 @@ func TestDocument_MaxLength_Validation(t *testing.T) { }) t.Run("update", func(t *testing.T) { - documentID := factory.NewDocument(owner, ownerPeopleID).WithTitle("Max Length Test").Create() + documentID := factory.NewDocument(owner, ownerProfileID.String()).WithTitle("Max Length Test").Create() query := ` mutation UpdateDocument($input: UpdateDocumentInput!) { @@ -1124,10 +1124,10 @@ func TestDocument_MaxLength_Validation(t *testing.T) { func TestDocument_Pagination(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Pagination Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() for i := 0; i < 5; i++ { - factory.NewDocument(owner, ownerPeopleID). + factory.NewDocument(owner, ownerProfileID.String()). WithTitle(fmt.Sprintf("Pagination Document %d", i)). Create() } @@ -1273,8 +1273,8 @@ func TestDocument_TenantIsolation(t *testing.T) { org1Owner := testutil.NewClient(t, testutil.RoleOwner) org2Owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(org1Owner).WithFullName("Org1 Document Owner").Create() - documentID := factory.NewDocument(org1Owner, peopleID).WithTitle("Org1 Document").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, org1Owner).GetProfileID() + documentID := factory.NewDocument(org1Owner, profileID.String()).WithTitle("Org1 Document").Create() t.Run("cannot read document from another organization", func(t *testing.T) { query := ` @@ -1380,10 +1380,10 @@ func TestDocument_TenantIsolation(t *testing.T) { func TestDocument_Ordering(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - ownerPeopleID := factory.NewPeople(owner).WithFullName("Document Ordering Owner").Create() + ownerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() - factory.NewDocument(owner, ownerPeopleID).WithTitle("AAA Order Test").Create() - factory.NewDocument(owner, ownerPeopleID).WithTitle("ZZZ Order Test").Create() + factory.NewDocument(owner, ownerProfileID.String()).WithTitle("AAA Order Test").Create() + factory.NewDocument(owner, ownerProfileID.String()).WithTitle("ZZZ Order Test").Create() t.Run("order by created_at descending", func(t *testing.T) { query := ` diff --git a/e2e/console/document_version_test.go b/e2e/console/document_version_test.go index 71254e309..89b0f9165 100644 --- a/e2e/console/document_version_test.go +++ b/e2e/console/document_version_test.go @@ -19,14 +19,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" "go.probo.inc/probo/e2e/internal/testutil" ) // createTestDocument creates a document and returns its ID and the document version ID func createTestDocument(t *testing.T, owner *testutil.Client) (docID string, docVersionID string) { t.Helper() - peopleID := factory.NewPeople(owner).WithFullName("Doc Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() query := ` mutation CreateDocument($input: CreateDocumentInput!) { @@ -69,7 +68,7 @@ func createTestDocument(t *testing.T, owner *testutil.Client) (docID string, doc "organizationId": owner.GetOrganizationID().String(), "title": "Test Document", "content": "Initial content", - "ownerId": peopleID, + "ownerId": profileID.String(), "documentType": "POLICY", "classification": "INTERNAL", }, @@ -264,7 +263,7 @@ func TestDocumentVersion_RequestSignature(t *testing.T) { publishedVersionID := publishResult.PublishDocumentVersion.DocumentVersion.ID // Create a person to sign - signerID := factory.NewPeople(owner).WithFullName("Document Signer").Create() + signerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() query := ` mutation RequestSignature($input: RequestSignatureInput!) { @@ -301,14 +300,14 @@ func TestDocumentVersion_RequestSignature(t *testing.T) { err = owner.Execute(query, map[string]any{ "input": map[string]any{ "documentVersionId": publishedVersionID, - "signatoryId": signerID, + "signatoryId": signerProfileID.String(), }, }, &result) require.NoError(t, err) assert.NotEmpty(t, result.RequestSignature.DocumentVersionSignatureEdge.Node.ID) assert.Equal(t, "REQUESTED", result.RequestSignature.DocumentVersionSignatureEdge.Node.State) - assert.Equal(t, signerID, result.RequestSignature.DocumentVersionSignatureEdge.Node.SignedBy.ID) + assert.Equal(t, signerProfileID.String(), result.RequestSignature.DocumentVersionSignatureEdge.Node.SignedBy.ID) } func TestDocumentVersion_BulkPublish(t *testing.T) { @@ -383,8 +382,8 @@ func TestDocumentVersion_BulkRequestSignatures(t *testing.T) { require.NoError(t, err) // Create multiple signers - signer1ID := factory.NewPeople(owner).WithFullName("Bulk Signer 1").Create() - signer2ID := factory.NewPeople(owner).WithFullName("Bulk Signer 2").Create() + signer1ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + signer2ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() query := ` mutation BulkRequestSignatures($input: BulkRequestSignaturesInput!) { @@ -413,7 +412,7 @@ func TestDocumentVersion_BulkRequestSignatures(t *testing.T) { err = owner.Execute(query, map[string]any{ "input": map[string]any{ "documentIds": []string{docID}, - "signatoryIds": []string{signer1ID, signer2ID}, + "signatoryIds": []string{signer1ProfileID.String(), signer2ProfileID.String()}, }, }, &result) require.NoError(t, err) diff --git a/e2e/console/mapping_test.go b/e2e/console/mapping_test.go index 60446625a..22de50968 100644 --- a/e2e/console/mapping_test.go +++ b/e2e/console/mapping_test.go @@ -19,7 +19,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" "go.probo.inc/probo/e2e/internal/testutil" ) @@ -370,7 +369,7 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) { controlID := createControlResult.CreateControl.ControlEdge.Node.ID // Create a document - peopleID := factory.NewPeople(owner).WithFullName("Doc Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() var createDocumentResult struct { CreateDocument struct { DocumentEdge struct { @@ -395,7 +394,7 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "title": "Document for Control Mapping", "content": "Document content", - "ownerId": peopleID, + "ownerId": profileID.String(), "documentType": "POLICY", "classification": "INTERNAL", }, @@ -760,7 +759,7 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) { riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID // Create a document - peopleID := factory.NewPeople(owner).WithFullName("Doc Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() var createDocumentResult struct { CreateDocument struct { DocumentEdge struct { @@ -785,7 +784,7 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "title": "Document for Risk Mapping", "content": "Document content", - "ownerId": peopleID, + "ownerId": profileID.String(), "documentType": "POLICY", "classification": "INTERNAL", }, @@ -874,7 +873,7 @@ func TestRiskObligationMapping_CreateDelete(t *testing.T) { riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID // Create an obligation - peopleID := factory.NewPeople(owner).WithFullName("Obligation Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() var createObligationResult struct { CreateObligation struct { ObligationEdge struct { @@ -899,7 +898,7 @@ func TestRiskObligationMapping_CreateDelete(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "area": "Risk Management", "requirement": "Obligation for Risk Mapping", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "NON_COMPLIANT", "type": "LEGAL", }, diff --git a/e2e/console/meeting_test.go b/e2e/console/meeting_test.go index f51028377..913489a58 100644 --- a/e2e/console/meeting_test.go +++ b/e2e/console/meeting_test.go @@ -690,8 +690,8 @@ func TestMeeting_SubResolvers_WithData(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - attendee1 := factory.NewPeople(owner).WithFullName("Attendee One").Create() - attendee2 := factory.NewPeople(owner).WithFullName("Attendee Two").Create() + attendee1ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + attendee2ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() var result struct { CreateMeeting struct { @@ -730,7 +730,7 @@ func TestMeeting_SubResolvers_WithData(t *testing.T) { "organizationId": owner.GetOrganizationID().String(), "name": "Meeting With Attendees", "date": time.Now().Format(time.RFC3339Nano), - "attendeeIds": []string{attendee1, attendee2}, + "attendeeIds": []string{attendee1ProfileID.String(), attendee2ProfileID.String()}, }, }, &result) require.NoError(t, err) diff --git a/e2e/console/nonconformity_test.go b/e2e/console/nonconformity_test.go index 1991cb95c..e933d00f9 100644 --- a/e2e/console/nonconformity_test.go +++ b/e2e/console/nonconformity_test.go @@ -21,7 +21,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" "go.probo.inc/probo/e2e/internal/testutil" ) @@ -100,7 +99,7 @@ func createAuditForNC(t *testing.T, owner *testutil.Client, name string) string func TestNonconformity_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("NC Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() auditID := createAuditForNC(t, owner, "NC Test Audit") query := ` @@ -143,7 +142,7 @@ func TestNonconformity_Create(t *testing.T) { "auditId": auditID, "rootCause": "Insufficient access controls", "correctiveAction": "Implement MFA", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", }, }, &result) @@ -159,7 +158,7 @@ func TestNonconformity_Create(t *testing.T) { func TestNonconformity_Update(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("NC Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() auditID := createAuditForNC(t, owner, "NC Update Test Audit") // Create a nonconformity to update @@ -191,7 +190,7 @@ func TestNonconformity_Update(t *testing.T) { "referenceId": fmt.Sprintf("NC-UPDATE-%d", time.Now().UnixNano()), "auditId": auditID, "rootCause": "Original root cause", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", }, }, &createResult) @@ -242,7 +241,7 @@ func TestNonconformity_Update(t *testing.T) { func TestNonconformity_Delete(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("NC Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() auditID := createAuditForNC(t, owner, "NC Delete Test Audit") // Create a nonconformity to delete @@ -274,7 +273,7 @@ func TestNonconformity_Delete(t *testing.T) { "referenceId": fmt.Sprintf("NC-DELETE-%d", time.Now().UnixNano()), "auditId": auditID, "rootCause": "Test root cause", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", }, }, &createResult) @@ -307,7 +306,7 @@ func TestNonconformity_Delete(t *testing.T) { func TestNonconformity_List(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("NC Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() auditID := createAuditForNC(t, owner, "NC List Test Audit") // Create multiple nonconformities @@ -340,7 +339,7 @@ func TestNonconformity_List(t *testing.T) { "referenceId": fmt.Sprintf("NC-LIST-%d-%d", i, time.Now().UnixNano()), "auditId": auditID, "rootCause": fmt.Sprintf("Root cause %d", i), - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "OPEN", }, }, &createResult) @@ -391,7 +390,7 @@ func TestNonconformity_List(t *testing.T) { func TestNonconformity_StatusValues(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("NC Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() auditID := createAuditForNC(t, owner, "NC Status Test Audit") statuses := []string{"OPEN", "IN_PROGRESS", "CLOSED"} @@ -428,7 +427,7 @@ func TestNonconformity_StatusValues(t *testing.T) { "referenceId": fmt.Sprintf("NC-STATUS-%s-%d", status, time.Now().UnixNano()), "auditId": auditID, "rootCause": "Test root cause", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": status, }, }, &result) diff --git a/e2e/console/obligation_test.go b/e2e/console/obligation_test.go index 54f6efe5f..062b90050 100644 --- a/e2e/console/obligation_test.go +++ b/e2e/console/obligation_test.go @@ -19,14 +19,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" "go.probo.inc/probo/e2e/internal/testutil" ) func TestObligation_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Obligation Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() query := ` mutation CreateObligation($input: CreateObligationInput!) { @@ -67,7 +66,7 @@ func TestObligation_Create(t *testing.T) { "source": "GDPR Article 5", "requirement": "Data must be processed lawfully", "regulator": "ICO", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "NON_COMPLIANT", "type": "LEGAL", }, @@ -85,7 +84,7 @@ func TestObligation_Create(t *testing.T) { func TestObligation_Update(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Obligation Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() // Create an obligation to update createQuery := ` @@ -114,7 +113,7 @@ func TestObligation_Update(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "area": "Original Area", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "NON_COMPLIANT", "type": "LEGAL", }, @@ -162,7 +161,7 @@ func TestObligation_Update(t *testing.T) { func TestObligation_Delete(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Obligation Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() // Create an obligation to delete createQuery := ` @@ -191,7 +190,7 @@ func TestObligation_Delete(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "area": "Obligation to Delete", - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "NON_COMPLIANT", "type": "LEGAL", }, @@ -226,7 +225,7 @@ func TestObligation_Delete(t *testing.T) { func TestObligation_List(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Obligation Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() // Create multiple obligations areas := []string{"Area A", "Area B", "Area C"} @@ -257,7 +256,7 @@ func TestObligation_List(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "area": area, - "ownerId": peopleID, + "ownerId": profileID.String(), "status": "NON_COMPLIANT", "type": "LEGAL", }, @@ -310,7 +309,7 @@ func TestObligation_List(t *testing.T) { func TestObligation_StatusValues(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.NewPeople(owner).WithFullName("Obligation Owner").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() statuses := []string{"NON_COMPLIANT", "PARTIALLY_COMPLIANT", "COMPLIANT"} @@ -344,7 +343,7 @@ func TestObligation_StatusValues(t *testing.T) { "input": map[string]any{ "organizationId": owner.GetOrganizationID().String(), "area": "Status Test " + status, - "ownerId": peopleID, + "ownerId": profileID.String(), "status": status, "type": "LEGAL", }, diff --git a/e2e/console/people_test.go b/e2e/console/people_test.go deleted file mode 100644 index 87205a0f7..000000000 --- a/e2e/console/people_test.go +++ /dev/null @@ -1,677 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -package console_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" - "go.probo.inc/probo/e2e/internal/testutil" -) - -func TestPeople_Create(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - t.Run("with full details", func(t *testing.T) { - query := ` - mutation CreatePeople($input: CreatePeopleInput!) { - createPeople(input: $input) { - peopleEdge { - node { - id - fullName - kind - position - } - } - } - } - ` - - var result struct { - CreatePeople struct { - PeopleEdge struct { - Node struct { - ID string `json:"id"` - FullName string `json:"fullName"` - Kind string `json:"kind"` - Position *string `json:"position"` - } `json:"node"` - } `json:"peopleEdge"` - } `json:"createPeople"` - } - - err := owner.Execute(query, map[string]any{ - "input": map[string]any{ - "organizationId": owner.GetOrganizationID().String(), - "fullName": "John Doe", - "primaryEmailAddress": "john.doe@example.com", - "additionalEmailAddresses": []string{}, - "kind": "EMPLOYEE", - "position": "Software Engineer", - }, - }, &result) - require.NoError(t, err) - - people := result.CreatePeople.PeopleEdge.Node - assert.NotEmpty(t, people.ID) - assert.Equal(t, "John Doe", people.FullName) - assert.Equal(t, "EMPLOYEE", people.Kind) - assert.Equal(t, "Software Engineer", *people.Position) - }) - - t.Run("with different kinds", func(t *testing.T) { - kinds := []struct { - name string - kind string - }{ - {"Employee", "EMPLOYEE"}, - {"Contractor", "CONTRACTOR"}, - {"Service Account", "SERVICE_ACCOUNT"}, - } - - for _, tt := range kinds { - t.Run(tt.name, func(t *testing.T) { - peopleID := factory.CreatePeople(owner, factory.Attrs{ - "fullName": "Person " + tt.kind, - "kind": tt.kind, - }) - - query := ` - query GetPeople($id: ID!) { - node(id: $id) { - ... on People { - id - kind - } - } - } - ` - - var result struct { - Node struct { - ID string `json:"id"` - Kind string `json:"kind"` - } `json:"node"` - } - - err := owner.Execute(query, map[string]any{"id": peopleID}, &result) - require.NoError(t, err) - assert.Equal(t, tt.kind, result.Node.Kind) - }) - } - }) - - t.Run("with additional emails", func(t *testing.T) { - t.Skip("additionalEmailAddresses feature not fully implemented") - }) -} - -func TestPeople_Update(t *testing.T) { - t.Skip("updatePeople has server bug with additional_email_addresses null constraint") - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.CreatePeople(owner, factory.Attrs{ - "fullName": "Person to Update", - }) - - query := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { - id - fullName - } - } - } - ` - - var result struct { - UpdatePeople struct { - People struct { - ID string `json:"id"` - FullName string `json:"fullName"` - } `json:"people"` - } `json:"updatePeople"` - } - - err := owner.Execute(query, map[string]any{ - "input": map[string]any{ - "id": peopleID, - "fullName": "Updated Name", - }, - }, &result) - require.NoError(t, err) - - assert.Equal(t, peopleID, result.UpdatePeople.People.ID) - assert.Equal(t, "Updated Name", result.UpdatePeople.People.FullName) -} - -func TestPeople_Delete(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - peopleID := factory.CreatePeople(owner, factory.Attrs{ - "fullName": "Person to Delete", - }) - - query := ` - mutation DeletePeople($input: DeletePeopleInput!) { - deletePeople(input: $input) { - deletedPeopleId - } - } - ` - - var result struct { - DeletePeople struct { - DeletedPeopleID string `json:"deletedPeopleId"` - } `json:"deletePeople"` - } - - err := owner.Execute(query, map[string]any{ - "input": map[string]any{ - "peopleId": peopleID, - }, - }, &result) - require.NoError(t, err) - assert.Equal(t, peopleID, result.DeletePeople.DeletedPeopleID) -} - -func TestPeople_List(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - // Create multiple people - peopleNames := []string{"Person A", "Person B", "Person C"} - for _, name := range peopleNames { - factory.CreatePeople(owner, factory.Attrs{"fullName": name}) - } - - query := ` - query ListPeoples($orgId: ID!) { - node(id: $orgId) { - ... on Organization { - peoples(first: 10) { - edges { - node { - id - fullName - } - } - totalCount - } - } - } - } - ` - - var result struct { - Node struct { - Peoples struct { - Edges []struct { - Node struct { - ID string `json:"id"` - FullName string `json:"fullName"` - } `json:"node"` - } `json:"edges"` - TotalCount int `json:"totalCount"` - } `json:"peoples"` - } `json:"node"` - } - - err := owner.Execute(query, map[string]any{ - "orgId": owner.GetOrganizationID().String(), - }, &result) - require.NoError(t, err) - assert.GreaterOrEqual(t, result.Node.Peoples.TotalCount, 3) -} - -func TestPeople_RequiredFields(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - tests := []struct { - name string - input map[string]any - skipOrganization bool - wantErrorContains string - }{ - { - name: "missing organizationId", - input: map[string]any{ - "fullName": "Test Person", - "primaryEmailAddress": "test@example.com", - "additionalEmailAddresses": []string{}, - "kind": "EMPLOYEE", - }, - skipOrganization: true, - wantErrorContains: "organizationId", - }, - { - name: "missing fullName", - input: map[string]any{ - "primaryEmailAddress": "test@example.com", - "additionalEmailAddresses": []string{}, - "kind": "EMPLOYEE", - }, - wantErrorContains: "fullName", - }, - { - name: "missing primaryEmailAddress", - input: map[string]any{ - "fullName": "Test Person", - "additionalEmailAddresses": []string{}, - "kind": "EMPLOYEE", - }, - wantErrorContains: "primaryEmailAddress", - }, - { - name: "missing kind", - input: map[string]any{ - "fullName": "Test Person", - "primaryEmailAddress": "test@example.com", - "additionalEmailAddresses": []string{}, - }, - wantErrorContains: "kind", - }, - { - name: "empty fullName", - input: map[string]any{ - "fullName": "", - "primaryEmailAddress": "test@example.com", - "additionalEmailAddresses": []string{}, - "kind": "EMPLOYEE", - }, - wantErrorContains: "full_name", - }, - { - name: "invalid kind enum", - input: map[string]any{ - "fullName": "Test Person", - "primaryEmailAddress": "test@example.com", - "additionalEmailAddresses": []string{}, - "kind": "INVALID_KIND", - }, - wantErrorContains: "kind", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - query := ` - mutation CreatePeople($input: CreatePeopleInput!) { - createPeople(input: $input) { - peopleEdge { - node { - id - } - } - } - } - ` - - input := make(map[string]any) - if !tt.skipOrganization { - input["organizationId"] = owner.GetOrganizationID().String() - } - for k, v := range tt.input { - input[k] = v - } - - _, err := owner.Do(query, map[string]any{"input": input}) - require.Error(t, err) - assert.Contains(t, err.Error(), tt.wantErrorContains) - }) - } -} - -func TestPeople_KindEnum(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - kinds := []string{ - "EMPLOYEE", - "CONTRACTOR", - } - - for _, kind := range kinds { - t.Run("create with kind "+kind, func(t *testing.T) { - peopleID := factory.NewPeople(owner). - WithFullName("Kind Test " + kind). - WithKind(kind). - Create() - - query := ` - query($id: ID!) { - node(id: $id) { - ... on People { - id - kind - } - } - } - ` - - var result struct { - Node struct { - ID string `json:"id"` - Kind string `json:"kind"` - } `json:"node"` - } - - err := owner.Execute(query, map[string]any{"id": peopleID}, &result) - require.NoError(t, err) - assert.Equal(t, kind, result.Node.Kind) - }) - } -} - -func TestPeople_SubResolvers(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - peopleID := factory.NewPeople(owner). - WithFullName("SubResolver Test Person"). - Create() - - t.Run("people node query", func(t *testing.T) { - query := ` - query GetPeople($id: ID!) { - node(id: $id) { - ... on People { - id - fullName - primaryEmailAddress - kind - } - } - } - ` - - var result struct { - Node struct { - ID string `json:"id"` - FullName string `json:"fullName"` - PrimaryEmailAddress string `json:"primaryEmailAddress"` - Kind string `json:"kind"` - } `json:"node"` - } - - err := owner.Execute(query, map[string]any{"id": peopleID}, &result) - require.NoError(t, err) - assert.Equal(t, peopleID, result.Node.ID) - assert.Equal(t, "SubResolver Test Person", result.Node.FullName) - }) - -} - -func TestPeople_InvalidID(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - t.Run("update with invalid ID", func(t *testing.T) { - query := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { - id - } - } - } - ` - - _, err := owner.Do(query, map[string]any{ - "input": map[string]any{ - "id": "invalid-id-format", - "fullName": "Test", - }, - }) - require.Error(t, err) - assert.Contains(t, err.Error(), "base64") - }) - - t.Run("delete with invalid ID", func(t *testing.T) { - query := ` - mutation DeletePeople($input: DeletePeopleInput!) { - deletePeople(input: $input) { - deletedPeopleId - } - } - ` - - _, err := owner.Do(query, map[string]any{ - "input": map[string]any{ - "peopleId": "invalid-id-format", - }, - }) - require.Error(t, err) - assert.Contains(t, err.Error(), "base64") - }) - - t.Run("query with non-existent ID", func(t *testing.T) { - query := ` - query GetPeople($id: ID!) { - node(id: $id) { - ... on People { - id - fullName - } - } - } - ` - - err := owner.ExecuteShouldFail(query, map[string]any{ - "id": "V0wtM0tMNmJBQ1lBQUFBQUFackhLSTJfbXJJRUFZVXo", - }) - require.Error(t, err, "Non-existent ID should return error") - }) -} - -func TestPeople_OmittablePosition(t *testing.T) { - t.Skip("Skipped: server returns internal error when updating position field") - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - - peopleID := factory.NewPeople(owner). - WithFullName("Position Test Person"). - Create() - - t.Run("set position", func(t *testing.T) { - query := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { - id - position - } - } - } - ` - - var result struct { - UpdatePeople struct { - People struct { - ID string `json:"id"` - Position *string `json:"position"` - } `json:"people"` - } `json:"updatePeople"` - } - - err := owner.Execute(query, map[string]any{ - "input": map[string]any{ - "id": peopleID, - "position": "Software Engineer", - }, - }, &result) - require.NoError(t, err) - require.NotNil(t, result.UpdatePeople.People.Position) - assert.Equal(t, "Software Engineer", *result.UpdatePeople.People.Position) - }) - - t.Run("clear position with null", func(t *testing.T) { - query := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { - id - position - } - } - } - ` - - var result struct { - UpdatePeople struct { - People struct { - ID string `json:"id"` - Position *string `json:"position"` - } `json:"people"` - } `json:"updatePeople"` - } - - err := owner.Execute(query, map[string]any{ - "input": map[string]any{ - "id": peopleID, - "position": nil, - }, - }, &result) - require.NoError(t, err) - assert.Nil(t, result.UpdatePeople.People.Position) - }) - - t.Run("update without position preserves value", func(t *testing.T) { - // First set a position - setQuery := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { - id - } - } - } - ` - - err := owner.Execute(setQuery, map[string]any{ - "input": map[string]any{ - "id": peopleID, - "position": "Senior Engineer", - }, - }, nil) - require.NoError(t, err) - - // Update only fullName - query := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { - id - fullName - position - } - } - } - ` - - var result struct { - UpdatePeople struct { - People struct { - ID string `json:"id"` - FullName string `json:"fullName"` - Position *string `json:"position"` - } `json:"people"` - } `json:"updatePeople"` - } - - err = owner.Execute(query, map[string]any{ - "input": map[string]any{ - "id": peopleID, - "fullName": "Updated Name", - }, - }, &result) - require.NoError(t, err) - require.NotNil(t, result.UpdatePeople.People.Position) - assert.Equal(t, "Senior Engineer", *result.UpdatePeople.People.Position) - }) -} - -func TestPeople_TenantIsolation(t *testing.T) { - t.Parallel() - - org1Owner := testutil.NewClient(t, testutil.RoleOwner) - org2Owner := testutil.NewClient(t, testutil.RoleOwner) - - peopleID := factory.NewPeople(org1Owner).WithFullName("Org1 Person").Create() - - t.Run("cannot read people from another organization", func(t *testing.T) { - query := ` - query($id: ID!) { - node(id: $id) { - ... on People { - id - fullName - } - } - } - ` - - var result struct { - Node *struct { - ID string `json:"id"` - FullName string `json:"fullName"` - } `json:"node"` - } - - err := org2Owner.Execute(query, map[string]any{"id": peopleID}, &result) - testutil.AssertNodeNotAccessible(t, err, result.Node == nil, "people") - }) - - t.Run("cannot update people from another organization", func(t *testing.T) { - query := ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { id } - } - } - ` - - _, err := org2Owner.Do(query, map[string]any{ - "input": map[string]any{ - "id": peopleID, - "fullName": "Hijacked Person", - }, - }) - require.Error(t, err, "Should not be able to update people from another org") - }) - - t.Run("cannot delete people from another organization", func(t *testing.T) { - query := ` - mutation DeletePeople($input: DeletePeopleInput!) { - deletePeople(input: $input) { - deletedPeopleId - } - } - ` - - _, err := org2Owner.Do(query, map[string]any{ - "input": map[string]any{ - "peopleId": peopleID, - }, - }) - require.Error(t, err, "Should not be able to delete people from another org") - }) -} diff --git a/e2e/console/rbac_test.go b/e2e/console/rbac_test.go index d9ffb502b..08190ad79 100644 --- a/e2e/console/rbac_test.go +++ b/e2e/console/rbac_test.go @@ -174,36 +174,6 @@ const ( } }` - createPeopleMutation = ` - mutation CreatePeople($input: CreatePeopleInput!) { - createPeople(input: $input) { - peopleEdge { node { id } } - } - }` - - updatePeopleMutation = ` - mutation UpdatePeople($input: UpdatePeopleInput!) { - updatePeople(input: $input) { - people { id } - } - }` - - deletePeopleMutation = ` - mutation DeletePeople($input: DeletePeopleInput!) { - deletePeople(input: $input) { - deletedPeopleId - } - }` - - listPeoplesQuery = ` - query GetPeoples($id: ID!) { - node(id: $id) { - ... on Organization { - peoples(first: 10) { totalCount } - } - } - }` - createVendorMutation = ` mutation CreateVendor($input: CreateVendorInput!) { createVendor(input: $input) { @@ -274,7 +244,6 @@ func TestRBAC(t *testing.T) { measureID := factory.NewMeasure(owner).WithName("RBAC Test Measure").Create() taskID := factory.NewTask(owner, measureID).WithName("RBAC Test Task").Create() riskID := factory.NewRisk(owner).WithName("RBAC Test Risk").Create() - peopleID := factory.NewPeople(owner).WithFullName("RBAC Test Person").Create() vendorID := factory.NewVendor(owner).WithName("RBAC Test Vendor").Create() tests := []struct { @@ -904,130 +873,6 @@ func TestRBAC(t *testing.T) { }, shouldAllow: true, }, - { - name: "owner can create people", - role: "owner", - client: owner, - query: createPeopleMutation, - variables: func() map[string]any { - return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "additionalEmailAddresses": []string{}, "kind": "EMPLOYEE"}} - }, - shouldAllow: true, - }, - { - name: "admin can create people", - role: "admin", - client: admin, - query: createPeopleMutation, - variables: func() map[string]any { - return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "additionalEmailAddresses": []string{}, "kind": "EMPLOYEE"}} - }, - shouldAllow: true, - }, - { - name: "viewer cannot create people", - role: "viewer", - client: viewer, - query: createPeopleMutation, - variables: func() map[string]any { - return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "additionalEmailAddresses": []string{}, "kind": "EMPLOYEE"}} - }, - shouldAllow: false, - }, - // TODO: Fix server-side issue - updatePeople mutation returns internal server error - // { - // name: "owner can update people", - // role: "owner", - // client: owner, - // query: updatePeopleMutation, - // variables: func() map[string]any { - // return map[string]any{"input": map[string]any{"id": peopleID, "fullName": factory.SafeName("Updated Person")}} - // }, - // shouldAllow: true, - // }, - // { - // name: "admin can update people", - // role: "admin", - // client: admin, - // query: updatePeopleMutation, - // variables: func() map[string]any { - // return map[string]any{"input": map[string]any{"id": peopleID, "fullName": factory.SafeName("Updated Person")}} - // }, - // shouldAllow: true, - // }, - { - name: "viewer cannot update people", - role: "viewer", - client: viewer, - query: updatePeopleMutation, - variables: func() map[string]any { - return map[string]any{"input": map[string]any{"id": peopleID, "fullName": factory.SafeName("Updated Person")}} - }, - shouldAllow: false, - }, - { - name: "owner can delete people", - role: "owner", - client: owner, - query: deletePeopleMutation, - variables: func() map[string]any { - id := factory.NewPeople(owner).WithFullName(factory.SafeName("ToDelete")).Create() - return map[string]any{"input": map[string]any{"peopleId": id}} - }, - shouldAllow: true, - }, - { - name: "admin can delete people", - role: "admin", - client: admin, - query: deletePeopleMutation, - variables: func() map[string]any { - id := factory.NewPeople(owner).WithFullName(factory.SafeName("ToDelete")).Create() - return map[string]any{"input": map[string]any{"peopleId": id}} - }, - shouldAllow: true, - }, - { - name: "viewer cannot delete people", - role: "viewer", - client: viewer, - query: deletePeopleMutation, - variables: func() map[string]any { - id := factory.NewPeople(owner).WithFullName(factory.SafeName("ToDelete")).Create() - return map[string]any{"input": map[string]any{"peopleId": id}} - }, - shouldAllow: false, - }, - { - name: "owner can list peoples", - role: "owner", - client: owner, - query: listPeoplesQuery, - variables: func() map[string]any { - return map[string]any{"id": owner.GetOrganizationID().String()} - }, - shouldAllow: true, - }, - { - name: "admin can list peoples", - role: "admin", - client: admin, - query: listPeoplesQuery, - variables: func() map[string]any { - return map[string]any{"id": owner.GetOrganizationID().String()} - }, - shouldAllow: true, - }, - { - name: "viewer can list peoples", - role: "viewer", - client: viewer, - query: listPeoplesQuery, - variables: func() map[string]any { - return map[string]any{"id": owner.GetOrganizationID().String()} - }, - shouldAllow: true, - }, { name: "owner can create vendor", role: "owner", diff --git a/e2e/console/risk_test.go b/e2e/console/risk_test.go index 632203348..84745a84a 100644 --- a/e2e/console/risk_test.go +++ b/e2e/console/risk_test.go @@ -881,13 +881,8 @@ func TestRisk_OmittableOwner(t *testing.T) { owner := testutil.NewClient(t, testutil.RoleOwner) // Create a people for owner assignment - peopleID := factory.NewPeople(owner). - WithFullName("Risk Owner Person"). - Create() - - riskID := factory.NewRisk(owner). - WithName("Owner Test Risk"). - Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + riskID := factory.NewRisk(owner).WithName("Owner Test Risk").Create() t.Run("set owner", func(t *testing.T) { query := ` @@ -919,11 +914,11 @@ func TestRisk_OmittableOwner(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "id": riskID, - "ownerId": peopleID, + "ownerId": profileID.String(), }, }, &result) require.NoError(t, err) - assert.Equal(t, peopleID, result.UpdateRisk.Risk.Owner.ID) + assert.Equal(t, profileID.String(), result.UpdateRisk.Risk.Owner.ID) }) t.Run("clear owner with null", func(t *testing.T) { diff --git a/e2e/console/task_assignment_test.go b/e2e/console/task_assignment_test.go index 8c9586c87..9566fdad0 100644 --- a/e2e/console/task_assignment_test.go +++ b/e2e/console/task_assignment_test.go @@ -30,7 +30,7 @@ func TestTask_Assign(t *testing.T) { // Create measure and task measureID := factory.NewMeasure(owner).Create() taskID := factory.NewTask(owner, measureID).Create() - peopleID := factory.NewPeople(owner).WithFullName("Task Assignee").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() query := ` mutation UpdateTask($input: UpdateTaskInput!) { @@ -61,14 +61,13 @@ func TestTask_Assign(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "taskId": taskID, - "assignedToId": peopleID, + "assignedToId": profileID.String(), }, }, &result) require.NoError(t, err) assert.Equal(t, taskID, result.UpdateTask.Task.ID) - assert.Equal(t, peopleID, result.UpdateTask.Task.AssignedTo.ID) - assert.Equal(t, "Task Assignee", result.UpdateTask.Task.AssignedTo.FullName) + assert.Equal(t, profileID.String(), result.UpdateTask.Task.AssignedTo.ID) } func TestTask_Unassign(t *testing.T) { @@ -78,7 +77,7 @@ func TestTask_Unassign(t *testing.T) { // Create measure, task, people and assign measureID := factory.NewMeasure(owner).Create() taskID := factory.NewTask(owner, measureID).Create() - peopleID := factory.NewPeople(owner).WithFullName("Person to Unassign").Create() + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() // First assign the task assignQuery := ` @@ -94,7 +93,7 @@ func TestTask_Unassign(t *testing.T) { _, err := owner.Do(assignQuery, map[string]any{ "input": map[string]any{ "taskId": taskID, - "assignedToId": peopleID, + "assignedToId": profileID.String(), }, }) require.NoError(t, err) diff --git a/e2e/console/task_test.go b/e2e/console/task_test.go index 5e8a03cb5..467cd191b 100644 --- a/e2e/console/task_test.go +++ b/e2e/console/task_test.go @@ -649,11 +649,8 @@ func TestTask_OmittableAssignee(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - // Create a people for assignee - peopleID := factory.NewPeople(owner). - WithFullName("Task Assignee Person"). - Create() - + // Create a profile for assignee + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() measureID := factory.NewMeasure(owner). WithName("Task Assignee Test"). Create() @@ -692,11 +689,11 @@ func TestTask_OmittableAssignee(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "taskId": taskID, - "assignedToId": peopleID, + "assignedToId": profileID.String(), }, }, &result) require.NoError(t, err) - assert.Equal(t, peopleID, result.UpdateTask.Task.AssignedTo.ID) + assert.Equal(t, profileID.String(), result.UpdateTask.Task.AssignedTo.ID) }) t.Run("clear assignee", func(t *testing.T) { diff --git a/e2e/console/vendor_test.go b/e2e/console/vendor_test.go index 958c196ef..ded3f2891 100644 --- a/e2e/console/vendor_test.go +++ b/e2e/console/vendor_test.go @@ -754,11 +754,8 @@ func TestVendor_OmittableBusinessOwner(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - // Create a people for owner assignment - peopleID := factory.NewPeople(owner). - WithFullName("Business Owner Person"). - Create() - + // Create a profile for owner assignment + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() vendorID := factory.NewVendor(owner). WithName("BusinessOwner Test Vendor"). Create() @@ -793,11 +790,11 @@ func TestVendor_OmittableBusinessOwner(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "id": vendorID, - "businessOwnerId": peopleID, + "businessOwnerId": profileID.String(), }, }, &result) require.NoError(t, err) - assert.Equal(t, peopleID, result.UpdateVendor.Vendor.BusinessOwner.ID) + assert.Equal(t, profileID.String(), result.UpdateVendor.Vendor.BusinessOwner.ID) }) t.Run("clear business owner with null", func(t *testing.T) { @@ -840,14 +837,9 @@ func TestVendor_OmittableSecurityOwner(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - // Create a people for owner assignment - peopleID := factory.NewPeople(owner). - WithFullName("Security Owner Person"). - Create() - - vendorID := factory.NewVendor(owner). - WithName("SecurityOwner Test Vendor"). - Create() + // Create a profile for owner assignment + profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() + vendorID := factory.NewVendor(owner).WithName("SecurityOwner Test Vendor").Create() t.Run("set security owner", func(t *testing.T) { query := ` @@ -879,11 +871,11 @@ func TestVendor_OmittableSecurityOwner(t *testing.T) { err := owner.Execute(query, map[string]any{ "input": map[string]any{ "id": vendorID, - "securityOwnerId": peopleID, + "securityOwnerId": profileID.String(), }, }, &result) require.NoError(t, err) - assert.Equal(t, peopleID, result.UpdateVendor.Vendor.SecurityOwner.ID) + assert.Equal(t, profileID.String(), result.UpdateVendor.Vendor.SecurityOwner.ID) }) t.Run("clear security owner with null", func(t *testing.T) { diff --git a/e2e/internal/factory/factory.go b/e2e/internal/factory/factory.go index 04bab605f..7a620e62e 100644 --- a/e2e/internal/factory/factory.go +++ b/e2e/internal/factory/factory.go @@ -371,48 +371,6 @@ func CreateRisk(c *testutil.Client, attrs ...Attrs) string { return result.CreateRisk.RiskEdge.Node.ID } -func CreatePeople(c *testutil.Client, attrs ...Attrs) string { - c.T.Helper() - - var a Attrs - if len(attrs) > 0 { - a = attrs[0] - } - - const query = ` - mutation($input: CreatePeopleInput!) { - createPeople(input: $input) { - peopleEdge { - node { id } - } - } - } - ` - - input := map[string]any{ - "organizationId": c.GetOrganizationID().String(), - "fullName": a.getString("fullName", SafeName("Person")), - "primaryEmailAddress": a.getString("primaryEmailAddress", SafeEmail()), - "additionalEmailAddresses": a.getSlice("additionalEmailAddresses", []string{}), - "kind": a.getString("kind", "EMPLOYEE"), - } - - var result struct { - CreatePeople struct { - PeopleEdge struct { - Node struct { - ID string `json:"id"` - } `json:"node"` - } `json:"peopleEdge"` - } `json:"createPeople"` - } - - err := c.Execute(query, map[string]any{"input": input}, &result) - require.NoError(c.T, err, "createPeople mutation failed") - - return result.CreatePeople.PeopleEdge.Node.ID -} - type VendorBuilder struct { client *testutil.Client attrs Attrs @@ -607,29 +565,6 @@ func (b *RiskBuilder) Create() string { return CreateRisk(b.client, b.attrs) } -type PeopleBuilder struct { - client *testutil.Client - attrs Attrs -} - -func NewPeople(c *testutil.Client) *PeopleBuilder { - return &PeopleBuilder{client: c, attrs: Attrs{}} -} - -func (b *PeopleBuilder) WithFullName(name string) *PeopleBuilder { - b.attrs["fullName"] = name - return b -} - -func (b *PeopleBuilder) WithKind(kind string) *PeopleBuilder { - b.attrs["kind"] = kind - return b -} - -func (b *PeopleBuilder) Create() string { - return CreatePeople(b.client, b.attrs) -} - func CreateAudit(c *testutil.Client, frameworkID string, attrs ...Attrs) string { c.T.Helper() diff --git a/e2e/internal/testutil/client.go b/e2e/internal/testutil/client.go index d8c5d9f07..f5c9dd599 100644 --- a/e2e/internal/testutil/client.go +++ b/e2e/internal/testutil/client.go @@ -48,6 +48,7 @@ type Client struct { baseURL string role TestRole userID gid.GID + profileID gid.GID organizationID gid.GID } @@ -89,7 +90,7 @@ func NewClientInOrg(t testing.TB, role TestRole, ownerClient *Client) *Client { }, } - client.setupTestUserInOrg(ownerClient) + client.SetupTestUserInOrg(ownerClient) return client } @@ -105,7 +106,7 @@ func (c *Client) setupTestUser() { // Create organization (this makes the user an OWNER) orgName := fmt.Sprintf("Test Org %s", uniqueID) - c.organizationID = c.createOrganization(orgName) + c.organizationID, c.profileID = c.createOrganization(orgName) // Assume organization session to use console API c.assumeOrganizationSession() @@ -116,7 +117,7 @@ func (c *Client) setupTestUser() { } } -func (c *Client) setupTestUserInOrg(ownerClient *Client) { +func (c *Client) SetupTestUserInOrg(ownerClient *Client) { uniqueID := generateUniqueID() email := fmt.Sprintf("test-%s@e2e.probo.test", uniqueID) password := "TestPassword123!" @@ -129,7 +130,7 @@ func (c *Client) setupTestUserInOrg(ownerClient *Client) { invitationID := ownerClient.inviteMember(email, fullName, coredata.MembershipRole(c.role)) // New user accepts invitation - c.acceptInvitation(invitationID) + c.profileID = c.acceptInvitation(invitationID) // Assume organization session to use console API c.assumeOrganizationSession() @@ -167,11 +168,16 @@ func (c *Client) signUp(email, password, fullName string) gid.GID { return userID } -func (c *Client) createOrganization(name string) gid.GID { +func (c *Client) createOrganization(name string) (gid.GID, gid.GID) { const query = ` mutation($input: CreateOrganizationInput!) { createOrganization(input: $input) { organization { id } + membershipEdge { + node { + profile { id } + } + } } } ` @@ -181,6 +187,14 @@ func (c *Client) createOrganization(name string) gid.GID { Organization struct { ID string `json:"id"` } `json:"organization"` + MembershipEdge struct { + Node struct { + ID string `json:"id"` + Profile struct { + ID string `json:"id"` + } `json:"profile"` + } `json:"node"` + } `json:"membershipEdge"` } `json:"createOrganization"` } @@ -192,7 +206,10 @@ func (c *Client) createOrganization(name string) gid.GID { orgID, err := gid.ParseGID(result.CreateOrganization.Organization.ID) require.NoError(c.T, err, "cannot parse organization ID") - return orgID + profileID, err := gid.ParseGID(result.CreateOrganization.MembershipEdge.Node.Profile.ID) + require.NoError(c.T, err, "cannot parse profile ID") + + return orgID, profileID } func (c *Client) updateOwnMembershipRole(role coredata.MembershipRole) { @@ -304,23 +321,42 @@ func (c *Client) inviteMember(email, fullName string, role coredata.MembershipRo return invitationID } -func (c *Client) acceptInvitation(invitationID gid.GID) { +func (c *Client) acceptInvitation(invitationID gid.GID) gid.GID { const query = ` mutation($input: AcceptInvitationInput!) { acceptInvitation(input: $input) { membershipEdge { - node { id } + node { + profile { id } + } } } } ` + var result struct { + AcceptInvitation struct { + MembershipEdge struct { + Node struct { + Profile struct { + ID string `json:"id"` + } `json:"profile"` + } `json:"node"` + } `json:"membershipEdge"` + } `json:"acceptInvitation"` + } + err := c.ExecuteConnect(query, map[string]any{ "input": map[string]any{ "invitationId": invitationID.String(), }, - }, nil) + }, &result) require.NoError(c.T, err, "acceptInvitation mutation failed") + + profileID, err := gid.ParseGID(result.AcceptInvitation.MembershipEdge.Node.Profile.ID) + require.NoError(c.T, err, "cannot parse profile ID") + + return profileID } func (c *Client) assumeOrganizationSession() { @@ -349,6 +385,10 @@ func (c *Client) GetUserID() gid.GID { return c.userID } +func (c *Client) GetProfileID() gid.GID { + return c.profileID +} + func (c *Client) GetOrganizationID() gid.GID { return c.organizationID } diff --git a/e2e/internal/testutil/testutil.go b/e2e/internal/testutil/testutil.go index 8f228d4ed..1d290c87a 100644 --- a/e2e/internal/testutil/testutil.go +++ b/e2e/internal/testutil/testutil.go @@ -24,6 +24,8 @@ import ( "sync" "syscall" "time" + + "go.gearno.de/kit/log" ) var ( @@ -65,7 +67,7 @@ func Setup() { done: make(chan error, 1), } - cmd := exec.Command(binaryPath, "-cfg-file", configPath) + cmd := exec.Command(binaryPath, "-cfg-file", configPath, "-format", log.FormatPretty) if coverDir != "" { cmd.Env = append(os.Environ(), "GOCOVERDIR="+coverDir) } else { diff --git a/pkg/coredata/membership_profile.go b/pkg/coredata/membership_profile.go index bbd5522f9..96efd22f8 100644 --- a/pkg/coredata/membership_profile.go +++ b/pkg/coredata/membership_profile.go @@ -61,7 +61,7 @@ func (p MembershipProfile) CursorKey(orderBy MembershipProfileOrderField) page.C } func (p *MembershipProfile) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) { - q := `SELECT m.organization_id FROM iam_membership_profiles mp JOIN iam_memberships m ON mp.membership_id = m.id WHERE mp.id = $1 LIMIT 1;` + q := `SELECT m.organization_id, mp.identity_id FROM iam_membership_profiles mp JOIN iam_memberships m ON mp.membership_id = m.id WHERE mp.id = $1 LIMIT 1;` var organizationID gid.GID if err := conn.QueryRow(ctx, q, p.ID).Scan(&organizationID); err != nil { @@ -241,6 +241,7 @@ func (p *MembershipProfiles) LoadByMeetingID( WITH attendees AS ( SELECT p.id, + p.tenant_id, p.identity_id, p.membership_id, i.email_address, diff --git a/pkg/coredata/migrations/20260203T132700Z.sql b/pkg/coredata/migrations/20260203T132700Z.sql index 8f1666019..52ad81031 100644 --- a/pkg/coredata/migrations/20260203T132700Z.sql +++ b/pkg/coredata/migrations/20260203T132700Z.sql @@ -445,6 +445,8 @@ WHERE -- 8. Now that references are filled, add the NOT NULL constraints to those who need it ALTER TABLE assets +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET @@ -452,6 +454,8 @@ SET ALTER TABLE continual_improvements +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET @@ -459,6 +463,8 @@ SET ALTER TABLE data +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET @@ -466,20 +472,28 @@ SET ALTER TABLE document_versions +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET NOT NULL; ALTER TABLE - meeting_attendees + meeting_attendees DROP CONSTRAINT meeting_attendees_pkey, +ALTER COLUMN + attendee_id DROP NOT NULL, ALTER COLUMN attendee_profile_id SET - NOT NULL; + NOT NULL, +ADD + PRIMARY KEY (attendee_profile_id); ALTER TABLE nonconformities +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET @@ -487,6 +501,8 @@ SET ALTER TABLE obligations +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET @@ -494,6 +510,8 @@ SET ALTER TABLE document_version_signatures +ALTER COLUMN + signed_by DROP NOT NULL, ALTER COLUMN signed_by_profile_id SET @@ -501,6 +519,8 @@ SET ALTER TABLE states_of_applicability +ALTER COLUMN + owner_id DROP NOT NULL, ALTER COLUMN owner_profile_id SET diff --git a/pkg/iam/iam_policies.go b/pkg/iam/iam_policies.go index 963b551d3..0dc188295 100644 --- a/pkg/iam/iam_policies.go +++ b/pkg/iam/iam_policies.go @@ -84,6 +84,18 @@ var IAMSelfManageInvitationPolicy = policy.NewPolicy( ). WithDescription("Allows users to view and accept invitations sent to them") +// IAMSelfManageProfilePolicy allows users to view their own profiles. +var IAMSelfManageProfilePolicy = policy.NewPolicy( + "iam:self-manage-profile", + "Self-Manage Profiles", + + // Users can view their own profiles + policy.Allow(ActionMembershipProfileGet). + WithSID("view-own-profiles"). + When(policy.Equals("principal.id", "resource.identity_id")), +). + WithDescription("Allows users to view their organization profiles") + // IAMSelfManageMembershipPolicy allows users to view their own memberships. var IAMSelfManageMembershipPolicy = policy.NewPolicy( "iam:self-manage-membership", diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index 7f3c2c3a6..c2778eb85 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -504,9 +504,9 @@ func (s *OrganizationService) CreateOrganization( ctx context.Context, identityID gid.GID, req *CreateOrganizationRequest, -) (*coredata.Organization, error) { +) (*coredata.Organization, *coredata.Membership, error) { if err := req.Validate(); err != nil { - return nil, fmt.Errorf("invalid request: %w", err) + return nil, nil, fmt.Errorf("invalid request: %w", err) } var ( @@ -584,7 +584,7 @@ func (s *OrganizationService) CreateOrganization( ) if err != nil { - return nil, fmt.Errorf("cannot upload logo file: %w", err) + return nil, nil, fmt.Errorf("cannot upload logo file: %w", err) } logoFile.FileSize = fileSize @@ -621,7 +621,7 @@ func (s *OrganizationService) CreateOrganization( ) if err != nil { - return nil, fmt.Errorf("cannot upload logo file: %w", err) + return nil, nil, fmt.Errorf("cannot upload logo file: %w", err) } horizontalLogoFile.FileSize = fileSize @@ -713,10 +713,10 @@ func (s *OrganizationService) CreateOrganization( }, ) if err != nil { - return nil, fmt.Errorf("cannot insert organization: %w", err) + return nil, nil, fmt.Errorf("cannot insert organization: %w", err) } - return organization, nil + return organization, membership, nil } func (s *OrganizationService) UpdateOrganization(ctx context.Context, organizationID gid.GID, req *UpdateOrganizationRequest) (*coredata.Organization, error) { diff --git a/pkg/iam/policy_set.go b/pkg/iam/policy_set.go index 6b476dc51..eb6828f43 100644 --- a/pkg/iam/policy_set.go +++ b/pkg/iam/policy_set.go @@ -66,6 +66,7 @@ func IAMPolicySet() *PolicySet { IAMSelfManageIdentityPolicy, IAMSelfManageSessionPolicy, IAMSelfManageInvitationPolicy, + IAMSelfManageProfilePolicy, IAMSelfManageMembershipPolicy, IAMSelfManagePersonalAPIKeyPolicy, ) diff --git a/pkg/probo/meeting_service.go b/pkg/probo/meeting_service.go index 866856079..1cbf1d0be 100644 --- a/pkg/probo/meeting_service.go +++ b/pkg/probo/meeting_service.go @@ -196,8 +196,8 @@ func (s MeetingService) Create( } if len(req.AttendeeIDs) > 0 { - var attendeePeople coredata.MembershipProfiles - if err := attendeePeople.LoadByIDs(ctx, conn, s.svc.scope, req.AttendeeIDs); err != nil { + var attendeeProfiles coredata.MembershipProfiles + if err := attendeeProfiles.LoadByIDs(ctx, conn, s.svc.scope, req.AttendeeIDs); err != nil { return fmt.Errorf("cannot load attendee profiles: %w", err) } diff --git a/pkg/server/api/connect/v1/v1_resolver.go b/pkg/server/api/connect/v1/v1_resolver.go index 96a9fa97c..458d7a3ea 100644 --- a/pkg/server/api/connect/v1/v1_resolver.go +++ b/pkg/server/api/connect/v1/v1_resolver.go @@ -251,7 +251,7 @@ func (r *membershipResolver) Identity(ctx context.Context, obj *types.Membership // Profile is the resolver for the profile field. func (r *membershipResolver) Profile(ctx context.Context, obj *types.Membership) (*types.MembershipProfile, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil { + if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet, authz.WithSkipAssumptionCheck()); err != nil { return nil, err } @@ -833,7 +833,7 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C Size: input.HorizontalLogoFile.Size, } } - organization, err := r.iam.OrganizationService.CreateOrganization( + organization, membership, err := r.iam.OrganizationService.CreateOrganization( ctx, identity.ID, &iam.CreateOrganizationRequest{ @@ -848,7 +848,8 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C } return &types.CreateOrganizationPayload{ - Organization: types.NewOrganization(organization), + Organization: types.NewOrganization(organization), + MembershipEdge: types.NewMembershipEdge(membership, coredata.MembershipOrderFieldCreatedAt), }, nil }