Commit Graph

16666 Commits

Author SHA1 Message Date
Jaanus 2365b30dfb fix: show admin settings nav link only to root admins 2026-10-12 14:38:24 +03:00
Mateusz Prusaczyk be018d7e0c fix(change-requests): reviewer button layout 2026-10-12 13:25:41 +02:00
Kamala 5436f7f50b feat: add expected lifetime and permanent flag cleanup reminders
Adds lifetime reminder alongside the pre-existing lifecycle reminder.
Only one banner at a time is rendered, and the lifecycle banner takes
precedence over the lifetime one.

### Expected lifetime reminder
- Rendered when the flag's expected lifetime has ended
(`expectedLifetimeEndsAt` is in the past) and the flag is not yet
completed or archived.
- Offers "Mark completed", which opens the existing mark completed
dialogue.

<img width="1497" height="610" alt="Screenshot 2026-10-09 at 18 02 21"
src="https://github.com/user-attachments/assets/bb82d77f-7af0-43f4-bed0-0119ed333b47"
/>


### Yearly check-in for permanent flags
- Rendered for permanent flags (`expectedLifetimeEndsAt` is `null`) once
a year has passed since flag creation, while the flag is not completed
or archived.
- Offers "Skip for now", which snoozes the reminder for a year in
local storage, and "Mark completed".

<img width="1541" height="672" alt="Screenshot 2026-10-09 at 17 14 15"
src="https://github.com/user-attachments/assets/a899d05b-ff40-46ef-81bc-7e2a8f83f16f"
/>


Also refactored so that banner actions no longer wrap awkwardly on
narrow screens.

Before: 
<img width="1167" height="125" alt="Screenshot 2026-10-09 at 16 54 25"
src="https://github.com/user-attachments/assets/598a26f5-06e1-4b82-be4c-3f0b41feb3c6"
/>


