Code Monkey home page Code Monkey logo

unleash-proxy's Introduction

What is Unleash?

Unleash is a powerful open source solution for feature management. It streamlines your development workflow, accelerates software delivery, and empowers teams to control how and when they roll out new features to end users. With Unleash, you can deploy code to production in smaller, more manageable releases at your own pace.

Feature flags in Unleash let you test your code with real production data, reducing the risk of negatively impacting your users' experience. It also enables your team to work on multiple features simultaneously without the need for separate feature branches.

Unleash is the most popular open source solution for feature flagging on GitHub. It supports 15 official client and server SDKs and over 15 community SDKs. You can even create your own SDK if you wish. Unleash is compatible with any language and framework.


Getting Started with Unleash

1. Setting Up Unleash

To get started with Unleash, you need git and docker installed on your machine.

Execute the following commands:

git clone [email protected]:Unleash/unleash.git
cd unleash
docker compose up -d

Then point your browser to localhost:4242 and log in using:

  • username: admin
  • password: unleash4all

If you'd rather run the source code in this repo directly via Node.js, see the step-by-step instructions to get up and running in the contributing guide.

2. Connect your SDK

Find your preferred SDK in our list of official SDKs and import it into your project. Follow the setup guides for your specific SDK.

If you use the docker compose file from the previous step, here's the configuration details you'll need to get going:

  • For front-end SDKs, use:
    • URL: http://localhost:4242/api/frontend/
    • clientKey: default:development.unleash-insecure-frontend-api-token
  • For server-side SDKs, use:
    • Unleash API URL: http://localhost:4242/api/
    • API token: default:development.unleash-insecure-api-token

If you use a different setup, your configuration details will most likely also be different.

Check a feature toggle

Checking the state of a feature toggle in your code is easy! The syntax will vary depending on your language, but all you need is a simple function call to check whether a toggle is available. Here's how it might look in Java:

if (unleash.isEnabled("AwesomeFeature")) {
  // do new, flashy thing
} else {
  // do old, boring stuff
}

Run Unleash on a service?

If you don't want to run Unleash locally, we also provide easy deployment setups for Heroku and Digital Ocean:

Deploy to Heroku Deploy to DigitalOcean

Configure and run Unleash anywhere

The above sections show you how to get up and running quickly and easily. When you're ready to start configuring and customizing Unleash for your own environment, check out the documentation for getting started with self-managed deployments, Unleash configuration options, or running Unleash locally via docker.


Online demo

Try out the Unleash online demo.

The Unleash online demo


Community and help — sharing is caring

We know that learning a new tool can be hard and time-consuming. We have a growing community that loves to help out. Please don't hesitate to reach out for help.

Join Unleash on Slack

💬 Join Unleash on Slack if you want ask open questions about Unleash, feature toggling or discuss these topics in general.

💻 Create a GitHub issue if you have found a bug or have ideas on how to improve Unleash.

📚 Visit the documentation for more in-depth descriptions, how-to guides, and more.

📖 Learn more about the principles of building and scaling feature flag solutions.


Contribute to Unleash

Unleash is the largest open source feature flag solution on GitHub. Building Unleash is a collaborative effort, and we owe a lot of gratitude to many smart and talented individuals. Building it together with the community ensures that we build a product that solves real problems for real people. We'd love to have your help too: Please feel free to open issues or provide pull requests.

Check out the CONTRIBUTING.md file for contribution guidelines and the Unleash developer guide for tips on environment setup, running the tests, and running Unleash from source.

Contributors

The Unleash contributors


Features our users love

Flexibility and adaptability

Security and performance

  • Privacy by design (GDPR and Schrems II). End-user data never leaves your application.
  • Audit logs
  • Enforce OWASP's secure headers via the strict HTTPS-only mode
  • Flexible hosting options: host it on premise or in the cloud (any cloud)
  • Scale the Unleash Proxy independently of the Unleash server to support any number of front-end clients without overloading your Unleash instance

Looking for more features?

If you're looking for one of the following features, please take a look at our Pro and Enterprise plans:


Architecture

Read more in the system overview section of the Unleash documentation.


Unleash SDKs

To connect your application to Unleash you'll need to use a client SDK for your programming language.

Official server-side SDKs:

Official front-end SDKs:

The front-end SDKs connects via the Unleash Proxy in order to ensure privacy, scalability and security.

Community SDKs:

If none of the official SDKs fit your need, there's also a number of community-developed SDKs where you might find an implementation for your preferred language (such as Elixir, Dart, Clojure, and more).


