Skip to content

Conversation

@FelixMalfait
Copy link
Member

Overview

This PR strengthens our permission system by introducing more granular role-based access control across the platform.

Changes

New Permissions Added

  • Applications - Control who can install and manage applications
  • Layouts - Control who can customize page layouts and UI structure
  • AI - Control access to AI features and agents
  • Upload File - Separate permission for file uploads
  • Download File - Separate permission for file downloads (frontend visibility)

Security Enhancements

  • Implemented whitelist-based validation for workspace field updates
  • Added explicit permission guards to core entity resolvers
  • Enhanced ESLint rule to enforce permission checks on all mutations
  • Created CustomPermissionGuard and NoPermissionGuard for better code documentation

Affected Components

  • Core entity resolvers: webhooks, files, domains, applications, layouts, postgres credentials
  • Workspace update mutations now use whitelist validation
  • Settings UI updated with new permission controls

Developer Experience

  • ESLint now catches missing permission guards during development
  • Explicit guard markers make permission requirements clear in code review
  • Comprehensive test coverage for new permission logic

Testing

  • ✅ All TypeScript type checks pass
  • ✅ ESLint validation passes
  • ✅ New permission guards properly enforced
  • ✅ Frontend UI displays new permissions correctly

Migration Notes

Existing workspaces will need to assign the new permissions to roles as needed. By default, all new permissions are set to false for non-admin roles.

- Add new granular permissions: Applications, Layouts, AI, Upload File, Download File
- Implement whitelist-based workspace field validation for improved security
- Add SettingsPermissionsGuard to core entity resolvers (webhooks, files, domains, etc.)
- Create CustomPermissionGuard and NoPermissionGuard for explicit permission documentation
- Enhance ESLint rule to enforce permission guards on all mutations
- Update frontend Settings UI with new permission controls
- Add PermissionsModule to all affected resolver modules

This improves the security posture by ensuring all mutations have explicit
permission requirements and prevents unauthorized access to sensitive operations.
@FelixMalfait FelixMalfait changed the title Enhance permission system with granular role-based access control Enhance role-check system with stricter checks Oct 28, 2025
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR introduces granular role-based access control by adding 5 new permissions (APPLICATIONS, LAYOUTS, AI, UPLOAD_FILE, DOWNLOAD_FILE) and implementing comprehensive security enhancements across the platform.

Key Changes:

  • Added new guard types (CustomPermissionGuard, NoPermissionGuard) to explicitly document permission handling patterns
  • Implemented whitelist-based field validation in WorkspaceService using WORKSPACE_FIELD_PERMISSIONS map - prevents unauthorized field updates
  • Applied permission guards to 7+ core resolvers (applications, layouts, files, webhooks, AI agents, postgres credentials, domains)
  • Enhanced ESLint rule to enforce permission guards on all mutations during development
  • Updated frontend UI with new permission controls in settings

Security Improvements:

  • Workspace field updates now require specific permissions per field (e.g., subdomain requires WORKSPACE, inviteHash requires WORKSPACE_MEMBERS)
  • Unknown fields are rejected with clear error messages
  • Permission validation grouped by permission type for efficiency
  • All mutations now have explicit permission guards (enforced by ESLint)

Confidence Score: 5/5

  • This PR is safe to merge - it strengthens security through comprehensive permission validation
  • The implementation is thorough and well-architected: whitelist-based validation prevents unauthorized updates, new guard types provide clear documentation, ESLint enforcement catches missing guards during development, and all changes follow established patterns
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
packages/twenty-server/src/engine/metadata-modules/permissions/constants/permission-flag-type.constants.ts 5/5 Added new permission types: APPLICATIONS, LAYOUTS, AI, UPLOAD_FILE, DOWNLOAD_FILE
packages/twenty-server/src/engine/guards/custom-permission.guard.ts 5/5 New guard for endpoints with custom permission logic (always returns true, serves as documentation)
packages/twenty-server/src/engine/guards/no-permission.guard.ts 5/5 New guard for special cases that intentionally bypass permission validation (onboarding flows, etc.)
packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts 5/5 Implemented whitelist-based validation for workspace field updates using WORKSPACE_FIELD_PERMISSIONS map
tools/eslint-rules/rules/graphql-resolvers-should-be-guarded.ts 5/5 Enhanced ESLint rule to require permission guards on mutations (accepts SettingsPermissionsGuard, CustomPermissionGuard, or NoPermissionGuard)

Sequence Diagram

