[field-level permissions] Upsert fieldPermission + use fieldPermission to compute permissions (#13050)

In this PR

- introduction of fieldPermission entity
- addition of upsertFieldPermission in role resolver
- computing of permissions taking fieldPermission into account. In order
to limit what is stored in Redis we only store fields restrictions. For
instance for objectMetadata with id XXX with a restriction on field with
id YYY we store:
`"XXX":{"canRead":true,"canUpdate":false,"canSoftDelete":false,"canDestroy":false,"restrictedFields":{"YYY":{"canRead":false,"canUpdate":null}}}`

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
Marie
2025-07-09 10:47:59 +02:00
committed by GitHub
parent 6ba6860e1c
commit 1cb60f943e
49 changed files with 1343 additions and 47 deletions

View File

@ -6,7 +6,7 @@ import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfa
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants';
import { ActorMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
import { DEFAULT_LABEL_IDENTIFIER_FIELD_NAME } from 'src/engine/metadata-modules/object-metadata/object-metadata.constants';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceCustomEntity } from 'src/engine/twenty-orm/decorators/workspace-custom-entity.decorator';

View File

@ -1,4 +1,4 @@
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
import { generateDeterministicIndexName } from 'src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';

View File

@ -72,6 +72,7 @@ describe('WorkspaceEntityManager', () => {
canUpdate: false,
canSoftDelete: false,
canDestroy: false,
restrictedFields: {},
},
},
};

View File

@ -1,6 +1,6 @@
import { Gate } from 'src/engine/twenty-orm/interfaces/gate.interface';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
export interface WorkspaceIndexMetadataArgs {
/**

View File

@ -75,6 +75,7 @@ describe('WorkspaceRepository', () => {
canUpdate: false,
canSoftDelete: false,
canDestroy: false,
restrictedFields: {},
},
};
mockQueryRunner = {} as QueryRunner;

View File

@ -1,4 +1,4 @@
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
import { getColumnsForIndex } from 'src/engine/twenty-orm/utils/get-default-columns-for-index.util';
describe('getColumnsForIndex', () => {

View File

@ -1,4 +1,4 @@
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
export const getColumnsForIndex = (indexType?: IndexType) => {
switch (indexType) {