backend-plugin-api: added PermissionsIntegrationsService definition

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-01-02 01:37:15 +01:00
parent 049d5d4676
commit 9ddfd94528
7 changed files with 169 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
Added new `PermissionIntegrationsService` that is used by plugins to register permissions, resource types, and rules into the permission system. This replaces the existing `createPermissionIntegrationRouter` from `@backstage/plugin-permission-node`.
+1
View File
@@ -58,6 +58,7 @@
"@backstage/errors": "workspace:^",
"@backstage/plugin-auth-node": "workspace:^",
"@backstage/plugin-permission-common": "workspace:^",
"@backstage/plugin-permission-node": "workspace:^",
"@backstage/types": "workspace:^",
"@types/express": "^4.17.6",
"@types/luxon": "^3.0.0",
+29
View File
@@ -16,8 +16,10 @@ import { isChildPath } from '@backstage/cli-common';
import { JsonObject } from '@backstage/types';
import { JsonValue } from '@backstage/types';
import { Knex } from 'knex';
import { Permission } from '@backstage/plugin-permission-common';
import { PermissionAttributes } from '@backstage/plugin-permission-common';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { PermissionRule } from '@backstage/plugin-permission-node';
import { QueryPermissionRequest } from '@backstage/plugin-permission-common';
import { QueryPermissionResponse } from '@backstage/plugin-permission-common';
import { Readable } from 'stream';
@@ -184,6 +186,11 @@ export namespace coreServices {
const lifecycle: ServiceRef<LifecycleService, 'plugin', 'singleton'>;
const logger: ServiceRef<LoggerService, 'plugin', 'singleton'>;
const permissions: ServiceRef<PermissionsService, 'plugin', 'singleton'>;
const permissionIntegrations: ServiceRef<
PermissionIntegrationsService,
'plugin',
'singleton'
>;
const pluginMetadata: ServiceRef<
PluginMetadataService,
'plugin',
@@ -425,6 +432,28 @@ export interface LoggerService {
warn(message: string, meta?: Error | JsonObject): void;
}
// @public
export interface PermissionIntegrationsService {
addPermissions(permissions: Permission[]): void;
addResourceType<const TResourceType extends string, TResource>(
options: PermissionIntegrationsServiceAddResourceTypeOptions<
TResourceType,
TResource
>,
): void;
}
// @public
export type PermissionIntegrationsServiceAddResourceTypeOptions<
TResourceType extends string,
TResource,
> = {
resourceType: TResourceType;
permissions?: Array<Permission>;
rules: PermissionRule<TResource, any, NoInfer_2<TResourceType>>[];
getResources?(resourceRefs: string[]): Promise<Array<TResource | undefined>>;
};
// @public
export interface PermissionsService extends PermissionEvaluator {
authorize(
@@ -0,0 +1,116 @@
/*
* 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 { Permission } from '@backstage/plugin-permission-common';
import { PermissionRule } from '@backstage/plugin-permission-node';
/**
* Prevent use of type parameter from contributing to type inference.
*
* https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795
* @ignore
*/
type NoInfer<T> = T extends infer S ? S : never;
/**
* Options for adding a resource type to the permission system.
*
* @public
*/
export type PermissionIntegrationsServiceAddResourceTypeOptions<
TResourceType extends string,
TResource,
> = {
/**
* The identifier for the resource type.
*/
resourceType: TResourceType;
/**
* Permissions that are available for this resource type.
*/
permissions?: Array<Permission>;
/**
* Permission rules that are available for this resource type.
*/
rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];
/**
* The function used to load associated resources based in the provided
* references.
*
* @remarks
*
* If this function is not provided the permission system will not be able to
* resolve conditional decisions except when requesting resources directly
* form the plugin.
*/
getResources?(resourceRefs: string[]): Promise<Array<TResource | undefined>>;
};
/**
* Permission system integration for registering resources and permissions.
*
* See the {@link https://backstage.io/docs/permissions/overview | permissions documentation}
* and the {@link https://backstage.io/docs/backend-system/core-services/permission-integrations | service documentation}
* for more details.
*
* @public
*/
export interface PermissionIntegrationsService {
/**
* Add permissions for this plugin to the permission system.
*/
addPermissions(permissions: Permission[]): void;
/**
* Add a new resource type that is owned by this plugin to the permission
* system.
*
* @remarks
*
* To make this concrete, we can use the Backstage software catalog as an
* example. The catalog has conditional rules around access to specific
* _entities_ in the catalog. The _type_ of resource is captured here as
* `resourceType`, a string identifier (`catalog-entity` in this example) that
* can be provided with permission definitions. This is merely a _type_ to
* verify that conditions in an authorization policy are constructed
* correctly, not a reference to a specific resource.
*
* The `rules` parameter is an array of
* {@link @backstage/plugin-permission-node#PermissionRule}s that introduce
* conditional filtering logic for resources; for the catalog, these are
* things like `isEntityOwner` or `hasAnnotation`. Rules describe how to
* filter a list of resources, and the `conditions` returned allow these rules
* to be applied with specific parameters (such as 'group:default/team-a', or
* 'backstage.io/edit-url').
*
* The `getResources` argument should load resources based on a reference
* identifier. For the catalog, this is an
* {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be
* any serialized format. This is used to add a permission integrations API
* via the HTTP router service. This API will be called by the
* `permission-backend` when authorization conditions relating to this plugin
* need to be evaluated.
*/
addResourceType<const TResourceType extends string, TResource>(
options: PermissionIntegrationsServiceAddResourceTypeOptions<
TResourceType,
TResource
>,
): void;
}
@@ -174,6 +174,19 @@ export namespace coreServices {
import('./PermissionsService').PermissionsService
>({ id: 'core.permissions' });
/**
* Permission system integration for registering resources and permissions.
*
* See {@link PermissionIntegrationsService}
* and {@link https://backstage.io/docs/backend-system/core-services/permission-integrations | the service docs}
* for more information.
*
* @public
*/
export const permissionIntegrations = createServiceRef<
import('./PermissionIntegrationsService').PermissionIntegrationsService
>({ id: 'core.permissionIntegrations' });
/**
* Built-in service for accessing metadata about the current plugin.
*
@@ -50,6 +50,10 @@ export type {
PermissionsService,
PermissionsServiceRequestOptions,
} from './PermissionsService';
export type {
PermissionIntegrationsService,
PermissionIntegrationsServiceAddResourceTypeOptions,
} from './PermissionIntegrationsService';
export type { PluginMetadataService } from './PluginMetadataService';
export type { RootHttpRouterService } from './RootHttpRouterService';
export type { RootLifecycleService } from './RootLifecycleService';
+1
View File
@@ -3774,6 +3774,7 @@ __metadata:
"@backstage/errors": "workspace:^"
"@backstage/plugin-auth-node": "workspace:^"
"@backstage/plugin-permission-common": "workspace:^"
"@backstage/plugin-permission-node": "workspace:^"
"@backstage/types": "workspace:^"
"@types/express": ^4.17.6
"@types/luxon": ^3.0.0