After: 
<img width="1020" height="116" alt="Screenshot 2026-10-09 at 18 01 06"
src="https://github.com/user-attachments/assets/3dad9389-f67c-4104-8408-edc44edd5000"
/>
2026-10-12 13:03:03 +02:00
Mateusz Prusaczyk 8812069153 fix(tags): Silent errors on assigning single-emoji tag 2026-10-12 12:53:26 +02:00
Jaanus Sellin b4672bfd1d feat: new invite signup page behind newInviteFlow flag (#12730) 2026-10-12 13:11:00 +03:00
Kathir Eswaran 6d3c2584e4 chore: remove dead queryMissingTokens experimental flag (#12729)
## About the changes
Removes the unused `queryMissingTokens` experimental flag from
`IFlagKey` and defaults (`UNLEASH_EXPERIMENTAL_QUERY_MISSING_TOKENS`).
No code, tests, frontend, or docs referenced it and implementation was
already gone, only the definition remained. No behavior change.
Closes #

### Important files

## Discussion points

## OSS PR checklist

- [x] I have read and agree to the [Unleash Contributor License
Agreement](https://github.com/Unleash/unleash/blob/main/CLA.md).
- [ ] I have added tests or explained why tests are not needed.
- [ ] I have updated documentation where relevant.
2026-10-09 15:26:40 +02:00
Mateusz Prusaczyk 91b5a52efb feat(tags): add frontend validation for renaming tags 2026-10-09 11:44:44 +00:00
Mateusz Prusaczyk f9f3b69138 fix(tags): incorrect bulk-tag assignment 2026-10-09 13:21:27 +02:00
Thomas Heartman 74fe31bd6d chore: flip cancel/save buttons in strategy edit/create dialog
To better align with the new forms and designs. Updates the order of the
buttons in each of the three callers.

Before:
<img width="322" height="82" alt="image"
src="https://github.com/user-attachments/assets/0f4027f4-4771-41de-a571-d59a1463d760"
/>


After:
<img width="321" height="111" alt="image"
src="https://github.com/user-attachments/assets/6a9df6da-1836-4e96-aeb1-a4168faf64ce"
/>
2026-10-09 11:01:14 +00:00
Mateusz Prusaczyk 6ca5d9f7e5 chore(tags): align the permissions for renaming and deleting 2026-10-09 12:53:41 +02:00
Kamala 61f0ae6076 feat: add custom date picking option for flag expected lifetime
Adds "Pick a date" to the expected lifetime row of the new create flag
dialog.

- Clicking the chip shows a date input defaulting to tomorrow, limited
to dates after today. The picked date becomes `lifetimeDays` in the
payload, counted as calendar days from today.
- The form's lifetime state is now a typed choice instead of a day
count:

  ```ts
  type Lifetime =
      | { type: 'preset'; days: number }
      | { type: 'custom'; endsAt: string }
      | { type: 'permanent' };

Examples of what is saved in local storage: 

User clicked the 30 days chip:
`"lifetime": { "type": "preset", "days": 30 }`

User picked 11 January 2027 in the calendar:
`"lifetime": { "type": "custom", "endsAt": "2027-01-11" }`

User clicked Permanent:
`"lifetime": { "type": "permanent" }`



https://github.com/user-attachments/assets/754a15b1-1ae4-4b4f-8615-233db732baa1
2026-10-09 11:58:41 +02:00
Kamala ba215951aa feat: add expectedLifetimeEndsAt to admin GET feature payload
Adds `expectedLifetimeEndsAt` to the admin `GET
/api/admin/projects/:projectId/features/:featureName` payload, behind
the `perFlagLifetime` flag. The flag page will use it to show the
cleanup reminder based on the flag's lifetime.

- A new `getLifetime(featureName)` read on the feature toggle store
returns a `FlagLifetime`: `{ type: 'permanent' }` when the flag's
lifetime is `0` or, failing that, its type has none, otherwise e.g. `{
type: 'expiring', days: 30 }` with the flag's own lifetime or its type's
as fallback. It returns `undefined` for a flag that does not exist.
- `getFeature` turns that into the date in the service: `null` for a
permanent flag, otherwise `createdAt` plus the days.
- `expectedLifetimeEndsAt` is absent when the flag is off or no lifetime
is known; `null` for a permanent flag or permanent type; otherwise
`createdAt` plus the lifetime in days.
- On the wire the field is an ISO 8601 string, like every other date on
the payload: the service returns a `Date` and [the controller passes the
response through
`serializeDates`](https://github.com/bricks-software/unleash-enterprise/blob/8399e1548cf76f0bc0d58d957aedba21f3691d38/oss/src/lib/features/feature-toggle/feature-toggle-controller.ts#L776-L781).


Not declared in `featureSchema` on purpose: the response schema is open
while this is behind feature flag.

Example, a release flag created on 7 October 2026 with a 30-day
lifetime:

```
{
  "name": "checkout-redesign",
  "type": "release",
  "createdAt": "2026-10-07T11:39:43.155Z",
  "expectedLifetimeEndsAt": "2026-11-06T11:39:43.155Z",
  ...
}
```

For a permanent flag the field is null. With the flag off it is absent.
2026-10-09 10:01:41 +02:00
Adam Bar 082f1c2f9e chore(strategies): split out new Strategy form; rename existing to Legacy
* moved `FeatureStrategyEnabledDisabled` directly to `StrategyFormBody`,
gated with new `allowEnableDisable` prop
* renamed legacy-UI-specific prop `generalTabExtras` to `statusContent`
as it now only holds feature flag status info (it will live separately
from `FeatureStrategyEnabledDisabled` so it needed to be split)
* copied `StrategyFormBody` to `LegacyStrategyFormBody` to be used once
the `singlePageStrategyForm` flag is disabled
* added `StrategyFormBodySelector` to route between (new)
`StrategyFormBody` and (current) `LegacyStrategyFormBody` based on
`singlePageStrategyForm` flag and updated callees not to choose the impl
on their own
* split out tests for old and new paths - identical by now, ready for
future divergence
* removed obsolete and no longer used `newStrategyConfiguration` flag

The split is shallow - both `StrategyFormBody` and
`LegacyStrategyFormBody` share lots of common dependencies. These would
need to be split out once we proceed with implementation of changes
within `StrategyFormBody`


[CXUX-449](https://linear.app/unleash/issue/CXUX-449/split-out-new-strategy-form-rename-existing-to-legacy)
2026-10-09 09:38:42 +02:00
irstavr 930a0ac58e fix(session): tell a missing session start from an unreadable one
Working on the [audit metrics for idle
timeouts](https://linear.app/unleash/project/configurable-idle-session-timeout-with-re-authentication-after-68a334e79506/issues)
met some obstacles on the way...

-`SessionTimeoutReason` codes would need a rename to be used as a metric
labe, move them to snake_case at the same time, so the value is usable

-`parse()` returns `undefined` for both a missing `authenticatedAt` and
one that will not parse, so both ended the session as `unknown-start`.

-a legacy session (_one started before timeouts get shipped_) is signed
out on its next request -- and during a rolling deploy the old pods keep
minting them => so it is a sustained login loop rather than a one-off
wave.
Now: If the session has a missing `start` is now backfilled to `now` and
the session carries on, only a `start` we cannot read ends it, under its
own reason
2026-10-09 09:27:04 +02:00
irstavr f4ca1e6221 fix(session): add endSession() and call it from six different modules
**Issue**
we have six modules (`logout,timeout mw,reset-password,oidc,saml x2`)
that end a session by hand and disagree on every step.
Working on idle timeouts, we spotted three of them clear the cookie with
no path, so under a non-empty `BASE_URI_PATH` they actually ...clear
nothing.

### This PR
As we did before with introducing `startSession` for all modules, we add
`endSession` besides it.
-destroys the row, 
-clears the cookie with the full sessionCookieOptions, and 
-sets Clear-Site-Data when the instance asks for it.

It's being called by all six modules so we stay consistent in all paths.

Why now before idle-timeouts ship:
`logout.ts:` redirects to `session.logoutUrl` before the destroy block,
so for SAML and OIDC the store wipe is never reached. The SSO providers
then clear the cookie with a bare `res.clearCookie(this.cookieName)`.

---------

Co-authored-by: irstavr <irstav@gmail.com>
2026-10-08 18:48:55 +02:00
Kamala 0509a49c15 chore: bump MUI to v9.4
Bumps MUI to most recent stable version. 
Mostly so that our toggle buttons gain better accessibility ([see
documentation](https://mui.com/material-ui/react-toggle-button/#accessibility)).
2026-10-08 16:04:24 +02:00
Øystein Lorentzen Vesth 50c080bbfd feat: New experimental install type that can be used by addon scheme
New install type that looks similar to the one used by slack-app. This
one expects a path relative to the addon it belongs to and sends
non-sensitive params to the server in the URL.

This will be used to support the GitHub App Manifest flow, since we need
to pass on details like organization name etc. I started by enhancing
the current Install property, but its easier to _remove_ this if we
choose not to go down the app manifest path.
2026-10-08 15:43:54 +02:00
Gergo Kekesi 501dc3e3c5 test: testServerRoute can answer with an empty body
Passing `null` to `testServerRoute` now answers with an empty body, as
endpoints that return 204 do.
2026-10-08 14:12:14 +01:00
Gergo Kekesi da1c6d097d refactor: rename EditPayloadSchema to PayloadSchemaSidebar
Renames `EditPayloadSchema` to `PayloadSchemaSidebar`, because saving
goes through an upsert and the same component both adds and edits a
schema.
2026-10-08 13:51:09 +01:00
Gergo Kekesi 647e1f32a0 fix: document the empty response of the environment toggle endpoints
The environment toggle endpoints (`POST
/api/admin/projects/:projectId/features/:featureName/environments/:environment/on`
and `/off`) document a feature in their 200 response, but the handlers
end with `res.status(200).end()` and have sent an empty body since they
were added in Unleash/unleash#880 (2021). The feature response was
declared when the docs were written in Unleash/unleash#1563 (2022), so
the response body was documented but never sent. This declares the empty
200 the endpoints already return, the same way the bulk toggle routes
do, and nothing about the endpoints' behaviour changes.
2026-10-08 13:36:56 +01:00
Mateusz Kwasniewski 8bbe7ede96 feature: predefined schema list
Selecting popular schemas grouped by categories that are used in the
wild (we may reconsider the grouping in future)
<img width="806" height="707" alt="Screenshot 2026-10-08 at 12 31 17"
src="https://github.com/user-attachments/assets/cc7f5355-c7f0-4209-b7d5-da7b0ca337cd"
/>

One selected the field is populated with a sample schema you can edit
(ginger cake pattern)
<img width="815" height="842" alt="Screenshot 2026-10-08 at 12 31 23"
src="https://github.com/user-attachments/assets/8428173c-aab5-4115-9e59-e484feeb7f05"
/>

No need to review the actual schemas. They will probably be changed
anyway and they take the most of this PR line count

Also perf impact is negligible. New templates are 3kb after gzip/minify
and this part of app is already lazy loaded and not part of the initial
bundle

All fields have human readable title to use for UI labels later with a
fall back to property key
2026-10-08 13:22:34 +01:00
Kamala 1e408f2acb feat: add new bare create flag dialog with expected lifetime
First step in adding a new create feature flag dialog (gated behind
`perFlagLifetime`), with the newly introduced lifetime selection. The
dialog has:

- flag type chips (Standard / Experiment / Kill switch) with a "Used
for" list for the standard types
- expected lifetime chips (7 / 30 / 90 days / Permanent) with a default
per type, kept when the user has picked one
- `lifetimeDays` in the create payload, posted only when set; `0` means
permanent, matching the backend

Some of the code is copied from the "old" create feature form dialog (I
left comments throughout this PR with the relevant LOCs).

Out of scope (for the sake of keeping the PR at a reasonable size): 

- "Pick a date" as a custom lifetime
- tracking for the new dialog
- the "Other optional settings" section (tags and impression data)



https://github.com/user-attachments/assets/f3139f4b-17c0-4c7b-83c3-39828cd59464
2026-10-08 14:20:30 +02:00
Mateusz Prusaczyk 8fd4102d5a feat(tags): merge tags on rename 2026-10-08 11:39:09 +00:00
Gergo Kekesi 1b7c1aad76 feat: payload schema store
A saved payload schema is now kept in memory and returned with the flag
as `payloadSchema`.

- In memory until the UI has shown what we need to store, so a restart
loses schemas and each instance has its own
- Added in the flag controller, not in the flag service where links are
read, because ten factories build that service and each would get its
own empty store
2026-10-08 11:15:55 +01:00
Gergo Kekesi 9d179b3094 chore: remove the Plausible chart from impact metrics
We've decided that we will no longer use Plausible, so its chart comes
out of impact metrics.

- Remove the `GET /impact-metrics/plausible` endpoint, its response
schema and the service call. It returned 404 unless the
`plausibleMetrics` flag was on and `PLAUSIBLE_TOKEN` was set, so no
customer could rely on it
- Remove the `plausibleMetrics` flag
(`UNLEASH_EXPERIMENTAL_PLAUSIBLE_METRICS`)
- Remove `PlausibleChart`, `PlausibleChartItem` and
`usePlausibleMetrics` from the impact metrics page
- Remove the generated `getPlausibleMetrics*` and
`plausibleMetricsResponseSchema*` frontend models
- `PLAUSIBLE_TOKEN` is no longer read, so the secret can be dropped from
deployments
2026-10-08 10:24:55 +01:00
Adam Bar dd5f93384a chore(strategies): add singlePageStrategyForm flag
Feature flag for
https://linear.app/unleash/project/ux-add-strategy-on-one-page-596c50d0299d
2026-10-08 10:55:03 +02:00
Mateusz Kwasniewski b05429921f feature: add feature schema modal 2026-10-08 08:17:34 +00:00
Gergo Kekesi ed4e3e6636 fix: flag name placeholder shows the project's naming example
The flag name placeholder always suggested kebab-case
(`Feature-flag-name`). It now shows the project's naming example when
there is one, and the pattern box under the input lost its left inset so
the two line up.

No new validation: the example is already checked against the pattern
when project settings are saved.

Before:
<img width="1114" height="546" alt="before"
src="https://github.com/user-attachments/assets/9f47b90b-b50d-4f2c-8551-f48750506d30"
/>

After:
<img width="1208" height="540" alt="after"
src="https://github.com/user-attachments/assets/07bbae70-ccb4-4270-96e8-7328d234f94b"
/>
2026-10-08 08:03:24 +00:00
Adam Bar 1b09654f12 fix: disable keyboard shortcut when its triggers are hidden, resolve modifiers exactly
Disables the shortcuts whose triggers or content are visually overlaid
with dialog backdrop, so that they stay inert when logically hidden.
Fixes shortcut matching to avoid ⌘+K triggering when ⌘+Shift+K is
actually pressed - check for exact modifiers state, not just inclusion.

[DX-4947](https://linear.app/unleash/issue/DX-4947/once-dialog-is-open-command-menu-keyboard-shortcut-should-be-inert)
2026-10-07 16:12:28 +02:00
Mateusz Prusaczyk dcdda37d5a chore(tags): add tracking for sorting tag types and tag value tables 2026-10-07 14:08:04 +00:00
Gergo Kekesi 9d19b09275 feat: payload schema access check
The endpoint now refuses to set a payload schema on a flag that is not
in the project named in the URL, because the permission is only checked
against that project.

- The check lives in a new service, as in the feature links (#1837) and
lifecycle (#1944) fixes
- Missing and archived flags get the same 404
2026-10-07 14:42:53 +01:00
Adam Bar 8323f30ef9 fix: adjust CreateProjectDialog modal sidebar height regardless of content scroll
Removes overflow rule that breaks the height of the sidebar when the
left-pane content is longer than sidebar and scrolled down.


[DX-4709](https://linear.app/unleash/issue/DX-4709/fix-create-project-modal-layout)

**Before**
<img width="1142" height="682" alt="image"
src="https://github.com/user-attachments/assets/fc34445a-0246-4ee8-ae49-9a24cd09abe1"
/>

**After**
<img width="1158" height="683" alt="image"
src="https://github.com/user-attachments/assets/8566b55d-803b-4111-b287-d9b593048984"
/>
2026-10-07 15:37:03 +02:00
Mateusz Kwasniewski 8e3d85311d feature: more descriptive message for unsupported schema 2026-10-07 13:35:15 +00:00
Gergo Kekesi a1eb092260 feat: payload schema validation
the endpoint now refuses a payload schema that is not a JSON Schema.

- Only draft 2020-12 is accepted
- Unknown keywords and formats are refused
- Ajv's type, tuple and required rules are off, because they refuse
valid and common schemas, such as a value of two types or a conditional
`required`. The tests name those cases.
2026-10-07 14:06:29 +01:00
Adam Bar 267e48a0b2 fix: don't force ChangeRequestTable width to avoid breaking layout on smaller breakpoints
Fix for Create Project dialog on smaller desktop breakpoints, where the
fixed size of ChangeRequestTable caused the sidebar to get cut. Just
letting the table flow freely to 100%.

[DX-4945](https://linear.app/unleash/issue/DX-4945/fix-create-project-dialog-layout)
2026-10-07 14:09:30 +02:00
Gastón Fournier 431cc8959e fix: hydrate streaming state and revision from one database snapshot
When a new node hydrates an environment while an update commits,
separate feature/segment/revision queries can combine old feature state
with a newer cursor. That revision's actual update is then skipped
because the delta processor considers it processed.

This PR reads hydration features, referenced-segment revision state and
all segments through transaction-scoped readers inside a read-only
PostgreSQL `REPEATABLE READ` transaction. Inject the snapshot reader
through the OSS composition root and initialize the cache and watermark
from that consistent result. The transaction runs on environment
initialization/rehydration, not every delta poll.

### TDD commit structure

1. `349a83c2` — **test: expose inconsistent delta hydration during a
concurrent commit**. Adds only
`oss/src/lib/features/client-feature-toggles/delta/delta-hydration-snapshot.test.ts`;
production code is unchanged.
2. `21625a4c` — **fix: read delta hydration from a repeatable-read
database snapshot**. Adds the snapshot reader, wires it into hydration,
and adapts existing unit fixtures to the injected reader. The regression
file is unchanged from commit 1.

### Regression coverage

The test follows nearby OSS database tests.

A method spy delegates to the real feature query and pauses after it
returns. Another DB connection atomically commits a feature change, a
referenced segment change and both events. Hydration must retain the
earlier state, segment constraints and watermark. A subsequent refresh
must deliver the committed feature/segment changes to a client resuming
from that earlier watermark. This tests actual isolation.
2026-10-07 13:41:12 +02:00
Gergo Kekesi c38d43cf80 feat: payload schema endpoint 2026-10-07 12:59:28 +02:00
Mateusz Kwasniewski 140bb4230a chore: clean up feature release plans leftovers 2026-10-07 12:44:30 +02:00
David Leek 8f718ece64 feat: gh-integration frontend mapping of appname to repos 2026-10-07 12:08:49 +02:00
Adam Bar 17708ad98f feat: feature overview: merge Links into Details
Merges Links into Flag details box separated with Divider, updates
styling (empty state font size, add button placement, spacing).

[DX-4929](https://linear.app/unleash/issue/DX-4929/ux-merge-flag-links-and-flag-details)

Figma reference:
https://www.figma.com/design/FWPiwvOA5JBRjRb88tBVAm/Flags-and-Strategy?node-id=2452-17136&m=dev
2026-10-07 11:48:04 +02:00
Adam Bar 64622a3a00 feat: feature overview description expand/collapse
Introduce "Show less" / "Show more" functionality into shared
`Truncator` component via new `expandable` property, off by default.

Also, fix `whiteSpace` style in `Truncator` so that it does not inherit
values that may break line-clamp functionality inadvertently.

[DX-4773](https://linear.app/unleash/issue/DX-4773/ux-expand-description-ff)
2026-10-07 08:23:14 +00:00
Gergo Kekesi cbbadaead5 chore: forbid Node.js builtin imports in frontend source
- Turns on Biome's `correctness/noNodejsModules` for
`oss/frontend/src/**`.
- #2019 imported `node:util` in a frontend file. Type check, unit tests
and the build passed, and the app broke in the browser (fixed in #2029).
This makes that import a lint error.
- Checked against the #2019 version of
`strategy-change-diff-calculation.ts`: lint fails on the import. Current
`main` passes with no hits, so no source changes are needed.
- Scoped to `src` so `vite.config.mts` and the Cypress config can keep
using Node builtins.
- Does not cover a dependency that imports a Node builtin. That still
needs a runtime check.
2026-10-07 08:58:18 +01:00
Adrian Cruz 723a9d2710 fix(auth): force OIDC re-auth behind sessionTimeouts (EG-4756)
## Summary
Make signing in again through OIDC ask for credentials, instead of the
IdP quietly reusing its own session. Gated behind `sessionTimeouts`, off
by default; with it off, OIDC sign-in works as today. The logout changes
apply with the flag on or off.

https://linear.app/unleash/issue/EG-4756/use-force-auth-for-the-oidc

## Key points
- With `sessionTimeouts` on, the sign-in request asks the IdP for a
fresh login (`prompt=login`, `max_age=300`), and the callback refuses an
ID token whose `auth_time` is older than 5 minutes or missing.
- The sign-in keeps what it asked for on its session, next to `state`
and `nonce`, so the callback checks exactly that even if the flag is
flipped in between.
- OIDC logout ends the user's sessions in every browser, as password
logout already does, and a database error there still signs this browser
out.
- OIDC logout clears the session cookie on the base path it was set on.

## Testing
- Sign-in: the request to the IdP carries `prompt` and `max_age` only
with the flag on. On a signed ID token, openid-client's own check lets a
sign-in from a minute ago in and refuses one from 10 minutes ago or with
no `auth_time`; with the flag off, a token without `auth_time` still
signs in.
- Flag flips: a sign-in started with the flag on is still checked if
it's turned off before the callback, and one started with it off isn't
refused if it's turned on.
- Logout: ends the user's sessions and clears the cookie on a `/hosted`
base path, and still signs this browser out when ending the other
sessions fails.
- On `pnpm run dev:enterprise` against a local Keycloak with the flag
on, signing in again showed Keycloak's password prompt even with a live
IdP session, and logging out in the browser ended a second session of
the same user. An authorize request with `prompt` and `max_age`
stripped, sent after the IdP login was 5 minutes old, got a code from
Keycloak without a prompt and Unleash refused it. With the flag off,
that same IdP session signed straight in. With Keycloak's `auth_time`
left out of the ID token, a sign-in started with the flag on was refused
even after restarting the server with it off.

## Notes
- Entra ID sends `auth_time` only when the app adds it as an optional
claim, so with the flag on, an Entra app without it can't sign in.
- Replaces #1921. Siblings: #1951 (SAML), #1950 (hosted JWT).
2026-10-07 09:53:43 +02:00
Christopher Kolstad 7099f0d4d4 Configure Dependabot for GitHub Actions and npm (#12230)
Added configuration for GitHub Actions and updated schedule for npm
dependencies.

Since the rest of our repos are using dependabot, this configures
dependabot as our dependency updater.

## About the changes

Closes #

### Important files

## Discussion points

## OSS PR checklist

- [x] I have read and agree to the [Unleash Contributor License
Agreement](https://github.com/Unleash/unleash/blob/main/CLA.md).
- [x] I have added tests or explained why tests are not needed.
- [x] I have updated documentation where relevant.
2026-10-07 09:50:30 +02:00
irstavr c837f99229 test(session): prove the session timeouts against real Postgres - EG-4708
Before this PR: every session test ran on `session.MemoryStore`, which
rewrites the whole record when a session is touched. But in prod
(`connect-session-knex`) updates only the `expired` column and leaves
the stored payload alone. So the store we actually ship on was never
tested.

Since we added the timeouts, current tests cannot actually assert on
session lifetime.

### What's new:

-added test helper`setupAppWithSessionStore`: now sessions live in
Postgres, with `sessionTimeouts` on by default (different test can
modify this). The rest helpers keep the in-memory store as before.

-added e2e `session-timeout` tests  against a real DB
-- idle window: a session nobody touched expires: a tab that only polls
does not keep itself alive - a fourteen one-minute reads survive, the
fifteenth minute ends it. the keep-alive moves the deadline, a plain
read does not. The keep-alive cannot revive an already-expired session.
Signing in again issues a new session id.
-- max-age: ends a session however active the user it, still applies on
its own with the timeouts off, not enforced while the flag is off.

-tested that sessions before the timeouts feature carry no timestamps,
so there's no window to measure -> they logout on 1st request.
(introduced in
[PR](https://github.com/bricks-software/unleash-enterprise/pull/1991))

-added e2e session tests: for the [keep-alive
endpoint](https://github.com/bricks-software/unleash-enterprise/pull/1992):
what it answers with a window in force, with the flag off, with no
session, and the ui-config interval both ways. Runs with
`strictSchemaValidation` on, so responses are checked against the new
schema.
2026-10-07 09:46:17 +02:00
Krzysztof (Kris) Kula d0fd5bbc0c chore: fix pnpm in the frontend directory
One file missed in
https://github.com/bricks-software/unleash-enterprise/pull/2019

```
/oss/frontend ❯ pnpm i
[ERROR] This project is configured to use 12.9.1 of pnpm. Your current pnpm is v11.15.1
Corepack invoked pnpm with this version, and pnpm does not switch versions when running under corepack.
Align the "packageManager" field in package.json with "devEngines.packageManager", or invoke pnpm directly (without corepack) so it can switch versions automatically.
If you want to bypass this version check, you can set the "pmOnFail" configuration to "warn" or "ignore" (e.g. via --pm-on-fail=ignore). If using "devEngines.packageManager", you can set its "onFail" to "warn" or "ignore"
```
2026-10-07 07:23:57 +00:00
renovate[bot] 9cf8d64753 chore(deps): update dependency browserslist to v4.29.3 (#12717)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [browserslist](https://redirect.github.com/browserslist/browserslist)
| [`4.29.2` →
`4.29.3`](https://renovatebot.com/diffs/npm/browserslist/4.29.2/4.29.3)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/browserslist/4.29.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/browserslist/4.29.2/4.29.3?slim=true)
|

---

### Release Notes

<details>
<summary>browserslist/browserslist (browserslist)</summary>

###
[`v4.29.3`](https://redirect.github.com/browserslist/browserslist/blob/HEAD/CHANGELOG.md#4293)

[Compare
Source](https://redirect.github.com/browserslist/browserslist/compare/4.29.2...4.29.3)

- Updated Firefox ESR.

</details>

---

### Configuration

📅 **Schedule**: (in timezone Europe/Madrid)

- Branch creation
  - "after 7pm every weekday,before 5am every weekday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Unleash/unleash).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMzQuMSIsInVwZGF0ZWRJblZlciI6IjQ0LjEzNC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-07 01:48:37 +00:00
renovate[bot] c36e648f06 chore(deps): update cypress-io/github-action action to v7.4.5 (#12716)
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
|
[cypress-io/github-action](https://redirect.github.com/cypress-io/github-action)
| action | patch | `v7.4.4` → `v7.4.5` | `v7.4.6` |

---

### Release Notes

<details>
<summary>cypress-io/github-action (cypress-io/github-action)</summary>

###
[`v7.4.5`](https://redirect.github.com/cypress-io/github-action/releases/tag/v7.4.5)

[Compare
Source](https://redirect.github.com/cypress-io/github-action/compare/v7.4.4...v7.4.5)

##### Bug Fixes

- **deps:** execute npm audit fix
([#&#8203;1917](https://redirect.github.com/cypress-io/github-action/issues/1917))
([789d836](https://redirect.github.com/cypress-io/github-action/commit/789d836053c5ca389c2905fc0c9f2909da778c46))

</details>

---

### Configuration

📅 **Schedule**: (in timezone Europe/Madrid)

- Branch creation
  - "after 7pm every weekday,before 5am every weekday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Unleash/unleash).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMzQuMSIsInVwZGF0ZWRJblZlciI6IjQ0LjEzNC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-07 01:47:55 +00:00
Mateusz Prusaczyk 58fb8e8f55 fix: remove usage of node:util in the frontend app
This PR https://github.com/bricks-software/unleash-enterprise/pull/2019
replaced `lodash.isequal` with `node:util`.
But node:util is not available in the frontend and it broke local app
<img width="1177" height="536" alt="image"
src="https://github.com/user-attachments/assets/23c677b6-2bc9-4427-b716-dec691eef375"
/>

At the same time it looks like we have
`[dequal](https://github.com/lukeed/dequal)` already in the codebase, so
we could just use that.
2026-10-06 14:36:37 +00:00
Gastón Fournier 216901f2ab fix(ci): require frontend E2E success in PR build gate (#12715)
## Summary

PR #12369 merged with a failing frontend E2E test because the required
`build` check only depended on the backend and frontend builds.

Call the existing frontend E2E workflow from PR Build and include its
result in the required `build` gate. E2E must succeed for the gate to
pass; backend and frontend builds can still be skipped by their existing
path filters. Remove the E2E workflow's standalone PR trigger to avoid
duplicate runs. E2E continues to run on every PR, and no branch
protection changes are needed.
2026-10-06 16:19:14 +02:00