Users of Unleash

Unleash is trusted by thousands of companies all over the world.

Proud Open-Source users: (send us a message if you want to add your logo here)

The Unleash logo encircled by logos for Finn.no, nav (the Norwegian Labour and Welfare Administration), Budgets, Otovo, and Amedia. The encircling logos are all connected to the Unleash logo.


Migration guides

Unleash has evolved significantly over the past few years, and we know how hard it can be to keep software up to date. If you're using the current major version, upgrading shouldn't be an issue. If you're on a previous major version, check out the Unleash migration guide!


Want to know more about Unleash?

Videos and podcasts

Articles and more

unleash-proxy's People

Contributors

andreas-unleash avatar captainglac1er avatar chriswk avatar dependabot[bot] avatar dzixxx avatar fredrikoseberg avatar gardleopard avatar gastonfournier avatar ivarconr avatar jonasws avatar kwasniew avatar lapa182 avatar lordoflairs avatar marybagratunyan avatar meemaw avatar mistic92 avatar naruthk avatar nunogois avatar nya1 avatar olav avatar pez avatar samdotci avatar seniorquico avatar sighphyre avatar sjaanus avatar thomasheartman avatar tymek avatar vkbandi avatar wizardfrag avatar zapplebee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

unleash-proxy's Issues

fix: Take full control of ETag header

Today ETag header is automatically calculated by express based on the payload. We should instead use the SDK updated event and generate this id in the proxy. This would allow us to provide the proxy SDKs with a 304 modified fast, without having to evaluate all feature toggles in memory.

Note: We would also need to consider the query params as part of the produced hash.

CORS Configuration does not apply for 304 refresh requests

Describe the bug

Configured our proxy server with the following

cors: {
        origin: 'http://localhost:3000'
    }

When making the initial request on page load for the flags, we get a perfect 200 with the header

Access-Control-Allow-Origin: http://localhost:3001

as expected, browser is happy.

Now, on a refresh request 30 seconds later (determined by refreshInterval) the same request is made with an extra header, something like

if-none-match: W/"101-w8M2PbyIXvu4DpZVMs3eAhoAXXU"

which I assume is just meant to save on compute by looking at a cache id. No problems

But the response we get (with a 304 as expected) does not have the CORS header like the original response has

Access-Control-Allow-Origin: http://localhost:3001

In fact, it has no CORS headers at all. This makes the browser unhappy and we end up with a failure every time it tries to refresh.

Steps to reproduce the bug

  1. Set the cors origins to be some value on the proxy server
  2. Make a request with Postman to get the toggles using a client id
  3. Note that the CORS origin you specified is set in the response header: Access-Control-Allow-Origin
  4. Take the ETag header from that response, and stick it in the request headers with the key if-none-match
  5. Make the request again, which should be a status code 304.
  6. Evaluate the headers, and notice the same CORS header is not included in the second response. Access-Control-Allow-Origin

Expected behavior

Expected behavior should be to still respond with a 304 HTTP code, but the requested CORS config should also be put on the response from the proxy server.

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

latest

Subscription type

Open source

Hosting type

Self-hosted

SDK information (language and version)

No response

Connecting to gitlab ERROR: Error: Unleash Repository error: Response was not statusCode 2XX, but was 401

Describe the bug

I'm running a proxy on my local that is connected to gitlab. When I use the code below to connect from a local express the output is Response was not statusCode 2XX, but was 401

try {
    const unleashProxy = createApp({
      unleashUrl: "http://localhost:3000/proxy",
      unleashApiToken: "not needed for gitlab",
      clientKeys: ["secret"],
      refreshInterval: 10000,
      logLevel: "debug",
    });
} catch (error) {
  console.error(error);
}

When trying to connect from postman to http://localhost:3000/proxy with the header {authorization: secret} the response is what I expected

{
    "toggles": [
        {
            "name": "logo_banner",
            "enabled": true,
            "variant": {
                "name": "disabled",
                "enabled": false
            }
        }
    ]
}

I'm assuming that the header isn't populated in the client but I'm not sure why.

Steps to reproduce the bug

No response

Expected behavior

No response

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

No response

Subscription type

Open source

Hosting type

None

SDK information (language and version)

"@unleash/proxy": "^0.13.1"

feat: GELF logger

Hey,

