frontend-app-api: make it possible to configure which extensions are forbidden

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-10-18 19:18:10 +02:00
parent 5aad4f7720
commit 89dc1250d8
3 changed files with 61 additions and 10 deletions
@@ -40,7 +40,9 @@ export function createAppGraph(options: CreateAppGraphOptions): AppGraph {
features: options.features,
builtinExtensions: options.builtinExtensions,
parameters: readAppExtensionsConfig(options.config),
forbidden: new Set(['core']),
}),
'core',
);
instantiateAppNodeTree(appGraph.root);
return appGraph;
@@ -234,4 +234,45 @@ describe('resolveAppNodeSpecs', () => {
expect(result.map(r => r.extension.id)).toEqual(['b', 'c', 'a']);
});
it('throws an error when a forbidden extension is overridden by a plugin', () => {
expect(() =>
resolveAppNodeSpecs({
features: [
createPlugin({ id: 'test', extensions: [makeExt('forbidden')] }),
],
builtinExtensions: [],
parameters: [],
forbidden: new Set(['forbidden']),
}),
).toThrow(
"It is forbidden to override the following extension(s): 'forbidden', which is done by the following plugin(s): 'test'",
);
});
it('throws an error when a forbidden extension is overridden by overrides', () => {
expect(() =>
resolveAppNodeSpecs({
features: [
createExtensionOverrides({ extensions: [makeExt('forbidden')] }),
],
builtinExtensions: [],
parameters: [],
forbidden: new Set(['forbidden']),
}),
).toThrow(
"It is forbidden to override the following extension(s): 'forbidden', which is done by one or more extension overrides",
);
});
it('throws an error when a forbidden extension is parametrized', () => {
expect(() =>
resolveAppNodeSpecs({
features: [],
builtinExtensions: [],
parameters: [{ id: 'forbidden', disabled: false }],
forbidden: new Set(['forbidden']),
}),
).toThrow("Configuration of the 'forbidden' extension is forbidden");
});
});
@@ -29,8 +29,9 @@ export function resolveAppNodeSpecs(options: {
features: (BackstagePlugin | ExtensionOverrides)[];
builtinExtensions: Extension<unknown>[];
parameters: Array<ExtensionParameters>;
forbidden?: Set<string>;
}): AppNodeSpec[] {
const { builtinExtensions, parameters } = options;
const { builtinExtensions, parameters, forbidden = new Set() } = options;
const plugins = options.features.filter(
(f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin',
@@ -48,20 +49,21 @@ export function resolveAppNodeSpecs(options: {
);
// Prevent core override
if (pluginExtensions.some(({ id }) => id === 'core')) {
const pluginIds = pluginExtensions
.filter(({ id }) => id === 'core')
.map(({ source }) => source.id);
if (pluginExtensions.some(({ id }) => forbidden.has(id))) {
const pluginsStr = pluginExtensions
.filter(({ id }) => forbidden.has(id))
.map(({ source }) => `'${source.id}'`)
.join(', ');
const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', ');
throw new Error(
`The following plugin(s) are overriding the 'core' extension which is forbidden: ${pluginIds.join(
',',
)}`,
`It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by the following plugin(s): ${pluginsStr}`,
);
}
if (overrideExtensions.some(({ id }) => id === 'root')) {
if (overrideExtensions.some(({ id }) => forbidden.has(id))) {
const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', ');
throw new Error(
`An extension override is overriding the 'root' extension which is forbidden`,
`It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by one or more extension overrides`,
);
}
const overrideExtensionIds = overrideExtensions.map(({ id }) => id);
@@ -164,6 +166,12 @@ export function resolveAppNodeSpecs(options: {
for (const overrideParam of parameters) {
const extensionId = overrideParam.id;
if (forbidden.has(extensionId)) {
throw new Error(
`Configuration of the '${extensionId}' extension is forbidden`,
);
}
const existingIndex = configuredExtensions.findIndex(
e => e.extension.id === extensionId,
);