diff --git a/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.test.ts new file mode 100644 index 0000000000..578c76378a --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2022 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 { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '@backstage/backend-test-utils'; +import { createPermissionResourceRef } from '@backstage/plugin-permission-node'; +import { permissionsRegistryServiceFactory } from './permissionsRegistryServiceFactory'; + +describe('permissionsRegistryServiceFactory', () => { + it('should reject resource refs from other plugins', async () => { + await expect( + startTestBackend({ + features: [ + permissionsRegistryServiceFactory, + createBackendPlugin({ + pluginId: 'test', + register(reg) { + reg.registerInit({ + deps: { permissionsRegistry: coreServices.permissionsRegistry }, + async init({ permissionsRegistry }) { + permissionsRegistry.addResourceType({ + resourceRef: createPermissionResourceRef< + unknown, + unknown + >().with({ + pluginId: 'other', + resourceType: 'some-resource', + }), + rules: [], + }); + }, + }); + }, + }), + ], + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Plugin 'test' startup failed; caused by Error: Resource type 'some-resource' belongs to plugin 'other', but was used with plugin 'test'"`, + ); + + await expect( + startTestBackend({ + features: [ + permissionsRegistryServiceFactory, + createBackendPlugin({ + pluginId: 'test', + register(reg) { + reg.registerInit({ + deps: { permissionsRegistry: coreServices.permissionsRegistry }, + async init({ permissionsRegistry }) { + permissionsRegistry.getPermissionRuleset( + createPermissionResourceRef().with({ + pluginId: 'other', + resourceType: 'some-resource', + }), + ); + }, + }); + }, + }), + ], + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Plugin 'test' startup failed; caused by Error: Resource type 'some-resource' belongs to plugin 'other', but was used with plugin 'test'"`, + ); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.ts b/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.ts index 993fb4e946..7ff6eabf03 100644 --- a/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.ts @@ -19,7 +19,18 @@ import { coreServices, createServiceFactory, } from '@backstage/backend-plugin-api'; -import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; +import { + PermissionResourceRef, + createPermissionIntegrationRouter, +} from '@backstage/plugin-permission-node'; + +function assertRefPluginId(ref: PermissionResourceRef, pluginId: string) { + if (ref.pluginId !== pluginId) { + throw new Error( + `Resource type '${ref.resourceType}' belongs to plugin '${ref.pluginId}', but was used with plugin '${pluginId}'`, + ); + } +} /** * Permission system integration for registering resources and permissions. @@ -35,9 +46,11 @@ export const permissionsRegistryServiceFactory = createServiceFactory({ deps: { lifecycle: coreServices.lifecycle, httpRouter: coreServices.httpRouter, + pluginMetadata: coreServices.pluginMetadata, }, - async factory({ httpRouter, lifecycle }) { + async factory({ httpRouter, lifecycle, pluginMetadata }) { const router = createPermissionIntegrationRouter(); + const pluginId = pluginMetadata.getId(); httpRouter.use(router); @@ -53,6 +66,7 @@ export const permissionsRegistryServiceFactory = createServiceFactory({ 'Cannot add permission resource types after the plugin has started', ); } + assertRefPluginId(resource.resourceRef, pluginId); router.addResourceType({ ...resource, resourceType: resource.resourceRef.resourceType, @@ -75,6 +89,7 @@ export const permissionsRegistryServiceFactory = createServiceFactory({ router.addPermissionRules(rules); }, getPermissionRuleset(resourceRef) { + assertRefPluginId(resourceRef, pluginId); return router.getPermissionRuleset(resourceRef); }, } satisfies PermissionsRegistryService;