[permissions] Remove raw queries and restrict its usage (#12360)

Closes https://github.com/twentyhq/core-team-issues/issues/748

In the frame of the work on permissions we

- remove all raw queries possible to use repositories instead
- forbid usage workspaceDataSource.executeRawQueries()
- restrict usage of workspaceDataSource.query() to force developers to
pass on shouldBypassPermissionChecks to use it.

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
Marie
2025-06-02 10:53:51 +02:00
committed by GitHub
parent 1ef7b7a474
commit 9706f0df13
49 changed files with 495 additions and 754 deletions

View File

@ -1,16 +1,14 @@
import { Module } from '@nestjs/common';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
import { BlocklistValidationService } from 'src/modules/blocklist/blocklist-validation-manager/services/blocklist-validation.service';
import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@Module({
imports: [
ObjectMetadataRepositoryModule.forFeature([
BlocklistWorkspaceEntity,
WorkspaceMemberWorkspaceEntity,
]),
ObjectMetadataRepositoryModule.forFeature([BlocklistWorkspaceEntity]),
TwentyORMModule,
],
providers: [BlocklistValidationService],
exports: [BlocklistValidationService],

View File

@ -8,10 +8,10 @@ import {
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { isDomain } from 'src/engine/utils/is-domain';
import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository';
import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity';
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
export type BlocklistItem = Omit<
@ -28,8 +28,7 @@ export class BlocklistValidationService {
constructor(
@InjectObjectMetadataRepository(BlocklistWorkspaceEntity)
private readonly blocklistRepository: BlocklistRepository,
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
private readonly workspaceMemberRepository: WorkspaceMemberRepository,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {}
public async validateBlocklistForCreateMany(
@ -84,8 +83,15 @@ export class BlocklistValidationService {
userId: string,
workspaceId: string,
) {
const workspaceMemberRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
workspaceId,
WorkspaceMemberWorkspaceEntity,
);
const currentWorkspaceMember =
await this.workspaceMemberRepository.getByIdOrFail(userId, workspaceId);
await workspaceMemberRepository.findOneByOrFail({
userId,
});
const currentBlocklist =
await this.blocklistRepository.getByWorkspaceMemberId(
@ -126,8 +132,16 @@ export class BlocklistValidationService {
return;
}
const workspaceMemberRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
workspaceId,
WorkspaceMemberWorkspaceEntity,
);
const currentWorkspaceMember =
await this.workspaceMemberRepository.getByIdOrFail(userId, workspaceId);
await workspaceMemberRepository.findOneByOrFail({
userId,
});
const currentBlocklist =
await this.blocklistRepository.getByWorkspaceMemberId(

View File

@ -1,46 +1,49 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity';
@Injectable()
export class BlocklistRepository {
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {}
public async getById(
id: string,
workspaceId: string,
): Promise<BlocklistWorkspaceEntity | null> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const blocklistItems =
await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."blocklist" WHERE "id" = $1`,
[id],
const blockListRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
workspaceId,
BlocklistWorkspaceEntity,
{
shouldBypassPermissionChecks: true,
},
);
if (!blocklistItems || blocklistItems.length === 0) {
return null;
}
return blocklistItems[0];
return blockListRepository.findOneBy({
id,
});
}
public async getByWorkspaceMemberId(
workspaceMemberId: string,
workspaceId: string,
): Promise<BlocklistWorkspaceEntity[]> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const blockListRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
workspaceId,
BlocklistWorkspaceEntity,
{
shouldBypassPermissionChecks: true,
},
);
return await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."blocklist" WHERE "workspaceMemberId" = $1`,
[workspaceMemberId],
workspaceId,
);
return blockListRepository.find({
where: {
workspaceMemberId,
},
});
}
}