Commit Graph

84 Commits

Author SHA1 Message Date
Félix Malfait ece265c6e4 Harden local file storage driver path resolution (#17783)
## Summary

- Normalize all file paths with `path.resolve` instead of `join` to
properly handle `..` segments in file path inputs
- Add `assertPathIsWithinStorage` guard on all write, delete, move,
copy, and existence-check operations
- Introduce `ACCESS_DENIED` exception code with i18n-ready user-friendly
message
- Read path already had realpath-based validation; updated its error
code to `ACCESS_DENIED` for consistency

## Test plan

- [x] Typecheck passes
- [x] Lint passes
- [x] Manual: verify file upload/download still works with valid paths
- [x] Manual: verify `../` in file paths is rejected with ACCESS_DENIED


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Etienne <etiennejouan@users.noreply.github.com>
2026-02-09 09:54:10 +00:00
Félix Malfait d7132b35d3 Centralize outbound HTTP requests through SecureHttpClientService (#17779)
## Summary

- Migrates all direct `axios` and `@nestjs/axios` `HttpService` usages
across the server to go through `SecureHttpClientService`, which
conditionally applies SSRF protection based on the
`OUTBOUND_HTTP_SAFE_MODE_ENABLED` config flag
- `SecureHttpClientService.getHttpClient()` now accepts optional
`AxiosRequestConfig` (e.g., `baseURL`) so callers can configure their
client while still getting protection
- Adds `getInternalHttpClient()` for trusted same-server requests (e.g.,
REST-to-GraphQL proxy, code-interpreter downloading internal files)
- Renames `getSecureAdapter` to `getSecureAxiosAdapter` for clarity
- Captcha drivers now receive a pre-configured `AxiosInstance` from the
module factory instead of creating their own

## Migrated services

| Service | Previous | Risk level |
|---------|----------|-----------|
| `file-upload.service` | `HttpService` | High (user-provided image
URLs) |
| `code-interpreter-tool` | `HttpService` + direct adapter | High
(user-provided file URLs) |
| `search-help-center-tool` | `axios.post()` | Low (hardcoded endpoints)
|
| `http-tool` | Already migrated | High (user-provided URLs) |
| `admin-panel.service` | `axios.get()` | Low (Docker Hub API) |
| `sign-in-up.service` | `HttpService` | Medium (logo URL validation) |
| `google-apis-scopes` | `HttpService` | Low (Google API) |
| `geo-map.service` | `HttpService` | Low (Google Maps API) |
| `telemetry.service` | `HttpService` | Low (telemetry endpoint) |
| `rest-api.service` | `HttpService` | Internal (uses
`getInternalHttpClient`) |
| `create-company.service` | `axios.create()` | Low (Twenty companies
API) |
| `google-recaptcha.driver` | `axios.create()` | Low (Google reCAPTCHA)
|
| `turnstile.driver` | `axios.create()` | Low (Cloudflare Turnstile) |

## Test plan

- [x] `npx nx typecheck twenty-server` passes
- [x] `npx nx lint:diff-with-main twenty-server` passes
- [x] Admin panel unit tests pass
- [x] Secure adapter unit tests pass

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-02-08 19:52:35 +01:00
Etienne 77d15356e1 Files v2 - Use Files field in attachment (#17707)
- Add FILES field on attachment
- Adapt Attachment logic in front to use new resolver/controller
- Update files-field logic to infer applicationId from fieldMetadataId +
ask for fieldMetadataId in upload resolver
- Design update


To do in next PR : 
- Adapt activity files logic
2026-02-05 16:42:19 +00:00
Charles Bochet 867b03393b Backfill package json for custom and standard app (#17681)
# Backfill application package files for custom and standard apps

- Backfill `package.json` / `yarn.lock` (and related fields) for
existing workspaces; new standard/custom apps get default dependency
files.
- Default package files under
`application/constants/default-package-files/`; util with hardcoded
checksums (comment on how to regenerate).
- New **FileFolder.Dependencies** for app dependency files;
**writeFile_v2** accepts optional `queryRunner` for transactional
writes.

Usages:
- **Upgrade command** `upgrade:1-17:backfill-application-package-files`:
standard/custom apps → default files; other apps → from logic function
layer.
- **Workspace creation**: create workspace with
`workspaceCustomApplicationId` first, then create application (enables
same-transaction insert). Migration makes workspace/application/file FKs
deferrable.
-  dev seeder
2026-02-03 21:23:29 +01:00
Paul Rastoin 476bdf764c Refactor flat entity maps to be universal oriented (#17665)
# Introduction
In preparation of the workspace agnostic builder, we're migrating
`FlatEntityMaps` to be universal identifier oriented and based
As in the builder context there're won't be any ids at all
Please also note that the FlatEntity is a UniversalFlatEntity superset

From
```ts
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';

export type FlatEntityMaps<T extends SyncableFlatEntity> = {
  byId: Partial<Record<string, T>>;
  idByUniversalIdentifier: Partial<Record<string, string>>;
  universalIdentifiersByApplicationId: Partial<Record<string, string[]>>;
};
```

To
```ts
export type FlatEntityMaps<
  T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
> = {
  byUniversalIdentifier: Partial<Record<string, T>>;
  universalIdentifierById: Partial<Record<string, string>>;
  universalIdentifiersByApplicationId: Partial<Record<string, string[]>>; // this might make more sense to be migrated to universalIdentifiersByApplicationUniversalIdentifier but it's the main topic of this PR
};
```

## Low level maps tools
Had to refactor find | create | delete | replace | find-many | get-sub
tools ( through mutations and or throw equivalent )
2026-02-03 16:16:02 +00:00
martmull 65678ed99f Upload files instead ofsources (#17608) 2026-02-03 12:11:10 +01:00
Charles Bochet 5996d0fc03 Refactor workflow to use new functions (#17552)
Removes the versioning system for logic functions (`latestVersion`,
`publishedVersions`) and simplifies the file storage structure.

### Changes
- Remove `publishOneLogicFunctionOrFail` and publishing logic from
workflow status updates
- Add `createLogicFunctionFromExistingLogicFunction` to duplicate logic
functions when creating draft workflow versions
- Update `createDraftStep` to create a new logic function copy instead
of referencing the same one
- Migrate file storage to v2 endpoints with
`applicationUniversalIdentifier`
- Unify path structure: source files at `source/workflow/{id}/`, built
files at `built-logic-function/workflow/{id}/`
- Store full paths in `sourceHandlerPath` and `builtHandlerPath` entity
fields
2026-01-30 15:42:36 +01:00
Etienne 4b66ae5320 Files Field - Add new controller (#17561)
Add new files field controller to fetch files from FILES field
2026-01-30 13:44:11 +00:00
Etienne 09de762285 Files v2 - FILES field update/create in common API (#17400)
## FILES Field update interface

```
mutation {
  updateCompany(
    id: "company-uuid"
    data: {
      filesfield: [
          { fileId: "new-file-uuid", label: "new-document.pdf" }
        ]
    }
  ) {
    id
    filesfield {
      fileId
      label
      extension
    }
  }
}
```
2026-01-29 13:33:26 +00:00
Etienne 22c7e207e3 File storage refactor - Switch to applicationUniversalIdentifier (#17541) 2026-01-29 10:39:19 +00:00
martmull 3412992e99 2162 Add asset watcher in twenty-sdk dev mode (#17513)
- assets are pushed in .twenty/output
- assets are uploaded in FileFolder.Assets
- not handled yet by the sync-manifest endpoint
2026-01-29 09:08:44 +00:00
Charles Bochet da6f1bbef3 Rename serverlessFunction to logicFunction (#17494)
## Summary

Rename "Serverless Function" to "Logic Function" across the codebase for
clearer naming.

### Environment Variable Changes

| Old | New |
|-----|-----|
| `SERVERLESS_TYPE` | `LOGIC_FUNCTION_TYPE` |
| `SERVERLESS_LAMBDA_REGION` | `LOGIC_FUNCTION_LAMBDA_REGION` |
| `SERVERLESS_LAMBDA_ROLE` | `LOGIC_FUNCTION_LAMBDA_ROLE` |
| `SERVERLESS_LAMBDA_SUBHOSTING_URL` |
`LOGIC_FUNCTION_LAMBDA_SUBHOSTING_URL` |
| `SERVERLESS_LAMBDA_ACCESS_KEY_ID` |
`LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID` |
| `SERVERLESS_LAMBDA_SECRET_ACCESS_KEY` |
`LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY` |

### Breaking Changes

- Environment variables must be updated in production deployments
- Database migration renames `serverlessFunction` → `logicFunction`
tables
2026-01-28 01:42:19 +01:00
Etienne 0459f25dec Files v2 - Add new workspace field file upload resolver (#17325) 2026-01-22 13:15:52 +00:00
martmull f92c8a98a4 2114 extensibility manage serverless execution from built code (#17317)
Summary

- Serverless functions are now built when created/updated instead of at
execution time
  - Added builtHandlerPath field to track pre-built function artifacts
- Renamed base-typescript-project to seed-project with pre-built ESM
output included
- Renamed file folder enums for consistency (Functions → BuiltFunction,
SourceCode → Source)
  - supports backwards compatibility with existing serverless functions

Tested with all combinations
- storage : local driver and S3 driver
- serverless : local driver and lambda driver
2026-01-22 12:56:44 +01:00
martmull 02a181a49f Add endpoint to upload application file (#17270)
As title
2026-01-20 14:10:34 +00:00
Angel98518 92a080b704 Improve image upload error handling and validation (#17188)
- Add URL validation in getImageBufferFromUrl utility
- Add response status validation and content-type checking
- Add timeout and connection error handling with specific error messages
- Validate buffer is not empty before processing
- Validate file type detection results before proceeding
- Ensure detected file type is actually an image format
- Add proper type safety for Axios error handling

This improves robustness when uploading images from URLs by:
- Preventing invalid URLs from being processed
- Providing clear error messages for different failure scenarios
- Ensuring only valid image files are processed
- Handling network errors gracefully

---------

Co-authored-by: GitTensor Miner <miner@gittensor.io>
2026-01-19 08:40:02 +00:00
Etienne 76cbe59929 File v2 - update core.file table (#17172)
For the following, I'll create the issues first
2026-01-16 15:59:39 +00:00
Paul Rastoin 942d2fef83 Remove sync-metadata and IS_WORKSPACE_CREATION_V2_ENABLED feature flag (#16997)
# Introduction
Followup of
https://github.com/twentyhq/twenty/pull/17001#pullrequestreview-3638508738
close https://github.com/twentyhq/core-team-issues/issues/1910

We've completely decom the `sync-metadata` in production. We're now then
removing its implementation in favor of the v2.

## TODO:
- [x] Remove sync-metadata implem and commands
- [x] Remove workspace decorators 
- [x] Type each deprecated field to deprecated on their workspaceEntity
- [x] Remove the `workspace-sync-metadata` folder entirely
- [x] remove workspace migration
- [x] workspace migration removal migration
- [x] remove the `v2` references from workspace manager file names
- [x] remove the `v2` references from workspace manager modules
- [ ] Double check impact on translation file path updates


## Note
- Removed the gate logic
- Remains some service v2 naming, serverless needs to be migrated on v2
fully
- Removed workspaceMigration service app health consumption, making it
always returning up ( no more down ) cc @FelixMalfait ( quite obsolete
health check now, will require complete refactor once we introduce inter
app dependency etc )
2026-01-08 15:45:12 +00:00
Paul Rastoin e3ffdb0c2b [BREAKING_CHANGE_NESTED_WORKSPACE]Refactor FlatEntity typing in aim of introducing UniversalFlatEntity (#16701)
# Introduction
Added a `WorkspaceRelated` and `AllNonWorkspaceRelatedEntity` to
simplify the `FlatEntityFrom` that now do not expect a string literal to
omit and itself builds the related many to one entities foreign key
aggregators

We now have the type grain over relation to syncable or just workspace
related entities

Added a migrations that sets the fk on missing entities

## Next
In upcoming PR we will be able to introduce such below type
```ts
import { type CastRecordTypeOrmDatePropertiesToString } from 'src/engine/metadata-modules/flat-entity/types/cast-record-typeorm-date-properties-to-string.type';
import { type ExtractEntityManyToOneEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-many-to-one-entity-relation-properties.type';
import { type ExtractEntityOneToManyEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-one-to-many-entity-relation-properties.type';
import { type ExtractEntityRelatedEntityProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-related-entity-properties.type';
import { type RemoveSuffix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/remove-suffix.type';
import { type SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/types/syncable-entity.interface';

export type UniversalFlatEntityFrom<TEntity extends SyncableEntity> = Omit<
  TEntity,
  | `${ExtractEntityManyToOneEntityRelationProperties<TEntity> & string}Id`
  | ExtractEntityRelatedEntityProperties<TEntity>
  | 'application'
  | 'workspaceId'
  | 'applicationId'
  | keyof CastRecordTypeOrmDatePropertiesToString<TEntity>
> &
  CastRecordTypeOrmDatePropertiesToString<TEntity> & {
    [P in ExtractEntityManyToOneEntityRelationProperties<TEntity> &
      string as `${RemoveSuffix<P, 's'>}UniversalIdentifier`]: string;
  } & {
    [P in ExtractEntityOneToManyEntityRelationProperties<
      TEntity,
      SyncableEntity
    > &
      string as `${RemoveSuffix<P, 's'>}UniversalIdentifiers`]: string[];
  };

```
2025-12-30 13:47:02 +00:00
Marie 19c9f957b1 Improve userFriendlyMessage devX (#16815)
Two challenges with error messages
- always provide a useful/meaningful error message for the end user
instead of the generic one. eg: show "Wrong password" and not "An error
occured"
- avoid technical details unless error regards a technical feature. eg:
show "An error occured" and not "Invalid post-hook payload."; but do
show "Invalid issuer URL." as it occurs while configuring SSO

What this PR does
- Make userFriendlyMessage mandatory for widely used
GraphqlQueryRunnerException and CommonQueryRunnerException, so that
developers are forced to ask themselves what the error message should
be, and as it contains very wide error codes (eg: "Bad request") which
should not be mapped to just one default message
- Keep userFriendlyMessage optional for service-specific exceptions (eg:
workflowStepExecutorException), but convert the error code to
userFriendlyMessage mapper to a switch case function with a typecheck
ensuring that all codes are mapped to a message. These default messages
are still overridable where they are thrown.
2025-12-30 09:08:43 +00:00
martmull 1cbbd04761 Function trigger updates 2 (#16608)
- Improves route trigger job performances
- expose function params types

## Before

<img width="938" height="271" alt="image"
src="https://github.com/user-attachments/assets/5752ba64-f31d-44ed-974d-536e63458f2c"
/>


## After

<img width="1000" height="559" alt="image"
src="https://github.com/user-attachments/assets/b1f4927a-5f43-49f0-a606-244c72356772"
/>
2025-12-16 18:20:26 +01:00
Félix Malfait 04c596817a feat(server): enforce userFriendlyMessage on all exceptions (#16589)
## Summary
This PR enforces that all custom exceptions must provide a
`userFriendlyMessage`, ensuring end users always see readable error
messages.

## Changes

### Core Changes
- **`CustomException` simplified**: Removed the `ForceFriendlyMessage`
generic parameter - `userFriendlyMessage` is now always required
- **Type safety**: The constructor now requires `{ userFriendlyMessage:
MessageDescriptor }` (no longer optional)

### Updated Files
- **74+ exception classes** updated to provide default user-friendly
messages using Lingui `msg` macro
- Each exception class has a sensible fallback message (e.g., `msg\`An
authentication error occurred.\``)
- Exception classes that had code-specific message maps retain their
behavior

## Benefits
- **Compile-time enforcement**: Forgetting to add a user-friendly
message now causes a TypeScript error
- **Better UX**: End users always see a localized, human-readable error
message
- **Simpler API**: No more boolean generic parameter to think about

## Testing
- `npx nx run twenty-server:typecheck` passes
- `npx nx run twenty-server:lint` passes

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Enforces `userFriendlyMessage` on `CustomException` and updates all
exception classes to supply localized default messages, with
filters/tests adjusted accordingly.
> 
> - **Core**:
> - Enforce required `userFriendlyMessage` in `CustomException` (remove
optional generic; constructor now requires `{ userFriendlyMessage:
MessageDescriptor }`).
> - **Exceptions**:
> - Update ~70+ exception classes to set default localized messages via
Lingui `msg` maps and pass them in constructors (e.g., `AuthException`,
`ObjectMetadataException`, `FieldMetadataException`, etc.).
> - Add fallback messages where needed (e.g., `INTERNAL_SERVER_ERROR` or
domain-specific defaults).
> - **HTTP/GraphQL Filters**:
> - Ensure fallbacks create `UnknownException` with `msg` for
user-friendly text in REST/GraphQL exception filters.
> - **Tests**:
>   - Adjust unit tests to pass `userFriendlyMessage` to exceptions.
> - Update Jest snapshots to include `extensions.userFriendlyMessage` or
message objects where applicable.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
221004fdfc0d97b7d152a258b347bf571e70f10e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-16 14:44:27 +01:00
martmull e289f3056e 1895 extensibility v1 application tokens 3 (#16504)
- moves applicationRoleId to application entity
- add new `APPLICATION` FieldActorSource and `APPLICATION`
JwtTokenTypeEnum value
- create a new token with applicationId when executing a function
- when applicationId is in token, check for application.defaultRole
permissions
-use twenty-shared types in `twenty-sdk/application`
- create a new import from generate called "Twenty" that you can use
directly without having to set TWENTY_API_KEY AND TWENTY_API_URL (keep
metadata or core parameter only)
- provide to serverless unique one time BEARER TOKEN to run it

Result
<img width="977" height="566" alt="image"
src="https://github.com/user-attachments/assets/e78428a0-5b13-4975-aa13-58ee3b32450c"
/>

<img width="910" height="596" alt="image"
src="https://github.com/user-attachments/assets/6ec72bf5-7655-4093-a45e-ad269595a324"
/>

<img width="741" height="568" alt="image"
src="https://github.com/user-attachments/assets/7683944c-fd79-4417-8fb2-8e4815cc112f"
/>
2025-12-15 17:44:23 +01:00
Abdul Rahman ae2919e564 fix: migrate wildcard routes to named parameters (#16380)
Closes #16189

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-12-09 09:52:32 +01:00
martmull 7f1e69740a 1895 extensibility v1 application tokens (#16365)
First PR to implement application tokens
- add new application role in twenty-server
- move duplicated constants and types to twenty-shared
- will  add role configuration utils into twenty-sdk in another PR
2025-12-08 10:42:46 +01:00
Charles Bochet eb362c6d5f Update workspace entities to make all TEXT nullable (#16144)
Follow up on #15926

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Co-authored-by: guillim <guigloo@msn.com>
2025-11-28 10:50:38 +01:00
Abdullah. 991bb6dbbf fix: crash in HeaderParser in dicer. (#15963)
Resolves [Dependabot Alert
74](https://github.com/twentyhq/twenty/security/dependabot/74).

Upgraded `graphql-upload` from `13.0.0` to `16.0.2`. Type exports
changed. API remains the same.

Tested the following upload flows:
- profile picture
- workspace logo
- rich text editor (image, video, file)
- record profile picture
- file associated to record.

They all work as intended, nothing breaks.
2025-11-21 11:09:47 +01:00
Félix Malfait bf638c3a4e Fix file controller route parameter extraction (#15924)
## Problem
When accessing file URLs like `/files/attachment/{token}/{filename}`,
the server was returning 500 errors with no logs. The issue was that the
route pattern `*path/:filename` was not properly extracting parameters,
causing `request.params[0]` to be undefined.

## Solution
- Changed route from `@Get('*path/:filename')` to
`@Get(':folder/:token/:filename')` for explicit parameter extraction
- Simplified `extractFileInfoFromRequest` to use named route parameters
directly instead of complex path parsing
- Removed unnecessary logging that was added during debugging
- Added test to verify route parameters are correctly extracted and
passed to FileService

## Testing
- Added unit test that verifies folder, token, and filename parameters
are correctly passed to the service
- Test will catch any future regressions where route parameters are not
properly extracted
2025-11-19 14:12:34 +01:00
Félix Malfait 5dfb66917c Upgrade NestJS from 10.x to 11.x (#15836)
## Overview
This PR upgrades all NestJS dependencies from version 10.x to 11.x,
following the [official migration
guide](https://docs.nestjs.com/migration-guide). This builds on top of
the v9 to v10 upgrade completed in PR #15835.

## Changes

### Dependencies Updated
**Core packages (10.x → 11.x):**
- `@nestjs/common`: 10.4.16 → 11.0.8
- `@nestjs/core`: 10.4.16 → 11.0.8
- `@nestjs/platform-express`: 10.4.16 → 11.0.8
- `@nestjs/config`: 3.2.3 → 3.3.0
- `@nestjs/passport`: 10.0.3 → 11.0.0
- `@nestjs/axios`: 3.0.2 → 3.1.2
- `@nestjs/schedule`: ^3.0.0 → ^4.1.1
- `@nestjs/serve-static`: 4.0.2 → 5.0.1
- `@nestjs/cache-manager`: ^2.2.1 → ^2.3.0
- `@nestjs/jwt`: 10.2.0 → 11.0.0
- `@nestjs/typeorm`: 10.0.2 → 11.0.0
- `@nestjs/terminus`: 11.0.0 (already on v11)
- `@nestjs/event-emitter`: 2.1.0 (compatible)

**DevDependencies:**
- `@nestjs/testing`: ^10.4.16 → ^11.0.8
- `@nestjs/schematics`: ^10.1.0 → ^11.0.2
- `@nestjs/cli`: 10.3.0 → 11.0.0

### Code Changes
**Fixed: TwentyConfigModule conditional imports**
- Updated `TwentyConfigModule.forRoot()` to use spread operator for
conditional imports
- Fixes TypeScript error with NestJS 11's stricter DynamicModule type
checking

**Cleanup: Removed unused package**
- Removed `@revertdotdev/revert-react` (not being used anywhere in the
codebase)

## Breaking Changes Addressed

### 1.  Reflector Type Inference
- **Impact**: None - codebase only uses `reflector.get()` method
- **Analysis**: Does not use `getAllAndMerge()` or `getAllAndOverride()`
(the methods with breaking changes)
- **Files reviewed**: feature-flag.guard.ts,
message-queue-metadata.accessor.ts,
workspace-query-hook-metadata.accessor.ts

### 2.  Lifecycle Hooks Execution Order
- **Change**: Termination hooks (`OnModuleDestroy`,
`BeforeApplicationShutdown`, `OnApplicationShutdown`) now execute in
REVERSE order
- **Analysis**: Reviewed all lifecycle hook implementations
  - Redis client cleanup
  - Database connection cleanup (GlobalWorkspaceDataSource)
  - BullMQ queue/worker cleanup
  - Cache storage cleanup
- **Result**: Dependency order is safe - services using connections
clean up before the connections themselves

### 3.  Middleware Registration Order
- **Change**: Global middleware now executes first regardless of import
order
- **Analysis**: Middleware is not registered as global, so execution
order remains consistent
- **Files reviewed**: app.module.ts, middleware.module.ts

## Testing

All tests passing and build successful:

**Unit Tests (283+ tests):**
-  Health module: 38 tests passed
-  Auth module: 115 tests passed (passport v11 integration)
-  REST API: 90 tests passed (middleware and express platform)
-  Feature flags: 17 tests passed (Reflector usage)
-  Workspace: 23 tests passed

**Build & Quality:**
-  Type checking: Passed
-  Linting: Passed
-  Build: 3,683 files compiled successfully

## Verification

Tested critical NestJS functionality:
-  Authentication & Security (JWT, OAuth, guards)
-  HTTP Platform (Express integration, REST endpoints)
-  Dependency Injection (Services, factories, providers)
-  Cache Management (Redis with @nestjs/cache-manager)
-  GraphQL (Query runners, resolvers)
-  Configuration (Environment config)
-  Scheduling (Cron jobs with @nestjs/schedule v4)
-  Lifecycle Hooks (Module initialization and cleanup)
-  Reflector (Metadata reflection in guards)

## Related PRs
- #15835 - Upgrade NestJS from 9.x to 10.x (completed)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Upgrades NestJS to v11 and updates routing patterns, auth strategies,
GraphQL schema options, and build/dist paths (scripts, Docker, Nx,
migrations, assets), plus enables Devtools in development.
> 
> - **Backend (NestJS 11 upgrade)**:
> - Bump `@nestjs/*` packages (core, platform-express, jwt, passport,
typeorm, serve-static, schedule, cli/testing/schematics) to v11.
> - Update REST/route-trigger/file controllers to new wildcard syntax
(`*path`).
> - Refactor OAuth (Google/Microsoft) and SAML strategies (abstract base
+ explicit `validate`); minor typings.
>   - Enable `DevtoolsModule` in development.
> - **GraphQL**:
> - Add `buildSchemaOptions.orphanedTypes` for client-config types; keep
Yoga/Sentry setup.
> - **Build/Runtime & Config**:
> - Standardize dist layout (remove `src` in paths): update scripts,
Docker `CMD`, Nx `project.json`, render scripts, TypeORM migration
paths, asset resolution.
> - Adjust `nest-cli.json` (watchOptions, asset globs, migrations
outDir, monorepo/root).
> - Improve config module imports (spread conditional); tsconfig
excludes `node_modules`.
>   - Minor Nx default: `start` target caching disabled.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1139fd85a97d0c72314d416d07464cc3c9942783. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-11-16 18:20:06 +01:00
Félix Malfait 9a80164cf3 Add comprehensive permission guard coverage across GraphQL and REST endpoints (#15739)
This PR enhances our security model by ensuring all GraphQL resolvers
and REST API endpoints have appropriate permission guards.

## Changes

### ESLint Rules
- Enhanced `graphql-resolvers-should-be-guarded` to require permission
guards on all resolvers (Query, Mutation, Subscription), not just
mutations
- Enhanced `rest-api-methods-should-be-guarded` to require permission
guards on all REST endpoints (GET, POST, PUT, PATCH, DELETE), not just
mutating methods
- Both rules now enforce consistent security: authentication guards +
permission guards for all endpoints

### Permission Guards Added

**Public Endpoints** - Added `NoPermissionGuard`:
- Auth-related queries (checkUserExists, findWorkspaceFromInviteHash,
validatePasswordResetToken)
- Billing webhooks (Stripe callbacks)
- SSO callbacks (SAML authentication)
- Workflow webhooks
- Cloudflare webhooks
- Route trigger endpoints
- GraphQL subscriptions
- Current workspace queries
- Geo-map address autocomplete
- View-related read operations (view-field, view-filter, view-group,
view-sort, view-filter-group)

**Settings Permission Guards** - Added `SettingsPermissionGuard`:
- API Keys management: `PermissionFlagType.API_KEYS_AND_WEBHOOKS`
- Webhooks management: `PermissionFlagType.API_KEYS_AND_WEBHOOKS`
- Page Layouts (write operations): `PermissionFlagType.LAYOUTS`
- REST Metadata API: `PermissionFlagType.DATA_MODEL`
- Agent operations: `PermissionFlagType.AI`
- Remote servers: `PermissionFlagType.DATA_MODEL`
- Remote tables: `PermissionFlagType.DATA_MODEL`
- Serverless functions: `PermissionFlagType.WORKFLOWS`

**Custom Permission Guards** - Added `CustomPermissionGuard`:
- REST Core API (permissions checked at query execution layer)
- Timeline calendar events (permission checks in service layer)
- Timeline messaging (permission checks in service layer)
- Search operations (permission checks in service layer)
- View operations (permission checks via dedicated view permission
guards)

### View Permission Guards
- Created dedicated `FindManyViewsPermissionGuard` and
`FindOneViewPermissionGuard` for reading views
- Created `CreateViewPermissionGuard` for view creation with
visibility-based permission checks
- All view child entities (view-field, view-filter, view-sort,
view-group, view-filter-group) use `NoPermissionGuard` for reads
- Write operations on view child entities use dedicated permission
guards that check parent view access

### Page Layout Permissions
- Read operations (GET/Query) now use `NoPermissionGuard` - users can
view layouts without LAYOUTS permission
- Write operations (POST/PATCH/DELETE/Mutation) require
`SettingsPermissionGuard(PermissionFlagType.LAYOUTS)`
- Applied consistently across page-layout, page-layout-tab, and
page-layout-widget endpoints

## Security Model
All endpoints now follow a consistent pattern:
1. **Authentication**: `UserAuthGuard`, `WorkspaceAuthGuard`, or
`PublicEndpointGuard`
2. **Authorization**: One of:
- `SettingsPermissionGuard(PermissionFlagType.XXX)` - for settings/admin
operations
- `CustomPermissionGuard` - when permissions are checked in service/data
layer
   - `NoPermissionGuard` - for public or non-sensitive read operations

The ESLint rules automatically enforce this pattern going forward.

## Stats
- 47 files changed
- 603 insertions, 163 deletions
- 3 new guard files created
2025-11-10 12:17:38 +01:00
Félix Malfait b7f5445926 fix: rename SettingsPermissionsGuard to SettingsPermissionGuard for consistency (#15712)
## Problem

The ESLint rule `graphql-resolvers-should-be-guarded` introduced in
#15392 was failing on main because the guard `SettingsPermissionsGuard`
had inconsistent naming.

## Root Cause

The guard was named `SettingsPermissionsGuard` (with an 's') which was
inconsistent with other permission guards:
-  `CustomPermissionGuard`  
-  `NoPermissionGuard`
-  `ImpersonatePermissionGuard`
-  `SettingsPermissionsGuard` (inconsistent!)

The ESLint rule checks if guard names end with `PermissionGuard`, but
`SettingsPermissionsGuard` ends with `sGuard`, so it wasn't recognized
as a permission guard.

## Solution

Renamed the guard to be consistent with the naming convention:

1.  Renamed file: `settings-permissions.guard.ts` →
`settings-permission.guard.ts`
2.  Renamed export: `SettingsPermissionsGuard` →
`SettingsPermissionGuard`
3.  Renamed internal class: `SettingsPermissionsMixin` →
`SettingsPermissionMixin`
4.  Updated all 122 references across 44 files in the codebase
5.  Renamed test file: `settings-permissions.guard.spec.ts` →
`settings-permission.guard.spec.ts`

## Testing

-  `npx nx run twenty-server:lint` passes
-  `npx nx run twenty-server:typecheck` passes
-  No references to the old name remain in the codebase
-  All previously failing resolver files now pass ESLint validation

## Related

Fixes issues introduced in #15392
2025-11-07 18:22:28 +01:00
Félix Malfait cff17db6cb Enhance role-check system with stricter checks (#15392)
## 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.
2025-11-07 15:37:17 +01:00
Félix Malfait c5564d9bd0 [BREAKING CHANGE] refactor: Add Entity suffix to TypeORM entity classes (#15239)
## Summary

This PR refactors all TypeORM entity classes in the Twenty codebase to
include an 'Entity' suffix (e.g., User → UserEntity, Workspace →
WorkspaceEntity) to improve code clarity and follow TypeORM naming
conventions.

## Changes

### Entity Renaming
-  Renamed **57 core TypeORM entities** with 'Entity' suffix
-  Updated all related imports, decorators, and type references
-  Fixed Repository<T>, @InjectRepository(), and
TypeOrmModule.forFeature() patterns
-  Fixed @ManyToOne/@OneToMany/@OneToOne decorator references

### Backward Compatibility
-  Preserved GraphQL schema names using @ObjectType('OriginalName')
decorators
-  **No breaking changes** to GraphQL API
-  **No database migrations** required
-  File names unchanged (user.entity.ts remains as-is)

### Code Quality
-  Fixed **497 TypeScript errors** (82% reduction from 606 to 109)
-  **All linter checks passing**
-  Improved type safety across the codebase

## Entities Renamed

```
User → UserEntity
Workspace → WorkspaceEntity
ApiKey → ApiKeyEntity
AppToken → AppTokenEntity
UserWorkspace → UserWorkspaceEntity
Webhook → WebhookEntity
FeatureFlag → FeatureFlagEntity
ApprovedAccessDomain → ApprovedAccessDomainEntity
TwoFactorAuthenticationMethod → TwoFactorAuthenticationMethodEntity
WorkspaceSSOIdentityProvider → WorkspaceSSOIdentityProviderEntity
EmailingDomain → EmailingDomainEntity
KeyValuePair → KeyValuePairEntity
PublicDomain → PublicDomainEntity
PostgresCredentials → PostgresCredentialsEntity
...and 43 more entities
```

## Impact

### Files Changed
- **400 files** modified
- **2,575 insertions**, **2,191 deletions**

### Progress
-  **82% complete** (497/606 errors fixed)
- ⚠️ **109 TypeScript errors** remain (18% of original)

## Remaining Work

The 109 remaining TypeScript errors are primarily:

1. **Function signature mismatches** (~15 errors) - Test mocks with
incorrect parameter counts
2. **Entity type mismatches** (~25 errors) - UserEntity vs
UserWorkspaceEntity confusion
3. **Pre-existing issues** (~50 errors) - Null safety and DTO
compatibility (unrelated to refactoring)
4. **Import type issues** (~10 errors) - Entities imported with 'import
type' but used as values
5. **Minor decorator issues** (~9 errors) - onDelete property
configurations

These can be addressed in follow-up PRs without blocking this
refactoring.

## Testing Checklist

- [x] Linter passing
- [ ] Unit tests should be run (CI will verify)
- [ ] Integration tests should be run (CI will verify)
- [ ] Manual testing recommended for critical user flows

## Breaking Changes

**None** - This is a pure refactoring with full backward compatibility:
- GraphQL API unchanged (uses original entity names)
- Database schema unchanged
- External APIs unchanged

## Notes

- Created comprehensive `REFACTORING_STATUS.md` documenting the entire
process
- All temporary scripts have been cleaned up
- Branch: `refactor/add-entity-suffix-to-typeorm-entities`

## Reviewers

Please review especially:
- Entity renaming patterns
- GraphQL backward compatibility
- Any areas where entity types are confused (UserEntity vs
UserWorkspaceEntity)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-10-22 09:55:20 +02:00
Félix Malfait f7421c5fc0 Add queue management dashboard (#15202)
Adds a comprehensive queue management interface to the admin panel for
viewing and managing background jobs.

**Features:**
- Queue detail pages showing paginated job lists (50 per page)
- Filter jobs by state: completed, failed, active, waiting, delayed,
paused
- Checkbox selection with bulk actions (delete jobs, retry failed jobs)
- Per-job dropdown menu for individual retry/delete
- Expandable rows showing error messages, stack traces, and job data
- Relative timestamps with hover tooltips
- Display attempt counts on failed jobs
- Dynamic retention policy info from backend

**Changes:**
- Backend: New AdminPanelQueueService with GraphQL endpoints for job
listing, retry, and delete
- Frontend: Queue detail page with QueueJobsTable component
- Updated retention policy: completed jobs kept 4 hours, failed jobs
kept 7 days (max 1000 each)
- Added JobState enum for type safety

<img width="634" height="696" alt="Screenshot_2025-10-20_at_11 45 25"
src="https://github.com/user-attachments/assets/c67bcd27-26cf-47f5-9575-3cd5684d006b"
/>
<img width="484" height="680" alt="Screenshot_2025-10-20_at_11 45 14"
src="https://github.com/user-attachments/assets/68725cc6-b3ec-4098-99ca-f9a717d6f8f1"
/>
<img width="490" height="643" alt="Screenshot_2025-10-20_at_11 45 05"
src="https://github.com/user-attachments/assets/b68a5809-33ff-4452-b48b-741aff7f1dd6"
/>



<img width="685" height="662" alt="Screenshot 2025-10-20 at 13 15 01"
src="https://github.com/user-attachments/assets/eeb5207b-de5c-4b18-bdde-392892053dab"
/>
2025-10-21 16:02:50 +02:00
martmull c681fb7fb6 1658 post mortem 0710 send batch events in webhook (#15022)
Use concurrent calls

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-10-11 12:48:40 +02:00
Abdul Rahman 0648dc5c65 Fix AI chat streaming persistence when command menu closes (#14854)
Closes [#1583](https://github.com/twentyhq/core-team-issues/issues/1583)


- Removed `messageId` column from `File` table and its references in
code (unrelated to this PR)
- Updated AI chat to use React Context API with persistent provider in
`CommandMenuContainer`
- Converted all AI chat component states to regular Recoil atoms (no
instance context needed)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-10-03 12:37:41 +02:00
Abdul Rahman 2685f4a5b9 Restructure agent chat messages with parts-based architecture (#14749)
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-09-29 13:31:55 +02:00
Weiko 584389e17f add code checksum to flat serverless function (#14721)
## Context
Now adding serverless code sync within the migration v2 logic itself. To
do that we need to follow the
- Prepare flat input
- Build migration
- Run migration
steps where now the serverless function entity will store in DB and
cache a checksum of its code and the flat input will contain the code
with the checksum. Build will compare checksum and create an update
action containing the code if it has changed and the migration will now
run the corresponding services (instead of calling those in the parent
serverless service exposed in the API) allowing us to keep that logic
functional for other use cases such as import/export, twenty-cli and
twenty upgrades.
2025-09-26 10:24:36 +02:00
Abdul Rahman 8d9617131c Feat: Add reasoning summary and tool details display for AI responses (#14414)
Closes [#1405](https://github.com/twentyhq/core-team-issues/issues/1405)

### Implemented Features
- Reasoning Summary: Collapsible display of AI thinking process with
real-time streaming
- Tool Execution: Detailed tool call rendering with expandable results
and loading states
- Error Handling: Clean error stream event display with proper
formatting


### Demo



https://github.com/user-attachments/assets/76ad29b7-d831-4bc8-a115-ad25f7ace6e2

<img width="504" height="819" alt="Screenshot 2025-09-12 at 3 23 39 AM"
src="https://github.com/user-attachments/assets/82dc177d-f009-4e8a-8901-ee1a49201984"
/>

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-09-17 11:30:24 +02:00
Raphaël Bosi 0bdd1c4803 Various fixes on core views (#14093)
- Fix fragments
- Add id to create inputs
- Refresh core views
- Fix kanban loading
- Fix core views creation from current view

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-08-29 11:20:56 +02:00
Weiko 533d7fe49a Deprecate legacy core datasource token (#14096) 2025-08-27 20:09:54 +02:00
Félix Malfait 3c0f3fd2ae Run yarn dedupe and upgrade TS (#13853)
Upgrading TS to the latest version, and cleaning up packages with yarn
dedupe
2025-08-12 15:18:59 +02:00
Félix Malfait 0236f79ccf Fix assert unreachable, remove unused variables (#13753)
Small code cleanup
2025-08-08 09:04:45 +02:00
Félix Malfait 8b4b9ef8da Change type import rule (#13751)
Forcing "type" to be explicit, works best will rollup on the frontend to
exclude depdendencies
2025-08-08 01:27:05 +02:00
Félix Malfait b44b46109c Update try/catch syntax (#13732)
Update try/catch syntax to prepare for eslint migration
2025-08-07 22:19:43 +02:00
Abdul Rahman 01f25519f6 fix: standardize GraphQL schema UUID field types (#13550)
Closes [#1264](https://github.com/twentyhq/core-team-issues/issues/1264)
2025-08-04 11:43:48 +02:00
Antoine Moreaux 23353e31e6 feat(domain-manager): refactor custom domain validation and improve c… (#13388) 2025-08-01 09:01:27 +02:00
Etienne 5c15a5954b Workspace Folder Deletion Error - add logs for investigation (#13385)
https://twenty-v7.sentry.io/issues/6565008010/events/latest/?environment=prod&project=4507072499810304&referrer=latest-event&sort=date

related to https://github.com/twentyhq/twenty/issues/12299
2025-07-24 13:34:41 +00:00
Etienne 21fb68b9e2 Fix workspace folder deletion error (#13270)
context : workspace folder deletion throws error when folder does not
exist (in case, workspace users have not upload any files (profil pic,
workflows, attachments, ...))
-> sentry errors :
https://twenty-v7.sentry.io/issues/6565008010/?referrer=github_integration

solution : check folder existence before deleting

test local and s3 storage : 
- create a workspace and delete workspace
- create a workspace, add an attachment and delete workspace

closes : https://github.com/twentyhq/twenty/issues/10745
closes : https://github.com/twentyhq/twenty/issues/12299
2025-07-17 23:01:02 +02:00
Abdul Rahman 72fd3b07e7 Add file support to agent chat (#13187)
https://github.com/user-attachments/assets/911d5d8d-cc2e-4c18-9f93-2663d84ff9ef

---------

Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
Co-authored-by: neo773 <62795688+neo773@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@twenty.com>
Co-authored-by: MD Readul Islam <99027968+readul-islam@users.noreply.github.com>
Co-authored-by: readul-islam <developer.readul@gamil.com>
Co-authored-by: Thomas des Francs <tdesfrancs@gmail.com>
Co-authored-by: Guillim <guillim@users.noreply.github.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-07-15 08:57:10 +02:00