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 e8f9fe97392..4caf68f565e 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 @@ -49,6 +49,7 @@ export enum PermissionsExceptionCode { ROLE_MUST_HAVE_AT_LEAST_ONE_TARGET = 'ROLE_MUST_HAVE_AT_LEAST_ONE_TARGET', ROLE_CANNOT_BE_ASSIGNED_TO_USERS = 'ROLE_CANNOT_BE_ASSIGNED_TO_USERS', APPLICATION_ROLE_NOT_FOUND = 'APPLICATION_ROLE_NOT_FOUND', + ROLE_BELONGS_TO_ANOTHER_APPLICATION = 'ROLE_BELONGS_TO_ANOTHER_APPLICATION', } const getPermissionsExceptionUserFriendlyMessage = ( @@ -143,6 +144,8 @@ const getPermissionsExceptionUserFriendlyMessage = ( return msg`This role cannot be assigned to users.`; 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.`; default: assertUnreachable(code); } diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts index 98659d9a86b..e03148fbe74 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts @@ -71,6 +71,7 @@ export const permissionGraphqlApiExceptionHandler = ( case PermissionsExceptionCode.COMPOSITE_TYPE_NOT_FOUND: case PermissionsExceptionCode.USER_WORKSPACE_NOT_FOUND: case PermissionsExceptionCode.APPLICATION_ROLE_NOT_FOUND: + case PermissionsExceptionCode.ROLE_BELONGS_TO_ANOTHER_APPLICATION: throw error; default: { return assertUnreachable(error.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 36299f920f0..0afe79c6228 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 @@ -10,6 +10,7 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util'; import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type'; import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type'; +import { validateRoleBelongsToCallerApplication } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util'; @Injectable() export class FlatFieldPermissionValidatorService { @@ -21,6 +22,7 @@ export class FlatFieldPermissionValidatorService { flatObjectMetadataMaps, flatFieldMetadataMaps, }, + buildOptions, }: UniversalFlatEntityValidationArgs< typeof ALL_METADATA_NAME.fieldPermission >): FailedFlatEntityValidation<'fieldPermission', 'create'> { @@ -63,12 +65,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.`, + }); + } } const referencedObjectMetadata = findFlatEntityByUniversalIdentifier({ 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 59067cb6e14..afd24f1b0fa 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 @@ -10,6 +10,7 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util'; import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type'; import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type'; +import { validateRoleBelongsToCallerApplication } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util'; @Injectable() export class FlatObjectPermissionValidatorService { @@ -20,6 +21,7 @@ export class FlatObjectPermissionValidatorService { flatRoleMaps, flatObjectMetadataMaps, }, + buildOptions, }: UniversalFlatEntityValidationArgs< typeof ALL_METADATA_NAME.objectPermission >): FailedFlatEntityValidation<'objectPermission', 'create'> { @@ -60,12 +62,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.`, + }); + } } const referencedObjectMetadata = findFlatEntityByUniversalIdentifier({ 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 c30c66587eb..0b84ab718cd 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 @@ -11,6 +11,7 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util'; import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type'; import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type'; +import { validateRoleBelongsToCallerApplication } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util'; @Injectable() export class FlatPermissionFlagValidatorService { @@ -20,6 +21,7 @@ export class FlatPermissionFlagValidatorService { flatPermissionFlagMaps: optimisticFlatPermissionFlagMaps, flatRoleMaps, }, + buildOptions, }: UniversalFlatEntityValidationArgs< typeof ALL_METADATA_NAME.permissionFlag >): FailedFlatEntityValidation<'permissionFlag', 'create'> { @@ -57,12 +59,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.`, + }); + } } const isValidFlag = 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 new file mode 100644 index 00000000000..71dc79c3978 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-belongs-to-caller-application.util.ts @@ -0,0 +1,29 @@ +import { msg, t } from '@lingui/core/macro'; + +import { PermissionsExceptionCode } from 'src/engine/metadata-modules/permissions/permissions.exception'; +import { type UniversalFlatRole } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-role.type'; +import { type FlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type'; +import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type'; + +export const validateRoleBelongsToCallerApplication = ({ + referencedRole, + buildOptions, +}: { + referencedRole: UniversalFlatRole; + buildOptions: WorkspaceMigrationBuilderOptions; +}): FlatEntityValidationError[] => { + if ( + referencedRole.applicationUniversalIdentifier !== + buildOptions.applicationUniversalIdentifier + ) { + 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.`, + }, + ]; + } + + return []; +}; 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-on-standard-role.integration-spec.ts.snap new file mode 100644 index 00000000000..7ae24088849 --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/application/__snapshots__/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts.snap @@ -0,0 +1,193 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Sync application should fail when creating permissions on a standard role from another app should fail when adding a field permission under the standard admin role 1`] = ` +{ + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "fieldPermission": [ + { + "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.", + }, + { + "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.", + }, + { + "code": "OBJECT_METADATA_NOT_FOUND_PERMISSIONS", + "message": "Object metadata not found", + "userFriendlyMessage": "Object metadata not found", + }, + { + "code": "FIELD_METADATA_NOT_FOUND", + "message": "Field metadata not found", + "userFriendlyMessage": "Field metadata not found", + }, + ], + "flatEntityMinimalInformation": { + "fieldMetadataUniversalIdentifier": Any, + "objectMetadataUniversalIdentifier": Any, + "roleUniversalIdentifier": Any, + "universalIdentifier": Any, + }, + "metadataName": "fieldPermission", + "status": "fail", + "type": "create", + }, + ], + "role": [ + { + "errors": [ + { + "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": { + "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 creating permissions on a standard role from another app should fail when adding a permission flag under the standard admin role 1`] = ` +{ + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "permissionFlag": [ + { + "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.", + }, + { + "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": { + "roleUniversalIdentifier": Any, + "universalIdentifier": Any, + }, + "metadataName": "permissionFlag", + "status": "fail", + "type": "create", + }, + ], + "role": [ + { + "errors": [ + { + "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": { + "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 creating permissions on a standard role from another app should fail when adding an object permission under the standard admin role 1`] = ` +{ + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "objectPermission": [ + { + "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.", + }, + { + "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.", + }, + { + "code": "OBJECT_METADATA_NOT_FOUND_PERMISSIONS", + "message": "Object metadata not found", + "userFriendlyMessage": "Object metadata not found", + }, + ], + "flatEntityMinimalInformation": { + "objectMetadataUniversalIdentifier": Any, + "roleUniversalIdentifier": Any, + "universalIdentifier": Any, + }, + "metadataName": "objectPermission", + "status": "fail", + "type": "create", + }, + ], + "role": [ + { + "errors": [ + { + "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": { + "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-on-standard-role.integration-spec.ts new file mode 100644 index 00000000000..336315d4575 --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/application/failing-sync-application-cross-app-permission-on-standard-role.integration-spec.ts @@ -0,0 +1,159 @@ +import { PermissionFlagType } from 'twenty-shared/constants'; + +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 { 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-0010-4000-a000-000000000010'; +const TEST_ROLE_ID = 'a1b2c3d4-0010-4000-a000-000000000011'; +const TEST_PERMISSION_FLAG_ID = 'a1b2c3d4-0010-4000-a000-000000000012'; +const TEST_OBJECT_PERMISSION_ID = 'a1b2c3d4-0010-4000-a000-000000000013'; +const TEST_FIELD_PERMISSION_ID = 'a1b2c3d4-0010-4000-a000-000000000014'; +const FAKE_OBJECT_ID = 'a1b2c3d4-0010-4000-a000-000000000020'; +const FAKE_FIELD_ID = 'a1b2c3d4-0010-4000-a000-000000000021'; + +describe('Sync application should fail when creating permissions on a standard role from another app', () => { + beforeAll(async () => { + await setupApplicationForSync({ + applicationUniversalIdentifier: TEST_APP_ID, + name: 'Test Cross App Permission App', + description: 'App for testing cross-app permission flag on standard role', + sourcePath: 'test-cross-app-permission', + }); + }, 60000); + + afterAll(async () => { + await globalThis.testDataSource.query( + `DELETE FROM core."role" WHERE "universalIdentifier" = $1`, + [TEST_ROLE_ID], + ); + + await globalThis.testDataSource.query( + `DELETE FROM core."file" WHERE "applicationId" IN ( + SELECT id FROM core."application" WHERE "universalIdentifier" = $1 + )`, + [TEST_APP_ID], + ); + + await globalThis.testDataSource.query( + `DELETE FROM core."application" + WHERE "universalIdentifier" = $1`, + [TEST_APP_ID], + ); + + await globalThis.testDataSource.query( + `DELETE FROM core."applicationRegistration" + WHERE "universalIdentifier" = $1`, + [TEST_APP_ID], + ); + }); + + it('should fail when adding a permission flag under the standard admin role', async () => { + const manifest = 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: 'Stolen Admin Role', + description: + 'Attempts to add permissions to the standard admin role', + permissionFlags: [ + { + universalIdentifier: TEST_PERMISSION_FLAG_ID, + flag: PermissionFlagType.WORKSPACE, + }, + ], + }, + ], + }, + }); + + const { errors } = await syncApplication({ + manifest, + expectToFail: true, + }); + + expectOneNotInternalServerErrorSnapshot({ errors }); + }, 60000); + + it('should fail when adding an object permission under the standard admin role', async () => { + const manifest = 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: 'Stolen Admin Role', + description: + 'Attempts to add object permission to the standard admin role', + objectPermissions: [ + { + universalIdentifier: TEST_OBJECT_PERMISSION_ID, + objectUniversalIdentifier: FAKE_OBJECT_ID, + }, + ], + }, + ], + }, + }); + + const { errors } = await syncApplication({ + manifest, + expectToFail: true, + }); + + expectOneNotInternalServerErrorSnapshot({ errors }); + }, 60000); + + it('should fail when adding a field permission under the standard admin role', async () => { + const manifest = 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: 'Stolen Admin Role', + description: + 'Attempts to add field permission to the standard admin role', + fieldPermissions: [ + { + universalIdentifier: TEST_FIELD_PERMISSION_ID, + objectUniversalIdentifier: FAKE_OBJECT_ID, + fieldUniversalIdentifier: FAKE_FIELD_ID, + }, + ], + }, + ], + }, + }); + + const { errors } = await syncApplication({ + manifest, + 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 69fe53b5106..1f8c54c4c82 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 @@ -68,6 +68,11 @@ exports[`Field permission upsert should fail when role is not editable (system r "fieldPermission": [ { "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.", + }, { "code": "ROLE_NOT_EDITABLE", "message": "Role is 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 46bdc119130..d4486886369 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 @@ -44,6 +44,11 @@ exports[`Object permission upsert should fail when role is not editable (system "objectPermission": [ { "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.", + }, { "code": "ROLE_NOT_EDITABLE", "message": "Role is 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 14ec2270e17..f27049f1cdc 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 @@ -22,6 +22,11 @@ exports[`Permission flag upsert should fail when role is not editable (system ro "permissionFlag": [ { "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.", + }, { "code": "ROLE_NOT_EDITABLE", "message": "Role is not editable",