Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 27d60f2145 Stale cached frontend bundle accesses renamed auth token field, causing TypeError
https://sonarly.com/issue/9837?type=bug

A user's browser running a stale cached frontend bundle (pre-auth-refactoring) tries to access `tokenPair.accessToken.token`, but the server now returns tokens under `accessOrWorkspaceAgnosticToken`, causing a TypeError on the `/welcome` page after Microsoft SSO redirect.

Fix: ## Root cause addressed

The Sentry `release` tag in `SentryInitEffect.tsx` was populated from `sentryConfig.release`, which the client fetches at runtime from the server's client config API (same as `APP_VERSION` on the server). This means every browser — including ones running a **stale cached bundle from a previous deployment** — always reports the *server's* current version to Sentry, hiding the frontend/backend version mismatch entirely.

The same applies to the `X-App-Version` header used for server-side version mismatch detection: the client sends the server's own version back at it, so the server's `APP_VERSION_MISMATCH` guard never fires for stale bundles.

## Fix

Two minimal changes that embed the build-time version directly in the JS bundle:

### 1. `packages/twenty-front/vite.config.ts` — inject `APP_VERSION` at build time

```typescript file=packages/twenty-front/vite.config.ts lines=34,256
// Destructure APP_VERSION from the loadEnv result:
APP_VERSION,   // added

// Add to the process.env define block:
REACT_APP_BUNDLE_VERSION: APP_VERSION,   // added
```

`loadEnv(mode, __dirname, '')` already loads **all** env vars (the empty-string prefix means no filtering). We just surface `APP_VERSION` (the same env var the server reads) into `process.env.REACT_APP_BUNDLE_VERSION` so it is statically replaced in the JS bundle at build time. When `APP_VERSION` is not set in the build environment the value falls back to `undefined`, preserving the existing behaviour.

### 2. `packages/twenty-front/src/modules/error-handler/components/SentryInitEffect.tsx` — prefer build-time version for Sentry `release`

```typescript file=packages/twenty-front/src/modules/error-handler/components/SentryInitEffect.tsx lines=41-47
release:
  process.env.REACT_APP_BUNDLE_VERSION ??
  sentryConfig?.release ??
  undefined,
```

`process.env.REACT_APP_BUNDLE_VERSION` is baked into the bundle at **build time**. When a user's browser runs a stale cached bundle (pre-upgrade), Sentry will now tag every error with that bundle's own version number, not the server's current version. This makes stale-bundle incidents immediately visible in Sentry as errors filed under the *old* release rather than the *current* one. The fallback to `sentryConfig?.release` preserves existing behaviour for deployments that do not set `APP_VERSION` at frontend build time.

## Why this is the right minimal fix

The direct crash (`tokenPair.accessToken.token` TypeError) and its cookie-invalidation safeguard (`isValidAuthTokenPair`) are **already fixed** in the codebase (commits `f52973d71d` / `09dd49d6d6`). What remained unfixed is the observability gap that allowed the incident to go undetected and misattributed: Sentry reported the server's version (`v1.18.1`) even though the actual running JS was from a much older bundle, making root-cause analysis difficult. This change closes that gap.
2026-03-05 11:50:19 +00:00
Sonarly Claude Code 56f21c3a7c Missing null-safe access on token pair property crashes SSE subscription during SSO login
https://sonarly.com/issue/9838?type=bug

A subscription hook accessing `tokenPair.accessToken.token` without optional chaining on the nested property throws a TypeError when users arrive at `/welcome` from Microsoft SSO and the token pair is in an intermediate authentication state.

Fix: ## Root Cause

`useIsLogged` returns `true` for any truthy `tokenPair` value (`!!tokenPair`), but during a Microsoft SSO redirect to `/welcome`, the `tokenPairState` cookie can contain a stale or partially-populated object that has the top-level object but lacks `accessOrWorkspaceAgnosticToken.token` (the nested path that SSE subscription code requires). This causes downstream consumers like `SSEClientEffect` and `SSEEventStreamEffect` to believe the user is fully authenticated and proceed with token-dependent operations that then crash on `undefined.token`.

## Fix

Use the already-existing `isValidAuthTokenPair` utility in `useIsLogged` so that `isLoggedIn` is only `true` when the token pair is structurally complete — i.e., `accessOrWorkspaceAgnosticToken` is a non-null object with a `token` string property. This is a 1-file, 2-line change.

```tsx file=packages/twenty-front/src/modules/auth/hooks/useIsLogged.ts lines=1-8
import { tokenPairState } from '@/auth/states/tokenPairState';
import { isValidAuthTokenPair } from '@/apollo/utils/isValidAuthTokenPair';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';

export const useIsLogged = (): boolean => {
  const [tokenPair] = useAtomState(tokenPairState);
  return isValidAuthTokenPair(tokenPair);
};
```

This prevents all `isLoggedIn`-gated SSE logic from running on a partially-populated token pair, eliminating the null-dereference on the nested `.token` property during SSO login flows.
2026-03-05 11:48:30 +00:00
2 changed files with 9 additions and 1 deletions
@@ -38,7 +38,13 @@ export const SentryInitEffect = () => {
init({
environment: sentryConfig?.environment ?? undefined,
release: sentryConfig?.release ?? undefined,
// Prefer the build-time bundle version over the server-provided
// release tag. The server reports its own runtime version, which
// masks stale-bundle mismatches in Sentry error reports.
release:
process.env.REACT_APP_BUNDLE_VERSION ??
sentryConfig?.release ??
undefined,
dsn: sentryConfig?.dsn,
integrations: [
browserTracingIntegration({}),
+2
View File
@@ -31,6 +31,7 @@ export default defineConfig(({ command, mode }) => {
SSL_KEY_PATH,
REACT_APP_PORT,
IS_DEBUG_MODE,
APP_VERSION,
} = env;
const port = isNonEmptyString(REACT_APP_PORT)
@@ -252,6 +253,7 @@ export default defineConfig(({ command, mode }) => {
REACT_APP_SERVER_BASE_URL,
IS_DEBUG_MODE,
IS_DEV_ENV: mode === 'development' ? 'true' : 'false',
REACT_APP_BUNDLE_VERSION: APP_VERSION,
},
},
css: {