1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-27 11:02:16 +01:00
Commit Graph

3094 Commits

Author SHA1 Message Date
Mateusz Kwasniewski
902c4cd7b8
chore: expose fake change request access read model (#10818) 2025-10-16 14:31:43 +02:00
Gastón Fournier
653b67b172
chore: remove uuid from the backend (#10807)
Backend only of: https://github.com/Unleash/unleash/pull/10806

This PR drops the uuid package from node modules and replaces it with
standard randomUUID usage that is available from 14.17 onwards, and we
have a minimum requirement of node 20 at Unleash.

[Node.js crypto](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions)
[Web crypto](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID)

Co-authored-by: Anastasiia Hladina <anastasiia.hladina@gmail.com>
2025-10-15 16:48:08 +02:00
Nuno Góis
4ff41fa6a9
chore: add warning about release plans in import-export (#10805)
https://linear.app/unleash/issue/2-3965/add-a-note-if-were-exporting-that-we-dont-understand-release-plans-in

Adds a warning about release plans in import/export.

It's not trivial to know every flag that will be exported in every
scenario, and whether they have release plans, so our logic here is
"have you configured release templates?"

<img width="706" height="516" alt="image"
src="https://github.com/user-attachments/assets/68ba8618-9887-491c-b46e-256b45700d74"
/>

<img width="732" height="503" alt="image"
src="https://github.com/user-attachments/assets/086e37d4-78ae-4647-93a2-5d1845c2758a"
/>
2025-10-15 14:44:30 +01:00
Mateusz Kwasniewski
f9ed38ca98
feat: milestone progression events more data (#10798) 2025-10-14 16:50:01 +02:00
Mateusz Kwasniewski
712943ed29
feat: milestone progression events (#10797) 2025-10-14 16:29:57 +02:00
Tymoteusz Czech
b5d1f6e075
chore: remove legacy flag UI (#10781) 2025-10-14 11:00:51 +02:00
Mateusz Kwasniewski
331d00b329
feat: make milestone progressions for source milestone unique (#10789) 2025-10-13 15:53:11 +02:00
Mateusz Kwasniewski
c74ca0d8ed
feat: measure time in release plan read model (#10788) 2025-10-13 15:06:56 +02:00
Mateusz Kwasniewski
6e6524be4d
refactor: remove unused release plan store method (#10787) 2025-10-13 14:37:30 +02:00
Mateusz Kwasniewski
7ef140c6dc
chore: remove type prefix (#10786) 2025-10-13 13:34:20 +02:00
Mateusz Kwasniewski
ffe91129e6
chore: move read model to value space (#10785) 2025-10-13 13:22:36 +02:00
Mateusz Kwasniewski
0d466b258b
chore: expose release plan read model (#10784) 2025-10-13 12:54:06 +02:00
Mateusz Kwasniewski
9db7bcffd5
feat: disallow negative condition interval (#10783) 2025-10-13 11:47:53 +02:00
Mateusz Kwasniewski
ea9f92bd88
fix: knex returns timestamp dates (#10782) 2025-10-13 11:15:00 +02:00
Mateusz Kwasniewski
3016da9146
fix: knex returns timestamp dates (#10780) 2025-10-13 11:01:19 +02:00
Mateusz Kwasniewski
8879cc4b46
fix: add transitive transition condition schema (#10776) 2025-10-10 12:44:34 +02:00
Mateusz Kwasniewski
0b7c141e70
feat: improved transition condition schema to be more explicit (#10773) 2025-10-10 12:16:58 +02:00
Mateusz Kwasniewski
d5a91a60e1
fix: release plan write model (#10772) 2025-10-10 09:38:14 +02:00
Mateusz Kwasniewski
fce4c5bbab
feat: milestone progression executed at in read model (#10771) 2025-10-10 09:00:15 +02:00
Simon Hornby
346b063f45
chore: add migration for tracking connected downstream edge nodes (#10765)
https://linear.app/unleash/issue/2-3938/endpoint-in-unleash-edge-validate-license

Database migration for a new `edge_node_presence` table and
`bucket_edge_heartbeat` function.
2025-10-09 15:38:07 +02:00
andrii-st
247dd3af51
docs: clarify archived query param syntax for api/admin/search/features (#10538)
## About the changes
This PR updates the [Search and filter
features](https://docs.getunleash.io/reference/api/unleash/search-features)
doc to clearly indicate `IS:` query syntax requirement for `archived`
query param.
2025-10-09 11:40:35 +03:00
Mateusz Kwasniewski
97297dd40f
feat: milestone executed at migration (#10767) 2025-10-09 10:33:08 +02:00
Nuno Góis
4722fd4081
chore: export environment and project stores (#10766)
https://linear.app/unleash/issue/2-3932/cloned-environments-enable-disabled-strategies-unexpectedly

This allows us to use them in Enterprise.
2025-10-09 08:56:59 +01:00
Mateusz Kwasniewski
cf018020df
chore: feature release plans flag (#10762) 2025-10-08 14:19:22 +02:00
Mateusz Kwasniewski
bb3d938f57
fix: transition condition type (#10760) 2025-10-08 12:50:05 +02:00
Mateusz Kwasniewski
f35804e55f
Improve release plan write model (#10759) 2025-10-08 12:27:32 +02:00
Mateusz Kwasniewski
43fa239e72
feat: milestone transition condition (#10757) 2025-10-08 11:30:04 +02:00
Nuno Góis
9948e577ee
fix: clone environments (#10755)
https://linear.app/unleash/issue/2-3932/cloned-environments-enable-disabled-strategies-unexpectedly

Cloning environments didn't work as expected. This fixes a few of
issues:
 - Disabled strategies remain disabled after cloning
 - All strategy properties are cloned (including e.g. title)
 - Strategy cloning respects the selected projects
 - Release plans and their milestones are now correctly cloned
2025-10-08 09:48:40 +01:00
Mateusz Kwasniewski
f2115cc3db
feat: move release plans to feature environments (#10746) 2025-10-08 09:39:37 +02:00
Gastón Fournier
fab5dc8725
fix: Information exposure through a stack trace (#10737)
Fix for
[https://github.com/Unleash/unleash/security/code-scanning/81](https://github.com/Unleash/unleash/security/code-scanning/81)

To prevent information exposure through stack traces, ensure that the
HTTP response sent to clients contains only sanitized, generic error
information, such as a status code and a simple message. Internal
details (including stack traces, error types, or internal error codes)
should not be sent to the client. These can be safely logged on the
server for debugging.

**The fix:**  
- Do not return the entire `finalError` object as JSON to the client, as
it may include fields like `stack` or `internalMessage`.
- Instead, return only a subset of fields that are safe to expose to the
user, in this case just `message` .
- Log the full error and any debugging details using the server-side
logger **as currently done**.


---
_Suggested fixes powered by Copilot Autofix. Review carefully before
merging._

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-10-07 16:41:40 +02:00
Gastón Fournier
8f2cf5386d
fix: flaky test when updated_at matches the time of query (#10752) 2025-10-07 16:03:57 +02:00
Gastón Fournier
6a63e27ebd
fix: get users total right at startup (#10750)
# Summary
Add optional lazy collection with TTL to our createGauge wrapper,
allowing a gauge to fetch its value on scrape and cache it for a
configurable duration. This lets us register a collect function directly
at gauge declaration without changing existing call sites or behavior.

We're experimenting with this, reason why we're only applying the
solution to `users_total` and will evaluate afterwards.

# Problem
- Some gauges should be computed on scrape (e.g., expensive or external
lookups) instead of being pushed continuously.
- Our current `createGauge` helper doesn’t make it easy to attach a
`collect` with caching. Each caller has to reimplement timing, caching,
and error handling.
- This leads to repeated costly work, inconsistent handling of unknown
values, and boilerplate.
# What changed
- `createGauge` now accepts two optional options in addition to the
usual prom-client options:
    - `fetchValue?: () => Promise<number | null>`
    - `ttlMs?: number`
- When `fetchValue` is provided:
    - We install a `collect` that fetches on scrape.
- Successful values are cached for `ttlMs` milliseconds (if `ttlMs` >
0).
    - If `ttlMs` is 0 or omitted, we fetch on every scrape.
- If `fetchValue` returns null or throws, we set `NaN` (indicates
`"unknown"`).

# Behavior details
## Caching:
- A value is “fresh” when successfully fetched within `ttlMs`.
- Only numeric successes are cached. null and errors are not cached;
we’ll refetch on the next scrape.
## Unknown values:
- null or thrown errors set the gauge to `NaN` so Prometheus won’t treat
it as zero.
## Compatibility:
- Backward compatible. Existing uses of `createGauge` are unchanged.
If a user-supplied `collect` exists, it still runs after the TTL logic
(can overwrite the value by design).
- API remains the same for the returned wrapper: `{ gauge, labels,
reset, set }`.
2025-10-07 14:22:33 +02:00
Mateusz Kwasniewski
5e2d95e0be
refactor: move release plan schemas to OSS (#10748) 2025-10-07 12:28:28 +02:00
Gastón Fournier
bade23974e
feat: allow test operation for patch (#10736)
## About the changes
This would allow users to add test statements to protect from concurrent
modifications. From
https://github.com/orgs/Unleash/discussions/10707#discussioncomment-14602784

E.g.
If you had this feature flag configuration
```
{
  "name": "flexibleRollout",
  "constraints": [
    {
      "contextName": "a",
      "operator": "IN",
      "values": [
        "100", "200", "300", "400", "500"
      ],
      "caseInsensitive": false,
      "inverted": false
    }
  ],
  "parameters": {
    "rollout": "100",
    "stickiness": "default",
    "groupId": "api-access"
  },
  "variants": [],
  "segments": [
    122
  ],
  "disabled": false
}
```

And you'd like to remove the value 300 from the constraints, you'd have
to first get the current values and then PATCH the strategy with the
following body:
```
[{ "op": "remove", "path": "/constraints/0/values/2" }]
```

This could fail in case of concurrent modifications (e.g. if someone
removed the value "100", then the index to remove "300" will no longer
be 2).

With the test operation, you'd be able to add a protection mechanism to
validate that the value at index 2 is still 300:
```
[
    { "op": "test", "path": "/constraints/0/values/2", "value": "300" },
    { "op": "remove", "path": "/constraints/0/values/2" }
]
```
If the test fails, the remove operation will not be applied.

I've tested this locally and works as expected:
1. If the value is still 300, it will remove it
2. The operation will fail if the value is no longer 300 because of
another change.
2025-10-06 16:52:10 +02:00
Mateusz Kwasniewski
c3491abf4b
feat: milestone progressions migration (#10738) 2025-10-06 13:47:02 +02:00
Gastón Fournier
b1f4ebd5eb
chore: return user id alongside max updated_at (#10732)
This is for internal use
2025-10-06 11:43:40 +02:00
David Leek
c39b4cd1b0
feat: add a suggestion banner at the bottom of empty feature-environments (#10725) 2025-10-06 09:02:15 +02:00
Mateusz Kwasniewski
c65a336783
feat: milestone start time update (#10730) 2025-10-03 14:09:49 +02:00
Mateusz Kwasniewski
f670505e56
feat: milestones started at migration (#10729) 2025-10-03 13:38:32 +02:00
Mateusz Kwasniewski
3ef2a7f93b
feat: add histogram to impact metrics (#10728) 2025-10-03 10:13:12 +02:00
Gastón Fournier
a927f1f42b
chore: new method that considers users updated at the same time (#10723)
We could have users updated at the exact same time, so we need to
include that timestamp in the next fetch to avoid missing users, but
also include the latest user id so we can exclude the ones already
fetched.

The following test shows how to process pages with this new method:

c03df86ee0/src/lib/features/users/user-updates-read-model.test.ts (L39-L65)
2025-10-03 09:24:53 +02:00
Tymoteusz Czech
9b5324ac92
feat: flag traffic billing display feature (#10718)
Feature flag and initial changes in Billing UI
2025-10-03 09:18:39 +02:00
Mateusz Kwasniewski
6c6d4c0ccc
chore: milestone progression flag (#10719) 2025-10-02 14:28:37 +02:00
Gastón Fournier
fb5d4cc7a1
fix: constraints should not be null (#10717)
## About the changes
In our code, we're not expecting constraints to be null:
https://github.com/search?q=repo%3AUnleash%2Funleash%20jsonb_array_elements(constraints)&type=code

It's unlikely to get a null value in constraints when using our API or
UI, but there might be cases where this can happen, as we saw in our
logs:
```
error: select "context_fields"."name", "context_fields"."description", "context_fields"."stickiness", "context_fields"."sort_order", "context_fields"."legal_values", "context_fields"."created_at", COUNT(DISTINCT CASE
                        WHEN features.archived_at IS NULL
                        THEN feature_strategies.project_name
                    END) AS used_in_projects, COUNT(DISTINCT CASE
                        WHEN features.archived_at IS NULL
                        THEN feature_strategies.feature_name
                    END) AS used_in_features from "context_fields" LEFT JOIN feature_strategies ON EXISTS (
                        SELECT 1
                        FROM jsonb_array_elements(feature_strategies.constraints) AS elem
                        WHERE elem ->> 'contextName' = context_fields.name
                      ) left join "features" on "features"."name" = "feature_strategies"."feature_name" group by "context_fields"."name", "context_fields"."description", "context_fields"."stickiness", "context_fields"."sort_order", "context_fields"."created_at" order by "name" asc - cannot extract elements from a scalar
```
which is likely due to:
`jsonb_array_elements(feature_strategies.constraints)` with null
constraints

For this reason, it seems reasonable to enforce the constraint at the
database level.
2025-10-02 12:45:53 +02:00
unleash-bot[bot]
da22cb0d65
chore(AI): etagVariant flag cleanup (#10714)
This PR cleans up the etagVariant flag. These changes were automatically
generated by AI and should be reviewed carefully.

Fixes #10711

## 🧹 AI Flag Cleanup Summary
This PR removes the `etagVariant` feature flag, making the versioned
ETag format
(`v2`) the default and only behavior for the client features API.
### 🚮 Removed
- **Feature Flag**
- Removed the `etagVariant` flag definition from `experimental.ts`.
- Removed conditional logic for ETag generation in
`client-feature-toggle.controller.ts`.
- **Testing**
- Removed parameterized tests for both states of the flag in
`feature.optimal304.e2e.test.ts`.
- Removed configuration of the `etagVariant` flag in test setup.
### 🛠 Kept
- **ETag Generation**
- The logic to generate ETags with a version suffix (`v1`) is now the
standard
behavior.
- **Testing**
- Tests have been updated to exclusively assert the presence of the `v1`
suffix in ETags.
### 📝 Why
The `etagVariant` feature flag has been successfully rolled out and is
now
considered complete. By removing the flag, we are simplifying the
codebase by
eliminating conditional paths and making the improved ETag format
permanent.
This change ensures all client API responses for features include a
versioned
ETag, which helps with cache-busting when the ETag format changes in the
future.

---------

Co-authored-by: unleash-bot <194219037+unleash-bot[bot]@users.noreply.github.com>
Co-authored-by: Gastón Fournier <gaston@getunleash.io>
2025-10-02 11:26:53 +02:00
Tymoteusz Czech
c7eb79038e
chore: add flags for UI filter refactor (#10708) 2025-10-01 09:20:25 +00:00
Nuno Góis
7462465a0b
chore: resource limits service (#10709)
https://linear.app/unleash/issue/2-3927/implement-resource-limits-service

Implements a resource limits service.

The implementation looks trivial (or even redundant) in OSS, but by
implementing a resource limits service we can make this potentially
dynamic and overridable.
2025-10-01 09:57:18 +01:00
Nuno Góis
e46f8881d1
chore: extract UI config logic into its own service (#10704)
https://linear.app/unleash/issue/2-3921/extract-ui-config-logic-into-its-own-service

Extracts UI config logic into its own service.

This is the first step to accomplish resource limits and license key
resources alignment.
2025-09-30 11:04:20 +01:00
Gastón Fournier
e0cdf6addd
feat: add users updated read model (#10693)
## About the changes
This adds a user read model using the updated_at new field in the users
table.
2025-09-24 17:39:03 +02:00
Mateusz Kwasniewski
413847374e
feat: using histogram metrics (#10695) 2025-09-24 17:02:29 +02:00