Skip to content

Conversation

@ketanMehtaa
Copy link
Contributor

fix #13460

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

Summary

This PR implements admin control over workspace creation by adding a new configuration variable `IS_WORKSPACE_CREATION_LIMITED_TO_WORKSPACE_ADMINS` that restricts workspace creation to admin users only. The implementation adds a new method `isWorkspaceCreationAllowed` in the `SignInUpService` that checks if workspace creation is limited and validates user permissions before allowing workspace creation.

The solution works by:

  1. Adding a new boolean config variable that defaults to false for backward compatibility
  2. Creating a countUserWorkspaces method in UserWorkspaceService to count how many workspaces a user belongs to
  3. Implementing permission logic that allows users with no existing workspaces to create their first workspace (for initial setup), but restricts additional workspace creation to users with canAccessFullAdminPanel permission when the restriction is enabled
  4. Integrating this check into the signUpInNewWorkspace resolver to enforce the restriction at the API level

The implementation follows existing patterns in the codebase, using the established AuthException mechanism for error handling and leveraging the existing user permission system (canAccessFullAdminPanel). This addresses the need for centralized instance management in enterprise deployments where administrators need to control workspace proliferation.

Changed Files
Filename Score Overview
packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts 5/5 Added countUserWorkspaces method to count workspaces for a given user
packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts 4/5 Integrated workspace creation permission check into signup resolver
packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts 4/5 Added new boolean config variable to control workspace creation restrictions
packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts 4/5 Implemented core logic for workspace creation permission validation

Confidence score: 4/5

  • This PR implements a well-structured security feature with minimal risk of breaking existing functionality
  • Score reflects solid implementation following existing patterns with appropriate error handling and backward compatibility
  • Pay close attention to the permission logic in sign-in-up.service.ts to ensure the admin validation works correctly

Sequence Diagram

sequenceDiagram
    participant User
    participant AuthResolver
    participant SignInUpService
    participant TwentyConfigService
    participant UserWorkspaceService
    participant UserRepository
    participant WorkspaceRepository
    participant DomainManagerService
    participant UserWorkspaceService2 as UserWorkspaceService
    participant OnboardingService

    User->>AuthResolver: "signUpInNewWorkspace()"
    AuthResolver->>SignInUpService: "isWorkspaceCreationAllowed(currentUser)"
    SignInUpService->>TwentyConfigService: "get('IS_WORKSPACE_CREATION_LIMITED_TO_WORKSPACE_ADMINS')"
    TwentyConfigService-->>SignInUpService: "config value"
    
    alt workspace creation is limited
        SignInUpService->>UserWorkspaceService: "countUserWorkspaces(currentUser.id)"
        UserWorkspaceService-->>SignInUpService: "workspace count"
        
        alt user has workspaces AND is not admin
            SignInUpService-->>AuthResolver: "throw AuthException('Workspace creation is restricted to admins')"
            AuthResolver-->>User: "AuthException"
        end
    end
    
    SignInUpService-->>AuthResolver: "validation passed"
    AuthResolver->>SignInUpService: "signUpOnNewWorkspace(userData)"
    SignInUpService->>DomainManagerService: "generateSubdomain()"
    DomainManagerService-->>SignInUpService: "subdomain"
    SignInUpService->>WorkspaceRepository: "create(workspaceData)"
    SignInUpService->>WorkspaceRepository: "save(workspace)"
    WorkspaceRepository-->>SignInUpService: "saved workspace"
    SignInUpService->>UserWorkspaceService2: "create(userWorkspaceData)"
    UserWorkspaceService2-->>SignInUpService: "userWorkspace"
    SignInUpService->>OnboardingService: "setOnboardingInviteTeamPending()"
    SignInUpService-->>AuthResolver: "{user, workspace}"
    AuthResolver-->>User: "SignUpOutput with loginToken"
Loading

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 493 to 496
await this.signInUpService.isWorkspaceCreationAllowed(currentUser);

const { user, workspace } = await this.signInUpService.signUpOnNewWorkspace(
{ type: 'existingUser', existingUser: currentUser },
Copy link

Choose a reason for hiding this comment

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

Potential bug: A race condition in signUpInNewWorkspace allows concurrent requests to bypass the single workspace creation limit for non-admin users because the check and creation are not atomic.
  • Description: The signUpInNewWorkspace resolver first checks if a user can create a workspace via isWorkspaceCreationAllowed and then performs the creation in a separate step. These two operations are not atomic. A race condition exists where a non-admin user with zero workspaces can send concurrent requests. Both requests can pass the permission check before either has created a user-workspace association. This allows both requests to proceed, resulting in the user creating multiple workspaces and bypassing the business logic that should restrict them to only one.

  • Suggested fix: Wrap the permission check in isWorkspaceCreationAllowed and the subsequent workspace creation logic within a single database transaction. Using a SERIALIZABLE isolation level will ensure the check-then-act sequence is atomic, preventing the race condition from allowing multiple workspace creations.
    severity: 0.55, confidence: 0.95

Did we get this right? 👍 / 👎 to inform future reviews.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 4, 2025

🚀 Preview Environment Ready!

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

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

Copy link
Member

@FelixMalfait FelixMalfait left a comment

Choose a reason for hiding this comment

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

Thank you!

@FelixMalfait FelixMalfait merged commit 66d9a6d into twentyhq:main Oct 6, 2025
36 of 39 checks passed
@github-actions
Copy link
Contributor

github-actions bot commented Oct 6, 2025

Thanks @ketanMehtaa for your contribution!
This marks your 4th PR on the repo. You're top 7% of all our contributors 🎉
See contributor page - Share on LinkedIn - Share on Twitter

Contributions

@ketanMehtaa ketanMehtaa deleted the fix/disableWorkspace branch October 6, 2025 09:02
Connorbelez added a commit to Connorbelez/FLCRMLMS that referenced this pull request Oct 6, 2025
- Introduced new field types: PDF and IMAGE, including their metadata structures.
- Updated GraphQL and REST API contracts to accommodate new field types.
- Implemented validation and utility functions for handling PDF and Image fields.
- Added integration tests to ensure proper functionality of new field types.
- Updated documentation and specifications related to the new features.

This commit enhances the data model by allowing users to upload and manage PDF and Image files, improving the overall functionality of the application.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Admin control to disable workspace creation for non-admin users

2 participants