I would like to add a new logger that addresses a GELF endpoint. I think this one would be useful in a professional environment, where GrayLog is often used as the central log management. However, I have some questions:

  • First, would something like this even be desired?
  • I would create a new folder src/logger and separate the corresponding loggers into individual files in it. Agreed?
  • Currently it is not possible to choose a different logger for dockerimages. I would also change that in the move by allowing a string to select the logger to use. options.logger would of course be preserved for node.js runtime environments. The information needed for GELF I would then also want to query for Docker via environment variables. For node.js there will be an option/config array.

Looking forward to a reply! 😊

The Proxy API returns all feature toggles, even those from projects that are disabled for the requested environment

Describe the bug

Suppose we have Projects A and B declared on Unleash, each containing a few feature toggles.
We also have Environments 1 and 2.

Project A is enabled for Environments 1 & 2.
Project B is enabled only for Environment 1.

Steps to reproduce the bug

  1. When requesting the list of feature toggles from the Proxy API for Environment 1, we get all feature toggles, from both Projects A and B, which works as expected
  2. But the same thing applies for Environment 2 as well, we receive all feature toggles from both Projects A and B, even though only Project A is enabled for Environment 2

Expected behavior

When requesting feature toggles for Environment 2, only the toggles from Project A should be returned

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

4.19.2

Subscription type

Enterprise

Hosting type

Self-hosted

SDK information (language and version)

No response

Wait for the proxy to be ready to receive traffic

We are trying to deploy unleash proxy with AWS Lambda.

The example of handler function is the following

import { createApp } from '@unleash/proxy';
import * as serverless from 'serverless-http';

export const proxyHandler = async (event, context) => {
  const app = createApp({
    unleashUrl: process.env.UNLEASH_URL,
    unleashApiToken: process.env.UNLEASH_API_TOKEN,
    clientKeys: ['some-secret'],
    refreshInterval: 1000,
  });

  const handler = serverless(app);

  return handler(event, context);
};

The problem is that we should wait for the 'ready' event to be triggered before ‘wrapping’ the app for serverless use.

I have seen an approach in library's examples when passing a client as a second argument to the createApp function and making client.emit('ready') after, but the Client class is not exported by the library so this is not possible for us.

Please, can you help me with an answer whether there's a good solution to wait for/check the proxy to be ready to receive traffic.

Problem Running on AWS Lambda

Describe the bug

I'm getting an error when running unleash proxy behind a lambda function of it not being able to use a functions utils.forOwn. I'm running the proxy behind a lambda function using the serverless-http package.

Steps to reproduce the bug

  1. Setup an http lambda function
  2. Write this code
import unleash from '@unleash/proxy';
import { LogLevel } from '@unleash/proxy/dist/logger';
import { APIGatewayProxyHandlerV2 } from 'aws-lambda';
import serverless from 'serverless-http';

const app = unleash.createApp({
  unleashUrl: process.env.UNLEASH_URL,
  unleashInstanceId: process.env.UNLEASH_INSTANCE_ID,
  unleashAppName: process.env.UNLEASH_APP_NAME,
  clientKeys: [process.env.UNLEASH_PROXY_CLIENT_KEYS!],
  unleashApiToken: process.env.UNLEASH_API_TOKEN,
  refreshInterval: 1000,
  logLevel: LogLevel.debug,
  enableOAS: true,
  proxyBasePath: '/unleash',
});

export const handler: APIGatewayProxyHandlerV2 = serverless(app);
  1. Make any /unleash/proxy call

Expected behavior

A list of toggles

