From 921a0f01c8a9c78dd56ca0b237855cf5190c3ff5 Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:39:26 +0200 Subject: [PATCH] Forbid permissions update cross app role retarget (#19982) closes https://github.com/twentyhq/twenty/issues/19807 --- .../permissions/permissions.exception.ts | 2 +- ...flat-field-permission-validator.service.ts | 22 +- ...lat-object-permission-validator.service.ts | 22 +- .../flat-permission-flag-validator.service.ts | 22 +- ...role-belongs-to-caller-application.util.ts | 4 +- ...on-standard-role.integration-spec.ts.snap} | 12 +- ...etarget-on-update.integration-spec.ts.snap | 190 +++++++++++++++ ...eate-on-standard-role.integration-spec.ts} | 0 ...ion-retarget-on-update.integration-spec.ts | 216 ++++++++++++++++++ ...permission-upsert.integration-spec.ts.snap | 4 +- ...permission-upsert.integration-spec.ts.snap | 4 +- ...ssion-flag-upsert.integration-spec.ts.snap | 6 +- 12 files changed, 470 insertions(+), 34 deletions(-) rename packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/{failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts.snap => failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts.snap} (91%) create mode 100644 packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts.snap rename packages/twenty-server/test/integration/metadata/suites/application/{failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts => failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts} (100%) create mode 100644 packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts index 4caf68f565..ec1a3c3693 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts @@ -145,7 +145,7 @@ const getPermissionsExceptionUserFriendlyMessage = ( case PermissionsExceptionCode.APPLICATION_ROLE_NOT_FOUND: return msg`No role assigned to the application.`; case PermissionsExceptionCode.ROLE_BELONGS_TO_ANOTHER_APPLICATION: - return msg`Cannot modify permissions on a role owned by another application.`; + return msg`Cannot target a role owned by another application.`; default: assertUnreachable(code); } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-field-permission-validator.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-field-permission-validator.service.ts index 0afe79c622..4d8d7865ba 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-field-permission-validator.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-field-permission-validator.service.ts @@ -145,6 +145,7 @@ export class FlatFieldPermissionValidatorService { flatObjectMetadataMaps, flatFieldMetadataMaps, }, + buildOptions, }: FlatEntityUpdateValidationArgs< typeof ALL_METADATA_NAME.fieldPermission >): FailedFlatEntityValidation<'fieldPermission', 'update'> { @@ -187,12 +188,21 @@ export class FlatFieldPermissionValidatorService { message: t`Role not found`, userFriendlyMessage: msg`Role not found`, }); - } else if (!referencedRole.isEditable) { - validationResult.errors.push({ - code: PermissionsExceptionCode.ROLE_NOT_EDITABLE, - message: t`Role is not editable`, - userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`, - }); + } else { + validationResult.errors.push( + ...validateRoleBelongsToCallerApplication({ + referencedRole, + buildOptions, + }), + ); + + if (!referencedRole.isEditable) { + validationResult.errors.push({ + code: PermissionsExceptionCode.ROLE_NOT_EDITABLE, + message: t`Role is not editable`, + userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`, + }); + } } if (isDefined(flatEntityUpdate.objectMetadataUniversalIdentifier)) { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-permission-validator.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-permission-validator.service.ts index afd24f1b0f..814cc9d923 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-permission-validator.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-permission-validator.service.ts @@ -125,6 +125,7 @@ export class FlatObjectPermissionValidatorService { flatRoleMaps, flatObjectMetadataMaps, }, + buildOptions, }: FlatEntityUpdateValidationArgs< typeof ALL_METADATA_NAME.objectPermission >): FailedFlatEntityValidation<'objectPermission', 'update'> { @@ -167,12 +168,21 @@ export class FlatObjectPermissionValidatorService { message: t`Role not found`, userFriendlyMessage: msg`Role not found`, }); - } else if (!referencedRole.isEditable) { - validationResult.errors.push({ - code: PermissionsExceptionCode.ROLE_NOT_EDITABLE, - message: t`Role is not editable`, - userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`, - }); + } else { + validationResult.errors.push( + ...validateRoleBelongsToCallerApplication({ + referencedRole, + buildOptions, + }), + ); + + if (!referencedRole.isEditable) { + validationResult.errors.push({ + code: PermissionsExceptionCode.ROLE_NOT_EDITABLE, + message: t`Role is not editable`, + userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`, + }); + } } if (isDefined(flatEntityUpdate.objectMetadataUniversalIdentifier)) { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-permission-flag-validator.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-permission-flag-validator.service.ts index 0b84ab718c..1bcf3a4290 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-permission-flag-validator.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-permission-flag-validator.service.ts @@ -120,6 +120,7 @@ export class FlatPermissionFlagValidatorService { flatPermissionFlagMaps: optimisticFlatPermissionFlagMaps, flatRoleMaps, }, + buildOptions, }: FlatEntityUpdateValidationArgs< typeof ALL_METADATA_NAME.permissionFlag >): FailedFlatEntityValidation<'permissionFlag', 'update'> { @@ -162,12 +163,21 @@ export class FlatPermissionFlagValidatorService { message: t`Role not found`, userFriendlyMessage: msg`Role not found`, }); - } else if (!referencedRole.isEditable) { - validationResult.errors.push({ - code: PermissionsExceptionCode.ROLE_NOT_EDITABLE, - message: t`Role is not editable`, - userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`, - }); + } else { + validationResult.errors.push( + ...validateRoleBelongsToCallerApplication({ + referencedRole, + buildOptions, + }), + ); + + if (!referencedRole.isEditable) { + validationResult.errors.push({ + code: PermissionsExceptionCode.ROLE_NOT_EDITABLE, + message: t`Role is not editable`, + userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`, + }); + } } if (isDefined(flatEntityUpdate.flag)) { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util.ts index 71dc79c397..d06406a8a9 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util.ts @@ -19,8 +19,8 @@ export const validateRoleBelongsToCallerApplication = ({ return [ { code: PermissionsExceptionCode.ROLE_BELONGS_TO_ANOTHER_APPLICATION, - message: t`Cannot modify permissions on a role owned by another application`, - userFriendlyMessage: msg`Cannot modify permissions on a role owned by another application.`, + message: t`Cannot target a role owned by another application`, + userFriendlyMessage: msg`Cannot target a role owned by another application.`, }, ]; } diff --git a/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts.snap similarity index 91% rename from packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts.snap rename to packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts.snap index 7ae2408884..341a8522d4 100644 --- a/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts.snap @@ -10,8 +10,8 @@ exports[`Sync application should fail when creating permissions on a standard ro "errors": [ { "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", - "message": "Cannot modify permissions on a role owned by another application", - "userFriendlyMessage": "Cannot modify permissions on a role owned by another application.", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", }, { "code": "ROLE_NOT_EDITABLE", @@ -80,8 +80,8 @@ exports[`Sync application should fail when creating permissions on a standard ro "errors": [ { "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", - "message": "Cannot modify permissions on a role owned by another application", - "userFriendlyMessage": "Cannot modify permissions on a role owned by another application.", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", }, { "code": "ROLE_NOT_EDITABLE", @@ -138,8 +138,8 @@ exports[`Sync application should fail when creating permissions on a standard ro "errors": [ { "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", - "message": "Cannot modify permissions on a role owned by another application", - "userFriendlyMessage": "Cannot modify permissions on a role owned by another application.", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", }, { "code": "ROLE_NOT_EDITABLE", diff --git a/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts.snap new file mode 100644 index 0000000000..41b69d2866 --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts.snap @@ -0,0 +1,190 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Sync application should fail when retargeting existing permissions to a standard role on update should fail when retargeting a field permission from own role to the standard admin role 1`] = ` +{ + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "fieldPermission": [ + { + "errors": [ + { + "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", + }, + { + "code": "ROLE_NOT_EDITABLE", + "message": "Role is not editable", + "userFriendlyMessage": "This role cannot be modified because it is a system role. Only custom roles can be edited.", + }, + ], + "flatEntityMinimalInformation": { + "universalIdentifier": Any, + }, + "metadataName": "fieldPermission", + "status": "fail", + "type": "update", + }, + ], + "role": [ + { + "errors": [ + { + "code": "ROLE_LABEL_ALREADY_EXISTS", + "message": "A role with this label already exists", + "userFriendlyMessage": "A role with this label already exists.", + }, + { + "code": "ENTITY_ALREADY_EXISTS", + "message": "Cannot create role: universalIdentifier "20202020-02c2-43f2-b94d-cab1f2b532eb" already exists in role maps from application "20202020-64aa-4b6f-b003-9c74b97cee20"", + }, + ], + "flatEntityMinimalInformation": { + "label": "Admin", + "universalIdentifier": Any, + }, + "metadataName": "role", + "status": "fail", + "type": "create", + }, + ], + }, + "message": "Validation failed for 1 role, 1 fieldPermission", + "summary": { + "fieldPermission": 1, + "role": 1, + "totalErrors": 2, + }, + "userFriendlyMessage": "Metadata validation failed", + }, + "message": "Validation errors occurred while syncing application manifest metadata", + "name": "GraphQLError", +} +`; + +exports[`Sync application should fail when retargeting existing permissions to a standard role on update should fail when retargeting a permission flag from own role to the standard admin role 1`] = ` +{ + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "permissionFlag": [ + { + "errors": [ + { + "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", + }, + { + "code": "ROLE_NOT_EDITABLE", + "message": "Role is not editable", + "userFriendlyMessage": "This role cannot be modified because it is a system role. Only custom roles can be edited.", + }, + ], + "flatEntityMinimalInformation": { + "universalIdentifier": Any, + }, + "metadataName": "permissionFlag", + "status": "fail", + "type": "update", + }, + ], + "role": [ + { + "errors": [ + { + "code": "ROLE_LABEL_ALREADY_EXISTS", + "message": "A role with this label already exists", + "userFriendlyMessage": "A role with this label already exists.", + }, + { + "code": "ENTITY_ALREADY_EXISTS", + "message": "Cannot create role: universalIdentifier "20202020-02c2-43f2-b94d-cab1f2b532eb" already exists in role maps from application "20202020-64aa-4b6f-b003-9c74b97cee20"", + }, + ], + "flatEntityMinimalInformation": { + "label": "Admin", + "universalIdentifier": Any, + }, + "metadataName": "role", + "status": "fail", + "type": "create", + }, + ], + }, + "message": "Validation failed for 1 role, 1 permissionFlag", + "summary": { + "permissionFlag": 1, + "role": 1, + "totalErrors": 2, + }, + "userFriendlyMessage": "Metadata validation failed", + }, + "message": "Validation errors occurred while syncing application manifest metadata", + "name": "GraphQLError", +} +`; + +exports[`Sync application should fail when retargeting existing permissions to a standard role on update should fail when retargeting an object permission from own role to the standard admin role 1`] = ` +{ + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "objectPermission": [ + { + "errors": [ + { + "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", + }, + { + "code": "ROLE_NOT_EDITABLE", + "message": "Role is not editable", + "userFriendlyMessage": "This role cannot be modified because it is a system role. Only custom roles can be edited.", + }, + ], + "flatEntityMinimalInformation": { + "universalIdentifier": Any, + }, + "metadataName": "objectPermission", + "status": "fail", + "type": "update", + }, + ], + "role": [ + { + "errors": [ + { + "code": "ROLE_LABEL_ALREADY_EXISTS", + "message": "A role with this label already exists", + "userFriendlyMessage": "A role with this label already exists.", + }, + { + "code": "ENTITY_ALREADY_EXISTS", + "message": "Cannot create role: universalIdentifier "20202020-02c2-43f2-b94d-cab1f2b532eb" already exists in role maps from application "20202020-64aa-4b6f-b003-9c74b97cee20"", + }, + ], + "flatEntityMinimalInformation": { + "label": "Admin", + "universalIdentifier": Any, + }, + "metadataName": "role", + "status": "fail", + "type": "create", + }, + ], + }, + "message": "Validation failed for 1 role, 1 objectPermission", + "summary": { + "objectPermission": 1, + "role": 1, + "totalErrors": 2, + }, + "userFriendlyMessage": "Metadata validation failed", + }, + "message": "Validation errors occurred while syncing application manifest metadata", + "name": "GraphQLError", +} +`; diff --git a/packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts similarity index 100% rename from packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts rename to packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-create-on-standard-role.integration-spec.ts diff --git a/packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts new file mode 100644 index 0000000000..cc6e6108fc --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-retarget-on-update.integration-spec.ts @@ -0,0 +1,216 @@ +import { PermissionFlagType } from 'twenty-shared/constants'; +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; + +import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util'; +import { buildBaseManifest } from 'test/integration/metadata/suites/application/utils/build-base-manifest.util'; +import { cleanupApplicationAndAppRegistration } from 'test/integration/metadata/suites/application/utils/cleanup-application-and-app-registration.util'; +import { setupApplicationForSync } from 'test/integration/metadata/suites/application/utils/setup-application-for-sync.util'; +import { syncApplication } from 'test/integration/metadata/suites/application/utils/sync-application.util'; + +import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; + +const TEST_APP_ID = 'a1b2c3d4-0020-4000-a000-000000000010'; +const TEST_ROLE_ID = 'a1b2c3d4-0020-4000-a000-000000000011'; +const TEST_PERMISSION_FLAG_ID = 'a1b2c3d4-0020-4000-a000-000000000012'; +const TEST_OBJECT_PERMISSION_ID = 'a1b2c3d4-0020-4000-a000-000000000013'; +const TEST_FIELD_PERMISSION_ID = 'a1b2c3d4-0020-4000-a000-000000000014'; + +const COMPANY_OBJECT_ID = STANDARD_OBJECTS.company.universalIdentifier; +const COMPANY_NAME_FIELD_ID = + STANDARD_OBJECTS.company.fields.name.universalIdentifier; + +describe('Sync application should fail when retargeting existing permissions to a standard role on update', () => { + beforeAll(async () => { + await setupApplicationForSync({ + applicationUniversalIdentifier: TEST_APP_ID, + name: 'Test Cross App Permission Retarget App', + description: 'App for testing cross-app permission retargeting on update', + sourcePath: 'test-cross-app-retarget', + }); + }, 60000); + + afterAll(async () => { + await cleanupApplicationAndAppRegistration({ + applicationUniversalIdentifier: TEST_APP_ID, + }); + }); + + it('should fail when retargeting a permission flag from own role to the standard admin role', async () => { + const initialManifest = buildBaseManifest({ + appId: TEST_APP_ID, + roleId: TEST_ROLE_ID, + overrides: { + roles: [ + { + universalIdentifier: TEST_ROLE_ID, + label: 'App Default Role', + description: 'Default role for the test app', + permissionFlags: [ + { + universalIdentifier: TEST_PERMISSION_FLAG_ID, + flag: PermissionFlagType.WORKSPACE, + }, + ], + }, + ], + }, + }); + + await syncApplication({ + manifest: initialManifest, + expectToFail: false, + }); + + const retargetManifest = buildBaseManifest({ + appId: TEST_APP_ID, + roleId: TEST_ROLE_ID, + overrides: { + roles: [ + { + universalIdentifier: TEST_ROLE_ID, + label: 'App Default Role', + description: 'Default role for the test app', + }, + { + universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, + label: 'Admin', + description: 'Attempts to retarget permission flag to admin role', + permissionFlags: [ + { + universalIdentifier: TEST_PERMISSION_FLAG_ID, + flag: PermissionFlagType.WORKSPACE, + }, + ], + }, + ], + }, + }); + + const { errors } = await syncApplication({ + manifest: retargetManifest, + expectToFail: true, + }); + + expectOneNotInternalServerErrorSnapshot({ errors }); + }, 60000); + + it('should fail when retargeting an object permission from own role to the standard admin role', async () => { + const initialManifest = buildBaseManifest({ + appId: TEST_APP_ID, + roleId: TEST_ROLE_ID, + overrides: { + roles: [ + { + universalIdentifier: TEST_ROLE_ID, + label: 'App Default Role', + description: 'Default role for the test app', + objectPermissions: [ + { + universalIdentifier: TEST_OBJECT_PERMISSION_ID, + objectUniversalIdentifier: COMPANY_OBJECT_ID, + }, + ], + }, + ], + }, + }); + + await syncApplication({ + manifest: initialManifest, + expectToFail: false, + }); + + const retargetManifest = buildBaseManifest({ + appId: TEST_APP_ID, + roleId: TEST_ROLE_ID, + overrides: { + roles: [ + { + universalIdentifier: TEST_ROLE_ID, + label: 'App Default Role', + description: 'Default role for the test app', + }, + { + universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, + label: 'Admin', + description: 'Attempts to retarget object permission to admin role', + objectPermissions: [ + { + universalIdentifier: TEST_OBJECT_PERMISSION_ID, + objectUniversalIdentifier: COMPANY_OBJECT_ID, + }, + ], + }, + ], + }, + }); + + const { errors } = await syncApplication({ + manifest: retargetManifest, + expectToFail: true, + }); + + expectOneNotInternalServerErrorSnapshot({ errors }); + }, 60000); + + it('should fail when retargeting a field permission from own role to the standard admin role', async () => { + const initialManifest = buildBaseManifest({ + appId: TEST_APP_ID, + roleId: TEST_ROLE_ID, + overrides: { + roles: [ + { + universalIdentifier: TEST_ROLE_ID, + label: 'App Default Role', + description: 'Default role for the test app', + fieldPermissions: [ + { + universalIdentifier: TEST_FIELD_PERMISSION_ID, + objectUniversalIdentifier: COMPANY_OBJECT_ID, + fieldUniversalIdentifier: COMPANY_NAME_FIELD_ID, + }, + ], + }, + ], + }, + }); + + await syncApplication({ + manifest: initialManifest, + expectToFail: false, + }); + + const retargetManifest = buildBaseManifest({ + appId: TEST_APP_ID, + roleId: TEST_ROLE_ID, + overrides: { + roles: [ + { + universalIdentifier: TEST_ROLE_ID, + label: 'App Default Role', + description: 'Default role for the test app', + }, + { + universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, + label: 'Admin', + description: 'Attempts to retarget field permission to admin role', + fieldPermissions: [ + { + universalIdentifier: TEST_FIELD_PERMISSION_ID, + objectUniversalIdentifier: COMPANY_OBJECT_ID, + fieldUniversalIdentifier: COMPANY_NAME_FIELD_ID, + }, + ], + }, + ], + }, + }); + + const { errors } = await syncApplication({ + manifest: retargetManifest, + expectToFail: true, + }); + + expectOneNotInternalServerErrorSnapshot({ errors }); + }, 60000); +}); diff --git a/packages/twenty-server/test/integration/metadata/suites/field-permission/__snapshots__/failing-field-permission-upsert.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-permission/__snapshots__/failing-field-permission-upsert.integration-spec.ts.snap index 1f8c54c4c8..23ce97b1ed 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-permission/__snapshots__/failing-field-permission-upsert.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-permission/__snapshots__/failing-field-permission-upsert.integration-spec.ts.snap @@ -70,8 +70,8 @@ exports[`Field permission upsert should fail when role is not editable (system r "errors": [ { "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", - "message": "Cannot modify permissions on a role owned by another application", - "userFriendlyMessage": "Cannot modify permissions on a role owned by another application.", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", }, { "code": "ROLE_NOT_EDITABLE", diff --git a/packages/twenty-server/test/integration/metadata/suites/object-permission/__snapshots__/failing-object-permission-upsert.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/object-permission/__snapshots__/failing-object-permission-upsert.integration-spec.ts.snap index d448688636..7ddd408a4f 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-permission/__snapshots__/failing-object-permission-upsert.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/object-permission/__snapshots__/failing-object-permission-upsert.integration-spec.ts.snap @@ -46,8 +46,8 @@ exports[`Object permission upsert should fail when role is not editable (system "errors": [ { "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", - "message": "Cannot modify permissions on a role owned by another application", - "userFriendlyMessage": "Cannot modify permissions on a role owned by another application.", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", }, { "code": "ROLE_NOT_EDITABLE", diff --git a/packages/twenty-server/test/integration/metadata/suites/permission-flag/__snapshots__/failing-permission-flag-upsert.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/permission-flag/__snapshots__/failing-permission-flag-upsert.integration-spec.ts.snap index f27049f1cd..550ea9e5c1 100644 --- a/packages/twenty-server/test/integration/metadata/suites/permission-flag/__snapshots__/failing-permission-flag-upsert.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/permission-flag/__snapshots__/failing-permission-flag-upsert.integration-spec.ts.snap @@ -9,7 +9,7 @@ exports[`Permission flag upsert should fail when permissionFlagKeys contains inv }, "userFriendlyMessage": "An error occurred.", }, - "message": "Value \"INVALID_FLAG\" does not exist in \"PermissionFlagType\" enum.", + "message": "Value "INVALID_FLAG" does not exist in "PermissionFlagType" enum.", "name": "GraphQLError", } `; @@ -24,8 +24,8 @@ exports[`Permission flag upsert should fail when role is not editable (system ro "errors": [ { "code": "ROLE_BELONGS_TO_ANOTHER_APPLICATION", - "message": "Cannot modify permissions on a role owned by another application", - "userFriendlyMessage": "Cannot modify permissions on a role owned by another application.", + "message": "Cannot target a role owned by another application", + "userFriendlyMessage": "Cannot target a role owned by another application.", }, { "code": "ROLE_NOT_EDITABLE",