Commit Graph
22 Commits
Author SHA1 Message Date
a63b31931f Extract SecureHttpClientService into its own module (#17828)
## Summary

- **Extract `SecureHttpClientService`** from `tool` module into a
dedicated `core-modules/secure-http-client/` module with proper NestJS
module encapsulation
- **Fix module hygiene**: 12 modules that incorrectly listed
`SecureHttpClientService` as a direct provider now properly import
`SecureHttpClientModule`
- **Add structured logging** for outbound HTTP requests with
workspace/user context (for GuardDuty alert correlation)
- **Rename type files** to follow one-export-per-file convention
(`get-secure-axios-adapter.types.ts` ->
`secure-adapter-dependencies.type.ts`, new
`outbound-request-context.type.ts` / `outbound-request-source.type.ts`)

### Why

`SecureHttpClientService` is a cross-cutting concern (used by auth,
captcha, file upload, geo-map, telemetry, admin-panel, REST API, contact
creation, webhooks, and workflow tools) but was bundled inside the
`tool` module. Most consumers worked around this by listing it as a
direct provider instead of importing a module, which is fragile and not
idiomatic NestJS.

## Test plan

- [x] All 60 unit tests pass (`secure-http-client.service.spec.ts`,
`get-secure-axios-adapter.util.spec.ts`, `is-private-ip.util.spec.ts`)
- [x] Related module tests pass (admin-panel, contact-creation, tool)
- [x] `npx nx typecheck twenty-server` passes
- [x] `npx nx lint:diff-with-main twenty-server` passes
- [x] Server compiles and bootstraps successfully


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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 09:16:51 +00:00
Félix MalfaitGitHubCursorclaude[bot] <41898282+claude[bot]@users.noreply.github.com>
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
MarieandGitHub 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
Félix MalfaitandGitHub 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
221004fdfc. 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
Félix MalfaitandGitHub e577c2d746 Update user friendly errors for translations (#15000)
Force msg typing instead of string for user friendly errors
2025-10-09 18:17:32 +02:00
Félix MalfaitandGitHub 0236f79ccf Fix assert unreachable, remove unused variables (#13753)
Small code cleanup
2025-08-08 09:04:45 +02:00
Félix MalfaitandGitHub 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
Antoine MoreauxandGitHub 23353e31e6 feat(domain-manager): refactor custom domain validation and improve c… (#13388) 2025-08-01 09:01:27 +02:00
Charles BochetandGitHub fdc6705a75 Remove old body on note and tasks (#13290)
Fixes: https://github.com/twentyhq/twenty/issues/13110

I'm deprecating note.body and task.body to remove confusion between body
and bodyV2

What will be left but should be done later to avoid breaking changes:
- re-add a body field in the graphql API only that points to the same
bodyV2 field in SQL (need to be handled in fields and filter for note
and task)
- (wait some time)
- remove bodyV2 field
2025-07-19 11:25:49 +02:00
Antoine MoreauxandGitHub b7e72c3aa6 feat(captcha): improve telemetry on captcha error (#12836) 2025-06-24 17:43:03 +02:00
Félix MalfaitandGitHub 4485e8e3db Update enums to be all caps (#12372)
- Make custom domain public (remove from lab)
- Use ALL_CAPS definition for enums
2025-05-29 14:08:36 +02:00
d133055609 Fix Client Config async loading (#12308)
Fix ClientConfig async loading

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-28 10:40:20 +02:00
Félix MalfaitandGitHub 9cdd0fdac0 Revert "Client config not render blocking (#12300)" (#12302)
This reverts commit 4ce7fc6987, to take
more time to address PR comments
2025-05-27 09:04:47 +02:00
Félix MalfaitandGitHub 4ce7fc6987 Client config not render blocking (#12300)
Changes for performance improvement.
The primary improvements include replacing GraphQL queries with
REST-based client configuration fetching and making the client config
non render-blocking
2025-05-27 00:06:48 +02:00
EtienneandGitHub 0ac4cc6899 captcha - keep consistency with token send to validation (#12195)
[Sentry
error](https://twenty-v7.sentry.io/issues/6494360796/events/322590f8af5c4475beebb66e5f22a2f7/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=previous-event&seerDrawer=true&sort=date&stream_index=6)
raised because of invalid argument type (undefined in some case when
string is expected)

closes https://github.com/twentyhq/core-team-issues/issues/869 and
closes https://github.com/twentyhq/twenty/issues/12208
2025-05-22 13:49:23 +02:00
a8423e8503 [QRQC_2] No explicit any in twenty-server (#12068)
# Introduction

Added a no-explicit-any rule to the twenty-server, not applicable to
tests and integration tests folder

Related to https://github.com/twentyhq/core-team-issues/issues/975
Discussed with Charles

## In case of conflicts
Until this is approved I won't rebased and handle conflict, just need to
drop two latest commits and re run the scripts etc

## Legacy
We decided not to handle the existing lint error occurrences and
programmatically ignored them through a disable next line rule comment

## Open question
We might wanna activate the
[no-explicit-any](https://typescript-eslint.io/rules/no-explicit-any/)
`ignoreRestArgs` for our use case ?
```
    ignoreRestArgs?: boolean;
```

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-05-15 16:26:38 +02:00
nitinandGitHub bd3ec6d5e3 rename core-module environment to twenty-config (#11445)
closes https://github.com/twentyhq/core-team-issues/issues/759
2025-04-09 14:11:26 +02:00
EtienneandGitHub 391392dd87 set up metrics collecting with open telemetry (#11236)
Done :  
- move metrics and health cache services from health module to metrics
module
- refactor metrics counter from specific method to set up from enum keys
- add OpenTelemetry (Otel) instrumentation for metrics
- set up Otel SDK to send metrics to Otel collector

To do later : 
- implement Otel instrumentation for traces + plug Sentry on top
2025-03-28 08:45:24 +01:00
EtienneandGitHub 96035f0ccf fix redis concurrency issue in health metrics + remove ongoing status count (#10717)
### Context
For calendar and message sync job health monitoring, we used to
increment a counter in redis cache which could lead to concurrency
issue.

### Solution
- Update to a set structure in place of counter + use sAdd redis method
which is atomic
- Each minute another counter was incremented on a new cache key ->
Update to a 15s window
- Remove ONGOING status not needed. We only need status at job end (or
fail).


###  Potential improvements
- Check for cache key existence before fetching data to avoid useless
call to redis ?

closes https://github.com/twentyhq/twenty/issues/10070
2025-03-07 14:41:46 +01:00
0210e07497 Only use CAPTCHA in logged out operations and pages (#10607)
Issue #10235

---------

Co-authored-by: ad-elias <elias@autodiligence.com>
2025-03-07 11:03:30 +01:00
EtienneandGitHub d4ffd52988 add invalid captcha and messageChannel sync status health monitoring (#10029)
Context : 
We want to implement some counters to monitor server health. First
counters will track : messageChannel sync status during job execution
and invalid captcha.

How : 
Counters are stored in cache and grouped by one-minute windows.
Controllers are created for each metric, aggregating counter over a
five-minutes window.
Endpoints are public and will be queried by Prometheus.

closes https://github.com/twentyhq/core-team-issues/issues/55
2025-02-10 11:24:42 +00:00
martmullandGitHub 3190f4a87b 6658 workflows add a first twenty piece email sender (#6965) 2024-09-12 11:00:25 +02:00