sequenceDiagram
    participant Client
    participant Resolver
    participant AuthGuard
    participant PermissionGuard
    participant PermissionsService
    participant WorkspaceService
    
    Client->>Resolver: GraphQL Mutation Request
    Resolver->>AuthGuard: @UseGuards(WorkspaceAuthGuard)
    AuthGuard->>AuthGuard: Verify authentication
    AuthGuard-->>Resolver: User authenticated
    
    alt Standard Permission Guard
        Resolver->>PermissionGuard: @UseGuards(SettingsPermissionsGuard(PERMISSION_TYPE))
        PermissionGuard->>PermissionsService: Check user permission
        PermissionsService->>PermissionsService: Query role permissions
        alt Has Permission
            PermissionsService-->>PermissionGuard: Permission granted
            PermissionGuard-->>Resolver: Access allowed
            Resolver->>WorkspaceService: Execute business logic
            WorkspaceService-->>Resolver: Return result
            Resolver-->>Client: Success response
        else No Permission
            PermissionsService-->>PermissionGuard: Permission denied
            PermissionGuard-->>Client: 403 Forbidden
        end
    else Custom Permission Guard
        Resolver->>PermissionGuard: @UseGuards(CustomPermissionGuard)
        PermissionGuard-->>Resolver: Always allow (marker)
        Resolver->>WorkspaceService: Execute with custom validation
        WorkspaceService->>WorkspaceService: validateWorkspaceUpdatePermissions()
        WorkspaceService->>WorkspaceService: Check WORKSPACE_FIELD_PERMISSIONS whitelist
        alt Field in whitelist
            WorkspaceService->>PermissionsService: Check field-specific permission
            alt Has Permission
                PermissionsService-->>WorkspaceService: Permission granted
                WorkspaceService-->>Resolver: Return result
                Resolver-->>Client: Success response
            else No Permission
                PermissionsService-->>WorkspaceService: Permission denied
                WorkspaceService-->>Client: 403 Forbidden with field list
            end
        else Field not in whitelist
            WorkspaceService-->>Client: 403 Field not allowed
        end
    else No Permission Guard
        Resolver->>PermissionGuard: @UseGuards(NoPermissionGuard)
        PermissionGuard-->>Resolver: Always allow (special cases)
        Resolver->>WorkspaceService: Execute without permission check
        WorkspaceService-->>Resolver: Return result
        Resolver-->>Client: Success response
    end
Loading

35 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@github-actions
Copy link
Contributor

github-actions bot commented Oct 28, 2025

🚀 Preview Environment Ready!

Your preview environment is available at: http://bore.pub:47578

This environment will automatically shut down when the PR is closed or after 5 hours.

FelixMalfait and others added 5 commits October 28, 2025 10:10
- Introduced new permission flags: BILLING and MANAGE_VIEWS.
- Updated GraphQL enums and metadata to include new permissions.
- Enhanced SettingsRolePermissionsSettingsSection to manage new permissions.
- Adjusted various resolvers to utilize the new permission flags for improved access control.

This update strengthens the permission system by providing more granular control over billing and view management functionalities.
@github-actions
Copy link
Contributor

github-actions bot commented Oct 28, 2025

📊 API Changes Report

GraphQL Schema Changes

GraphQL Schema Changes

[log]
Detected the following changes (10) between schemas:

[log] ✖ Enum value ADMIN_PANEL was removed from enum PermissionFlagType
[log] ⚠ Enum value AI was added to enum PermissionFlagType
[log] ⚠ Enum value AI_SETTINGS was added to enum PermissionFlagType
[log] ⚠ Enum value APPLICATIONS was added to enum PermissionFlagType
[log] ⚠ Enum value BILLING was added to enum PermissionFlagType
[log] ⚠ Enum value CONNECTED_ACCOUNTS was added to enum PermissionFlagType
[log] ⚠ Enum value DOWNLOAD_FILE was added to enum PermissionFlagType
[log] ⚠ Enum value LAYOUTS was added to enum PermissionFlagType
[log] ⚠ Enum value UPLOAD_FILE was added to enum PermissionFlagType
[log] ⚠ Enum value VIEWS was added to enum PermissionFlagType
[error] Detected 1 breaking change
⚠️ Breaking changes or errors detected in GraphQL schema

[log] 
Detected the following changes (10) between schemas:

