From 8805f938d534283dc1e193d4501e41f2a26c9684 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 8 Jan 2025 11:03:59 +0100 Subject: [PATCH] catalog-backend: add support for permission integrations service + test Signed-off-by: Patrik Oldsberg --- .changeset/loud-walls-build.md | 5 ++ plugins/catalog-backend/report.api.md | 2 + .../src/service/CatalogBuilder.ts | 19 ++++- .../src/service/CatalogPlugin.test.ts | 71 +++++++++++++++++++ .../src/service/CatalogPlugin.ts | 3 + 5 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 .changeset/loud-walls-build.md create mode 100644 plugins/catalog-backend/src/service/CatalogPlugin.test.ts diff --git a/.changeset/loud-walls-build.md b/.changeset/loud-walls-build.md new file mode 100644 index 0000000000..28a6ef3e0b --- /dev/null +++ b/.changeset/loud-walls-build.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +The catalog backend now supports the new `PermissionIntegrationsService`, which can be used to add custom permission rules. diff --git a/plugins/catalog-backend/report.api.md b/plugins/catalog-backend/report.api.md index ea7e11d0d7..db7a4818be 100644 --- a/plugins/catalog-backend/report.api.md +++ b/plugins/catalog-backend/report.api.md @@ -49,6 +49,7 @@ import { locationSpecToMetadataName as locationSpecToMetadataName_2 } from '@bac import { LoggerService } from '@backstage/backend-plugin-api'; import { Permission } from '@backstage/plugin-permission-common'; import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; +import { PermissionIntegrationsService } from '@backstage/backend-plugin-api'; import { PermissionRule } from '@backstage/plugin-permission-node'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { PermissionsService } from '@backstage/backend-plugin-api'; @@ -198,6 +199,7 @@ export type CatalogEnvironment = { config: RootConfigService; reader: UrlReaderService; permissions: PermissionsService | PermissionAuthorizer; + permissionIntegrations?: PermissionIntegrationsService; scheduler?: SchedulerService; discovery?: DiscoveryService; auth?: AuthService; diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 7ce308e796..ab3751eb90 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -114,6 +114,7 @@ import { RootConfigService, UrlReaderService, SchedulerService, + PermissionIntegrationsService, } from '@backstage/backend-plugin-api'; import { entitiesResponseToObjects } from './response'; @@ -136,6 +137,7 @@ export type CatalogEnvironment = { config: RootConfigService; reader: UrlReaderService; permissions: PermissionsService | PermissionAuthorizer; + permissionIntegrations?: PermissionIntegrationsService; scheduler?: SchedulerService; discovery?: DiscoveryService; auth?: AuthService; @@ -478,6 +480,7 @@ export class CatalogBuilder { logger, permissions, scheduler, + permissionIntegrations, discovery = HostDiscovery.fromConfig(config), } = this.env; @@ -554,7 +557,8 @@ export class CatalogBuilder { permissionsService, createConditionTransformer(this.permissionRules), ); - const permissionIntegrationRouter = createPermissionIntegrationRouter({ + + const catalogPermissionResource = { resourceType: RESOURCE_TYPE_CATALOG_ENTITY, getResources: async (resourceRefs: string[]) => { const { entities } = await unauthorizedEntitiesCatalog.entities({ @@ -584,7 +588,18 @@ export class CatalogBuilder { }, permissions: this.permissions, rules: this.permissionRules, - }); + } as const; + + let permissionIntegrationRouter: + | ReturnType + | undefined; + if (permissionIntegrations) { + permissionIntegrations.addResourceType(catalogPermissionResource); + } else { + permissionIntegrationRouter = createPermissionIntegrationRouter( + catalogPermissionResource, + ); + } const locationStore = new DefaultLocationStore(dbClient); const configLocationProvider = new ConfigLocationEntityProvider(config); diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.test.ts b/plugins/catalog-backend/src/service/CatalogPlugin.test.ts new file mode 100644 index 0000000000..3390f9c901 --- /dev/null +++ b/plugins/catalog-backend/src/service/CatalogPlugin.test.ts @@ -0,0 +1,71 @@ +/* + * 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 request from 'supertest'; +import { startTestBackend } from '@backstage/backend-test-utils'; +import { catalogPlugin } from './CatalogPlugin'; +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { createCatalogPermissionRule } from '../permissions'; + +describe('catalogPlugin', () => { + it('should support custom permission rules', async () => { + const { server } = await startTestBackend({ + features: [ + catalogPlugin, + createBackendModule({ + pluginId: 'catalog', + moduleId: 'custom-rules', + register(reg) { + reg.registerInit({ + deps: { + permissionIntegrations: coreServices.permissionIntegrations, + }, + async init({ permissionIntegrations }) { + permissionIntegrations.addPermissionRules([ + createCatalogPermissionRule({ + name: 'test', + resourceType: 'catalog-entity', + description: 'Test permission rule', + apply() { + return true; + }, + toQuery() { + return { key: 'test' }; + }, + }), + ]); + }, + }); + }, + }), + ], + }); + + const res = await request(server).get( + '/api/catalog/.well-known/backstage/permissions/metadata', + ); + + expect(res.status).toBe(200); + expect(res.body.rules).toContainEqual({ + name: 'test', + resourceType: 'catalog-entity', + paramsSchema: expect.any(Object), + description: 'Test permission rule', + }); + }); +}); diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index 4da0b612cd..c076f68980 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -227,6 +227,7 @@ export const catalogPlugin = createBackendPlugin({ config: coreServices.rootConfig, reader: coreServices.urlReader, permissions: coreServices.permissions, + permissionIntegrations: coreServices.permissionIntegrations, database: coreServices.database, httpRouter: coreServices.httpRouter, lifecycle: coreServices.rootLifecycle, @@ -242,6 +243,7 @@ export const catalogPlugin = createBackendPlugin({ reader, database, permissions, + permissionIntegrations, httpRouter, lifecycle, scheduler, @@ -254,6 +256,7 @@ export const catalogPlugin = createBackendPlugin({ config, reader, permissions, + permissionIntegrations, database, scheduler, logger,