mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-08 01:15:49 +02:00
Refactor: rename frontend api key (#1935)
* refactor: rename frontend api key * fix: api token schema tests
This commit is contained in:
parent
037b8eacd3
commit
3266e9c22a
@ -36,13 +36,13 @@ const apiAccessMiddleware = (
|
|||||||
try {
|
try {
|
||||||
const apiToken = req.header('authorization');
|
const apiToken = req.header('authorization');
|
||||||
const apiUser = apiTokenService.getUserForToken(apiToken);
|
const apiUser = apiTokenService.getUserForToken(apiToken);
|
||||||
const { CLIENT, PROXY } = ApiTokenType;
|
const { CLIENT, FRONTEND } = ApiTokenType;
|
||||||
|
|
||||||
if (apiUser) {
|
if (apiUser) {
|
||||||
if (
|
if (
|
||||||
(apiUser.type === CLIENT && !isClientApi(req)) ||
|
(apiUser.type === CLIENT && !isClientApi(req)) ||
|
||||||
(apiUser.type === PROXY && !isProxyApi(req)) ||
|
(apiUser.type === FRONTEND && !isProxyApi(req)) ||
|
||||||
(apiUser.type === PROXY && !experimental.embedProxy)
|
(apiUser.type === FRONTEND && !experimental.embedProxy)
|
||||||
) {
|
) {
|
||||||
res.status(403).send({ message: TOKEN_TYPE_ERROR_MESSAGE });
|
res.status(403).send({ message: TOKEN_TYPE_ERROR_MESSAGE });
|
||||||
return;
|
return;
|
||||||
|
@ -56,10 +56,10 @@ test('should set metadata', async () => {
|
|||||||
expect(token.projects).toBeUndefined();
|
expect(token.projects).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should allow for embedded proxy (frontend) key', async () => {
|
test('should allow for frontend key (embedded proxy)', async () => {
|
||||||
let token = await createApiToken.validateAsync({
|
let token = await createApiToken.validateAsync({
|
||||||
username: 'test',
|
username: 'test',
|
||||||
type: 'proxy',
|
type: 'frontend',
|
||||||
project: 'default',
|
project: 'default',
|
||||||
metadata: {
|
metadata: {
|
||||||
corsOrigins: ['*'],
|
corsOrigins: ['*'],
|
||||||
@ -68,10 +68,10 @@ test('should allow for embedded proxy (frontend) key', async () => {
|
|||||||
expect(token.error).toBeUndefined();
|
expect(token.error).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should set environment to default for proxy key', async () => {
|
test('should set environment to default for frontend key', async () => {
|
||||||
let token = await createApiToken.validateAsync({
|
let token = await createApiToken.validateAsync({
|
||||||
username: 'test',
|
username: 'test',
|
||||||
type: 'proxy',
|
type: 'frontend',
|
||||||
project: 'default',
|
project: 'default',
|
||||||
metadata: {
|
metadata: {
|
||||||
corsOrigins: ['*'],
|
corsOrigins: ['*'],
|
||||||
|
@ -10,7 +10,11 @@ export const createApiToken = joi
|
|||||||
.string()
|
.string()
|
||||||
.lowercase()
|
.lowercase()
|
||||||
.required()
|
.required()
|
||||||
.valid(ApiTokenType.ADMIN, ApiTokenType.CLIENT, ApiTokenType.PROXY),
|
.valid(
|
||||||
|
ApiTokenType.ADMIN,
|
||||||
|
ApiTokenType.CLIENT,
|
||||||
|
ApiTokenType.FRONTEND,
|
||||||
|
),
|
||||||
expiresAt: joi.date().optional(),
|
expiresAt: joi.date().optional(),
|
||||||
project: joi.when('projects', {
|
project: joi.when('projects', {
|
||||||
not: joi.required(),
|
not: joi.required(),
|
||||||
@ -18,7 +22,7 @@ export const createApiToken = joi
|
|||||||
}),
|
}),
|
||||||
projects: joi.array().min(0).optional(),
|
projects: joi.array().min(0).optional(),
|
||||||
environment: joi.when('type', {
|
environment: joi.when('type', {
|
||||||
is: joi.string().valid(ApiTokenType.CLIENT, ApiTokenType.PROXY),
|
is: joi.string().valid(ApiTokenType.CLIENT, ApiTokenType.FRONTEND),
|
||||||
then: joi.string().optional().default(DEFAULT_ENV),
|
then: joi.string().optional().default(DEFAULT_ENV),
|
||||||
otherwise: joi.string().optional().default(ALL),
|
otherwise: joi.string().optional().default(ALL),
|
||||||
}),
|
}),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ApiTokenService } from './api-token-service';
|
import { ApiTokenService } from './api-token-service';
|
||||||
import { createTestConfig } from '../../test/config/test-config';
|
import { createTestConfig } from '../../test/config/test-config';
|
||||||
import { IUnleashConfig } from '../server-impl';
|
import { IUnleashConfig } from '../server-impl';
|
||||||
import { ApiTokenType } from '../types/models/api-token';
|
import { ApiTokenType, IApiTokenCreate } from '../types/models/api-token';
|
||||||
import FakeApiTokenStore from '../../test/fixtures/fake-api-token-store';
|
import FakeApiTokenStore from '../../test/fixtures/fake-api-token-store';
|
||||||
import FakeEnvironmentStore from '../../test/fixtures/fake-environment-store';
|
import FakeEnvironmentStore from '../../test/fixtures/fake-environment-store';
|
||||||
|
|
||||||
@ -33,3 +33,37 @@ test('Should init api token', async () => {
|
|||||||
|
|
||||||
expect(tokens).toHaveLength(1);
|
expect(tokens).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Shouldn't return frontend token when secret is undefined", async () => {
|
||||||
|
const token: IApiTokenCreate = {
|
||||||
|
environment: 'default',
|
||||||
|
projects: ['*'],
|
||||||
|
secret: '*:*:some-random-string',
|
||||||
|
type: ApiTokenType.FRONTEND,
|
||||||
|
username: 'front',
|
||||||
|
expiresAt: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const config: IUnleashConfig = createTestConfig({});
|
||||||
|
const apiTokenStore = new FakeApiTokenStore();
|
||||||
|
const environmentStore = new FakeEnvironmentStore();
|
||||||
|
|
||||||
|
await environmentStore.create({
|
||||||
|
name: 'default',
|
||||||
|
enabled: true,
|
||||||
|
protected: true,
|
||||||
|
type: 'test',
|
||||||
|
sortOrder: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const apiTokenService = new ApiTokenService(
|
||||||
|
{ apiTokenStore, environmentStore },
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
|
||||||
|
await apiTokenService.createApiTokenWithProjects(token);
|
||||||
|
await apiTokenService.fetchActiveTokens();
|
||||||
|
|
||||||
|
expect(apiTokenService.getUserForToken(undefined)).toEqual(undefined);
|
||||||
|
expect(apiTokenService.getUserForToken('')).toEqual(undefined);
|
||||||
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { ADMIN, CLIENT, PROXY } from '../types/permissions';
|
import { ADMIN, CLIENT, FRONTEND } from '../types/permissions';
|
||||||
import { IUnleashStores } from '../types/stores';
|
import { IUnleashStores } from '../types/stores';
|
||||||
import { IUnleashConfig } from '../types/option';
|
import { IUnleashConfig } from '../types/option';
|
||||||
import ApiUser from '../types/api-user';
|
import ApiUser from '../types/api-user';
|
||||||
@ -29,8 +29,8 @@ const resolveTokenPermissions = (tokenType: string) => {
|
|||||||
return [CLIENT];
|
return [CLIENT];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenType === ApiTokenType.PROXY) {
|
if (tokenType === ApiTokenType.FRONTEND) {
|
||||||
return [PROXY];
|
return [FRONTEND];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
@ -69,7 +69,7 @@ export class ApiTokenService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchActiveTokens(): Promise<void> {
|
async fetchActiveTokens(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.activeTokens = await this.getAllActiveTokens();
|
this.activeTokens = await this.getAllActiveTokens();
|
||||||
} finally {
|
} finally {
|
||||||
@ -102,12 +102,18 @@ export class ApiTokenService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getUserForToken(secret: string): ApiUser | undefined {
|
public getUserForToken(secret: string): ApiUser | undefined {
|
||||||
|
if (!secret) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
let token = this.activeTokens.find((t) => t.secret === secret);
|
let token = this.activeTokens.find((t) => t.secret === secret);
|
||||||
|
|
||||||
// If the token is not found, try to find it in the legacy format with the metadata alias
|
// If the token is not found, try to find it in the legacy format with the metadata alias
|
||||||
// This is to ensure that previous proxies we set up for our customers continue working
|
// This is to ensure that previous proxies we set up for our customers continue working
|
||||||
if (!token) {
|
if (!token && secret) {
|
||||||
token = this.activeTokens.find((t) => t.metadata.alias === secret);
|
token = this.activeTokens.find(
|
||||||
|
(t) => t.metadata.alias && t.metadata.alias === secret,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
|
@ -115,6 +115,6 @@ export class ProxyService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static assertExpectedTokenType({ type }: ApiUser) {
|
private static assertExpectedTokenType({ type }: ApiUser) {
|
||||||
assert(type === ApiTokenType.PROXY || type === ApiTokenType.ADMIN);
|
assert(type === ApiTokenType.FRONTEND || type === ApiTokenType.ADMIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ export const ALL = '*';
|
|||||||
export enum ApiTokenType {
|
export enum ApiTokenType {
|
||||||
CLIENT = 'client',
|
CLIENT = 'client',
|
||||||
ADMIN = 'admin',
|
ADMIN = 'admin',
|
||||||
PROXY = 'proxy',
|
FRONTEND = 'frontend',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILegacyApiTokenCreate {
|
export interface ILegacyApiTokenCreate {
|
||||||
@ -108,9 +108,9 @@ export const validateApiToken = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === ApiTokenType.PROXY && environment === ALL) {
|
if (type === ApiTokenType.FRONTEND && environment === ALL) {
|
||||||
throw new BadDataError(
|
throw new BadDataError(
|
||||||
'Proxy token cannot be scoped to all environments',
|
'Frontend token cannot be scoped to all environments',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//Special
|
//Special
|
||||||
export const ADMIN = 'ADMIN';
|
export const ADMIN = 'ADMIN';
|
||||||
export const CLIENT = 'CLIENT';
|
export const CLIENT = 'CLIENT';
|
||||||
export const PROXY = 'PROXY';
|
export const FRONTEND = 'FRONTEND';
|
||||||
export const NONE = 'NONE';
|
export const NONE = 'NONE';
|
||||||
|
|
||||||
export const CREATE_FEATURE = 'CREATE_FEATURE';
|
export const CREATE_FEATURE = 'CREATE_FEATURE';
|
||||||
|
@ -246,7 +246,7 @@ Object {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"type": Object {
|
"type": Object {
|
||||||
"description": "client, admin, proxy.",
|
"description": "client, admin, frontend.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"username": Object {
|
"username": Object {
|
||||||
@ -683,7 +683,7 @@ Object {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"type": Object {
|
"type": Object {
|
||||||
"description": "client, admin, proxy.",
|
"description": "client, admin, frontend.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"username": Object {
|
"username": Object {
|
||||||
|
@ -88,7 +88,7 @@ const createProject = async (id: string): Promise<void> => {
|
|||||||
await app.services.projectService.createProject({ id, name: id }, user);
|
await app.services.projectService.createProject({ id, name: id }, user);
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should require a proxy token or an admin token', async () => {
|
test('should require a frontend token or an admin token', async () => {
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
@ -117,64 +117,64 @@ test('should allow requests with an admin token', async () => {
|
|||||||
.expect((res) => expect(res.body).toEqual({ toggles: [] }));
|
.expect((res) => expect(res.body).toEqual({ toggles: [] }));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not allow admin requests with a proxy token', async () => {
|
test('should not allow admin requests with a frontend token', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/admin/features')
|
.get('/api/admin/features')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(403);
|
.expect(403);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not allow client requests with a proxy token', async () => {
|
test('should not allow client requests with a frontend token', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/client/features')
|
.get('/api/client/features')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(403);
|
.expect(403);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not allow requests with an invalid proxy token', async () => {
|
test('should not allow requests with an invalid frontend token', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyToken.secret.slice(0, -1))
|
.set('Authorization', frontendToken.secret.slice(0, -1))
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(401);
|
.expect(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should allow requests with a proxy token', async () => {
|
test('should allow requests with a frontend token', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => expect(res.body).toEqual({ toggles: [] }));
|
.expect((res) => expect(res.body).toEqual({ toggles: [] }));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return 405 from unimplemented endpoints', async () => {
|
test('should return 405 from unimplemented endpoints', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await app.request
|
await app.request
|
||||||
.post('/api/frontend')
|
.post('/api/frontend')
|
||||||
.send({})
|
.send({})
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(405);
|
.expect(405);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend/client/features')
|
.get('/api/frontend/client/features')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(405);
|
.expect(405);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend/health')
|
.get('/api/frontend/health')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(405);
|
.expect(405);
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend/internal-backstage/prometheus')
|
.get('/api/frontend/internal-backstage/prometheus')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(405);
|
.expect(405);
|
||||||
});
|
});
|
||||||
@ -183,16 +183,16 @@ test('should return 405 from unimplemented endpoints', async () => {
|
|||||||
test.todo('should enforce token CORS settings');
|
test.todo('should enforce token CORS settings');
|
||||||
|
|
||||||
test('should accept client registration requests', async () => {
|
test('should accept client registration requests', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await app.request
|
await app.request
|
||||||
.post('/api/frontend/client/register')
|
.post('/api/frontend/client/register')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.send({})
|
.send({})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(400);
|
.expect(400);
|
||||||
await app.request
|
await app.request
|
||||||
.post('/api/frontend/client/register')
|
.post('/api/frontend/client/register')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.send({
|
.send({
|
||||||
appName: randomId(),
|
appName: randomId(),
|
||||||
instanceId: randomId(),
|
instanceId: randomId(),
|
||||||
@ -211,7 +211,7 @@ test('should store proxy client metrics', async () => {
|
|||||||
const appName = randomId();
|
const appName = randomId();
|
||||||
const instanceId = randomId();
|
const instanceId = randomId();
|
||||||
const featureName = randomId();
|
const featureName = randomId();
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
const adminToken = await createApiToken(ApiTokenType.ADMIN, {
|
const adminToken = await createApiToken(ApiTokenType.ADMIN, {
|
||||||
projects: ['*'],
|
projects: ['*'],
|
||||||
environment: '*',
|
environment: '*',
|
||||||
@ -232,7 +232,7 @@ test('should store proxy client metrics', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.post('/api/frontend/client/metrics')
|
.post('/api/frontend/client/metrics')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.send({
|
.send({
|
||||||
appName,
|
appName,
|
||||||
instanceId,
|
instanceId,
|
||||||
@ -246,7 +246,7 @@ test('should store proxy client metrics', async () => {
|
|||||||
.expect((res) => expect(res.text).toEqual('OK'));
|
.expect((res) => expect(res.text).toEqual('OK'));
|
||||||
await app.request
|
await app.request
|
||||||
.post('/api/frontend/client/metrics')
|
.post('/api/frontend/client/metrics')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.send({
|
.send({
|
||||||
appName,
|
appName,
|
||||||
instanceId,
|
instanceId,
|
||||||
@ -282,7 +282,7 @@ test('should store proxy client metrics', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should filter features by enabled/disabled', async () => {
|
test('should filter features by enabled/disabled', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await createFeatureToggle({
|
await createFeatureToggle({
|
||||||
name: 'enabledFeature1',
|
name: 'enabledFeature1',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -300,7 +300,7 @@ test('should filter features by enabled/disabled', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -324,7 +324,7 @@ test('should filter features by enabled/disabled', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should filter features by strategies', async () => {
|
test('should filter features by strategies', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await createFeatureToggle({
|
await createFeatureToggle({
|
||||||
name: 'featureWithoutStrategies',
|
name: 'featureWithoutStrategies',
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@ -345,7 +345,7 @@ test('should filter features by strategies', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -363,7 +363,7 @@ test('should filter features by strategies', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should filter features by constraints', async () => {
|
test('should filter features by constraints', async () => {
|
||||||
const proxyToken = await createApiToken(ApiTokenType.PROXY);
|
const frontendToken = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
await createFeatureToggle({
|
await createFeatureToggle({
|
||||||
name: 'featureWithAppNameA',
|
name: 'featureWithAppNameA',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -396,19 +396,19 @@ test('should filter features by constraints', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend?appName=a')
|
.get('/api/frontend?appName=a')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => expect(res.body.toggles).toHaveLength(2));
|
.expect((res) => expect(res.body.toggles).toHaveLength(2));
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend?appName=b')
|
.get('/api/frontend?appName=b')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => expect(res.body.toggles).toHaveLength(1));
|
.expect((res) => expect(res.body.toggles).toHaveLength(1));
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend?appName=c')
|
.get('/api/frontend?appName=c')
|
||||||
.set('Authorization', proxyToken.secret)
|
.set('Authorization', frontendToken.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => expect(res.body.toggles).toHaveLength(0));
|
.expect((res) => expect(res.body.toggles).toHaveLength(0));
|
||||||
@ -419,11 +419,11 @@ test('should filter features by project', async () => {
|
|||||||
const projectB = 'projectB';
|
const projectB = 'projectB';
|
||||||
await createProject(projectA);
|
await createProject(projectA);
|
||||||
await createProject(projectB);
|
await createProject(projectB);
|
||||||
const proxyTokenDefault = await createApiToken(ApiTokenType.PROXY);
|
const frontendTokenDefault = await createApiToken(ApiTokenType.FRONTEND);
|
||||||
const proxyTokenProjectA = await createApiToken(ApiTokenType.PROXY, {
|
const frontendTokenProjectA = await createApiToken(ApiTokenType.FRONTEND, {
|
||||||
projects: [projectA],
|
projects: [projectA],
|
||||||
});
|
});
|
||||||
const proxyTokenProjectAB = await createApiToken(ApiTokenType.PROXY, {
|
const frontendTokenProjectAB = await createApiToken(ApiTokenType.FRONTEND, {
|
||||||
projects: [projectA, projectB],
|
projects: [projectA, projectB],
|
||||||
});
|
});
|
||||||
await createFeatureToggle({
|
await createFeatureToggle({
|
||||||
@ -445,7 +445,7 @@ test('should filter features by project', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyTokenDefault.secret)
|
.set('Authorization', frontendTokenDefault.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -462,7 +462,7 @@ test('should filter features by project', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyTokenProjectA.secret)
|
.set('Authorization', frontendTokenProjectA.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -479,7 +479,7 @@ test('should filter features by project', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyTokenProjectAB.secret)
|
.set('Authorization', frontendTokenProjectAB.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -521,15 +521,21 @@ test('should filter features by environment', async () => {
|
|||||||
environmentB,
|
environmentB,
|
||||||
'default',
|
'default',
|
||||||
);
|
);
|
||||||
const proxyTokenEnvironmentDefault = await createApiToken(
|
const frontendTokenEnvironmentDefault = await createApiToken(
|
||||||
ApiTokenType.PROXY,
|
ApiTokenType.FRONTEND,
|
||||||
|
);
|
||||||
|
const frontendTokenEnvironmentA = await createApiToken(
|
||||||
|
ApiTokenType.FRONTEND,
|
||||||
|
{
|
||||||
|
environment: environmentA,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const frontendTokenEnvironmentB = await createApiToken(
|
||||||
|
ApiTokenType.FRONTEND,
|
||||||
|
{
|
||||||
|
environment: environmentB,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const proxyTokenEnvironmentA = await createApiToken(ApiTokenType.PROXY, {
|
|
||||||
environment: environmentA,
|
|
||||||
});
|
|
||||||
const proxyTokenEnvironmentB = await createApiToken(ApiTokenType.PROXY, {
|
|
||||||
environment: environmentB,
|
|
||||||
});
|
|
||||||
await createFeatureToggle({
|
await createFeatureToggle({
|
||||||
name: 'featureInEnvironmentDefault',
|
name: 'featureInEnvironmentDefault',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -549,7 +555,7 @@ test('should filter features by environment', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyTokenEnvironmentDefault.secret)
|
.set('Authorization', frontendTokenEnvironmentDefault.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -566,7 +572,7 @@ test('should filter features by environment', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyTokenEnvironmentA.secret)
|
.set('Authorization', frontendTokenEnvironmentA.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
@ -583,7 +589,7 @@ test('should filter features by environment', async () => {
|
|||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/frontend')
|
.get('/api/frontend')
|
||||||
.set('Authorization', proxyTokenEnvironmentB.secret)
|
.set('Authorization', frontendTokenEnvironmentB.secret)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
4
src/test/fixtures/fake-api-token-store.ts
vendored
4
src/test/fixtures/fake-api-token-store.ts
vendored
@ -44,7 +44,9 @@ export default class FakeApiTokenStore
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAllActive(): Promise<IApiToken[]> {
|
async getAllActive(): Promise<IApiToken[]> {
|
||||||
return this.tokens.filter((token) => token.expiresAt > new Date());
|
return this.tokens.filter(
|
||||||
|
(token) => token.expiresAt === null || token.expiresAt > new Date(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async insert(newToken: IApiTokenCreate): Promise<IApiToken> {
|
async insert(newToken: IApiTokenCreate): Promise<IApiToken> {
|
||||||
|
Loading…
Reference in New Issue
Block a user