<!-- Thanks for creating a PR! To make it easier for reviewers and
everyone else to understand what your changes relate to, please add some
relevant content to the headings below. Feel free to ignore or delete
sections that you don't think are relevant. Thank you! ❤️ -->
- Add `change_request_enabled` column to `projects` and
`project_environments`
- Modified the store to include the new column
- Added new column to Project open api schema
## About the changes
<!-- Describe the changes introduced. What are they and why are they
being introduced? Feel free to also add screenshots or steps to view the
changes if they're visual. -->
<!-- Does it close an issue? Multiple? -->
Closes #
<!-- (For internal contributors): Does it relate to an issue on public
roadmap? -->
<!--
Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item:
#
-->
### Important files
<!-- PRs can contain a lot of changes, but not all changes are equally
important. Where should a reviewer start looking to get an overview of
the changes? Are any files particularly important? -->
## Discussion points
<!-- Anything about the PR you'd like to discuss before it gets merged?
Got any questions or doubts? -->
## What
This PR updates the `paramToBool` function to first check whether the
incoming argument is a boolean. This fixes the bug where using `true` or
`false` (e.g. `Strategies=false`) in the query would cause the server to
crash.
I've also added a test case to check for these values.
## Why
While working on the import/export API docs, I noticed that using
`false` in an export request caused the server to crash.
As we want to allow `true` and `false` (and use these values in the
documentation), we should ensure that they work as expected.
## Background
It's likely that this bug was introduced when we added the new OpenAPI
query parameters to the export endpoint. Because of the way that the
OpenAPI service we use does conversion, we now get `true` and `false`
converted to actual boolean values instead of strings. The `paramToBool`
function didn't account for that previously, which is why it caused the
server to crash.
## What
This PR fixes a bug where fetching a feature toggle via the
`/api/admin/projects/:projectId/features/:featureName` endpoint doesn't
validate that the feature belongs to the provided project. The same
thing applies to the archive functionality. This has also been fixed.
In doing so, it also adds corresponding tests to check for edge cases,
updates the 403 error response we use to provide clearer steps for the
user, and adds more error responses to the OpenAPI documentation.
## Why
As mentioned in #2337, it's unexpected that the provided project
shouldn't matter at all, and after discussions internally, it was also
discovered that this was never intended to be the case.
## Discussion points
It might be worth rethinking this for Unleash v5. Why does the features
API need the projects part at all when features are unique across the
entire instance? Would it be worth reverting to a simpler feature API
later or would that introduce issues with regards to how different
projects can have different active environments and so on?
### Further improvements
I have _not_ provided schemas for the error responses for the endpoints
at this time. I considered it, but because it would introduce new schema
code, more tests, etc, I decided to leave it for later. There's a
thorough OpenAPI walkthrough coming up, so I think it makes sense to do
it as part of that work instead. I am happy to be challenged on this,
however, and will implement it if you think it's better.
### Why 403 when the project is wrong?
We could also have used the 404 status code for when the feature exists
but doesn't belong to this project, but this would require more (and
more complex) code. We also already use 403 for cases like this for
post, patch, and put. Finally, the [HTTP spec's section on the 403
status code](https://httpwg.org/specs/rfc9110.html#status.403) says the
following (emphasis mine):
> The 403 (Forbidden) status code indicates that the server
**_understood the request but refuses to fulfill it_**. A server that
wishes to make public why the request has been forbidden can describe
that reason in the response content (if any).
>
> If authentication credentials were provided in the request, the server
considers them insufficient to grant access. The client SHOULD NOT
automatically repeat the request with the same credentials. The client
MAY repeat the request with new or different credentials. However, **_a
request might be forbidden for reasons unrelated to the credentials_**.
As such, I think using 403 makes sense in this case.
---
Closes#2337.
* Fixes a memory leak where events would trigger the data polling to restart. Any event would setup another polling interval, which would strain our database. Separated the logic for fetching the data and the polling, and made sure that the polling was only initialized once.
* fix: limit total of PATs a user can have
* increase PAT limit to 10
* Update src/lib/services/pat-service.ts
Co-authored-by: Simon Hornby <liquidwicked64@gmail.com>
* disable button on the front-end when PAT limit is reached
* import from server instead of repeating ourselves
Co-authored-by: Simon Hornby <liquidwicked64@gmail.com>
* OpenAPI(feat): add new 'Segments' tag
## What
This change adds a new Segments tag to the list of valid OpenAPI tags.
## Why
When updating tags for the enterprise version of Unleash, I realized
we didn't have any tags that were appropriate for the segments
endpoints.
* chore: Update snapshot
* Add suggest-change-store.ts and db migration
* Add suggest-change-store.ts and db migration
* change payload and event data type
* Update src/lib/db/suggest-change-store.ts
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
* split to 3 tables, create event on every change
* split to 3 tables, create event on every change
* Move service to enterprise
PR Comments
* PR Comments
* replacy createdBy string with User
* replace createdBy string with User
* added event to docs
* return entire changeset after adding a change
* bug fix
* bug fix
* move add change return to service layer
* PR comments
* added user id to user objects
* added user id to user objects
* added user id to user objects
* bug fix
* Rework
* Remove event and fix queries
* Update snapshot
* Remove console logs
* Fix
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
Co-authored-by: sjaanus <sellinjaanus@gmail.com>
* fix: filter empty metrics before we collect last seen toggles.
fixes: #2104
* fix: add a last-seen service to batch last-seen toggle updates
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
* fix: PATs should have an unique description
* add pat validation on the back-end service
* Update src/lib/services/pat-service.ts
Co-authored-by: Simon Hornby <liquidwicked64@gmail.com>
* fix: only consider current user's PATs
* fix tests
* cleanup
* Update frontend/src/component/user/Profile/PersonalAPITokensTab/CreatePersonalAPIToken/CreatePersonalAPIToken.tsx
Co-authored-by: Thomas Heartman <thomas@getunleash.ai>
* Update src/test/e2e/api/admin/user/pat.e2e.test.ts
Co-authored-by: Thomas Heartman <thomas@getunleash.ai>
Co-authored-by: Simon Hornby <liquidwicked64@gmail.com>
Co-authored-by: Thomas Heartman <thomas@getunleash.ai>
* fixed segments not being copied
* fix fmt
* bug fix
* return segmentId[] when getting a feature strategy
* do not return segments if they are not there
* Update src/lib/services/feature-toggle-service.ts
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
* fix lint
* fix: more explicit column sorting and bug fix
* update snapshot
* rollback
* add segment ids to feature strategies
* bug fix
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
## What
This PR does two things:
1. Add tests to ensure that all OpenAPI tags are listed in the root-level `tags` property of the spec.
2. Changes the tags for endpoints that use any of the deprecated tags (specifically `admin`).
## Why
When we moved to using the docusaurus OpenAPI doc generator, we made some changes to existing tags. Moving away from having just 'admin', 'client', and one or two more, we now use a more granular system, which makes it easier to find an endpoint by category.
However, there's currently nothing enforcing this and this bit of knowledge hasn't been clearly communicated to anyone. Because of this, we have some endpoints that are currently just grouped under a general 'admin' tag.
This has two drawbacks:
- In Swagger UI, all these endpoints are grouped together. This means that they break with the expectation that each endpoint has its own category. Further, being lumped together means that the 'admin' group is hard to read.
- The 'admin' tag is (on purpose) not included in the root-level `tags` property of the generated OpenAPI spec. This means that the OpenAPI docusaurus generator doesn't pick up those endpoints, which means that they're not included in the docs on docs.getunleash.io.
## How
By implementing tests that:
1. Check that the tags included in the spec are a subset of the "approved" tags
2. By checking each path in the OpenAPI spec and making sure that all its tags are listed in the root-level tag list. If this is not the case, the test fails and it logs an error explaining what is wrong to the console. An example of such a message is:
```
The OpenAPI spec contains path-level tags that are not listed in the root-level tags object. The relevant paths, operation ids, and tags are as follows:
POST /api/admin/feedback (operation id: createFeedback) has the following invalid tags: "admin"
PUT /api/admin/feedback/{id} (operation id: updateFeedback) has the following invalid tags: "admin"
For reference, the root-level tags are: "Addons", "Admin UI", "API tokens", "Archive", "Auth", "Client", "Context", "Edge", "Environments", "Events", "Features", "Import/Export", "Metrics", "Operational", "Playground", "Projects", "Public signup tokens", "Strategies", "Tags", "Unstable", "Users"
```
## Commits
* fix: ensure that all root-level tags in the spec are 'approved tags'
* fix: test that all listed path tags exist in the root-level tags
* fix: use "API tokens" tag for PAT endpoints
* fix: add comment explaining why tags test is there
* fix: Update snapshot
* fix: ensure that spec tags are a subset of the approved Tags
* fix: improve error message when tags don't match
* fix: further tweaks in log format
* refactor: user creation screen cleanup
* feat: deprecation notice for google sso
* fix: docs openid typo
* invite link bar
* invite link page
* fix prettier docs
* regenerated openapi
* hooks for invite page api
* update openapi
* feat: invite link update
* feat: add public signup token soft-delete
* public signup frontend feature flag
* fix: new user api issues
* feat: allow for creating new user from invite link
* Feat/invite user public controller (#2106)
* added PublicInviteController for public urls
* added PublicInviteController for public urls
* added PublicInviteController for public urls
* added PublicInviteController for public urls
* fix test
* fix test
* update openapi
* refactor: password reset props
* fix: public invite schema and validation
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
* user invite frontend
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
* invite link delete confirmation dialog
* refactor: password reset action
* fix: new user invite loading state
* fix: run ts check with ci
* revert openapi changes
* fix: invite token api interface
* fix: openapi schema index
* fix: update test snapshots
* update frontend snapshot
* fix: prettier ci
* fix: updates after review
Co-authored-by: andreas-unleash <104830839+andreas-unleash@users.noreply.github.com>
Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
* Middleware first version
* Middleware tests
* Add tests
* Finish middleware tests
* Add type for request
* Add flagresolver
* Fix snapshot
* Update flags and tests
* Put it back as default
* Update snapshot
* bug fix
* bug fix
* remove doc file
* store fixes
* bug fix
* rollback deleted file
* fix test
* add url to token
* return all tokens not just active
* add url fix
* PR comment
* PR comment
* PR comment
* add the flag to the experimental options
* fix env var name
## What
This PR adds an extra layer of OpenAPI validation testing to what we already have. It also fixes any issues that make the new tests fail.
## Why
While the current OpenAPI validation takes care of _some_ things, there's also things it misses, as shown by #2055. By adding the OpenAPI Enforcer package, we should hopefully be able to catch more of these errors in the future. The enforcer _does_ flag the issue in #2055 as an error.
## How
By adding the OpenAPI Enforcer package and making whatever changes it picks up on.
By adding location headers to all our 201 endpoints. I also had to change some signatures on `create` store methods so that they actually return something (a lot of them just returned `void`).
## Discussion points
### Code changes
Some of the code changes may not be necessary or we may want to change more code to align with what changes have been done. It may be worth standardizing on a pattern for `*store.create` methods, so that they always return an identifier or the stored object, for instance.
### On relative URIs
The 201 location headers use relative URIs to point to the created resources. This seemed to be the easiest way to me, as we don't need to worry about figuring out what the absolute URL of the instance is (though we could probably just concat it to the request URI?). The algorithm for determining relative URIs is described in [RFC 3986 section 5](https://www.rfc-editor.org/rfc/rfc3986#section-5).
There's also some places where I'm not sure we _can_ provide accurate location url. I think they're supposed to point _directly at_ whatever the resource is, but for some resources (such as api tokens), you can only get it as part of a collection. From [RFC 9110 on the location field](https://httpwg.org/specs/rfc9110.html#field.location) (emphasis mine):
> the Location header field in a [201 (Created)](https://httpwg.org/specs/rfc9110.html#status.201) response is supposed to provide a URI that is **specific** to the created resource.
A link to a collection is not specific. I'm not sure what best to do about this.
### Inline comments
I've added a number of inline PR comments that I'd love to get some feedback on too. Have a look and let me know what you think!
### Unfinished business
I've added some juicy comments to some of the files here. They contain non-blocking issues that I'm tracking (via github issues). We should resolve them in the future, but right now they can stay as they are.
## Commits
* Feat: add openapi-enforcer + tests; fix _some_ issues
* Test: allow non-standard string formats
* validation: fix _some_ 201 created location header endpoints
* #1391: fix remaining 201 location headers missing
* Refactor: use the ajv options object instead of add* methods
* #1391: flag validation errors and warnings as test failures
* #1391: modify patch schema to specify either object or array
We don't provide many patch endpoints, so we _could_ create separate
patch operation objects for each one. I think that makes sense to do
as part of the larger cleanup. For now, I think it's worth to simply
turn it into one of these. While it's not entirely accurate, it's
better than what we had before.
* Refactor: make tests easier to read
* #1391: use enum for valid token types
This was previously only a description. This may seem like a breaking
change because OpenAPI would previously accept any string. However,
Joi also performs validation on this, so invalid values wouldn't work
previously either.
* #1391: Comment out default parameter values for now
This isn't the _right_ way, but it's the pragmatic solution. It's not
a big deal and this works as a stopgap solution.
* #1391: add todo note for api token schema fixes
* #1391: update snapshot
* Revert "#1391: modify patch schema to specify either object or array"
This reverts commit 0dd5d0faa1.
Turns out we need to allow much more than just objects and arrays.
I'll leave this as is for now.
* Chore(#1391): update comment explaining api token schema TODO
* #1391: modify some test code and add comment
* #1391: update tests and spec to allow 'any' type in schema
* Chore: remove comment
* #1391: add tests for context field stores
* #1391: add location header for public signup links
* #1391: fix query parameter description.
There was indeed a bug in the package, and this has been addressed
now, so we can go back to describing the params properly.
* Refactor(#1391): don't check for OpenAPI version in snapshot tests
remove the version from the received specification. The version
_is_ a required field, but having the version listed in automated
testing causes issues when trying to deploy new versions of the
API (due to mismatch between new tag versions etc). That's why we
remove it.
* #1391: test that the "semver" property is present
* #1391: test that the openapi version is valid semver
* Chore(#1391): comment formatting
* First version ready
* Final
* Refactor
* Update pat store
* Website revert
* Website revert
* Update
* Revert website
* Revert docs to main
* Revert docs to main
* Fix eslint
* Test
* Fix table name
* Fix(#1391): Expose API version even when not running via npm/yarn
## What
Expose the current Unleash version in the generated OpenAPI docs, even
when running via docker or other processes.
## Why
An OpenAPI spec without a version isn't valid. This causes some of our
generation tools (such as the one for documentation) to fail.
## How
By changing how we fetch the current version:
Previously, we used `process.env.npm_package_version!`. However, when
you're not running with yarn or npm, this is `undefined`. That causes
the version number to not be included when running tests and when
running using the official docker image.
Instead, we now use `version` from `lib/util/version`. This is the
same version as the one used by the UI config endpoint, so it should
be the same one as what the front end displays. To the best of my
knowledge, this _is_ the version of the API.
## Discussion
It _may_ be that I have misunderstood what the version represents, but
from what I can tell, it just exports what's listed as the version in
package.json.
The source code of the `lib/util/version` file is:
```ts
// export module version
require('pkginfo')(module, 'version');
const { version } = module.exports;
export default version;
module.exports = version;
```
* Refactor(#1391): rename imported variable for clarity