diff --git a/.changeset/olive-carrots-move.md b/.changeset/olive-carrots-move.md new file mode 100644 index 0000000000..b2cf4337b2 --- /dev/null +++ b/.changeset/olive-carrots-move.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-proxy-backend': minor +--- + +**BREAKING**: Removed support for the old backend system. + +As part of this change the plugin export from `/alpha` as been removed. If you are currently importing `@backstage/plugin-proxy-backend/alpha`, please update your import to `@backstage/plugin-proxy-backend`. diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index 45701ac660..e97f04a5ee 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -48,7 +48,6 @@ "@backstage/plugin-permission-backend": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", - "@backstage/plugin-proxy-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^", "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", diff --git a/packages/backend-legacy/src/index.ts b/packages/backend-legacy/src/index.ts index c883603efb..4632cddc56 100644 --- a/packages/backend-legacy/src/index.ts +++ b/packages/backend-legacy/src/index.ts @@ -42,7 +42,6 @@ import catalog from './plugins/catalog'; import events from './plugins/events'; import kubernetes from './plugins/kubernetes'; import scaffolder from './plugins/scaffolder'; -import proxy from './plugins/proxy'; import search from './plugins/search'; import techdocs from './plugins/techdocs'; import app from './plugins/app'; @@ -129,7 +128,6 @@ async function main() { const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder')); const authEnv = useHotMemoize(module, () => createEnv('auth')); - const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); const searchEnv = useHotMemoize(module, () => createEnv('search')); const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes')); @@ -145,7 +143,6 @@ async function main() { apiRouter.use('/search', await search(searchEnv)); apiRouter.use('/techdocs', await techdocs(techdocsEnv)); apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); - apiRouter.use('/proxy', await proxy(proxyEnv)); apiRouter.use('/permission', await permission(permissionEnv)); apiRouter.use(notFoundHandler()); diff --git a/packages/backend-legacy/src/plugins/proxy.ts b/packages/backend-legacy/src/plugins/proxy.ts deleted file mode 100644 index 273e791f1c..0000000000 --- a/packages/backend-legacy/src/plugins/proxy.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createRouter } from '@backstage/plugin-proxy-backend'; -import { Router } from 'express'; -import { PluginEnvironment } from '../types'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - return await createRouter({ - logger: env.logger, - config: env.config, - discovery: env.discovery, - }); -} diff --git a/plugins/proxy-backend/dev/index.ts b/plugins/proxy-backend/dev/index.ts index 4e4f84056a..e0e3f8fd43 100644 --- a/plugins/proxy-backend/dev/index.ts +++ b/plugins/proxy-backend/dev/index.ts @@ -19,7 +19,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; import { proxyEndpointsExtensionPoint } from '@backstage/plugin-proxy-node/alpha'; const backend = createBackend(); -backend.add(import('../src/alpha')); +backend.add(import('../src')); backend.add( createBackendModule({ diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index da550487c8..69978f2a4e 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -24,16 +24,12 @@ "license": "Apache-2.0", "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", "./package.json": "./package.json" }, "main": "src/index.ts", "types": "src/index.ts", "typesVersions": { "*": { - "alpha": [ - "src/alpha.ts" - ], "package.json": [ "package.json" ] @@ -53,21 +49,11 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-common": "^0.25.0", "@backstage/backend-plugin-api": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/plugin-proxy-node": "workspace:^", "@backstage/types": "workspace:^", - "@types/express": "^4.17.6", - "express": "^4.17.1", "express-promise-router": "^4.1.0", - "http-proxy-middleware": "^2.0.0", - "morgan": "^1.10.0", - "uuid": "^11.0.0", - "winston": "^3.2.1", - "yaml": "^2.0.0", - "yn": "^4.0.0", - "yup": "^1.0.0" + "http-proxy-middleware": "^2.0.0" }, "devDependencies": { "@backstage/backend-app-api": "workspace:^", @@ -76,8 +62,9 @@ "@backstage/cli": "workspace:^", "@backstage/config-loader": "workspace:^", "@backstage/errors": "workspace:^", + "@types/express": "^4.17.6", "@types/http-proxy-middleware": "^1.0.0", - "@types/yup": "^0.32.0", + "express": "^4.17.1", "msw": "^2.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/proxy-backend/report-alpha.api.md b/plugins/proxy-backend/report-alpha.api.md deleted file mode 100644 index 4b3b1dfdc6..0000000000 --- a/plugins/proxy-backend/report-alpha.api.md +++ /dev/null @@ -1,13 +0,0 @@ -## API Report File for "@backstage/plugin-proxy-backend" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { BackendFeature } from '@backstage/backend-plugin-api'; - -// @alpha (undocumented) -const _feature: BackendFeature; -export default _feature; - -// (No @packageDocumentation comment for this package) -``` diff --git a/plugins/proxy-backend/report.api.md b/plugins/proxy-backend/report.api.md index 90e7f54378..b0b38a8451 100644 --- a/plugins/proxy-backend/report.api.md +++ b/plugins/proxy-backend/report.api.md @@ -4,32 +4,8 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; -import { DiscoveryService } from '@backstage/backend-plugin-api'; -import express from 'express'; -import { Logger } from 'winston'; -import { ProxyConfig } from '@backstage/plugin-proxy-node/alpha'; -import { RootConfigService } from '@backstage/backend-plugin-api'; - -// @public @deprecated -export function createRouter(options: RouterOptions): Promise; // @public const proxyPlugin: BackendFeature; export default proxyPlugin; - -// @public @deprecated (undocumented) -export interface RouterOptions { - // (undocumented) - additionalEndpoints?: ProxyConfig; - // (undocumented) - config: RootConfigService; - // (undocumented) - discovery: DiscoveryService; - // (undocumented) - logger: Logger; - // (undocumented) - reviveConsumedRequestBodies?: boolean; - // (undocumented) - skipInvalidProxies?: boolean; -} ``` diff --git a/plugins/proxy-backend/src/alpha.ts b/plugins/proxy-backend/src/alpha.ts deleted file mode 100644 index 6efe450ac3..0000000000 --- a/plugins/proxy-backend/src/alpha.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { proxyPlugin } from './plugin'; - -/** @alpha */ -const _feature = proxyPlugin; -export default _feature; diff --git a/plugins/proxy-backend/src/index.ts b/plugins/proxy-backend/src/index.ts index ae0b6235f9..6383d3fa55 100644 --- a/plugins/proxy-backend/src/index.ts +++ b/plugins/proxy-backend/src/index.ts @@ -21,4 +21,3 @@ */ export { proxyPlugin as default } from './plugin'; -export * from './service'; diff --git a/plugins/proxy-backend/src/plugin.ts b/plugins/proxy-backend/src/plugin.ts index 52c1c26acd..6124b0bc66 100644 --- a/plugins/proxy-backend/src/plugin.ts +++ b/plugins/proxy-backend/src/plugin.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import { loggerToWinstonLogger } from '@backstage/backend-common'; import { createBackendPlugin, coreServices, } from '@backstage/backend-plugin-api'; -import { createRouterInternal } from './service/router'; +import { createRouter } from './service/router'; import { proxyEndpointsExtensionPoint } from '@backstage/plugin-proxy-node/alpha'; /** @@ -45,10 +44,10 @@ export const proxyPlugin = createBackendPlugin({ httpRouter: coreServices.httpRouter, }, async init({ config, discovery, logger, httpRouter }) { - await createRouterInternal({ + await createRouter({ config, discovery, - logger: loggerToWinstonLogger(logger), + logger, httpRouterService: httpRouter, additionalEndpoints, }); diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index d862107e00..6f81659ceb 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -60,7 +60,7 @@ describe('createRouter reloadable configuration', () => { const backend = await startTestBackend({ features: [ - import('../alpha'), + import('..'), createServiceFactory({ service: coreServices.rootConfig, deps: {}, diff --git a/plugins/proxy-backend/src/service/router.credentials.test.ts b/plugins/proxy-backend/src/service/router.credentials.test.ts index 6d1f529b30..6ed7e636ec 100644 --- a/plugins/proxy-backend/src/service/router.credentials.test.ts +++ b/plugins/proxy-backend/src/service/router.credentials.test.ts @@ -77,7 +77,7 @@ describe('credentials', () => { const backend = await startTestBackend({ features: [ - import('../alpha'), + import('..'), mockServices.rootConfig.factory({ data: config }), authServiceFactory, httpAuthServiceFactory, diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 8dcabed16b..66d6de2f28 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -14,12 +14,7 @@ * limitations under the License. */ -import { - HostDiscovery, - loggerToWinstonLogger, -} from '@backstage/backend-common'; import { mockServices } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; import { Request, Response } from 'express'; import * as http from 'http'; import { @@ -39,27 +34,37 @@ const mockCreateProxyMiddleware = createProxyMiddleware as jest.MockedFunction< >; describe('createRouter', () => { + const deps = { + logger: mockServices.logger.mock(), + discovery: mockServices.discovery(), + httpRouterService: mockServices.httpRouter.mock(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('where all proxy config are valid', () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - const config = new ConfigReader({ - backend: { - baseUrl: 'https://example.com:7007', - listen: { - port: 7007, + const config = mockServices.rootConfig({ + data: { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, + }, }, - }, - proxy: { - endpoints: { - '/test': { - target: 'https://example.com', - headers: { - Authorization: 'Bearer supersecret', + proxy: { + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, }, }); - const discovery = HostDiscovery.fromConfig(config); beforeEach(() => { mockCreateProxyMiddleware.mockClear(); @@ -67,29 +72,29 @@ describe('createRouter', () => { it('works', async () => { const router = await createRouter({ + ...deps, config, - logger, - discovery, }); expect(router).toBeDefined(); }); it('supports deprecated proxy configuration', async () => { const router = await createRouter({ + ...deps, config: mockServices.rootConfig({ data: { proxy: { - '/test': { - target: 'https://example.com', - headers: { - Authorization: 'Bearer supersecret', + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, }, }), - logger, - discovery, }); expect(router).toBeDefined(); expect(mockCreateProxyMiddleware).toHaveBeenCalledWith( @@ -102,10 +107,22 @@ describe('createRouter', () => { it('revives request bodies when set', async () => { const router = await createRouter({ - config, - logger, - discovery, - reviveConsumedRequestBodies: true, + ...deps, + config: mockServices.rootConfig({ + data: { + proxy: { + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, + }, + }, + reviveConsumedRequestBodies: true, + }, + }, + }), }); expect(router).toBeDefined(); @@ -120,8 +137,7 @@ describe('createRouter', () => { it('does not revive request bodies when not set', async () => { const router = await createRouter({ config, - logger, - discovery, + ...deps, }); expect(router).toBeDefined(); @@ -133,32 +149,30 @@ describe('createRouter', () => { describe('where buildMiddleware would fail', () => { it('throws an error if skip failures is not set', async () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - logger.warn = jest.fn(); - const config = new ConfigReader({ - backend: { - baseUrl: 'https://example.com:7007', - listen: { - port: 7007, + const config = mockServices.rootConfig({ + data: { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, + }, }, - }, - // no target would cause the buildMiddleware to fail - proxy: { - endpoints: { - '/test': { - headers: { - Authorization: 'Bearer supersecret', + // no target would cause the buildMiddleware to fail + proxy: { + endpoints: { + '/test': { + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, }, }); - const discovery = HostDiscovery.fromConfig(config); await expect( createRouter({ + ...deps, config, - logger, - discovery, }), ).rejects.toThrow( new Error( @@ -168,34 +182,32 @@ describe('createRouter', () => { }); it('works if skip failures is set', async () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - logger.warn = jest.fn(); - const config = new ConfigReader({ - backend: { - baseUrl: 'https://example.com:7007', - listen: { - port: 7007, - }, - }, - // no target would cause the buildMiddleware to fail - proxy: { - endpoints: { - '/test': { - headers: { - Authorization: 'Bearer supersecret', - }, + const config = mockServices.rootConfig({ + data: { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, }, }, + // no target would cause the buildMiddleware to fail + proxy: { + endpoints: { + '/test': { + headers: { + Authorization: 'Bearer supersecret', + }, + }, + }, + skipInvalidProxies: true, + }, }, }); - const discovery = HostDiscovery.fromConfig(config); const router = await createRouter({ + ...deps, config, - logger, - discovery, - skipInvalidProxies: true, }); - expect((logger.warn as jest.Mock).mock.calls[0][0]).toEqual( + expect(deps.logger.warn.mock.calls[0][0]).toEqual( 'skipped configuring /test due to Proxy target for route "/test" must be a string, but is of type undefined', ); expect(router).toBeDefined(); @@ -204,14 +216,21 @@ describe('createRouter', () => { }); describe('buildMiddleware', () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); + const logger = mockServices.logger.mock(); + const httpRouterService = mockServices.httpRouter.mock(); beforeEach(() => { mockCreateProxyMiddleware.mockClear(); }); it('accepts strings prefixed by /', async () => { - buildMiddleware('/proxy', logger, '/test', 'http://mocked'); + buildMiddleware( + '/proxy', + logger, + '/test', + 'http://mocked', + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -227,11 +246,20 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); + + expect(logger.info).not.toHaveBeenCalled(); + fullConfig.logProvider!({} as any).log('test'); + expect(logger.info).toHaveBeenCalledWith('test'); }); it('accepts routes not prefixed with / when path is not suffixed with /', async () => { - buildMiddleware('/proxy', logger, 'test', 'http://mocked'); + buildMiddleware( + '/proxy', + logger, + 'test', + 'http://mocked', + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -247,11 +275,16 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); }); it('accepts routes prefixed with / when path is suffixed with /', async () => { - buildMiddleware('/proxy/', logger, '/test', 'http://mocked'); + buildMiddleware( + '/proxy/', + logger, + '/test', + 'http://mocked', + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -267,14 +300,19 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); }); it('limits allowedMethods', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - allowedMethods: ['GET', 'DELETE'], - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + allowedMethods: ['GET', 'DELETE'], + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -290,13 +328,18 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); }); it('permits default headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -334,12 +377,18 @@ describe('buildMiddleware', () => { }); it('permits default and configured headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - headers: { - Authorization: 'my-token', + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + headers: { + Authorization: 'my-token', + }, }, - }); + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -367,10 +416,16 @@ describe('buildMiddleware', () => { }); it('permits configured headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - allowedHeaders: ['authorization', 'cookie'], - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + allowedHeaders: ['authorization', 'cookie'], + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -399,9 +454,15 @@ describe('buildMiddleware', () => { }); it('responds default headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -441,10 +502,16 @@ describe('buildMiddleware', () => { }); it('responds configured headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - allowedHeaders: ['set-cookie'], - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + allowedHeaders: ['set-cookie'], + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -477,6 +544,7 @@ describe('buildMiddleware', () => { { target: 'http://mocked', }, + httpRouterService, true, ); @@ -497,9 +565,15 @@ describe('buildMiddleware', () => { }); it('does not revive request body when not configured', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -511,10 +585,22 @@ describe('buildMiddleware', () => { it('rejects malformed target URLs', async () => { expect(() => - buildMiddleware('/proxy', logger, '/test', 'backstage.io'), + buildMiddleware( + '/proxy', + logger, + '/test', + 'backstage.io', + httpRouterService, + ), ).toThrow(/Proxy target is not a valid URL/); expect(() => - buildMiddleware('/proxy', logger, '/test', { target: 'backstage.io' }), + buildMiddleware( + '/proxy', + logger, + '/test', + { target: 'backstage.io' }, + httpRouterService, + ), ).toThrow(/Proxy target is not a valid URL/); }); }); diff --git a/plugins/proxy-backend/src/service/router.ts b/plugins/proxy-backend/src/service/router.ts index 934b1fcecb..a6a52db63a 100644 --- a/plugins/proxy-backend/src/service/router.ts +++ b/plugins/proxy-backend/src/service/router.ts @@ -14,20 +14,19 @@ * limitations under the License. */ -import { Config } from '@backstage/config'; -import express from 'express'; +import type express from 'express'; import Router from 'express-promise-router'; import { createProxyMiddleware, fixRequestBody, RequestHandler, } from 'http-proxy-middleware'; -import { Logger } from 'winston'; import http from 'http'; import { JsonObject } from '@backstage/types'; import { DiscoveryService, HttpRouterService, + LoggerService, RootConfigService, } from '@backstage/backend-plugin-api'; import { ProxyConfig } from '@backstage/plugin-proxy-node/alpha'; @@ -54,15 +53,13 @@ const safeForwardHeaders = [ ]; /** - * @public - * @deprecated Please migrate to the new backend system as this will be removed in the future. + * @internal */ export interface RouterOptions { - logger: Logger; + logger: LoggerService; config: RootConfigService; discovery: DiscoveryService; - skipInvalidProxies?: boolean; - reviveConsumedRequestBodies?: boolean; + httpRouterService: HttpRouterService; additionalEndpoints?: ProxyConfig; } @@ -70,11 +67,11 @@ export interface RouterOptions { // given config. export function buildMiddleware( pathPrefix: string, - logger: Logger, + logger: LoggerService, route: string, config: string | ProxyConfig, + httpRouterService: HttpRouterService, reviveConsumedRequestBodies?: boolean, - httpRouterService?: HttpRouterService, ): RequestHandler { let fullConfig: ProxyConfig; let credentialsPolicy: string; @@ -100,7 +97,7 @@ export function buildMiddleware( } if (credentialsPolicy === 'dangerously-allow-unauthenticated') { - httpRouterService?.addAuthPolicy({ + httpRouterService.addAuthPolicy({ path: route, allow: 'unauthenticated', }); @@ -154,7 +151,13 @@ export function buildMiddleware( } // Attach the logger to the proxy config - fullConfig.logProvider = () => logger; + fullConfig.logProvider = () => ({ + log: logger.info.bind(logger), + debug: logger.debug.bind(logger), + info: logger.info.bind(logger), + warn: logger.warn.bind(logger), + error: logger.error.bind(logger), + }); // http-proxy-middleware uses this log level to check if it should log the // requests that it proxies. Setting this to the most verbose log level // ensures that it always logs these requests. Our logger ends up deciding @@ -229,7 +232,10 @@ export function buildMiddleware( return createProxyMiddleware(filter, fullConfig); } -function readProxyConfig(config: Config, logger: Logger): JsonObject { +function readProxyConfig( + config: RootConfigService, + logger: LoggerService, +): JsonObject { const endpoints = config .getOptionalConfig('proxy.endpoints') ?.get(); @@ -256,49 +262,16 @@ function readProxyConfig(config: Config, logger: Logger): JsonObject { return rootEndpoints; } -/** - * Creates a new - * {@link https://expressjs.com/en/api.html#router | "express router"} that - * proxies each target configured under the `proxy.endpoints` key of the config. - * - * @remarks - * - * Example configuration: - * - * ```yaml - * proxy: - * endpoints: - * # Option 1: Simple URL String - * simple-example: http://simple.example.com:8080 - * # Option 2: `http-proxy-middleware` compatible object - * '/larger-example/v1': - * target: http://larger.example.com:8080/svc.v1 - * headers: - * Authorization: Bearer ${EXAMPLE_AUTH_TOKEN} - * ``` - * - * @see https://backstage.io/docs/plugins/proxying - * @public - * @deprecated Please migrate to the new backend system as this will be removed in the future. - */ +/** @internal */ export async function createRouter( options: RouterOptions, -): Promise { - return createRouterInternal(options); -} - -export async function createRouterInternal( - options: RouterOptions & { httpRouterService?: HttpRouterService }, ): Promise { const router = Router(); let currentRouter = Router(); const skipInvalidProxies = - options.skipInvalidProxies ?? - options.config.getOptionalBoolean('proxy.skipInvalidProxies') ?? - false; + options.config.getOptionalBoolean('proxy.skipInvalidProxies') ?? false; const reviveConsumedRequestBodies = - options.reviveConsumedRequestBodies ?? options.config.getOptionalBoolean('proxy.reviveConsumedRequestBodies') ?? false; const proxyOptions = { @@ -345,7 +318,7 @@ export async function createRouterInternal( }); } - options.httpRouterService?.use(router); + options.httpRouterService.use(router); return router; } @@ -353,12 +326,12 @@ function configureMiddlewares( options: { reviveConsumedRequestBodies: boolean; skipInvalidProxies: boolean; - logger: Logger; + logger: LoggerService; }, router: express.Router, pathPrefix: string, proxyConfig: ProxyConfig, - httpRouterService?: HttpRouterService, + httpRouterService: HttpRouterService, ) { Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => { try { @@ -369,8 +342,8 @@ function configureMiddlewares( options.logger, route, proxyRouteConfig, - options.reviveConsumedRequestBodies, httpRouterService, + options.reviveConsumedRequestBodies, ), ); } catch (e) { diff --git a/yarn.lock b/yarn.lock index 6df31ca425..b85ee80a51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7054,29 +7054,20 @@ __metadata: resolution: "@backstage/plugin-proxy-backend@workspace:plugins/proxy-backend" dependencies: "@backstage/backend-app-api": "workspace:^" - "@backstage/backend-common": ^0.25.0 "@backstage/backend-defaults": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" - "@backstage/config": "workspace:^" "@backstage/config-loader": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-proxy-node": "workspace:^" "@backstage/types": "workspace:^" "@types/express": ^4.17.6 "@types/http-proxy-middleware": ^1.0.0 - "@types/yup": ^0.32.0 express: ^4.17.1 express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 - morgan: ^1.10.0 msw: ^2.0.0 - uuid: ^11.0.0 - winston: ^3.2.1 - yaml: ^2.0.0 - yn: ^4.0.0 - yup: ^1.0.0 languageName: unknown linkType: soft @@ -20752,15 +20743,6 @@ __metadata: languageName: node linkType: hard -"@types/yup@npm:^0.32.0": - version: 0.32.0 - resolution: "@types/yup@npm:0.32.0" - dependencies: - yup: "*" - checksum: 5b30f1118bca288d949bcd4c7e17d1425ffa320eddd751a78c895b158fae0b6cbf242ced45ad47e9e70643c9475da09a7ad004192fb6f2111791d37e6a627e73 - languageName: node - linkType: hard - "@types/zen-observable@npm:^0.8.0": version: 0.8.7 resolution: "@types/zen-observable@npm:0.8.7" @@ -28684,7 +28666,6 @@ __metadata: "@backstage/plugin-permission-backend": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" - "@backstage/plugin-proxy-backend": "workspace:^" "@backstage/plugin-scaffolder-backend": "workspace:^" "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^" "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^" @@ -40224,13 +40205,6 @@ __metadata: languageName: node linkType: hard -"property-expr@npm:^2.0.5": - version: 2.0.6 - resolution: "property-expr@npm:2.0.6" - checksum: 89977f4bb230736c1876f460dd7ca9328034502fd92e738deb40516d16564b850c0bbc4e052c3df88b5b8cd58e51c93b46a94bea049a3f23f4a022c038864cab - languageName: node - linkType: hard - "property-information@npm:^5.0.0": version: 5.6.0 resolution: "property-information@npm:5.6.0" @@ -44997,13 +44971,6 @@ __metadata: languageName: node linkType: hard -"tiny-case@npm:^1.0.3": - version: 1.0.3 - resolution: "tiny-case@npm:1.0.3" - checksum: 3f7a30c39d5b0e1bc097b0b271bec14eb5b836093db034f35a0de26c14422380b50dc12bfd37498cf35b192f5df06f28a710712c87ead68872a9e37ad6f6049d - languageName: node - linkType: hard - "tiny-glob@npm:0.2.9": version: 0.2.9 resolution: "tiny-glob@npm:0.2.9" @@ -45149,13 +45116,6 @@ __metadata: languageName: node linkType: hard -"toposort@npm:^2.0.2": - version: 2.0.2 - resolution: "toposort@npm:2.0.2" - checksum: d64c74b570391c9432873f48e231b439ee56bc49f7cb9780b505cfdf5cb832f808d0bae072515d93834dd6bceca5bb34448b5b4b408335e4d4716eaf68195dcb - languageName: node - linkType: hard - "tosource@npm:^2.0.0-alpha.3": version: 2.0.0-alpha.3 resolution: "tosource@npm:2.0.0-alpha.3" @@ -47844,18 +47804,6 @@ __metadata: languageName: node linkType: hard -"yup@npm:*, yup@npm:^1.0.0": - version: 1.4.0 - resolution: "yup@npm:1.4.0" - dependencies: - property-expr: ^2.0.5 - tiny-case: ^1.0.3 - toposort: ^2.0.2 - type-fest: ^2.19.0 - checksum: 20a2ee0c1e891979ca16b34805b3a3be9ab4bea6ea3d2f9005b998b4dc992d0e4d7b53e5f4d8d9423420046630fb44fdf0ecf7e83bc34dd83392bca046c5229d - languageName: node - linkType: hard - "zen-observable@npm:^0.10.0": version: 0.10.0 resolution: "zen-observable@npm:0.10.0"