From 68ffb9e67dad51d82321226c6ef4aad7ad708ac7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 10 Oct 2023 10:10:27 +0200 Subject: [PATCH] frontend-app-api: reject undeclared attachments Signed-off-by: Patrik Oldsberg --- .changeset/five-hornets-provide.md | 5 +++ .../wiring/createExtensionInstance.test.ts | 43 +++++++++++++++++++ .../src/wiring/createExtensionInstance.ts | 9 ++++ 3 files changed, 57 insertions(+) create mode 100644 .changeset/five-hornets-provide.md diff --git a/.changeset/five-hornets-provide.md b/.changeset/five-hornets-provide.md new file mode 100644 index 0000000000..a422c5fbc8 --- /dev/null +++ b/.changeset/five-hornets-provide.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +The app will now reject any extensions that attach to nonexistent inputs. diff --git a/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts b/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts index 6550d76608..70f70368d3 100644 --- a/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts +++ b/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts @@ -250,6 +250,49 @@ describe('createExtensionInstance', () => { ); }); + it('should refuse to create an instance with undeclared inputs', () => { + expect(() => + createExtensionInstance({ + attachments: new Map([ + [ + 'declared', + [ + createExtensionInstance({ + attachments: new Map(), + config: { output: 'many1' }, + extension: simpleExtension, + }), + ], + ], + [ + 'undeclared', + [ + createExtensionInstance({ + attachments: new Map(), + config: { output: 'many1' }, + extension: simpleExtension, + }), + ], + ], + ]), + config: undefined, + extension: createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + declared: createExtensionInput({ + test: testDataRef, + }), + }, + output: {}, + factory() {}, + }), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', received undeclared input(s) 'undeclared'", + ); + }); + it('should refuse to create an instance with multiple inputs for required singleton', () => { expect(() => createExtensionInstance({ diff --git a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts b/packages/frontend-app-api/src/wiring/createExtensionInstance.ts index 9aec3078bc..ad3b858a60 100644 --- a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts +++ b/packages/frontend-app-api/src/wiring/createExtensionInstance.ts @@ -60,6 +60,15 @@ function resolveInputs( inputMap: AnyExtensionInputMap, attachments: Map, ) { + const undeclaredAttachments = Array.from(attachments.keys()).filter( + name => inputMap[name] === undefined, + ); + if (undeclaredAttachments.length > 0) { + throw new Error( + `received undeclared input(s) '${undeclaredAttachments.join("', '")}'`, + ); + } + return mapValues(inputMap, (input, inputName) => { const attachedInstances = attachments.get(inputName) ?? []; if (input.config.singleton) {