{
  "toggles": [
    {
      "name": "string",
      "enabled": true,
      "impressionData": true,
      "variant": {
        "name": "string",
        "enabled": true,
        "payload": {
          "type": "string",
          "value": "string"
        }
      }
    }
  ]

Logs, error output, etc.

{"error":"Whoops! We dropped the ball on this one (an unexpected error occurred): utils.forOwn is not a function"}

Screenshots

No response

Additional context

I'm utilizing the sst framework, hosting the endpoint behind a /unleash/{proxy+} endpoint through an AWS Api Gateway HTTP API

Unleash version

0.10.4

Subscription type

Open source

Hosting type

Self-hosted

SDK information (language and version)

No response

feat: Add config for instanceId

Currently it is not possible do define the instanceId that unleash-proxy is using in its unleash-client.
unleash-proxy generates a random instanceId that can not be overwriten in any way.

This makes it impossible to use unleash-proxy with a GitLab Managed Unleash Instance.
GitLab uses instanceId's as a way of identifiying different users and requires you to use a specific instanceId provided by them.

It would be awesome if you could make the instanceId configurable, for example via an environment variable.

Pass `req` to context enrichers

Describe the feature request

#87 introduced the notion of ContextEnrichers, which take the context of feature toggle evaluation modify it in some meaningful way. The use case of #87 is built around using fields that are already part of the context from the start.

To support more use cases, it would be helpful to pass the full request to context enrichers, so further custom information can be pulled from it into the context.

Background

Taking only fields from the existing context to enrich it is really limiting. This is especially true if you run the unleash-proxy embedded in a node application that already preprocesses the request a bit. Imagine running an application with authentication and having session information at hand (at req.user).

You would want to provide the user information as part of the context to use it in strategies. Without having access to the request, this is not possible. A workaround could only be knowing which requests unleash-proxy handles and how the context is transferred in each of them (req.query, req.body), and adding the fields there via a custom middleware, completely sidestepping the context enrichers in an honestly rather fragile way.

Solution suggestions

Enhance the ContextEnrichter interface to consume a Request. Pass the current req to the enrichContext function, so it can provide it to the context enricher chain.

This depends partly on #109, which makes sure enrichContext is actually called consistently across use endpoints

POST request

Hi,

I saw that it's possible to send a POST request with context information to the proxy, but when I try with Postman, I got an error

<pre>TypeError: Cannot read properties of undefined (reading &#39;map&#39;)<br> &nbsp; &nbsp;at Client.getDefinedToggles (C:\private\git\node_modules\@unleash\proxy\dist\client.js:75:28)<br> &nbsp; &nbsp;at UnleashProxy.lookupToggles (C:\private\git\node_modules\@unleash\proxy\dist\unleash-proxy.js:61:41)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (C:\private\git\node_modules\express\lib\router\layer.js:95:5)<br> &nbsp; &nbsp;at next (C:\private\git\node_modules\express\lib\router\route.js:137:13)<br> &nbsp; &nbsp;at Route.dispatch (C:\private\git\node_modules\express\lib\router\route.js:112:3)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (C:\private\git\node_modules\express\lib\router\layer.js:95:5)<br> &nbsp; &nbsp;at C:\private\git\node_modules\express\lib\router\index.js:281:22<br> &nbsp; &nbsp;at Function.process_params (C:\private\git\node_modules\express\lib\router\index.js:335:12)<br> &nbsp; &nbsp;at next (C:\private\git\node_modules\express\lib\router\index.js:275:10)<br> &nbsp; &nbsp;at Function.handle (C:\private\git\node_modules\express\lib\router\index.js:174:3)</pre>

My Payload
{"userId":"test"}

Best regards
Meex

Allow configuring the value for httpOptions.rejectUnauthorized via Environment variables

When using unleash proxy docker image, it is not possible to configure it to allow self signed certificates, I have tried using the environment variables NODE_EXTRA_CA_CERTS and NODE_TLS_REJECT_UNAUTHORIZED, both doesn't appear to stop the "request to https://gitlab.example.com/api/v4/feature_flags/unleash/000000/client/register failed, reason: self signed certificate in certificate chain" error.

The only workaround is to run the unleash proxy as a node js application and adding httpOptions: { rejectUnauthorized: false } in the createApp configuration

Example

const app = createApp({
    unleashUrl: 'https://gitlab.example.com/api/v4/feature_flags/unleash/000000',
    unleashInstanceId: '0xx-0x0_xxXXXXX0_xx0',
    unleashApiToken: 'xxxxx-xxxxxxxxxxxxxxxxxx',
    unleashAppName: "example",
    clientKeys: ['some-secret'],
    proxyPort: 3000,
    **httpOptions: { rejectUnauthorized: false }**
});

If the value for httpOptions.rejectUnauthorized can be read from the Environment variables, then we can use the unleash proxy with the provided docker image

Document how to use the proxy from a Proxy SDK

Hello again,

It is not super clear that UNLEASH_PROXY_SECRETS corresponds to clientKey when creating the client from the JavaScript Proxy SDK.

To make it easier to get started, maybe an example in the README after the list of Proxy SDKs might clarify? Or just mention that the secret should go in clientKey.

Or even change clientKey to proxySecret?

Feat: provide a graphql API

Currently the proxy has a simple http API.

In environments already leveraging graphql it could be beneficial to expose a graphql API as well.

I envision companies would be leveraging graphql stitching to make it performant for clients.

It should be optionally loaded.

👍🏼 If you think this is a good idea.

Disable prometheus endpoint

Describe the bug

Is it possible to add configuration option to disable prometheus endpoints, like one the unleash API server? This can potentially expose sensitive underlying host information.

Endpoint added in #78

Steps to reproduce the bug

No response

Expected behavior

No response

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

No response

Subscription type

No response

Hosting type

No response

SDK information (language and version)

No response

Custom SSL/TLS certificates in Docker image

We are trying to implement Unleash in my organization. We have deployed the Unleash server internally, and it listens on an internal HTTPS address. The Unleash proxy is therefore unable to connect to it, since it does not have the root CA certificate for our internal addresses. The Unleash proxy shows this error:

ERROR: FetchError: Unleash Repository error: request to https://internal.address/api/client/features failed, reason: self signed certificate in certificate chain

They way we normally work around this is by adding our local CA certificate in our docker images. However, this is not possible to do with the Unleash Proxy because the running user does not have root permissions, so it cannot make any modifications .

A method or some documentation on how to work with custom CA certificates should be added, for situations such as this.

Thanks!

Feature: Allow Turning a Feature On/Off from Context Perspective

As of now, unleash-proxy is a suitable solution for one of my use cases i.e. fetch enabled features for a context. Let's say I have a context property (constraint) of location on features A, B, and C. With unleash-proxy in place, I can easily find if A, B, and C are enabled on location, say X.

Extending to it, I have another use case where I want to be able to enable/disable a feature for a particular context (constraint). For instance, ideally, given a feature name and constraint's contextName and value, I want an API that would internally fetch that feature by name, iterate over all of its strategies, and for each strategy, iterate over all the constraints, and then finally add the value to the list of values of that constraint.

Right now, I am handling all of this logic on my end using the following steps:

  1. Get feature by name (unleash-server API call)
  2. Iterate over strategies and constraints of the fetched feature object, updating the payload, and then updating the feature (unleash-server API call).

Ideally, these responsibilities should not be on consumer's end because the logic is a bit complex and involves two network requests.

Getting an empty `toggles` array

Hi,

I've set up an Unleash instance and have confirmed that it works by using Postman. When I hit https://unleash-dev.innago.com/api/client/features I get a 200 OK with the following response:

{
	"version": 2,
	"features": [
		{
			"strategies": [],
			"enabled": false,
			"name": "testing-toggles",
			"description": "Temporary flag for testing using Unleash for release toggles. To be deleted once experiments are done.",
			"project": "default",
			"stale": false,
			"type": "release",
			"variants": []
		}
	],
	"query": null
}

I've also setup a proxy. But when I hit https://unleash-dev-proxy.innago.com/proxy I receive a 200 OK with the following payload:

{
	"toggles": []
}

In both of the above API calls I do not pass a request body and only set the Authorization header with the proper token.

To try and debug this, I have set the log level on the proxy to debug and here is what the logs show when I'm hitting it:

INFO: Get enabled feature toggles for provided context [ { remoteAddress: '::ffff:10.42.1.157', properties: {} } ]

And here is part of my YAML file:

spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      workload.user.cattle.io/workloadselector: apps.deployment-innago-dev-innago-dev-unleash-proxy
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: innago-dev-unleash-proxy
        client: innago
        environment: dev
        workload.user.cattle.io/workloadselector: apps.deployment-innago-dev-innago-dev-unleash-proxy
    spec:
      affinity: {}
      containers:
      - env:
        - name: UNLEASH_PROXY_SECRETS
          value: REDACTED
        - name: UNLEASH_URL
          value: https://unleash-dev.innago.com/api
        - name: UNLEASH_API_TOKEN
          value: REDACTED
        - name: LOG_LEVEL
          value: debug
        image: unleashorg/unleash-proxy
        imagePullPolicy: Always
        name: container-0
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

What could cause the proxy to return an empty toggles array?

Support for refresh interval jitter

Describe the feature request

Add support to configure refresh interval jitter.

Background

Having all proxy instances send metrics at the same time can put uneven load on the server, that would much easier to handle if there was a jitter.

Solution suggestions

Add a refreshIntervalJitter config option.

`proxyBasePath` requires leading slash to work correctly

Describe the bug

When providing a proxyBasePath, it must start with a leading slash to work correctly. The example in the docs does not have a leading slash.

Mentioned in this Slack thread.

Steps to reproduce the bug

  1. Run the proxy as via Node.js
  2. Specify some/base as the base path
  3. try to curl http://localhost:3000/some/base/proxy
  4. Get a 404

Expected behavior

I'd expect the proxy to "do what I mean". Whether I use a leading or trailing slash in a path section shouldn't matter. These things always catches someone off guard, and in this case I really can't see any reason why it should matter.

In other words, regardless of which of the following options you provide, the result should be the same (/base/path/proxy):

  • /base/path/
  • /base/path
  • base/path/
  • base/path

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

No response

Subscription type

No response

Hosting type

No response

SDK information (language and version)

0.10 of the Proxy

ERROR: Error: Unleash Repository error: Response was not statusCode 2XX, but was 401

Hi

I deployed unleash and postgress as described here:
https://hub.docker.com/r/unleashorg/unleash-server

I logged into unleash using 'admin' and 'unleash4all'.
i created an api token as admin.

i then ran unleash-proxy as documented using the token.

docker run    -e UNLEASH_PROXY_SECRETS=some-secret    -e UNLEASH_URL=http://192.168.122.195:4242/api/    -e UNLEASH_API_TOKEN=728934fd84bb7926ecd5367602fe5efc3550c66778b210d978576254    -p 3000:3000    unleashorg/unleash-proxy
Unleash-proxy is listening on port 3000!
ERROR: Error: Unleash Repository error: Response was not statusCode 2XX, but was 401 
ERROR: Error: Unleash Repository error: Response was not statusCode 2XX, but was 401 

hitting the interface http://192.168.122.195:4242/api/ returns

{"type":"password","path":"/auth/simple/login","message":"You must sign in order to use Unleash","defaultHidden":false}

Unable to Launch on Node 12

Launch my application with following error:

***/node_modules/@unleash/proxy/dist/config.js:44
    return resolveStringToArray(tags)?.map((tag) => {
                                      ^

SyntaxError: Unexpected token '.'
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (***/node_modules/@unleash/proxy/dist/app.js:11:18)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (***/node_modules/@unleash/proxy/dist/index.js:7:15)
    at Module._compile (internal/modules/cjs/loader.js:999:30)

I think the issue is causing by the optional chaining, it's not supported on Node v12. (supported from v14)

fix: Improve loading of custom strategies in docker.

In order to successfully load custom strategies inside docker you will currently need to also bundle the unleash-client dependency, like this:

npm init -y
npm install unleash-client

Now you should be able to load a custom strategy like this in docker:

docker run \
   -e UNLEASH_PROXY_SECRETS=some-secret \
   -e UNLEASH_URL=https://app.unleash-hosted.com/demo/api/ \
   -e UNLEASH_API_TOKEN=56907a2fa53c1d16101d509a10b78e36190b0f918d9f122d \
   -e UNLEASH_CUSTOM_STRATEGIES_FILE=/config/toggle-strategies.js \
   --mount type=bind,source="$(pwd)"/config,target=/config \
   -p 3333:3000 \
   unleashorg/unleash-proxy

And in the local directory in ./config/toggle-strategies.js I have:

const unleash = require('unleash-client');

class WorkspaceStrategy extends unleash.Strategy {
  constructor() {
    super('fy-workspace');
  }

  isEnabled(parameters, context) {
    return parameters['fy-workspace-id'].includes(context['fy-workspace-id']);
  }
}

module.exports = [new WorkspaceStrategy()];

We should not require the user to also add the unleash-client dependency because we already have this inside the proxy. We need to find a way to reuse the loaded dependency when loading these custom strategy implementations from a mounted folder.

Docker file does not start server

The docker file merely runs dist/server

but server just defines a start function

we need a small example folder where you import the project (or yarn install it) and then run it similar to the example

Return disabled toggles as well on the proxy endpoint

Describe the feature request

Currently, the proxy endpoint returns only toggles evaluated as enabled by the Proxy for the current user, as stated inside the docs https://docs.getunleash.io/sdks/unleash-proxy#payload.
It there any particular reasoning for this design choice?

Background

In our flows we would need to know if the Proxy performed a proper evaluation to disabled OR if the Unleash instance doesn't even have the queried toggle defined.

Solution suggestions

Can this be achieved, if not through the default proxy endpoint implementation, then maybe by using either a different endpoint or a query param? Subsequently, can this be added inside the Android Proxy SDK and the rest of the SDKs (https://docs.getunleash.io/sdks/unleash-proxy#how-to-connect-to-the-proxy)?

Unexpected behavior when isEnabled in Custom Strategy definition has an exception thrown

Describe the bug

If you create a custom strategy, and try to access a property of undefined during the isEnabled method, the entire call for getting features given a context returns a 404 - which is a very strange response. I would expect it to at least log the error, or throw a 500. Had me chasing reverse proxy/cache-ing issues for three-four hours 😂

Steps to reproduce the bug

Create a custom strategy that accesses a property of undefined. Not the notAField in the return statement, this will surely throw a 'cannot access property accountId of undefined

You could also probably just throw an Error in the function as well and get the same result, though I did not test that.

const { Strategy } = require('unleash-client');

class AccountsStrategy extends Strategy {
    constructor() {
        super('Accounts');
    }

    isEnabled(parameters, context) {
            return parameters.accountIds.includes(context.notAField.accountId);
    }
}

module.exports.AccountsStrategy = AccountsStrategy;

Now, register that custom strategy, and make a call to the proxy with a feature configured to be using that custom strategy.

The app will respond with a 404 Not Found error.

Expected behavior

I'd expect this to fail a little more noticeably, or at least log the exception and return false for the feature. Not a random 404 that has nothing to do with the logic of the code.

Logs, error output, etc.

Setting log level to debug would show the context of the user's request before returning a 404, so I knew it was getting routed properly. 


INFO: Get enabled feature toggles for provided context [
  {
    appName: 'myApp',
    environment: 'production',
    userId: 'myUserId',
    remoteAddress: '::1',
    properties: { accountId: 'validAccountId' }
  }
]


### Screenshots

_No response_

### Additional context

This happened on the Node.js version of the self-hosted proxy, not the Docker one. Was able to reproduce in the cloud as well as locally. 

### Unleash version

latest

### Subscription type

Open source

### Hosting type

Self-hosted

### SDK information (language and version)

Was connecting to the proxy via the Javascript client SDK

Fix: index.ts should not call start()

We should not call start in index.ts and move it to a separate file (start-server.ts) which also should be the main entry point in package.json.

Also docker needs to call start-server.js

fix: Add config for CORS header

today we have a default for CORS. It could be good if the customers was allowed to configure their custom CORS header when needed.

Cannot connect to local unleash server

Hello,

I'm trying to set up a local unleash server with the unleash proxy. However, I'm facing this error when running unleash-proxy:
ERROR: FetchError: Unleash Repository error: request to http://localhost:4242/api/client/features failed, reason: connect ECONNREFUSED 127.0.0.1:4242

I started the unleash-docker following these instructions: https://github.com/Unleash/unleash-docker#work-locally-with-this-repo

And I'm running unleash-proxy with this:
docker run -e UNLEASH_PROXY_SECRETS=some-secret -e UNLEASH_URL=http://localhost:4242/api/ -e UNLEASH_API_TOKEN="*:development.03b484052e9244c40ec4080216c4f00fcb3ef5e2c995a4468814e3bf" -p 3000:3000 unleashorg/unleash-proxy

How can I troubleshoot this error?

Thanks in advance.

Using proxy and proxy client in the same process

When i run the unleash-proxy in a nodejs process where i also want to read toggle states, how should i query them?
I see that there is an option to replace fetch in unleash-proxy-client-js but is it prossible to query the proxy without making an extra http request?
I see the second argument of createApp() is client, but it's not documented yet. Would it be safe to use that?

Also, thanks a lot for this great tool! ❤️

Port option not honored

Hello, thanks for providing!

I'm running another service at port 3000 so tried starting the proxy like so:

docker run \
   -e UNLEASH_PROXY_SECRETS=some-secret \
   -e UNLEASH_URL=https://app.unleash-hosted.com/demo/api/ \
   -e UNLEASH_API_TOKEN=56907a2fa53c1d16101d509a10b78e36190b0f918d9f122d \
   -p 3333:3333 \
   unleashorg/unleash-proxy

However, it returns:

Unleash-proxy is listening on port 3000!

And it's not just the message that is wrong, I think, because:

$ curl http://0.0.0.0:3333/proxy -H "Authorization: some-secret"  

curl: (52) Empty reply from server

Whereas if I start with -p 3000:3000 I get some nice flag config back.

Types declarations missing in package

When i try to install the @unleash/proxy package into an Typescript project. My compiler is complaining that there are no type definitions for this package.

TS7016: Could not find a declaration file for module '@unleash/proxy'. '/path-to-project/node_modules/@unleash/proxy/dist/index.js' implicitly has an 'any' type.   Try `npm i --save-dev @types/unleash__proxy` if it exists or add a new declaration (.d.ts) file containing `declare module '@unleash/proxy';`

When i look into the package in my node_modules folder i can confirm, that there are no .d.ts files.
Defining the module by myself like this:

declare module '@unleash/proxy' {
    export * from '@unleash/proxy';
}

only leads to an error saying that there are no types for package compression (a dependency of @unleash/proxy)
As this is not my direct dependency, i actually dont want to install the types for this..

Would it be possible to publish theses types within the package? This would make it alot easier to use it with typescript.

feat: Helm chart

An official Helm chart would simplify deployments to Kubernetes.

OpenAPI gets broken when using PROXY_BASE_PATH

Describe the bug

Hi!

When I try to use PROXY_BASE_PATH: "base-path" with ENABLE_OAS: "true" all of the requests to unleash proxy which I make using OpenAPI interface return 404.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /base-path/base-path/proxy</pre>
</body>
</html>

Seem like the reason for 404 is duplicated part /base-path in the url. Maybe there is some misconfiguration of OpenAPI when PROXY_BASE_PATH is used

Steps to reproduce the bug

I used similar docker-compose.yml:

version: '3.8'

services:
  unleash:
    image: unleashorg/unleash-proxy
    environment:
      ENABLE_OAS: "true"
      PROXY_BASE_PATH: "base-path"
      UNLEASH_PROXY_CLIENT_KEYS: $UNLEASH_PROXY_CLIENT_KEYS
      UNLEASH_URL: $UNLEASH_URL
      UNLEASH_INSTANCE_ID: $UNLEASH_INSTANCE_ID
      UNLEASH_APP_NAME: $UNLEASH_APP_NAME
      UNLEASH_API_TOKEN: $UNLEASH_API_TOKEN
    ports:
      - 3000:3000

Run it and then go to http://127.0.0.1:3000/base-path/docs/openapi/

If you try to execute any request using OpenAPI Interface, it returns 404 in response

Expected behavior

No response

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

No response

Subscription type

None

Hosting type

None

SDK information (language and version)

No response

use `logger.debug` in `getAllToggles`

Describe the feature request

Hey there,

Inside the getAllToggles api there is a logger usage:

this.logger.info(
            'Get all feature toggles for provided context',
            inContext,
        );

This log can be very spammy with high traffic, and it seems the purpose of this log is for debugging/troubleshooting, so I would like to suggest changing it to:

this.logger.debug(
            'Get all feature toggles for provided context',
            inContext,
        );

If it is accepted as a request for change I can submit a PR for it.

Background

No response

Solution suggestions

No response

Wrong instructions in Readme

In the code
const apiToken = req.header('authorization');
in the documentation
curl http://localhost:3000/proxy -H "Authorization: some-secret"

That's not going to work on *nix.

Authorize users based on JWT token

Provide a list of specific JWT token provider instead of a shared secret.

In my example, I'm building a single page application using Azure B2C as the user base. I envision that I can give this package some kind of public version of telling that it should accept all valid tokens from my JWT token provider. This would make this proxy more secure by not relying on having a shared secret with the website.

Unleash Proxy does not return Feature flags for dev environment

Describe the bug

Feature Flags have been created in the Gitlab repository named test-feature1 (for All Environments) and test-feature2 (for dev environments).

Unleash-proxy is configured with this repository - the following environment variables are set:

-env:
   -name: UNLEASH_ENVIRONMENT
     value:dev
   -name: UNLEASH_API_TOKEN
     value: some_gitlab_access_api_token
   -name: UNLEASH_PROXY_CLIENT_KEYS
     value: W0JHeVYSFwyBXEY7IV8BHogSx3L
   - name: UNLEASH_URL
     value: https://gitlab.domain/api/v4/feature_flags/unleash/8113
   - name: LOG_LEVEL
     value: info
   - name: UNLEASH_APP_NAME
     value: some_app_name
   -name: UNLEASH_INSTANCE_ID
     value: some_instance_id
   - name: JSON_LOGGER
     value: "true"

When I try to get Feature Flags from unleash-proxy I only get test-feature1 (For All Environments) and not for test-feature2 (for dev).

$ curl --silent unleash-proxy-app-dev.ingress-domain.lan/proxy -H "Authorization: W0JHeVYSFwyBXEY7IV8BHogSx3L" | jq
{
   "toggles": [
     {
       "name": "test-feature1",
       "enabled": true
       "variant": {
         "name": "disabled",
         "enabled": false
       }
     }
   ]
}

If you set the Feature Flags for test-feature2 to All Environments, then the query returns two Feature Flags.

test-feature1 (For All Environments) and test-feature2 (For dev) are both enabled.

How to get Feature Flag from request to unleash proxy for dev environment?

Steps to reproduce the bug

No response

Expected behavior

Should return flags for dev environments.

Logs, error output, etc.

No response

Screenshots

No response

Additional context

No response

Unleash version

0.13.1

Subscription type

Open source

Hosting type

Self-hosted

SDK information (language and version)

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.