backend-defaults: make permissionRegistry reject refs from other plugins

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-02-04 12:32:11 +01:00
parent 7500c99ecc
commit 2c7d35f844
2 changed files with 99 additions and 2 deletions
@@ -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<unknown, unknown>().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'"`,
);
});
});
@@ -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;