1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

chore: origin middleware (#7695)

https://linear.app/unleash/issue/2-2489/create-a-first-iteration-of-an-origin-middleware-that-logs-ui-and-api

Small spike around what the first iteration of an "origin middleware"
would look like.

No strong feelings all around, so feel free to tell me this is all wrong
and we should go a different route. However diving a little bit into it
personally helps me wrap my head around it, so it may help you too.
This commit is contained in:
Nuno Góis 2024-07-30 10:42:50 +01:00 committed by GitHub
parent d8e756586a
commit 50167d4f9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 106 additions and 1 deletions

View File

@ -144,6 +144,7 @@ exports[`should create default config 1`] = `
},
"migrationLock": true,
"navigationSidebar": true,
"originMiddleware": false,
"outdatedSdksBanner": false,
"parseProjectFromSession": false,
"personalAccessTokensKillSwitch": false,

View File

@ -30,6 +30,7 @@ import { catchAllErrorHandler } from './middleware/catch-all-error-handler';
import NotFoundError from './error/notfound-error';
import { bearerTokenMiddleware } from './middleware/bearer-token-middleware';
import { auditAccessMiddleware } from './middleware';
import { originMiddleware } from './middleware/origin-middleware';
export default async function getApp(
config: IUnleashConfig,
@ -177,6 +178,8 @@ export default async function getApp(
rbacMiddleware(config, stores, services.accessService),
);
app.use(`${baseUriPath}/api/admin`, originMiddleware(config));
app.use(`${baseUriPath}/api/admin`, auditAccessMiddleware(config));
app.use(
`${baseUriPath}/api/admin`,

View File

@ -0,0 +1,66 @@
import { originMiddleware } from './origin-middleware';
import type { IUnleashConfig } from '../types';
import { createTestConfig } from '../../test/config/test-config';
import type { Request, Response } from 'express';
const TEST_UNLEASH_TOKEN = 'TEST_UNLEASH_TOKEN';
const TEST_USER_AGENT = 'TEST_USER_AGENT';
describe('originMiddleware', () => {
const req = { headers: {}, path: '' } as Request;
const res = {} as Response;
const next = jest.fn();
const loggerMock = {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
fatal: jest.fn(),
};
const getLogger = jest.fn(() => loggerMock);
let config: IUnleashConfig;
beforeEach(() => {
config = createTestConfig({
getLogger,
experimental: {
flags: {
originMiddleware: true,
},
},
});
});
it('should call next', () => {
const middleware = originMiddleware(config);
middleware(req, res, next);
expect(next).toHaveBeenCalled();
});
it('should log UI request', () => {
const middleware = originMiddleware(config);
middleware(req, res, next);
expect(loggerMock.debug).toHaveBeenCalledWith('UI request', {
method: req.method,
});
});
it('should log API request', () => {
const middleware = originMiddleware(config);
req.headers.authorization = TEST_UNLEASH_TOKEN;
req.headers['user-agent'] = TEST_USER_AGENT;
middleware(req, res, next);
expect(loggerMock.debug).toHaveBeenCalledWith('API request', {
method: req.method,
userAgent: TEST_USER_AGENT,
});
});
});

View File

@ -0,0 +1,29 @@
import type { Request, Response, NextFunction } from 'express';
import type { IUnleashConfig } from '../types';
export const originMiddleware = ({
getLogger,
flagResolver,
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>) => {
const logger = getLogger('/middleware/origin-middleware.ts');
logger.debug('Enabling origin middleware');
return (req: Request, _: Response, next: NextFunction) => {
if (!flagResolver.isEnabled('originMiddleware')) {
return next();
}
const isUI = !req.headers.authorization;
if (isUI) {
logger.debug('UI request', { method: req.method });
} else {
logger.debug('API request', {
method: req.method,
userAgent: req.headers['user-agent'],
});
}
next();
};
};

View File

@ -70,7 +70,8 @@ export type IFlagKey =
| 'insightsV2'
| 'integrationEvents'
| 'featureCollaborators'
| 'improveCreateFlagFlow';
| 'improveCreateFlagFlow'
| 'originMiddleware';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@ -339,6 +340,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_IMPROVE_CREATE_FLAG_FLOW,
false,
),
originMiddleware: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_ORIGIN_MIDDLEWARE,
false,
),
};
export const defaultExperimentalOptions: IExperimentalOptions = {

View File

@ -60,6 +60,7 @@ process.nextTick(async () => {
integrationEvents: true,
featureCollaborators: true,
improveCreateFlagFlow: true,
originMiddleware: true,
},
},
authentication: {