From f1d32fb998d857408afcb193cf5c8aef46a30fb3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Aug 2023 16:21:59 +0200 Subject: [PATCH 1/7] backend-next: install proxy backend Signed-off-by: Patrik Oldsberg --- packages/backend-next/package.json | 1 + packages/backend-next/src/index.ts | 4 ++++ yarn.lock | 1 + 3 files changed, 6 insertions(+) diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index 38f85fb8c0..af4f483db0 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -42,6 +42,7 @@ "@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-search-backend": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", diff --git a/packages/backend-next/src/index.ts b/packages/backend-next/src/index.ts index fa7561e211..df3ce24618 100644 --- a/packages/backend-next/src/index.ts +++ b/packages/backend-next/src/index.ts @@ -39,6 +39,7 @@ import { devtoolsPlugin } from '@backstage/plugin-devtools-backend'; import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { adrPlugin } from '@backstage/plugin-adr-backend'; import { lighthousePlugin } from '@backstage/plugin-lighthouse-backend'; +import { proxyPlugin } from '@backstage/plugin-proxy-backend'; const backend = createBackend(); @@ -98,6 +99,9 @@ backend.add(kubernetesPlugin()); // Lighthouse backend.add(lighthousePlugin()); +// Proxy +backend.add(proxyPlugin()); + // Permissions backend.add(permissionPlugin()); backend.add(permissionModuleAllowAllPolicy()); diff --git a/yarn.lock b/yarn.lock index 1fb653e7bc..9e829b5a58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25172,6 +25172,7 @@ __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-search-backend": "workspace:^" "@backstage/plugin-search-backend-module-catalog": "workspace:^" From 7daf65bfcfa1be447d9a48bd1c935e5227dcc06c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Aug 2023 16:25:19 +0200 Subject: [PATCH 2/7] proxy-backend: deprecate root proxy config, move to proxy.endpoints instead Signed-off-by: Patrik Oldsberg --- .changeset/rotten-rabbits-move.md | 5 + plugins/proxy-backend/config.d.ts | 100 +++++++++++--------- plugins/proxy-backend/src/plugin.ts | 51 +++++----- plugins/proxy-backend/src/service/router.ts | 59 +++++++++++- 4 files changed, 137 insertions(+), 78 deletions(-) create mode 100644 .changeset/rotten-rabbits-move.md diff --git a/.changeset/rotten-rabbits-move.md b/.changeset/rotten-rabbits-move.md new file mode 100644 index 0000000000..f2e1ffda08 --- /dev/null +++ b/.changeset/rotten-rabbits-move.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-proxy-backend': minor +--- + +Defining proxy endpoints directly under the root `proxy` configuration key is deprecated. Endpoints should now be declared under `proxy.endpoints` instead. The `skipInvalidProxies` and `reviveConsumedRequestBodies` can now also be configured through static configuration. diff --git a/plugins/proxy-backend/config.d.ts b/plugins/proxy-backend/config.d.ts index bc9cf7765a..79e1cfcba6 100644 --- a/plugins/proxy-backend/config.d.ts +++ b/plugins/proxy-backend/config.d.ts @@ -15,51 +15,63 @@ */ export interface Config { - /** - * A list of forwarding-proxies. Each key is a route to match, - * below the prefix that the proxy plugin is mounted on. It must - * start with a '/'. - */ proxy?: { - [key: string]: - | string - | { - /** - * Target of the proxy. Url string to be parsed with the url module. - */ - target: string; - /** - * Object with extra headers to be added to target requests. - */ - headers?: { - /** @visibility secret */ - Authorization?: string; - /** @visibility secret */ - authorization?: string; - /** @visibility secret */ - 'X-Api-Key'?: string; - /** @visibility secret */ - 'x-api-key'?: string; - [key: string]: string | undefined; + /** + * Rather than failing to start up, the proxy backend will instead just warn on invalid endpoints. + */ + skipInvalidProxies?: boolean; + + /** + * Revive request bodies that have already been consumed by earlier middleware. + */ + reviveConsumedRequestBodies?: boolean; + + /** + * A list of forwarding-proxies. Each key is a route to match, + * below the prefix that the proxy plugin is mounted on. It must + * start with a '/'. + */ + endpoints?: { + [key: string]: + | string + | { + /** + * Target of the proxy. Url string to be parsed with the url module. + */ + target: string; + /** + * Object with extra headers to be added to target requests. + */ + headers?: { + /** @visibility secret */ + Authorization?: string; + /** @visibility secret */ + authorization?: string; + /** @visibility secret */ + 'X-Api-Key'?: string; + /** @visibility secret */ + 'x-api-key'?: string; + [key: string]: string | undefined; + }; + /** + * Changes the origin of the host header to the target URL. Default: true. + */ + changeOrigin?: boolean; + /** + * Rewrite target's url path. Object-keys will be used as RegExp to match paths. + * If pathRewrite is not specified, it is set to a single rewrite that removes the entire prefix and route. + */ + pathRewrite?: { [regexp: string]: string }; + /** + * Limit the forwarded HTTP methods, for example allowedMethods: ['GET'] to enforce read-only access. + */ + allowedMethods?: string[]; + /** + * Limit the forwarded HTTP methods. By default, only the headers that are considered safe for CORS + * and headers that are set by the proxy will be forwarded. + */ + allowedHeaders?: string[]; }; - /** - * Changes the origin of the host header to the target URL. Default: true. - */ - changeOrigin?: boolean; - /** - * Rewrite target's url path. Object-keys will be used as RegExp to match paths. - * If pathRewrite is not specified, it is set to a single rewrite that removes the entire prefix and route. - */ - pathRewrite?: { [regexp: string]: string }; - /** - * Limit the forwarded HTTP methods, for example allowedMethods: ['GET'] to enforce read-only access. - */ - allowedMethods?: string[]; - /** - * Limit the forwarded HTTP methods. By default, only the headers that are considered safe for CORS - * and headers that are set by the proxy will be forwarded. - */ - allowedHeaders?: string[]; - }; + }; }; } diff --git a/plugins/proxy-backend/src/plugin.ts b/plugins/proxy-backend/src/plugin.ts index c8dbdb4a08..e4c14b0037 100644 --- a/plugins/proxy-backend/src/plugin.ts +++ b/plugins/proxy-backend/src/plugin.ts @@ -26,32 +26,25 @@ import { createRouter } from './service/router'; * * @alpha */ -export const proxyPlugin = createBackendPlugin( - (options?: { - skipInvalidProxies?: boolean; - reviveConsumedRequestBodies?: boolean; - }) => ({ - pluginId: 'proxy', - register(env) { - env.registerInit({ - deps: { - config: coreServices.rootConfig, - discovery: coreServices.discovery, - logger: coreServices.logger, - httpRouter: coreServices.httpRouter, - }, - async init({ config, discovery, logger, httpRouter }) { - httpRouter.use( - await createRouter({ - config, - discovery, - logger: loggerToWinstonLogger(logger), - skipInvalidProxies: options?.skipInvalidProxies, - reviveConsumedRequestBodies: options?.reviveConsumedRequestBodies, - }), - ); - }, - }); - }, - }), -); +export const proxyPlugin = createBackendPlugin({ + pluginId: 'proxy', + register(env) { + env.registerInit({ + deps: { + config: coreServices.rootConfig, + discovery: coreServices.discovery, + logger: coreServices.logger, + httpRouter: coreServices.httpRouter, + }, + async init({ config, discovery, logger, httpRouter }) { + httpRouter.use( + await createRouter({ + config, + discovery, + logger: loggerToWinstonLogger(logger), + }), + ); + }, + }); + }, +}); diff --git a/plugins/proxy-backend/src/service/router.ts b/plugins/proxy-backend/src/service/router.ts index 6912965659..f8f6a3fdab 100644 --- a/plugins/proxy-backend/src/service/router.ts +++ b/plugins/proxy-backend/src/service/router.ts @@ -191,6 +191,37 @@ export function buildMiddleware( return createProxyMiddleware(filter, fullConfig); } +function readProxyConfig(config: Config, logger: Logger): unknown { + const endpoints = config.getOptional('proxy.endpoints'); + if (endpoints) { + if (typeof endpoints !== 'object' || Array.isArray(endpoints)) { + throw new Error('proxy configuration must be an object'); + } + return endpoints; + } + + const root = config.getOptional('proxy'); + if (!root) { + return {}; + } + if (typeof root !== 'object' || Array.isArray(root)) { + throw new Error('deprecated proxy configuration must be an object'); + } + + const rootEndpoints = Object.fromEntries( + Object.entries(root).filter(([key]) => key.startsWith('/')), + ); + if (Object.keys(rootEndpoints).length === 0) { + return {}; + } + + logger.warn( + "Configuring proxy endpoints in the root 'proxy' configuration is deprecated. Move this configuration to 'proxy.endpoints' instead.", + ); + + return rootEndpoints; +} + /** * Creates a new {@link https://expressjs.com/en/api.html#router | "express router"} that proxy each target configured under the `proxy` key of the config * @example @@ -215,25 +246,39 @@ export async function createRouter( const router = Router(); let currentRouter = Router(); + const skipInvalidProxies = + options.skipInvalidProxies ?? + options.config.getOptionalBoolean('proxy.skipInvalidProxies') ?? + false; + const reviveConsumedRequestBodies = + options.reviveConsumedRequestBodies ?? + options.config.getOptionalBoolean('proxy.reviveConsumedRequestBodies') ?? + false; + const proxyOptions = { + skipInvalidProxies, + reviveConsumedRequestBodies, + logger: options.logger, + }; + const externalUrl = await options.discovery.getExternalBaseUrl('proxy'); const { pathname: pathPrefix } = new URL(externalUrl); - const proxyConfig = options.config.getOptional('proxy') ?? {}; - configureMiddlewares(options, currentRouter, pathPrefix, proxyConfig); + const proxyConfig = readProxyConfig(options.config, options.logger); + configureMiddlewares(proxyOptions, currentRouter, pathPrefix, proxyConfig); router.use((...args) => currentRouter(...args)); if (options.config.subscribe) { let currentKey = JSON.stringify(proxyConfig); options.config.subscribe(() => { - const newProxyConfig = options.config.getOptional('proxy') ?? {}; + const newProxyConfig = readProxyConfig(options.config, options.logger); const newKey = JSON.stringify(newProxyConfig); if (currentKey !== newKey) { currentKey = newKey; currentRouter = Router(); configureMiddlewares( - options, + proxyOptions, currentRouter, pathPrefix, newProxyConfig, @@ -246,7 +291,11 @@ export async function createRouter( } function configureMiddlewares( - options: RouterOptions, + options: { + reviveConsumedRequestBodies: boolean; + skipInvalidProxies: boolean; + logger: Logger; + }, router: express.Router, pathPrefix: string, proxyConfig: any, From c7f8ad78f7e05782493555355ed3e697093fb787 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Aug 2023 16:25:30 +0200 Subject: [PATCH 3/7] app-config: move proxy endpoints to proxy.endpoints Signed-off-by: Patrik Oldsberg --- app-config.yaml | 123 ++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 8dcd052e61..e6195eefe3 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -49,80 +49,81 @@ backend: # See README.md in the proxy-backend plugin for information on the configuration format proxy: - '/circleci/api': - target: https://circleci.com/api/v1.1 - headers: - Circle-Token: ${CIRCLECI_AUTH_TOKEN} + endpoints: + '/circleci/api': + target: https://circleci.com/api/v1.1 + headers: + Circle-Token: ${CIRCLECI_AUTH_TOKEN} - '/jenkins/api': - target: http://localhost:8080 - headers: - Authorization: ${JENKINS_BASIC_AUTH_HEADER} + '/jenkins/api': + target: http://localhost:8080 + headers: + Authorization: ${JENKINS_BASIC_AUTH_HEADER} - '/travisci/api': - target: https://api.travis-ci.com - changeOrigin: true - headers: - Authorization: ${TRAVISCI_AUTH_TOKEN} - travis-api-version: '3' + '/travisci/api': + target: https://api.travis-ci.com + changeOrigin: true + headers: + Authorization: ${TRAVISCI_AUTH_TOKEN} + travis-api-version: '3' - '/newrelic/apm/api': - target: https://api.newrelic.com/v2 - headers: - X-Api-Key: ${NEW_RELIC_REST_API_KEY} + '/newrelic/apm/api': + target: https://api.newrelic.com/v2 + headers: + X-Api-Key: ${NEW_RELIC_REST_API_KEY} - '/newrelic/api': - target: https://api.newrelic.com - headers: - X-Api-Key: ${NEW_RELIC_USER_KEY} + '/newrelic/api': + target: https://api.newrelic.com + headers: + X-Api-Key: ${NEW_RELIC_USER_KEY} - '/pagerduty': - target: https://api.pagerduty.com - headers: - Authorization: Token token=${PAGERDUTY_TOKEN} + '/pagerduty': + target: https://api.pagerduty.com + headers: + Authorization: Token token=${PAGERDUTY_TOKEN} - '/buildkite/api': - target: https://api.buildkite.com/v2/ - headers: - Authorization: ${BUILDKITE_TOKEN} + '/buildkite/api': + target: https://api.buildkite.com/v2/ + headers: + Authorization: ${BUILDKITE_TOKEN} - '/sentry/api': - target: https://sentry.io/api/ - allowedMethods: ['GET'] - headers: - Authorization: ${SENTRY_TOKEN} + '/sentry/api': + target: https://sentry.io/api/ + allowedMethods: ['GET'] + headers: + Authorization: ${SENTRY_TOKEN} - '/ilert': - target: https://api.ilert.com - allowedMethods: ['GET', 'POST', 'PUT'] - allowedHeaders: ['Authorization'] - headers: - Authorization: ${ILERT_AUTH_HEADER} + '/ilert': + target: https://api.ilert.com + allowedMethods: ['GET', 'POST', 'PUT'] + allowedHeaders: ['Authorization'] + headers: + Authorization: ${ILERT_AUTH_HEADER} - '/airflow': - target: https://your.airflow.instance.com/api/v1 - headers: - Authorization: ${AIRFLOW_BASIC_AUTH_HEADER} + '/airflow': + target: https://your.airflow.instance.com/api/v1 + headers: + Authorization: ${AIRFLOW_BASIC_AUTH_HEADER} - '/gocd': - target: https://your.gocd.instance.com/go/api - allowedMethods: ['GET'] - allowedHeaders: ['Authorization'] - headers: - Authorization: Basic ${GOCD_AUTH_CREDENTIALS} + '/gocd': + target: https://your.gocd.instance.com/go/api + allowedMethods: ['GET'] + allowedHeaders: ['Authorization'] + headers: + Authorization: Basic ${GOCD_AUTH_CREDENTIALS} - '/dynatrace': - target: https://your.dynatrace.instance.com/api/v2 - headers: - Authorization: 'Api-Token ${DYNATRACE_ACCESS_TOKEN}' + '/dynatrace': + target: https://your.dynatrace.instance.com/api/v2 + headers: + Authorization: 'Api-Token ${DYNATRACE_ACCESS_TOKEN}' - '/stackstorm': - target: https://your.stackstorm.instance.com/api - headers: - St2-Api-Key: ${ST2_API_KEY} + '/stackstorm': + target: https://your.stackstorm.instance.com/api + headers: + St2-Api-Key: ${ST2_API_KEY} - '/puppetdb': - target: https://your.puppetdb.instance.com + '/puppetdb': + target: https://your.puppetdb.instance.com organization: name: My Company From 24450b8a40e0d68805ccc1aca86064f6c80befdb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Aug 2023 16:47:29 +0200 Subject: [PATCH 4/7] proxy-backend: update tests to use proxy.endpoints Signed-off-by: Patrik Oldsberg --- plugins/proxy-backend/package.json | 1 + .../src/service/router.config.test.ts | 75 +++++++++++-------- .../proxy-backend/src/service/router.test.ts | 26 ++++--- yarn.lock | 1 + 4 files changed, 61 insertions(+), 42 deletions(-) diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 56439cd0f3..d7eb3ad435 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -49,6 +49,7 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", + "@backstage/config-loader": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index 5f90f847e4..fffdcb5142 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -15,7 +15,11 @@ */ import { getVoidLogger, SingleHostDiscovery } from '@backstage/backend-common'; -import { ConfigReader } from '@backstage/config'; +import { + ConfigSources, + MutableConfigSource, + StaticConfigSource, +} from '@backstage/config-loader'; import express from 'express'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -56,34 +60,36 @@ describe('createRouter reloadable configuration', () => { const logger = getVoidLogger(); // Grab the subscriber function and use mutable config data to mock a config file change - let subscriber: () => void; - const mutableConfigData: any = { - backend: { - baseUrl: 'http://localhost:7007', - listen: { - port: 7007, - }, - }, - proxy: { - '/test': { - target: 'https://non-existing-example.com', - pathRewrite: { - '.*': '/', + const mutableConfigSource = MutableConfigSource.create({ data: {} }); + const config = await ConfigSources.toConfig( + ConfigSources.merge([ + StaticConfigSource.create({ + data: { + backend: { + baseUrl: 'http://localhost:7007', + listen: { + port: 7007, + }, + }, + proxy: { + endpoints: { + '/test': { + target: 'https://non-existing-example.com', + pathRewrite: { + '.*': '/', + }, + }, + }, + }, }, - }, - }, - }; + }), + mutableConfigSource, + ]), + ); - const mockConfig = Object.assign(new ConfigReader(mutableConfigData), { - subscribe: (s: () => void) => { - subscriber = s; - return { unsubscribe: () => {} }; - }, - }); - - const discovery = SingleHostDiscovery.fromConfig(mockConfig); + const discovery = SingleHostDiscovery.fromConfig(config); const router = await createRouter({ - config: mockConfig, + config, logger, discovery, }); @@ -100,13 +106,18 @@ describe('createRouter reloadable configuration', () => { expect(response1.status).toEqual(200); - mutableConfigData.proxy['/test2'] = { - target: 'https://non-existing-example.com', - pathRewrite: { - '.*': '/', + mutableConfigSource.setData({ + proxy: { + endpoints: { + '/test2': { + target: 'https://non-existing-example.com', + pathRewrite: { + '.*': '/', + }, + }, + }, }, - }; - subscriber!(); + }); const response2 = await agent.get('/test2'); diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 9e8c909d25..f69b0d38b7 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -45,10 +45,12 @@ describe('createRouter', () => { }, }, proxy: { - '/test': { - target: 'https://example.com', - headers: { - Authorization: 'Bearer supersecret', + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, @@ -112,9 +114,11 @@ describe('createRouter', () => { }, // no target would cause the buildMiddleware to fail proxy: { - '/test': { - headers: { - Authorization: 'Bearer supersecret', + endpoints: { + '/test': { + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, @@ -141,9 +145,11 @@ describe('createRouter', () => { }, // no target would cause the buildMiddleware to fail proxy: { - '/test': { - headers: { - Authorization: 'Bearer supersecret', + endpoints: { + '/test': { + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, diff --git a/yarn.lock b/yarn.lock index 9e829b5a58..33681796da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8055,6 +8055,7 @@ __metadata: "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/config-loader": "workspace:^" "@types/express": ^4.17.6 "@types/http-proxy-middleware": ^0.19.3 "@types/supertest": ^2.0.8 From 76a710edd9f4a70908f6602a1cef2355e64ea075 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Aug 2023 16:52:28 +0200 Subject: [PATCH 5/7] proxy-backend: add test for deprecated configuration Signed-off-by: Patrik Oldsberg --- plugins/proxy-backend/package.json | 1 + .../proxy-backend/src/service/router.test.ts | 27 +++++++++++++++++++ yarn.lock | 1 + 3 files changed, 29 insertions(+) diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index d7eb3ad435..959c946d55 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -48,6 +48,7 @@ "yup": "^0.32.9" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/config-loader": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index f69b0d38b7..2b58e52e94 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -15,6 +15,7 @@ */ import { getVoidLogger, SingleHostDiscovery } 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'; @@ -70,6 +71,32 @@ describe('createRouter', () => { expect(router).toBeDefined(); }); + it('supports deprecated proxy configuration', async () => { + const router = await createRouter({ + config: mockServices.rootConfig({ + data: { + proxy: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, + }, + }, + }, + }), + logger, + discovery, + }); + expect(router).toBeDefined(); + expect(mockCreateProxyMiddleware).toHaveBeenCalledWith( + expect.any(Function), + expect.objectContaining({ + target: 'https://example.com', + }), + ); + }); + it('revives request bodies when set', async () => { const router = await createRouter({ config, diff --git a/yarn.lock b/yarn.lock index 33681796da..7256f2b11d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8053,6 +8053,7 @@ __metadata: dependencies: "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/config-loader": "workspace:^" From 9995962c31c79fa0682ad9dd210e909d51c1b18d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 3 Aug 2023 11:49:01 +0200 Subject: [PATCH 6/7] proxy-backend: update API report Signed-off-by: Patrik Oldsberg --- plugins/proxy-backend/api-report.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plugins/proxy-backend/api-report.md b/plugins/proxy-backend/api-report.md index 12d799bdf7..9c5cf5f9ef 100644 --- a/plugins/proxy-backend/api-report.md +++ b/plugins/proxy-backend/api-report.md @@ -13,14 +13,7 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common'; export function createRouter(options: RouterOptions): Promise; // @alpha -export const proxyPlugin: ( - options?: - | { - skipInvalidProxies?: boolean | undefined; - reviveConsumedRequestBodies?: boolean | undefined; - } - | undefined, -) => BackendFeature; +export const proxyPlugin: () => BackendFeature; // @public (undocumented) export interface RouterOptions { From 44b1ab77e8a9efd38c78b0822256e5c775104cef Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 7 Aug 2023 11:33:03 +0200 Subject: [PATCH 7/7] proxy-backend: let config reader check for objects Signed-off-by: Patrik Oldsberg --- plugins/proxy-backend/src/service/router.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/proxy-backend/src/service/router.ts b/plugins/proxy-backend/src/service/router.ts index f8f6a3fdab..61fddb60ed 100644 --- a/plugins/proxy-backend/src/service/router.ts +++ b/plugins/proxy-backend/src/service/router.ts @@ -192,21 +192,15 @@ export function buildMiddleware( } function readProxyConfig(config: Config, logger: Logger): unknown { - const endpoints = config.getOptional('proxy.endpoints'); + const endpoints = config.getOptionalConfig('proxy.endpoints')?.get(); if (endpoints) { - if (typeof endpoints !== 'object' || Array.isArray(endpoints)) { - throw new Error('proxy configuration must be an object'); - } return endpoints; } - const root = config.getOptional('proxy'); + const root = config.getOptionalConfig('proxy')?.get(); if (!root) { return {}; } - if (typeof root !== 'object' || Array.isArray(root)) { - throw new Error('deprecated proxy configuration must be an object'); - } const rootEndpoints = Object.fromEntries( Object.entries(root).filter(([key]) => key.startsWith('/')),