From cc94fbd3b3ebab0049a5df7148440e3d51ec2b07 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 20 Sep 2023 11:46:15 +0200 Subject: [PATCH] feat(frontend-app-api): prevent plugins overring root extensions Signed-off-by: Camila Belo --- .../src/wiring/createApp.test.tsx | 8 ++--- .../frontend-app-api/src/wiring/parameters.ts | 36 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index a2f42257f0..339948eec1 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -20,7 +20,7 @@ import { createInstances } from './createApp'; import { MockConfigApi } from '@backstage/test-utils'; describe('createInstances', () => { - it('throws an error when a root extension is overridden', () => { + it('throws an error when a root extension is parametrized', () => { const config = new MockConfigApi({ app: { extensions: [ @@ -39,11 +39,11 @@ describe('createInstances', () => { }), ]; expect(() => createInstances({ config, plugins })).toThrow( - 'There is a root extension in the app config file and root extensions are not configurable', + 'A "root" extension was detected on the config file and root extensions are not configurable', ); }); - it('throws an error when cyclical dependencies are found', () => { + it('throws an error when a root extension is overridden', () => { const config = new MockConfigApi({}); const plugins = [ createPlugin({ @@ -60,7 +60,7 @@ describe('createInstances', () => { }), ]; expect(() => createInstances({ config, plugins })).toThrow( - 'There is a cyclical dependency with the extension "core.layout": core.layout → core.routes → root → core.layout', + 'The following plugins are overriding root extensions and root extensions cannot be overridden: plugin', ); }); }); diff --git a/packages/frontend-app-api/src/wiring/parameters.ts b/packages/frontend-app-api/src/wiring/parameters.ts index b18853ab5c..1f4fda12e9 100644 --- a/packages/frontend-app-api/src/wiring/parameters.ts +++ b/packages/frontend-app-api/src/wiring/parameters.ts @@ -196,18 +196,30 @@ export function mergeExtensionParameters(options: { }): ExtensionInstanceParameters[] { const { sources, builtinExtensions, parameters } = options; + const pluginExtensions = sources.flatMap(source => + source.extensions.map(extension => ({ ...extension, source })), + ); + + // Prevent root override + if (pluginExtensions.some(({ id }) => id === 'root')) { + const rootPluginIds = pluginExtensions + .filter(({ id }) => id === 'root') + .map(({ source }) => source.id); + throw new Error( + `The following plugins are overriding root extensions and root extensions cannot be overridden: ${rootPluginIds}`, + ); + } + const overrides = [ - ...sources.flatMap(plugin => - plugin.extensions.map(extension => ({ - extension, - params: { - source: plugin, - at: extension.at, - disabled: extension.disabled, - config: undefined as unknown, - }, - })), - ), + ...pluginExtensions.map(({ source, ...extension }) => ({ + extension, + params: { + source, + at: extension.at, + disabled: extension.disabled, + config: undefined as unknown, + }, + })), ...builtinExtensions.map(extension => ({ extension, params: { @@ -225,7 +237,7 @@ export function mergeExtensionParameters(options: { // Prevent root parametrization if (extensionId === 'root') { throw new Error( - 'There is a root extension in the app config file and root extensions are not configurable', + 'A "root" extension was detected on the config file and root extensions are not configurable', ); }