[log] ✖  Enum value ADMIN_PANEL was removed from enum PermissionFlagType
[log] ⚠  Enum value AI was added to enum PermissionFlagType
[log] ⚠  Enum value AI_SETTINGS was added to enum PermissionFlagType
[log] ⚠  Enum value APPLICATIONS was added to enum PermissionFlagType
[log] ⚠  Enum value BILLING was added to enum PermissionFlagType
[log] ⚠  Enum value CONNECTED_ACCOUNTS was added to enum PermissionFlagType
[log] ⚠  Enum value DOWNLOAD_FILE was added to enum PermissionFlagType
[log] ⚠  Enum value LAYOUTS was added to enum PermissionFlagType
[log] ⚠  Enum value UPLOAD_FILE was added to enum PermissionFlagType
[log] ⚠  Enum value VIEWS was added to enum PermissionFlagType
[error] Detected 1 breaking change
Error generating diff

GraphQL Metadata Schema Changes

GraphQL Metadata Schema Changes

[log]
Detected the following changes (10) between schemas:

[log] ✖ Enum value ADMIN_PANEL was removed from enum PermissionFlagType
[log] ⚠ Enum value AI was added to enum PermissionFlagType
[log] ⚠ Enum value AI_SETTINGS was added to enum PermissionFlagType
[log] ⚠ Enum value APPLICATIONS was added to enum PermissionFlagType
[log] ⚠ Enum value BILLING was added to enum PermissionFlagType
[log] ⚠ Enum value CONNECTED_ACCOUNTS was added to enum PermissionFlagType
[log] ⚠ Enum value DOWNLOAD_FILE was added to enum PermissionFlagType
[log] ⚠ Enum value LAYOUTS was added to enum PermissionFlagType
[log] ⚠ Enum value UPLOAD_FILE was added to enum PermissionFlagType
[log] ⚠ Enum value VIEWS was added to enum PermissionFlagType
[error] Detected 1 breaking change
⚠️ Breaking changes or errors detected in GraphQL metadata schema

[log] 
Detected the following changes (10) between schemas:

[log] ✖  Enum value ADMIN_PANEL was removed from enum PermissionFlagType
[log] ⚠  Enum value AI was added to enum PermissionFlagType
[log] ⚠  Enum value AI_SETTINGS was added to enum PermissionFlagType
[log] ⚠  Enum value APPLICATIONS was added to enum PermissionFlagType
[log] ⚠  Enum value BILLING was added to enum PermissionFlagType
[log] ⚠  Enum value CONNECTED_ACCOUNTS was added to enum PermissionFlagType
[log] ⚠  Enum value DOWNLOAD_FILE was added to enum PermissionFlagType
[log] ⚠  Enum value LAYOUTS was added to enum PermissionFlagType
[log] ⚠  Enum value UPLOAD_FILE was added to enum PermissionFlagType
[log] ⚠  Enum value VIEWS was added to enum PermissionFlagType
[error] Detected 1 breaking change
Error generating diff

⚠️ Please review these API changes carefully before merging.

⚠️ Breaking Change Protocol

Breaking changes detected but PR title does not contain "breaking" - CI will pass but action needed.

🔄 Options:

  1. If this IS a breaking change: Add "breaking" to your PR title and add BREAKING CHANGE: to your commit message
  2. If this is NOT a breaking change: The API diff tool may have false positives - please review carefully

For breaking changes, add to commit message:

feat: add new API endpoint

BREAKING CHANGE: removed deprecated field from User schema

Icon: IconLayoutSidebarRightCollapse,
},
{
key: PermissionFlagType.MANAGE_VIEWS,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we want to do that one right we need a comprehensive work in the FE.

For instance at the moment when a user choose to hide or show a field on a view, it updates the view.
I think a user that does not have the MANAGE_VIEW permission should still be able to display a field that is being hidden, but that it should not update the view for everyone.

Overall I think the introduction of this permission would be less painful for users who won't have it if we introduce private / common views, otherwise users without the permissions will be restricted in their attempts to display data as they want to (if they need to hide / show a field each time they visit a view for instance)

Copy link
Member Author

@FelixMalfait FelixMalfait Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made two changes that should help:

  • Moved Views from Settings to Tools which means it's now provisioned by default for Member roles (including existing)
  • Made changes on the frontend so that changes are not persisted when the permission is missing, that way the user can still resize or move columns but it's only a local change

I agree private views would be nice as a followup.

@UseGuards(WorkspaceAuthGuard)
@UseGuards(
WorkspaceAuthGuard,
SettingsPermissionsGuard(PermissionFlagType.WORKFLOWS),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this linked to workflows?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thomtrp could you please double check? I assumed it was but if you can double check I'm not missing anything, thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are planning to migrate workflows on that entity but for now I think this is only used by applications. Could you confirm @martmull?

@FelixMalfait
Copy link
Member Author

TODO: Don't load agent threads/ask ai if there's no AI permission

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants