-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[permission] Override query builders db-executing methods #11714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…-twenty-global-orm-manager
…ty-global-orm-manager
…ty-global-orm-manager
…ty-global-orm-manager
…ty-global-orm-manager
|
||
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; | ||
|
||
export class WorkspaceQueryBuilder< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we actually don't need this: we use a SelectQueryBuilder in the initial createQueryBuilder method in workspace.repository
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This PR implements a comprehensive permission system overhaul for database operations in the Twenty server, replacing the single WorkspaceQueryBuilder with specialized query builders for different operations.
- Added new specialized query builders (
WorkspaceInsertQueryBuilder
,WorkspaceDeleteQueryBuilder
,WorkspaceSoftDeleteQueryBuilder
) with proper permission validation - Implemented permission checks in execute() methods across all query builders using
validateQueryIsPermittedOrThrow
- Added support for permissions V2 feature flag with backward compatibility
- Added extensive integration tests covering permission scenarios for guest roles, admin roles, and API keys
- Note: PR description appears to be incorrect as it references mobile display improvements but changes are about permission handling
17 file(s) reviewed, 14 comment(s)
Edit PR Review Bot Settings | Greptile
packages/twenty-server/src/engine/twenty-orm/repository/permissions.util.ts
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts
Outdated
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts
Outdated
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts
Show resolved
Hide resolved
.../suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts
Show resolved
Hide resolved
afterAll(async () => { | ||
const disablePermissionsQuery = updateFeatureFlagFactory( | ||
SEED_APPLE_WORKSPACE_ID, | ||
'IsPermissionsV2Enabled', | ||
false, | ||
); | ||
|
||
expect(response.body.data).toStrictEqual({ deletePerson: null }); | ||
expect(response.body.errors).toBeDefined(); | ||
expect(response.body.errors[0].message).toBe( | ||
PermissionsExceptionMessage.PERMISSION_DENIED, | ||
); | ||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN); | ||
}); | ||
await makeGraphqlAPIRequest(disablePermissionsQuery); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: ensure feature flag is disabled even if test fails by using try/finally
}); | ||
|
||
it('should throw a permission error when user does not have permission (guest role)', async () => { | ||
const personId = randomUUID(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: personId is redefined here but never used in the test - the recordId in the operation could use the outer personId
id: { | ||
in: [randomUUID(), randomUUID()], | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Using random UUIDs in the filter when testing permission denial could mask actual permission issues. Consider using the same personId1/personId2 that were created to ensure the test is checking permissions and not just failing because records don't exist.
id: { | |
in: [randomUUID(), randomUUID()], | |
}, | |
id: { | |
in: [personId1, personId2], | |
}, |
beforeAll(async () => { | ||
const enablePermissionsQuery = updateFeatureFlagFactory( | ||
SEED_APPLE_WORKSPACE_ID, | ||
'IsPermissionsV2Enabled', | ||
true, | ||
); | ||
|
||
await makeGraphqlAPIRequest(enablePermissionsQuery); | ||
}); | ||
|
||
afterAll(async () => { | ||
const disablePermissionsQuery = updateFeatureFlagFactory( | ||
SEED_APPLE_WORKSPACE_ID, | ||
'IsPermissionsV2Enabled', | ||
false, | ||
); | ||
|
||
await makeGraphqlAPIRequest(disablePermissionsQuery); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Feature flag state changes in beforeAll/afterAll could affect other test suites running in parallel. Consider using a unique workspace ID for these tests.
afterAll(async () => { | ||
const disablePermissionsQuery = updateFeatureFlagFactory( | ||
SEED_APPLE_WORKSPACE_ID, | ||
'IsPermissionsV2Enabled', | ||
false, | ||
); | ||
|
||
expect(response.body.data).toStrictEqual({ restorePeople: null }); | ||
expect(response.body.errors).toBeDefined(); | ||
expect(response.body.errors[0].message).toBe( | ||
PermissionsExceptionMessage.PERMISSION_DENIED, | ||
); | ||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN); | ||
}); | ||
await makeGraphqlAPIRequest(disablePermissionsQuery); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Ensure feature flag is properly reset even if tests fail by using try/finally
afterAll(async () => { | |
const disablePermissionsQuery = updateFeatureFlagFactory( | |
SEED_APPLE_WORKSPACE_ID, | |
'IsPermissionsV2Enabled', | |
false, | |
); | |
expect(response.body.data).toStrictEqual({ restorePeople: null }); | |
expect(response.body.errors).toBeDefined(); | |
expect(response.body.errors[0].message).toBe( | |
PermissionsExceptionMessage.PERMISSION_DENIED, | |
); | |
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN); | |
}); | |
await makeGraphqlAPIRequest(disablePermissionsQuery); | |
}); | |
afterAll(async () => { | |
try { | |
const disablePermissionsQuery = updateFeatureFlagFactory( | |
SEED_APPLE_WORKSPACE_ID, | |
'IsPermissionsV2Enabled', | |
false, | |
); | |
await makeGraphqlAPIRequest(disablePermissionsQuery); | |
} catch (error) { | |
console.error('Failed to reset permissions feature flag:', error); | |
throw error; | |
} | |
}); |
.../suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts
Outdated
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts
Outdated
Show resolved
Hide resolved
...y-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts
Outdated
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts
Outdated
Show resolved
Hide resolved
packages/twenty-server/src/engine/twenty-orm/repository/permissions.util.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 👏
closes twentyhq/core-team-issues#843