packages/backend-plugin-api: updated PermissionsRegistryService to use rule accessors and resource refs

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-01-30 09:41:55 +01:00
parent b71f634e3b
commit 72cddf2971
8 changed files with 83 additions and 15 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-test-utils': patch
---
Added the new `getRuleAccessor` method to `mockServices.permissionsRegistry`.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-plugin-api': patch
'@backstage/backend-defaults': patch
---
Updated `PermissionsRegistryService` to use `PermissionResourceRef`s and added the `getRuleAccessor` method.
@@ -15,6 +15,7 @@
*/
import {
PermissionsRegistryService,
coreServices,
createServiceFactory,
} from '@backstage/backend-plugin-api';
@@ -52,7 +53,10 @@ export const permissionsRegistryServiceFactory = createServiceFactory({
'Cannot add permission resource types after the plugin has started',
);
}
router.addResourceType(resource);
router.addResourceType({
...resource,
resourceType: resource.resourceRef.resourceType,
});
},
addPermissions(permissions) {
if (started) {
@@ -70,6 +74,9 @@ export const permissionsRegistryServiceFactory = createServiceFactory({
}
router.addPermissionRules(rules);
},
};
getRuleAccessor(resourceRef) {
return router.getRuleAccessor(resourceRef);
},
} satisfies PermissionsRegistryService;
},
});
+18 -5
View File
@@ -19,7 +19,9 @@ 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 { PermissionResourceRef } from '@backstage/plugin-permission-node';
import { PermissionRule } from '@backstage/plugin-permission-node';
import { PermissionRuleAccessor } from '@backstage/plugin-permission-node';
import { QueryPermissionRequest } from '@backstage/plugin-permission-common';
import { QueryPermissionResponse } from '@backstage/plugin-permission-common';
import { Readable } from 'stream';
@@ -466,23 +468,34 @@ export interface LoggerService {
export interface PermissionsRegistryService {
addPermissionRules(rules: PermissionRule<any, any, string>[]): void;
addPermissions(permissions: Permission[]): void;
addResourceType<const TResourceType extends string, TResource>(
addResourceType<const TResourceType extends string, TResource, TQuery>(
options: PermissionsRegistryServiceAddResourceTypeOptions<
TResourceType,
TResource
TResource,
TQuery
>,
): void;
getRuleAccessor<TResourceType extends string, TResource, TQuery>(
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,
): PermissionRuleAccessor<TResource, TQuery, TResourceType>;
}
// @public
export type PermissionsRegistryServiceAddResourceTypeOptions<
TResourceType extends string,
TResource,
TQuery,
> = {
resourceType: TResourceType;
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>;
permissions?: Array<Permission>;
rules: PermissionRule<TResource, any, NoInfer_2<TResourceType>>[];
getResources?(resourceRefs: string[]): Promise<Array<TResource | undefined>>;
rules: PermissionRule<
NoInfer_2<TResource>,
NoInfer_2<TQuery>,
NoInfer_2<TResourceType>
>[];
getResources?(
resourceRefs: string[],
): Promise<Array<NoInfer_2<TResource> | undefined>>;
};
// @public
@@ -15,7 +15,11 @@
*/
import { Permission } from '@backstage/plugin-permission-common';
import { PermissionRule } from '@backstage/plugin-permission-node';
import {
PermissionResourceRef,
PermissionRule,
PermissionRuleAccessor,
} from '@backstage/plugin-permission-node';
/**
* Prevent use of type parameter from contributing to type inference.
@@ -33,11 +37,12 @@ type NoInfer<T> = T extends infer S ? S : never;
export type PermissionsRegistryServiceAddResourceTypeOptions<
TResourceType extends string,
TResource,
TQuery,
> = {
/**
* The identifier for the resource type.
* The {@link @backstage/plugin-permission-node#PermissionResourceRef} that identifies the resource type.
*/
resourceType: TResourceType;
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>;
/**
* Permissions that are available for this resource type.
@@ -47,7 +52,11 @@ export type PermissionsRegistryServiceAddResourceTypeOptions<
/**
* Permission rules that are available for this resource type.
*/
rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];
rules: PermissionRule<
NoInfer<TResource>,
NoInfer<TQuery>,
NoInfer<TResourceType>
>[];
/**
* The function used to load associated resources based in the provided
@@ -59,7 +68,9 @@ export type PermissionsRegistryServiceAddResourceTypeOptions<
* resolve conditional decisions except when requesting resources directly
* from the plugin.
*/
getResources?(resourceRefs: string[]): Promise<Array<TResource | undefined>>;
getResources?(
resourceRefs: string[],
): Promise<Array<NoInfer<TResource> | undefined>>;
};
/**
@@ -122,10 +133,22 @@ export interface PermissionsRegistryService {
* called by the `permission-backend` when authorization conditions relating
* to this plugin need to be evaluated.
*/
addResourceType<const TResourceType extends string, TResource>(
addResourceType<const TResourceType extends string, TResource, TQuery>(
options: PermissionsRegistryServiceAddResourceTypeOptions<
TResourceType,
TResource
TResource,
TQuery
>,
): void;
/**
* Returns a lookup function that can be used to look up rules for the provided resource by name.
*
* @remarks
*
* Primarily intended for use with {@link @backstage/plugin-permission-node#createConditionAuthorizer} and {@link @backstage/plugin-permission-node#createConditionTransformer}.
*/
getRuleAccessor<TResourceType extends string, TResource, TQuery>(
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,
): PermissionRuleAccessor<TResource, TQuery, TResourceType>;
}
@@ -489,6 +489,7 @@ export namespace mockServices {
addPermissionRules: jest.fn(),
addPermissions: jest.fn(),
addResourceType: jest.fn(),
getRuleAccessor: jest.fn(),
}));
}
+3
View File
@@ -173,6 +173,9 @@ export function createPermissionIntegrationRouter<
TResource
>,
): void;
getRuleAccessor<TResource, TQuery, TResourceType extends string>(
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,
): PermissionRuleAccessor<TResource, TQuery, TResourceType>;
};
// @public
@@ -30,7 +30,7 @@ import {
PermissionCriteria,
PolicyDecision,
} from '@backstage/plugin-permission-common';
import { PermissionRule } from '../types';
import { PermissionRule, PermissionRuleAccessor } from '../types';
import {
NoInfer,
createGetRule,
@@ -439,6 +439,9 @@ export function createPermissionIntegrationRouter<
TResource
>,
): void;
getRuleAccessor<TResource, TQuery, TResourceType extends string>(
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,
): PermissionRuleAccessor<TResource, TQuery, TResourceType>;
} {
const store = new PermissionIntegrationMetadataStore();
@@ -528,5 +531,12 @@ export function createPermissionIntegrationRouter<
) {
store.addResourceType(resource);
},
getRuleAccessor<TResource, TQuery, TResourceType extends string>(
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,
): PermissionRuleAccessor<TResource, TQuery, TResourceType> {
return store.getRuleMapper(
resourceRef.resourceType,
) as PermissionRuleAccessor<TResource, TQuery, TResourceType>;
},
});
}